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 lazy val json = JSON(bindingTree) 133} 134 135// We adapt the following three traits from rocket-chip. 136// Source: rocket-chip/src/main/scala/subsystem/Ports.scala 137trait HaveSlaveAXI4Port { 138 this: BaseXSSoc => 139 140 val idBits = 16 141 142 val l3FrontendAXI4Node = AXI4MasterNode(Seq(AXI4MasterPortParameters( 143 Seq(AXI4MasterParameters( 144 name = "dma", 145 id = IdRange(0, 1 << idBits) 146 )) 147 ))) 148 private val errorDevice = LazyModule(new TLError( 149 params = DevNullParams( 150 address = Seq(AddressSet(0x0, 0x7fffffffL)), 151 maxAtomic = 8, 152 maxTransfer = 64), 153 beatBytes = L3InnerBusWidth / 8 154 )) 155 private val error_xbar = TLXbar() 156 157 error_xbar := 158 AXI4ToTL() := 159 AXI4UserYanker(Some(1)) := 160 AXI4Fragmenter() := 161 AXI4IdIndexer(1) := 162 l3FrontendAXI4Node 163 errorDevice.node := error_xbar 164 l3_xbar := 165 TLBuffer() := 166 error_xbar 167 168 val dma = InModuleBody { 169 l3FrontendAXI4Node.makeIOs() 170 } 171} 172 173trait HaveAXI4MemPort { 174 this: BaseXSSoc => 175 val device = new MemoryDevice 176 // 40-bit physical address 177 val memRange = AddressSet(0x00000000L, 0xffffffffffL).subtract(AddressSet(0x0L, 0x7fffffffL)) 178 val memAXI4SlaveNode = AXI4SlaveNode(Seq( 179 AXI4SlavePortParameters( 180 slaves = Seq( 181 AXI4SlaveParameters( 182 address = memRange, 183 regionType = RegionType.UNCACHED, 184 executable = true, 185 supportsRead = TransferSizes(1, L3BlockSize), 186 supportsWrite = TransferSizes(1, L3BlockSize), 187 interleavedId = Some(0), 188 resources = device.reg("mem") 189 ) 190 ), 191 beatBytes = L3OuterBusWidth / 8 192 ) 193 )) 194 195 val mem_xbar = TLXbar() 196 mem_xbar :=* TLBuffer() :=* TLCacheCork() :=* bankedNode 197 memAXI4SlaveNode := 198 AXI4UserYanker() := 199 AXI4Deinterleaver(L3BlockSize) := 200 TLToAXI4() := 201 TLWidthWidget(L3OuterBusWidth / 8) := 202 mem_xbar 203 204 val memory = InModuleBody { 205 memAXI4SlaveNode.makeIOs() 206 } 207} 208 209 210trait HaveAXI4PeripheralPort { this: BaseXSSoc => 211 // on-chip devices: 0x3800_000 - 0x3fff_ffff 212 val onChipPeripheralRange = AddressSet(0x38000000L, 0x07ffffffL) 213 val uartRange = AddressSet(0x40600000, 0xf) 214 val uartDevice = new SimpleDevice("serial", Seq("xilinx,uartlite")) 215 val uartParams = AXI4SlaveParameters( 216 address = Seq(uartRange), 217 regionType = RegionType.UNCACHED, 218 supportsRead = TransferSizes(1, 8), 219 supportsWrite = TransferSizes(1, 8), 220 resources = uartDevice.reg 221 ) 222 val peripheralRange = AddressSet( 223 0x0, 0x7fffffff 224 ).subtract(onChipPeripheralRange).flatMap(x => x.subtract(uartRange)) 225 val peripheralNode = AXI4SlaveNode(Seq(AXI4SlavePortParameters( 226 Seq(AXI4SlaveParameters( 227 address = peripheralRange, 228 regionType = RegionType.UNCACHED, 229 supportsRead = TransferSizes(1, 8), 230 supportsWrite = TransferSizes(1, 8), 231 interleavedId = Some(0) 232 ), uartParams), 233 beatBytes = 8 234 ))) 235 236 peripheralNode := 237 AXI4UserYanker() := 238 AXI4Deinterleaver(8) := 239 TLToAXI4() := 240 peripheralXbar 241 242 val peripheral = InModuleBody { 243 peripheralNode.makeIOs() 244 } 245 246} 247 248class XSTop()(implicit p: Parameters) extends XSTopWithoutDMA 249 with HaveSlaveAXI4Port 250 251class XSTopWithoutDMA()(implicit p: Parameters) extends BaseXSSoc() 252 with HaveAXI4MemPort 253 with HaveAXI4PeripheralPort 254{ 255 ResourceBinding { 256 val width = ResourceInt(2) 257 val model = "freechips,rocketchip-unknown" 258 Resource(ResourceAnchors.root, "model").bind(ResourceString(model)) 259 Resource(ResourceAnchors.root, "compat").bind(ResourceString(model + "-dev")) 260 Resource(ResourceAnchors.soc, "compat").bind(ResourceString(model + "-soc")) 261 Resource(ResourceAnchors.root, "width").bind(width) 262 Resource(ResourceAnchors.soc, "width").bind(width) 263 Resource(ResourceAnchors.cpus, "width").bind(ResourceInt(1)) 264 def bindManagers(xbar: TLNexusNode) = { 265 ManagerUnification(xbar.edges.in.head.manager.managers).foreach{ manager => 266 manager.resources.foreach(r => r.bind(manager.toResource)) 267 } 268 } 269 bindManagers(l3_xbar.asInstanceOf[TLNexusNode]) 270 bindManagers(peripheralXbar.asInstanceOf[TLNexusNode]) 271 } 272 273 println(s"FPGASoC cores: $NumCores banks: $L3NBanks block size: $L3BlockSize bus size: $L3OuterBusWidth") 274 275 val core_with_l2 = soc.cores.map(coreParams => 276 LazyModule(new XSCoreWithL2()(p.alterPartial({ 277 case XSCoreParamsKey => coreParams 278 }))) 279 ) 280 281 for (i <- 0 until NumCores) { 282 peripheralXbar := TLBuffer() := core_with_l2(i).uncache 283 l3_xbar := TLBuffer() := core_with_l2(i).memory_port 284 } 285 286 val clint = LazyModule(new CLINT(CLINTParams(0x38000000L), 8)) 287 clint.node := peripheralXbar 288 289 val clintIntSinks = Array.fill(NumCores){ 290 val clintSink = LazyModule(new IntSinkNodeToModule(2)) 291 clintSink.sinkNode := clint.intnode 292 clintSink 293 } 294 295 val fakeTreeNode = new GenericLogicalTreeNode 296 val beu = LazyModule( 297 new BusErrorUnit(new XSL1BusErrors(NumCores), BusErrorUnitParams(0x38010000), fakeTreeNode)) 298 beu.node := peripheralXbar 299 300 class IntSinkNodeToModule(val sinks: Int)(implicit p: Parameters) extends LazyModule { 301 val sinkNode = IntSinkNode(IntSinkPortSimple(1, sinks)) 302 lazy val module = new LazyModuleImp(this){ 303 val out = IO(Output(Vec(sinks, Bool()))) 304 out.zip(sinkNode.in.head._1).foreach{ case (o, i) => o := i } 305 } 306 } 307 308 class IntSourceNodeToModule(val num: Int)(implicit p: Parameters) extends LazyModule { 309 val sourceNode = IntSourceNode(IntSourcePortSimple(num, ports = 1, sources = 1)) 310 lazy val module = new LazyModuleImp(this){ 311 val in = IO(Input(Vec(num, Bool()))) 312 in.zip(sourceNode.out.head._1).foreach{ case (i, s) => s := i } 313 } 314 } 315 316 val plic = LazyModule(new TLPLIC(PLICParams(0x3c000000L), 8)) 317 val plicSource = LazyModule(new IntSourceNodeToModule(NrExtIntr)) 318 val plicIntSinks = Array.fill(NumCores){ 319 val plicSink = LazyModule(new IntSinkNodeToModule(1)) 320 plicSink.sinkNode := plic.intnode 321 plicSink 322 } 323 plic.intnode := beu.intNode 324 plic.intnode := plicSource.sourceNode 325 326 plic.node := peripheralXbar 327 328 val l3cache = if (useFakeL3Cache) null else LazyModule(new InclusiveCache( 329 CacheParameters( 330 level = 3, 331 ways = L3NWays, 332 sets = L3NSets, 333 blockBytes = L3BlockSize, 334 beatBytes = L3InnerBusWidth / 8, 335 cacheName = "L3", 336 uncachedGet = false, 337 enablePerf = false 338 ), 339 InclusiveCacheMicroParameters( 340 memCycles = 25, 341 writeBytes = 32 342 ), 343 fpga = debugOpts.FPGAPlatform 344 )) 345 if(!useFakeL3Cache){ 346 ResourceBinding{ 347 Resource(l3cache.device, "reg").bind(ResourceAddress(0)) 348 } 349 } 350 val l3Ignore = if (useFakeL3Cache) TLIgnoreNode() else null 351 352 if (useFakeL3Cache) { 353 bankedNode :*= l3Ignore :*= l3_xbar 354 } 355 else { 356 bankedNode :*= l3cache.node :*= TLBuffer() :*= l3_xbar 357 } 358 359 lazy val module = new LazyRawModuleImp(this) { 360 ElaborationArtefacts.add("dts", dts) 361 ElaborationArtefacts.add("graphml", graphML) 362 ElaborationArtefacts.add("json", json) 363 ElaborationArtefacts.add("plusArgs", freechips.rocketchip.util.PlusArgArtefacts.serialize_cHeader()) 364 365 val io = IO(new Bundle { 366 val clock = Input(Bool()) 367 val reset = Input(Bool()) 368 val extIntrs = Input(UInt(NrExtIntr.W)) 369 // val meip = Input(Vec(NumCores, Bool())) 370 val ila = if(debugOpts.FPGAPlatform && EnableILA) Some(Output(new ILABundle)) else None 371 }) 372 childClock := io.clock.asClock() 373 374 withClockAndReset(childClock, io.reset) { 375 val resetGen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 376 resetGen.suggestName("top_reset_gen") 377 childReset := resetGen.io.out 378 } 379 380 withClockAndReset(childClock, childReset) { 381 plicSource.module.in := io.extIntrs.asBools() 382 383 for (i <- 0 until NumCores) { 384 val core_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 385 core_reset_gen.suggestName(s"core_${i}_reset_gen") 386 core_with_l2(i).module.reset := core_reset_gen.io.out 387 core_with_l2(i).module.io.hartId := i.U 388 core_with_l2(i).module.io.externalInterrupt.msip := clintIntSinks(i).module.out(0) 389 core_with_l2(i).module.io.externalInterrupt.mtip := clintIntSinks(i).module.out(1) 390 core_with_l2(i).module.io.externalInterrupt.meip := plicIntSinks(i).module.out(0) 391 beu.module.io.errors.l1plus(i) := core_with_l2(i).module.io.l1plus_error 392 beu.module.io.errors.icache(i) := core_with_l2(i).module.io.icache_error 393 beu.module.io.errors.dcache(i) := core_with_l2(i).module.io.dcache_error 394 } 395 396 if (!useFakeL3Cache) { 397 val l3_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 398 l3_reset_gen.suggestName("l3_reset_gen") 399 l3cache.module.reset := l3_reset_gen.io.out 400 } 401 // TODO: wrap this in a module 402 val freq = 100 403 val cnt = RegInit(freq.U) 404 val tick = cnt === 0.U 405 cnt := Mux(tick, freq.U, cnt - 1.U) 406 clint.module.io.rtcTick := tick 407 } 408 } 409} 410 411object TopMain extends App with HasRocketChipStageUtils { 412 override def main(args: Array[String]): Unit = { 413 val (config, firrtlOpts) = ArgParser.parse(args) 414 XiangShanStage.execute(firrtlOpts, Seq( 415 ChiselGeneratorAnnotation(() => { 416 val soc = LazyModule(new XSTop()(config)) 417 soc.module 418 }) 419 )) 420 ElaborationArtefacts.files.foreach{ case (extension, contents) => 421 writeOutputFile("./build", s"XSTop.${extension}", contents()) 422 } 423 } 424} 425