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