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, TLTimer, DebugModule} 28import firrtl.stage.RunFirrtlTransformAnnotation 29import freechips.rocketchip.diplomacy._ 30import freechips.rocketchip.tilelink._ 31import freechips.rocketchip.amba.axi4._ 32import freechips.rocketchip.devices.tilelink._ 33import freechips.rocketchip.diplomaticobjectmodel.logicaltree.GenericLogicalTreeNode 34import freechips.rocketchip.interrupts._ 35import freechips.rocketchip.stage.phases.GenerateArtefacts 36import freechips.rocketchip.jtag.JTAGIO 37import freechips.rocketchip.tile.{BusErrorUnit, BusErrorUnitParams, XLen} 38import freechips.rocketchip.tilelink 39import freechips.rocketchip.util.{ElaborationArtefacts, HasRocketChipStageUtils} 40import freechips.rocketchip.devices.debug.{DebugIO, ResetCtrlIO} 41import sifive.blocks.inclusivecache.{CacheParameters, InclusiveCache, InclusiveCacheMicroParameters} 42import xiangshan.cache.prefetch.L2Prefetcher 43 44 45 46class XSCoreWithL2()(implicit p: Parameters) extends LazyModule 47 with HasXSParameter with HasSoCParameter { 48 private val core = LazyModule(new XSCore) 49 private val l2prefetcher = LazyModule(new L2Prefetcher()) 50 private val busPMU = BusPerfMonitor(enable = true) 51 private val l2cache = if (useFakeL2Cache) null else LazyModule(new InclusiveCache( 52 CacheParameters( 53 level = 2, 54 ways = L2NWays, 55 sets = L2NSets, 56 blockBytes = L2BlockSize, 57 beatBytes = L1BusWidth / 8, // beatBytes = l1BusDataWidth / 8 58 cacheName = s"L2", 59 uncachedGet = true, 60 enablePerf = false 61 ), 62 InclusiveCacheMicroParameters( 63 memCycles = 25, 64 writeBytes = 32 65 ), 66 fpga = debugOpts.FPGAPlatform 67 )) 68 if(!useFakeL2Cache) { 69 ResourceBinding { 70 Resource(l2cache.device, "reg").bind(ResourceAddress(hardId)) 71 } 72 } 73 74 val memory_port = TLIdentityNode() 75 val uncache = TLXbar() 76 77 if (!useFakeDCache) { 78 busPMU := TLBuffer() := core.memBlock.dcache.clientNode 79 } 80 if (!useFakeL1plusCache) { 81 busPMU := TLBuffer() := core.l1pluscache.clientNode 82 } 83 if (!useFakePTW) { 84 busPMU := TLBuffer() := core.ptw.node 85 } 86 busPMU := TLBuffer() := l2prefetcher.clientNode 87 if (useFakeL2Cache) { 88 memory_port := TLXbar() :=* busPMU 89 } 90 else { 91 memory_port := l2cache.node := TLBuffer() := TLXbar() :=* busPMU 92 } 93 94 uncache := TLBuffer() := core.frontend.instrUncache.clientNode 95 uncache := TLBuffer() := core.memBlock.uncache.clientNode 96 97 lazy val module = new LazyModuleImp(this) { 98 val io = IO(new Bundle { 99 val hartId = Input(UInt(64.W)) 100 val externalInterrupt = new ExternalInterruptIO 101 val l1plus_error, icache_error, dcache_error = new L1CacheErrorInfo 102 }) 103 104 core.module.io.hartId := io.hartId 105 core.module.io.externalInterrupt := io.externalInterrupt 106 l2prefetcher.module.io.enable := core.module.io.l2_pf_enable 107 if (useFakeL2Cache) { 108 l2prefetcher.module.io.in := DontCare 109 } 110 else { 111 l2prefetcher.module.io.in <> l2cache.module.io 112 } 113 io.l1plus_error <> core.module.io.l1plus_error 114 io.icache_error <> core.module.io.icache_error 115 io.dcache_error <> core.module.io.dcache_error 116 117 val core_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 118 core.module.reset := core_reset_gen.io.out 119 120 val l2_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 121 l2prefetcher.module.reset := l2_reset_gen.io.out 122 if (!useFakeL2Cache) { 123 l2cache.module.reset := l2_reset_gen.io.out 124 } 125 } 126} 127 128abstract class BaseXSSoc()(implicit p: Parameters) extends LazyModule 129 with HasSoCParameter 130 with BindingScope 131{ 132 val bankedNode = BankBinder(L3NBanks, L3BlockSize) 133 val peripheralXbar = TLXbar() 134 val l3_xbar = TLXbar() 135 lazy val dts = DTS(bindingTree) 136 lazy val json = JSON(bindingTree) 137} 138 139// We adapt the following three traits from rocket-chip. 140// Source: rocket-chip/src/main/scala/subsystem/Ports.scala 141trait HaveSlaveAXI4Port { 142 this: BaseXSSoc => 143 144 val idBits = 16 145 146 val l3FrontendAXI4Node = AXI4MasterNode(Seq(AXI4MasterPortParameters( 147 Seq(AXI4MasterParameters( 148 name = "dma", 149 id = IdRange(0, 1 << idBits) 150 )) 151 ))) 152 private val errorDevice = LazyModule(new TLError( 153 params = DevNullParams( 154 address = Seq(AddressSet(0x0, 0x7fffffffL)), 155 maxAtomic = 8, 156 maxTransfer = 64), 157 beatBytes = L3InnerBusWidth / 8 158 )) 159 private val error_xbar = TLXbar() 160 161 error_xbar := 162 AXI4ToTL() := 163 AXI4UserYanker(Some(1)) := 164 AXI4Fragmenter() := 165 AXI4IdIndexer(1) := 166 l3FrontendAXI4Node 167 errorDevice.node := error_xbar 168 l3_xbar := 169 TLBuffer() := 170 error_xbar 171 172 val dma = InModuleBody { 173 l3FrontendAXI4Node.makeIOs() 174 } 175} 176 177trait HaveAXI4MemPort { 178 this: BaseXSSoc => 179 val device = new MemoryDevice 180 // 40-bit physical address 181 val memRange = AddressSet(0x00000000L, 0xffffffffffL).subtract(AddressSet(0x0L, 0x7fffffffL)) 182 val memAXI4SlaveNode = AXI4SlaveNode(Seq( 183 AXI4SlavePortParameters( 184 slaves = Seq( 185 AXI4SlaveParameters( 186 address = memRange, 187 regionType = RegionType.UNCACHED, 188 executable = true, 189 supportsRead = TransferSizes(1, L3BlockSize), 190 supportsWrite = TransferSizes(1, L3BlockSize), 191 interleavedId = Some(0), 192 resources = device.reg("mem") 193 ) 194 ), 195 beatBytes = L3OuterBusWidth / 8 196 ) 197 )) 198 199 val mem_xbar = TLXbar() 200 mem_xbar :=* TLBuffer() :=* TLCacheCork() :=* bankedNode 201 memAXI4SlaveNode := 202 AXI4UserYanker() := 203 AXI4Deinterleaver(L3BlockSize) := 204 TLToAXI4() := 205 TLWidthWidget(L3OuterBusWidth / 8) := 206 mem_xbar 207 208 val memory = InModuleBody { 209 memAXI4SlaveNode.makeIOs() 210 } 211} 212 213 214trait HaveAXI4PeripheralPort { this: BaseXSSoc => 215 // on-chip devices: 0x3800_0000 - 0x3fff_ffff 0x0000_0000 - 0x0000_0fff 216 val onChipPeripheralRange = AddressSet(0x38000000L, 0x07ffffffL) 217 val uartRange = AddressSet(0x40600000, 0xf) 218 val uartDevice = new SimpleDevice("serial", Seq("xilinx,uartlite")) 219 val uartParams = AXI4SlaveParameters( 220 address = Seq(uartRange), 221 regionType = RegionType.UNCACHED, 222 supportsRead = TransferSizes(1, 8), 223 supportsWrite = TransferSizes(1, 8), 224 resources = uartDevice.reg 225 ) 226 val peripheralRange = AddressSet( 227 0x0, 0x7fffffff 228 ).subtract(onChipPeripheralRange).flatMap(x => x.subtract(uartRange)) 229 val peripheralNode = AXI4SlaveNode(Seq(AXI4SlavePortParameters( 230 Seq(AXI4SlaveParameters( 231 address = peripheralRange, 232 regionType = RegionType.UNCACHED, 233 supportsRead = TransferSizes(1, 8), 234 supportsWrite = TransferSizes(1, 8), 235 interleavedId = Some(0) 236 ), uartParams), 237 beatBytes = 8 238 ))) 239 240 peripheralNode := 241 AXI4UserYanker() := 242 AXI4Deinterleaver(8) := 243 TLToAXI4() := 244 peripheralXbar 245 246 val peripheral = InModuleBody { 247 peripheralNode.makeIOs() 248 } 249 250} 251 252class XSTop()(implicit p: Parameters) extends XSTopWithoutDMA 253 with HaveSlaveAXI4Port 254 255class XSTopWithoutDMA()(implicit p: Parameters) extends BaseXSSoc() 256 with HaveAXI4MemPort 257 with HaveAXI4PeripheralPort 258{ 259 ResourceBinding { 260 val width = ResourceInt(2) 261 val model = "freechips,rocketchip-unknown" 262 Resource(ResourceAnchors.root, "model").bind(ResourceString(model)) 263 Resource(ResourceAnchors.root, "compat").bind(ResourceString(model + "-dev")) 264 Resource(ResourceAnchors.soc, "compat").bind(ResourceString(model + "-soc")) 265 Resource(ResourceAnchors.root, "width").bind(width) 266 Resource(ResourceAnchors.soc, "width").bind(width) 267 Resource(ResourceAnchors.cpus, "width").bind(ResourceInt(1)) 268 def bindManagers(xbar: TLNexusNode) = { 269 ManagerUnification(xbar.edges.in.head.manager.managers).foreach{ manager => 270 manager.resources.foreach(r => r.bind(manager.toResource)) 271 } 272 } 273 bindManagers(l3_xbar.asInstanceOf[TLNexusNode]) 274 bindManagers(peripheralXbar.asInstanceOf[TLNexusNode]) 275 } 276 277 println(s"FPGASoC cores: $NumCores banks: $L3NBanks block size: $L3BlockSize bus size: $L3OuterBusWidth") 278 279 val core_with_l2 = soc.cores.map(coreParams => 280 LazyModule(new XSCoreWithL2()(p.alterPartial({ 281 case XSCoreParamsKey => coreParams 282 }))) 283 ) 284 285 for (i <- 0 until NumCores) { 286 peripheralXbar := TLBuffer() := core_with_l2(i).uncache 287 l3_xbar := TLBuffer() := core_with_l2(i).memory_port 288 } 289 290 val clint = LazyModule(new CLINT(CLINTParams(0x38000000L), 8)) 291 clint.node := peripheralXbar 292 293 val clintIntSinks = Array.fill(NumCores){ 294 val clintSink = LazyModule(new IntSinkNodeToModule(2)) 295 clintSink.sinkNode := clint.intnode 296 clintSink 297 } 298 299 val fakeTreeNode = new GenericLogicalTreeNode 300 val beu = LazyModule( 301 new BusErrorUnit(new XSL1BusErrors(NumCores), BusErrorUnitParams(0x38010000), fakeTreeNode)) 302 beu.node := peripheralXbar 303 304 class IntSinkNodeToModule(val sinks: Int)(implicit p: Parameters) extends LazyModule { 305 val sinkNode = IntSinkNode(IntSinkPortSimple(1, sinks)) 306 lazy val module = new LazyModuleImp(this){ 307 val out = IO(Output(Vec(sinks, Bool()))) 308 out.zip(sinkNode.in.head._1).foreach{ case (o, i) => o := i } 309 } 310 } 311 312 class IntSourceNodeToModule(val num: Int)(implicit p: Parameters) extends LazyModule { 313 val sourceNode = IntSourceNode(IntSourcePortSimple(num, ports = 1, sources = 1)) 314 lazy val module = new LazyModuleImp(this){ 315 val in = IO(Input(Vec(num, Bool()))) 316 in.zip(sourceNode.out.head._1).foreach{ case (i, s) => s := i } 317 } 318 } 319 320 val plic = LazyModule(new TLPLIC(PLICParams(0x3c000000L), 8)) 321 val plicSource = LazyModule(new IntSourceNodeToModule(NrExtIntr)) 322 val plicIntSinks = Array.fill(NumCores){ 323 val plicSink = LazyModule(new IntSinkNodeToModule(1)) 324 plicSink.sinkNode := plic.intnode 325 plicSink 326 } 327 plic.intnode := beu.intNode 328 plic.intnode := plicSource.sourceNode 329 330 plic.node := peripheralXbar 331 332 val l3cache = if (useFakeL3Cache) null else LazyModule(new InclusiveCache( 333 CacheParameters( 334 level = 3, 335 ways = L3NWays, 336 sets = L3NSets, 337 blockBytes = L3BlockSize, 338 beatBytes = L3InnerBusWidth / 8, 339 cacheName = "L3", 340 uncachedGet = false, 341 enablePerf = false 342 ), 343 InclusiveCacheMicroParameters( 344 memCycles = 25, 345 writeBytes = 32 346 ), 347 fpga = debugOpts.FPGAPlatform 348 )) 349 if(!useFakeL3Cache){ 350 ResourceBinding{ 351 Resource(l3cache.device, "reg").bind(ResourceAddress(0)) 352 } 353 } 354 val l3Ignore = if (useFakeL3Cache) TLIgnoreNode() else null 355 356 if (useFakeL3Cache) { 357 bankedNode :*= l3Ignore :*= l3_xbar 358 } 359 else { 360 bankedNode :*= l3cache.node :*= BusPerfMonitor(enable = true) :*= TLBuffer() :*= l3_xbar 361 } 362 363 val debugModule = LazyModule(new DebugModule(NumCores)(p)) 364 debugModule.debug.node := peripheralXbar 365 val debugIntSink = LazyModule(new IntSinkNodeToModule(NumCores)) 366 debugIntSink.sinkNode := debugModule.debug.dmOuter.dmOuter.intnode 367 debugModule.debug.dmInner.dmInner.sb2tlOpt.foreach { sb2tl => 368 l3_xbar := TLBuffer() := TLWidthWidget(1) := sb2tl.node 369 } 370 371 lazy val module = new LazyRawModuleImp(this) { 372 ElaborationArtefacts.add("dts", dts) 373 ElaborationArtefacts.add("graphml", graphML) 374 ElaborationArtefacts.add("json", json) 375 ElaborationArtefacts.add("plusArgs", freechips.rocketchip.util.PlusArgArtefacts.serialize_cHeader()) 376 377 val io = IO(new Bundle { 378 val clock = Input(Bool()) 379 val reset = Input(Bool()) 380 val extIntrs = Input(UInt(NrExtIntr.W)) 381 // val meip = Input(Vec(NumCores, Bool())) 382 val ila = if(debugOpts.FPGAPlatform && EnableILA) Some(Output(new ILABundle)) else None 383 val systemjtag = new Bundle { 384 val jtag = Flipped(new JTAGIO(hasTRSTn = false)) 385 val reset = Input(Bool()) // No reset allowed on top 386 val mfr_id = Input(UInt(11.W)) 387 val part_number = Input(UInt(16.W)) 388 val version = Input(UInt(4.W)) 389 } 390 // val resetCtrl = new ResetCtrlIO(NumCores)(p) 391 }) 392 childClock := io.clock.asClock() 393 394 withClockAndReset(childClock, io.reset) { 395 val resetGen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 396 resetGen.suggestName("top_reset_gen") 397 childReset := resetGen.io.out | debugModule.module.io.debugIO.ndreset 398 } 399 400 withClockAndReset(childClock, childReset) { 401 plicSource.module.in := io.extIntrs.asBools() 402 403 for (i <- 0 until NumCores) { 404 val core_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 405 core_reset_gen.suggestName(s"core_${i}_reset_gen") 406 core_with_l2(i).module.reset := core_reset_gen.io.out 407 core_with_l2(i).module.io.hartId := i.U 408 core_with_l2(i).module.io.externalInterrupt.msip := clintIntSinks(i).module.out(0) 409 core_with_l2(i).module.io.externalInterrupt.mtip := clintIntSinks(i).module.out(1) 410 core_with_l2(i).module.io.externalInterrupt.meip := plicIntSinks(i).module.out(0) 411 core_with_l2(i).module.io.externalInterrupt.debug := debugIntSink.module.out(i) 412 beu.module.io.errors.l1plus(i) := core_with_l2(i).module.io.l1plus_error 413 beu.module.io.errors.icache(i) := core_with_l2(i).module.io.icache_error 414 beu.module.io.errors.dcache(i) := core_with_l2(i).module.io.dcache_error 415 } 416 417 if (!useFakeL3Cache) { 418 val l3_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 419 l3_reset_gen.suggestName("l3_reset_gen") 420 l3cache.module.reset := l3_reset_gen.io.out 421 } 422 // TODO: wrap this in a module 423 val freq = 100 424 val cnt = RegInit(freq.U) 425 val tick = cnt === 0.U 426 cnt := Mux(tick, freq.U, cnt - 1.U) 427 clint.module.io.rtcTick := tick 428 429 debugModule.module.io.resetCtrl.hartIsInReset.foreach {x => x := childReset.asBool() } 430 debugModule.module.io.clock := io.clock 431 debugModule.module.io.reset := io.reset 432 433 debugModule.module.io.debugIO.reset := io.systemjtag.reset // TODO: use synchronizer? 434 debugModule.module.io.debugIO.clock := childClock 435 debugModule.module.io.debugIO.dmactiveAck := debugModule.module.io.debugIO.dmactive // TODO: delay 3 cycles? 436 // jtag connector 437 debugModule.module.io.debugIO.systemjtag.foreach { x => 438 x.jtag <> io.systemjtag.jtag 439 x.reset := io.systemjtag.reset 440 x.mfr_id := io.systemjtag.mfr_id 441 x.part_number := io.systemjtag.part_number 442 x.version := io.systemjtag.version 443 } 444 } 445 } 446} 447 448object TopMain extends App with HasRocketChipStageUtils { 449 override def main(args: Array[String]): Unit = { 450 val (config, firrtlOpts) = ArgParser.parse(args) 451 XiangShanStage.execute(firrtlOpts, Seq( 452 ChiselGeneratorAnnotation(() => { 453 val soc = LazyModule(new XSTop()(config)) 454 soc.module 455 }) 456 )) 457 ElaborationArtefacts.files.foreach{ case (extension, contents) => 458 writeOutputFile("./build", s"XSTop.${extension}", contents()) 459 } 460 } 461} 462