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