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