1/*************************************************************************************** 2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3* Copyright (c) 2020-2021 Peng Cheng Laboratory 4* 5* XiangShan is licensed under Mulan PSL v2. 6* You can use this software according to the terms and conditions of the Mulan PSL v2. 7* You may obtain a copy of Mulan PSL v2 at: 8* http://license.coscl.org.cn/MulanPSL2 9* 10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13* 14* See the Mulan PSL v2 for more details. 15***************************************************************************************/ 16 17package top 18 19import chisel3._ 20import chisel3.util._ 21import xiangshan._ 22import utils._ 23import system._ 24import device._ 25import chisel3.stage.ChiselGeneratorAnnotation 26import chipsalliance.rocketchip.config._ 27import device.{AXI4Plic, DebugModule, TLTimer} 28import freechips.rocketchip.diplomacy._ 29import freechips.rocketchip.tilelink._ 30import freechips.rocketchip.amba.axi4._ 31import freechips.rocketchip.devices.tilelink._ 32import freechips.rocketchip.diplomaticobjectmodel.logicaltree.GenericLogicalTreeNode 33import freechips.rocketchip.interrupts._ 34import freechips.rocketchip.jtag.JTAGIO 35import freechips.rocketchip.tile.{BusErrorUnit, BusErrorUnitParams, XLen} 36import freechips.rocketchip.tilelink 37import freechips.rocketchip.util.{ElaborationArtefacts, HasRocketChipStageUtils} 38import huancun.debug.TLLogger 39import huancun.{HCCacheParamsKey, HuanCun} 40import freechips.rocketchip.devices.debug.{DebugIO, ResetCtrlIO} 41 42class XSCoreWithL2()(implicit p: Parameters) extends LazyModule 43 with HasXSParameter with HasSoCParameter { 44 private val core = LazyModule(new XSCore) 45 private val busPMU = BusPerfMonitor(enable = !debugOpts.FPGAPlatform) 46 private val l2cacheOpt = coreParams.L2CacheParamsOpt.map(l2param => 47 LazyModule(new HuanCun()(new Config((_, _, _) => { 48 case HCCacheParamsKey => l2param 49 }))) 50 ) 51 // (icache/ptw/dcache) => l2 or mem 52 private val l1_xbar = TLXbar() 53 54 val memory_port = TLIdentityNode() 55 val uncache = TLXbar() 56 57 if (coreParams.dcacheParametersOpt.nonEmpty) { 58 busPMU := TLLogger(s"L2_L1D_$hardId", !debugOpts.FPGAPlatform) := core.memBlock.dcache.clientNode 59 } 60 busPMU := core.frontend.icache.clientNode 61 if (!coreParams.softPTW) { 62 busPMU := core.ptw.node 63 } 64 l1_xbar :=* busPMU 65 l2cacheOpt match { 66 case Some(l2) => 67 val l2_binder = BankBinder(coreParams.L2NBanks, 64) 68 memory_port :=* l2_binder :*= l2.node :*= l1_xbar 69 case None => 70 memory_port := l1_xbar 71 } 72 73 uncache := TLBuffer() := core.frontend.instrUncache.clientNode 74 uncache := TLBuffer() := core.memBlock.uncache.clientNode 75 76 lazy val module = new LazyModuleImp(this) { 77 val io = IO(new Bundle { 78 val hartId = Input(UInt(64.W)) 79 val externalInterrupt = new ExternalInterruptIO 80 val l1plus_error, icache_error, dcache_error = new L1CacheErrorInfo 81 }) 82 83 core.module.io.hartId := io.hartId 84 core.module.io.externalInterrupt := io.externalInterrupt 85 86 io.l1plus_error <> core.module.io.l1plus_error 87 io.icache_error <> core.module.io.icache_error 88 io.dcache_error <> core.module.io.dcache_error 89 90 val core_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 91 core.module.reset := core_reset_gen.io.out 92 93 val l2_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 94 l2cacheOpt.foreach( _.module.reset := l2_reset_gen.io.out) 95 } 96} 97 98abstract class BaseXSSoc()(implicit p: Parameters) extends LazyModule 99 with HasSoCParameter 100 with BindingScope 101{ 102 val bankedNode = BankBinder(L3NBanks, L3BlockSize) 103 val peripheralXbar = TLXbar() 104 val l3_xbar = TLXbar() 105 lazy val dts = DTS(bindingTree) 106 lazy val json = JSON(bindingTree) 107} 108 109// We adapt the following three traits from rocket-chip. 110// Source: rocket-chip/src/main/scala/subsystem/Ports.scala 111trait HaveSlaveAXI4Port { 112 this: BaseXSSoc => 113 114 val idBits = 14 115 116 val l3FrontendAXI4Node = AXI4MasterNode(Seq(AXI4MasterPortParameters( 117 Seq(AXI4MasterParameters( 118 name = "dma", 119 id = IdRange(0, 1 << idBits) 120 )) 121 ))) 122 private val errorDevice = LazyModule(new TLError( 123 params = DevNullParams( 124 address = Seq(AddressSet(0x0, 0x7fffffffL)), 125 maxAtomic = 8, 126 maxTransfer = 64), 127 beatBytes = L3InnerBusWidth / 8 128 )) 129 private val error_xbar = TLXbar() 130 131 error_xbar := 132 TLFIFOFixer() := 133 TLWidthWidget(16) := 134 AXI4ToTL() := 135 AXI4UserYanker(Some(1)) := 136 AXI4Fragmenter() := 137 AXI4IdIndexer(1) := 138 l3FrontendAXI4Node 139 errorDevice.node := error_xbar 140 l3_xbar := 141 TLBuffer() := 142 error_xbar 143 144 val dma = InModuleBody { 145 l3FrontendAXI4Node.makeIOs() 146 } 147} 148 149trait HaveAXI4MemPort { 150 this: BaseXSSoc => 151 val device = new MemoryDevice 152 // 40-bit physical address 153 val memRange = AddressSet(0x00000000L, 0xffffffffffL).subtract(AddressSet(0x0L, 0x7fffffffL)) 154 val memAXI4SlaveNode = AXI4SlaveNode(Seq( 155 AXI4SlavePortParameters( 156 slaves = Seq( 157 AXI4SlaveParameters( 158 address = memRange, 159 regionType = RegionType.UNCACHED, 160 executable = true, 161 supportsRead = TransferSizes(1, L3BlockSize), 162 supportsWrite = TransferSizes(1, L3BlockSize), 163 interleavedId = Some(0), 164 resources = device.reg("mem") 165 ) 166 ), 167 beatBytes = L3OuterBusWidth / 8 168 ) 169 )) 170 171 val mem_xbar = TLXbar() 172 mem_xbar :=* TLBuffer() :=* TLCacheCork() :=* bankedNode 173 memAXI4SlaveNode := 174 AXI4UserYanker() := 175 AXI4Deinterleaver(L3BlockSize) := 176 TLToAXI4() := 177 TLWidthWidget(L3OuterBusWidth / 8) := 178 mem_xbar 179 180 val memory = InModuleBody { 181 memAXI4SlaveNode.makeIOs() 182 } 183} 184 185 186trait HaveAXI4PeripheralPort { this: BaseXSSoc => 187 // on-chip devices: 0x3800_0000 - 0x3fff_ffff 0x0000_0000 - 0x0000_0fff 188 val onChipPeripheralRange = AddressSet(0x38000000L, 0x07ffffffL) 189 val uartRange = AddressSet(0x40600000, 0xf) 190 val uartDevice = new SimpleDevice("serial", Seq("xilinx,uartlite")) 191 val uartParams = AXI4SlaveParameters( 192 address = Seq(uartRange), 193 regionType = RegionType.UNCACHED, 194 supportsRead = TransferSizes(1, 8), 195 supportsWrite = TransferSizes(1, 8), 196 resources = uartDevice.reg 197 ) 198 val peripheralRange = AddressSet( 199 0x0, 0x7fffffff 200 ).subtract(onChipPeripheralRange).flatMap(x => x.subtract(uartRange)) 201 val peripheralNode = AXI4SlaveNode(Seq(AXI4SlavePortParameters( 202 Seq(AXI4SlaveParameters( 203 address = peripheralRange, 204 regionType = RegionType.UNCACHED, 205 supportsRead = TransferSizes(1, 8), 206 supportsWrite = TransferSizes(1, 8), 207 interleavedId = Some(0) 208 ), uartParams), 209 beatBytes = 8 210 ))) 211 212 peripheralNode := 213 AXI4UserYanker() := 214 AXI4Deinterleaver(8) := 215 TLToAXI4() := 216 peripheralXbar 217 218 val peripheral = InModuleBody { 219 peripheralNode.makeIOs() 220 } 221 222} 223 224class XSTop()(implicit p: Parameters) extends XSTopWithoutDMA 225 with HaveSlaveAXI4Port 226 227class XSTopWithoutDMA()(implicit p: Parameters) extends BaseXSSoc() 228 with HaveAXI4MemPort 229 with HaveAXI4PeripheralPort 230{ 231 ResourceBinding { 232 val width = ResourceInt(2) 233 val model = "freechips,rocketchip-unknown" 234 Resource(ResourceAnchors.root, "model").bind(ResourceString(model)) 235 Resource(ResourceAnchors.root, "compat").bind(ResourceString(model + "-dev")) 236 Resource(ResourceAnchors.soc, "compat").bind(ResourceString(model + "-soc")) 237 Resource(ResourceAnchors.root, "width").bind(width) 238 Resource(ResourceAnchors.soc, "width").bind(width) 239 Resource(ResourceAnchors.cpus, "width").bind(ResourceInt(1)) 240 def bindManagers(xbar: TLNexusNode) = { 241 ManagerUnification(xbar.edges.in.head.manager.managers).foreach{ manager => 242 manager.resources.foreach(r => r.bind(manager.toResource)) 243 } 244 } 245 bindManagers(l3_xbar.asInstanceOf[TLNexusNode]) 246 bindManagers(peripheralXbar.asInstanceOf[TLNexusNode]) 247 } 248 249 println(s"FPGASoC cores: $NumCores banks: $L3NBanks block size: $L3BlockSize bus size: $L3OuterBusWidth") 250 251 val core_with_l2 = soc.cores.map(coreParams => 252 LazyModule(new XSCoreWithL2()(p.alterPartial({ 253 case XSCoreParamsKey => coreParams 254 }))) 255 ) 256 257 for (i <- 0 until NumCores) { 258 peripheralXbar := TLBuffer() := core_with_l2(i).uncache 259 val l2_l3_pmu = BusPerfMonitor(enable = !debugOpts.FPGAPlatform) 260 l3_xbar :=* TLBuffer() :=* TLLogger(s"L3_L2_$i", !debugOpts.FPGAPlatform) :=* l2_l3_pmu :=* core_with_l2(i).memory_port 261 } 262 263 val clint = LazyModule(new CLINT(CLINTParams(0x38000000L), 8)) 264 clint.node := peripheralXbar 265 266 val clintIntSinks = Array.fill(NumCores){ 267 val clintSink = LazyModule(new IntSinkNodeToModule(2)) 268 clintSink.sinkNode := clint.intnode 269 clintSink 270 } 271 272 val fakeTreeNode = new GenericLogicalTreeNode 273 val beu = LazyModule( 274 new BusErrorUnit(new XSL1BusErrors(NumCores), BusErrorUnitParams(0x38010000), fakeTreeNode)) 275 beu.node := peripheralXbar 276 277 class IntSinkNodeToModule(val sinks: Int)(implicit p: Parameters) extends LazyModule { 278 val sinkNode = IntSinkNode(IntSinkPortSimple(1, sinks)) 279 lazy val module = new LazyModuleImp(this){ 280 val out = IO(Output(Vec(sinks, Bool()))) 281 out.zip(sinkNode.in.head._1).foreach{ case (o, i) => o := i } 282 } 283 } 284 285 class IntSourceNodeToModule(val num: Int)(implicit p: Parameters) extends LazyModule { 286 val sourceNode = IntSourceNode(IntSourcePortSimple(num, ports = 1, sources = 1)) 287 lazy val module = new LazyModuleImp(this){ 288 val in = IO(Input(Vec(num, Bool()))) 289 in.zip(sourceNode.out.head._1).foreach{ case (i, s) => s := i } 290 } 291 } 292 293 val plic = LazyModule(new TLPLIC(PLICParams(0x3c000000L), 8)) 294 val plicSource = LazyModule(new IntSourceNodeToModule(NrExtIntr)) 295 val plicIntSinks = Array.fill(NumCores){ 296 val plicSink = LazyModule(new IntSinkNodeToModule(1)) 297 plicSink.sinkNode := plic.intnode 298 plicSink 299 } 300 plic.intnode := beu.intNode 301 plic.intnode := plicSource.sourceNode 302 303 plic.node := peripheralXbar 304 305 val l3cacheOpt = soc.L3CacheParamsOpt.map(l3param => 306 LazyModule(new HuanCun()(new Config((_, _, _) => { 307 case HCCacheParamsKey => l3param 308 }))) 309 ) 310 val l3_mem_pmu = BusPerfMonitor(enable = !debugOpts.FPGAPlatform) 311 312 l3cacheOpt match { 313 case Some(l3) => 314 bankedNode :*= TLLogger("MEM_L3", !debugOpts.FPGAPlatform) :*= l3_mem_pmu :*= l3.node :*= TLBuffer() :*= l3_xbar 315 case None => bankedNode :*= TLAdapterNode() :*= l3_xbar 316 } 317 318 val debugModule = LazyModule(new DebugModule(NumCores)(p)) 319 debugModule.debug.node := peripheralXbar 320 val debugIntSink = Array.fill(NumCores){ 321 val debugSink = LazyModule(new IntSinkNodeToModule(1)) 322 debugSink.sinkNode := debugModule.debug.dmOuter.dmOuter.intnode 323 debugSink 324 } 325 debugModule.debug.dmInner.dmInner.sb2tlOpt.foreach { sb2tl => 326 l3_xbar := TLBuffer() := TLWidthWidget(1) := sb2tl.node 327 } 328 329 lazy val module = new LazyRawModuleImp(this) { 330 ElaborationArtefacts.add("dts", dts) 331 ElaborationArtefacts.add("graphml", graphML) 332 ElaborationArtefacts.add("json", json) 333 ElaborationArtefacts.add("plusArgs", freechips.rocketchip.util.PlusArgArtefacts.serialize_cHeader()) 334 335 val io = IO(new Bundle { 336 val clock = Input(Bool()) 337 val reset = Input(Bool()) 338 val sram_config = Input(UInt(5.W)) 339 val osc_clock = Input(Bool()) 340 val pll_output = Output(UInt(14.W)) 341 val extIntrs = Input(UInt(NrExtIntr.W)) 342 // val meip = Input(Vec(NumCores, Bool())) 343 val ila = if(debugOpts.FPGAPlatform && EnableILA) Some(Output(new ILABundle)) else None 344 val systemjtag = new Bundle { 345 val jtag = Flipped(new JTAGIO(hasTRSTn = false)) 346 val reset = Input(Bool()) // No reset allowed on top 347 val mfr_id = Input(UInt(11.W)) 348 val part_number = Input(UInt(16.W)) 349 val version = Input(UInt(4.W)) 350 } 351 // val resetCtrl = new ResetCtrlIO(NumCores)(p) 352 }) 353 io.pll_output := DontCare 354 dontTouch(io.sram_config) 355 dontTouch(io.osc_clock) 356 dontTouch(io.pll_output) 357 childClock := io.clock.asClock() 358 359 withClockAndReset(childClock, io.reset) { 360 val resetGen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 361 resetGen.suggestName("top_reset_gen") 362 childReset := resetGen.io.out | debugModule.module.io.debugIO.ndreset 363 } 364 365 withClockAndReset(childClock, childReset) { 366 plicSource.module.in := io.extIntrs.asBools() 367 368 for (i <- 0 until NumCores) { 369 val core_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 370 core_reset_gen.suggestName(s"core_${i}_reset_gen") 371 core_with_l2(i).module.reset := core_reset_gen.io.out 372 core_with_l2(i).module.io.hartId := i.U 373 core_with_l2(i).module.io.externalInterrupt.msip := clintIntSinks(i).module.out(0) 374 core_with_l2(i).module.io.externalInterrupt.mtip := clintIntSinks(i).module.out(1) 375 core_with_l2(i).module.io.externalInterrupt.meip := plicIntSinks(i).module.out(0) 376 core_with_l2(i).module.io.externalInterrupt.debug := debugIntSink(i).module.out(0) 377 beu.module.io.errors.l1plus(i) := core_with_l2(i).module.io.l1plus_error 378 beu.module.io.errors.icache(i) := core_with_l2(i).module.io.icache_error 379 beu.module.io.errors.dcache(i) := core_with_l2(i).module.io.dcache_error 380 } 381 382 if (l3cacheOpt.nonEmpty) { 383 val l3_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 384 l3_reset_gen.suggestName("l3_reset_gen") 385 l3cacheOpt.get.module.reset := l3_reset_gen.io.out 386 } 387 // TODO: wrap this in a module 388 val freq = 100 389 val cnt = RegInit(freq.U) 390 val tick = cnt === 0.U 391 cnt := Mux(tick, freq.U, cnt - 1.U) 392 clint.module.io.rtcTick := tick 393 394 debugModule.module.io.resetCtrl.hartIsInReset.foreach {x => x := childReset.asBool() } 395 debugModule.module.io.clock := io.clock 396 debugModule.module.io.reset := io.reset 397 398 debugModule.module.io.debugIO.reset := io.systemjtag.reset // TODO: use synchronizer? 399 debugModule.module.io.debugIO.clock := childClock 400 debugModule.module.io.debugIO.dmactiveAck := debugModule.module.io.debugIO.dmactive // TODO: delay 3 cycles? 401 // jtag connector 402 debugModule.module.io.debugIO.systemjtag.foreach { x => 403 x.jtag <> io.systemjtag.jtag 404 x.reset := io.systemjtag.reset 405 x.mfr_id := io.systemjtag.mfr_id 406 x.part_number := io.systemjtag.part_number 407 x.version := io.systemjtag.version 408 } 409 } 410 } 411} 412 413object TopMain extends App with HasRocketChipStageUtils { 414 override def main(args: Array[String]): Unit = { 415 val (config, firrtlOpts) = ArgParser.parse(args) 416 val soc = DisableMonitors(p => LazyModule(new XSTop()(p)))(config) 417 XiangShanStage.execute(firrtlOpts, Seq( 418 ChiselGeneratorAnnotation(() => { 419 soc.module 420 }) 421 )) 422 ElaborationArtefacts.files.foreach{ case (extension, contents) => 423 writeOutputFile("./build", s"XSTop.${extension}", contents()) 424 } 425 } 426} 427