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