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 system 18 19import org.chipsalliance.cde.config.{Field, Parameters} 20import chisel3._ 21import chisel3.util._ 22import device.{DebugModule, TLPMA, TLPMAIO} 23import freechips.rocketchip.amba.axi4._ 24import freechips.rocketchip.devices.tilelink._ 25import freechips.rocketchip.diplomacy.{AddressSet, IdRange, InModuleBody, LazyModule, LazyModuleImp, MemoryDevice, RegionType, SimpleDevice, TransferSizes} 26import freechips.rocketchip.interrupts.{IntSourceNode, IntSourcePortSimple} 27import freechips.rocketchip.regmapper.{RegField, RegFieldDesc, RegFieldGroup} 28import freechips.rocketchip.tilelink._ 29import freechips.rocketchip.util.AsyncQueueParams 30import huancun._ 31import top.BusPerfMonitor 32import utility.{ReqSourceKey, TLClientsMerger, TLEdgeBuffer, TLLogger} 33import xiangshan.backend.fu.PMAConst 34import xiangshan.{DebugOptionsKey, XSTileKey} 35import coupledL2.EnableCHI 36import coupledL2.tl2chi.CHIIssue 37 38case object SoCParamsKey extends Field[SoCParameters] 39 40case class SoCParameters 41( 42 EnableILA: Boolean = false, 43 PAddrBits: Int = 48, 44 extIntrs: Int = 64, 45 L3NBanks: Int = 4, 46 L3CacheParamsOpt: Option[HCCacheParameters] = Some(HCCacheParameters( 47 name = "L3", 48 level = 3, 49 ways = 8, 50 sets = 2048 // 1MB per bank 51 )), 52 XSTopPrefix: Option[String] = None, 53 NodeIDWidthList: Map[String, Int] = Map( 54 "B" -> 7, 55 "E.b" -> 11 56 ), 57 NumHart: Int = 64, 58 NumIRFiles: Int = 7, 59 NumIRSrc: Int = 256, 60 UseXSNoCTop: Boolean = false, 61 IMSICUseTL: Boolean = false, 62 CHIAsyncBridge: AsyncQueueParams = AsyncQueueParams( 63 depth = 4, 64 sync = 3 65 ) 66){ 67 // L3 configurations 68 val L3InnerBusWidth = 256 69 val L3BlockSize = 64 70 // on chip network configurations 71 val L3OuterBusWidth = 256 72} 73 74trait HasSoCParameter { 75 implicit val p: Parameters 76 77 val soc = p(SoCParamsKey) 78 val debugOpts = p(DebugOptionsKey) 79 val tiles = p(XSTileKey) 80 val enableCHI = p(EnableCHI) 81 val issue = p(CHIIssue) 82 83 val NumCores = tiles.size 84 val EnableILA = soc.EnableILA 85 86 // L3 configurations 87 val L3InnerBusWidth = soc.L3InnerBusWidth 88 val L3BlockSize = soc.L3BlockSize 89 val L3NBanks = soc.L3NBanks 90 91 // on chip network configurations 92 val L3OuterBusWidth = soc.L3OuterBusWidth 93 94 val NrExtIntr = soc.extIntrs 95 96 val SetIpNumValidSize = soc.NumHart * soc.NumIRFiles 97 98 val NumIRSrc = soc.NumIRSrc 99} 100 101class ILABundle extends Bundle {} 102 103 104abstract class BaseSoC()(implicit p: Parameters) extends LazyModule with HasSoCParameter { 105 val bankedNode = Option.when(!enableCHI)(BankBinder(L3NBanks, L3BlockSize)) 106 val peripheralXbar = Option.when(!enableCHI)(TLXbar()) 107 val l3_xbar = Option.when(!enableCHI)(TLXbar()) 108 val l3_banked_xbar = Option.when(!enableCHI)(TLXbar()) 109 110 val soc_xbar = Option.when(enableCHI)(AXI4Xbar()) 111} 112 113// We adapt the following three traits from rocket-chip. 114// Source: rocket-chip/src/main/scala/subsystem/Ports.scala 115trait HaveSlaveAXI4Port { 116 this: BaseSoC => 117 118 val idBits = 14 119 120 val l3FrontendAXI4Node = AXI4MasterNode(Seq(AXI4MasterPortParameters( 121 Seq(AXI4MasterParameters( 122 name = "dma", 123 id = IdRange(0, 1 << idBits) 124 )) 125 ))) 126 127 if (l3_xbar.isDefined) { 128 val errorDevice = LazyModule(new TLError( 129 params = DevNullParams( 130 address = Seq(AddressSet(0x0, 0x7fffffffL)), 131 maxAtomic = 8, 132 maxTransfer = 64), 133 beatBytes = L3InnerBusWidth / 8 134 )) 135 errorDevice.node := 136 l3_xbar.get := 137 TLFIFOFixer() := 138 TLWidthWidget(32) := 139 AXI4ToTL() := 140 AXI4UserYanker(Some(1)) := 141 AXI4Fragmenter() := 142 AXI4Buffer() := 143 AXI4Buffer() := 144 AXI4IdIndexer(1) := 145 l3FrontendAXI4Node 146 } 147 148 val dma = InModuleBody { 149 l3FrontendAXI4Node.makeIOs() 150 } 151} 152 153trait HaveAXI4MemPort { 154 this: BaseSoC => 155 val device = new MemoryDevice 156 // 48-bit physical address 157 val memRange = AddressSet(0x00000000L, 0xffffffffffffL).subtract(AddressSet(0x0L, 0x7fffffffL)) 158 val memAXI4SlaveNode = AXI4SlaveNode(Seq( 159 AXI4SlavePortParameters( 160 slaves = Seq( 161 AXI4SlaveParameters( 162 address = memRange, 163 regionType = RegionType.UNCACHED, 164 executable = true, 165 supportsRead = TransferSizes(1, L3BlockSize), 166 supportsWrite = TransferSizes(1, L3BlockSize), 167 interleavedId = Some(0), 168 resources = device.reg("mem") 169 ) 170 ), 171 beatBytes = L3OuterBusWidth / 8, 172 requestKeys = if (debugOpts.FPGAPlatform) Seq() else Seq(ReqSourceKey), 173 ) 174 )) 175 176 val mem_xbar = TLXbar() 177 val l3_mem_pmu = BusPerfMonitor(name = "L3_Mem", enable = !debugOpts.FPGAPlatform && !enableCHI, stat_latency = true) 178 val axi4mem_node = AXI4IdentityNode() 179 180 if (enableCHI) { 181 axi4mem_node := 182 soc_xbar.get 183 } else { 184 mem_xbar :=* 185 TLBuffer.chainNode(2) := 186 TLCacheCork() := 187 l3_mem_pmu := 188 TLClientsMerger() := 189 TLXbar() :=* 190 bankedNode.get 191 192 mem_xbar := 193 TLWidthWidget(8) := 194 TLBuffer.chainNode(3, name = Some("PeripheralXbar_to_MemXbar_buffer")) := 195 peripheralXbar.get 196 197 axi4mem_node := 198 TLToAXI4() := 199 TLSourceShrinker(64) := 200 TLWidthWidget(L3OuterBusWidth / 8) := 201 TLBuffer.chainNode(2) := 202 mem_xbar 203 } 204 205 memAXI4SlaveNode := 206 AXI4Buffer() := 207 AXI4Buffer() := 208 AXI4Buffer() := 209 AXI4IdIndexer(idBits = 14) := 210 AXI4UserYanker() := 211 AXI4Deinterleaver(L3BlockSize) := 212 axi4mem_node 213 214 val memory = InModuleBody { 215 memAXI4SlaveNode.makeIOs() 216 } 217} 218 219trait HaveAXI4PeripheralPort { this: BaseSoC => 220 // on-chip devices: 0x3800_0000 - 0x3fff_ffff 0x0000_0000 - 0x0000_0fff 221 val onChipPeripheralRange = AddressSet(0x38000000L, 0x07ffffffL) 222 val uartRange = AddressSet(0x40600000, 0x3f) 223 val uartDevice = new SimpleDevice("serial", Seq("xilinx,uartlite")) 224 val uartParams = AXI4SlaveParameters( 225 address = Seq(uartRange), 226 regionType = RegionType.UNCACHED, 227 supportsRead = TransferSizes(1, 32), 228 supportsWrite = TransferSizes(1, 32), 229 resources = uartDevice.reg 230 ) 231 val peripheralRange = AddressSet( 232 0x0, 0x7fffffff 233 ).subtract(onChipPeripheralRange).flatMap(x => x.subtract(uartRange)) 234 val peripheralNode = AXI4SlaveNode(Seq(AXI4SlavePortParameters( 235 Seq(AXI4SlaveParameters( 236 address = peripheralRange, 237 regionType = RegionType.UNCACHED, 238 supportsRead = TransferSizes(1, 32), 239 supportsWrite = TransferSizes(1, 32), 240 interleavedId = Some(0) 241 ), uartParams), 242 beatBytes = 8 243 ))) 244 245 val axi4peripheral_node = AXI4IdentityNode() 246 val error_xbar = Option.when(enableCHI)(TLXbar()) 247 248 peripheralNode := 249 AXI4UserYanker() := 250 AXI4IdIndexer(idBits = 2) := 251 AXI4Buffer() := 252 AXI4Buffer() := 253 AXI4Buffer() := 254 AXI4Buffer() := 255 AXI4UserYanker() := 256 // AXI4Deinterleaver(8) := 257 axi4peripheral_node 258 259 if (enableCHI) { 260 val error = LazyModule(new TLError( 261 params = DevNullParams( 262 address = Seq(AddressSet(0x1000000000000L, 0xffffffffffffL)), 263 maxAtomic = 8, 264 maxTransfer = 64), 265 beatBytes = 8 266 )) 267 error.node := error_xbar.get 268 axi4peripheral_node := 269 AXI4Deinterleaver(8) := 270 TLToAXI4() := 271 error_xbar.get := 272 TLBuffer.chainNode(2, Some("llc_to_peripheral_buffer")) := 273 TLFIFOFixer() := 274 TLWidthWidget(L3OuterBusWidth / 8) := 275 AXI4ToTL() := 276 AXI4UserYanker() := 277 soc_xbar.get 278 } else { 279 axi4peripheral_node := 280 AXI4Deinterleaver(8) := 281 TLToAXI4() := 282 TLBuffer.chainNode(3) := 283 peripheralXbar.get 284 } 285 286 val peripheral = InModuleBody { 287 peripheralNode.makeIOs() 288 } 289 290} 291 292class MemMisc()(implicit p: Parameters) extends BaseSoC 293 with HaveAXI4MemPort 294 with PMAConst 295 with HaveAXI4PeripheralPort 296{ 297 298 val peripheral_ports = Option.when(!enableCHI)(Array.fill(NumCores) { TLTempNode() }) 299 val core_to_l3_ports = Option.when(!enableCHI)(Array.fill(NumCores) { TLTempNode() }) 300 301 val l3_in = TLTempNode() 302 val l3_out = TLTempNode() 303 304 val device_xbar = Option.when(enableCHI)(TLXbar()) 305 device_xbar.foreach(_ := error_xbar.get) 306 307 if (l3_banked_xbar.isDefined) { 308 l3_in :*= TLEdgeBuffer(_ => true, Some("L3_in_buffer")) :*= l3_banked_xbar.get 309 l3_banked_xbar.get := TLBuffer.chainNode(2) := l3_xbar.get 310 } 311 bankedNode match { 312 case Some(bankBinder) => 313 bankBinder :*= TLLogger("MEM_L3", !debugOpts.FPGAPlatform && debugOpts.AlwaysBasicDB) :*= l3_out 314 case None => 315 } 316 317 if(soc.L3CacheParamsOpt.isEmpty){ 318 l3_out :*= l3_in 319 } 320 321 if (!enableCHI) { 322 for (port <- peripheral_ports.get) { 323 peripheralXbar.get := TLBuffer.chainNode(2, Some("L2_to_L3_peripheral_buffer")) := port 324 } 325 } 326 327 core_to_l3_ports.foreach { case _ => 328 for ((core_out, i) <- core_to_l3_ports.get.zipWithIndex){ 329 l3_banked_xbar.get :=* 330 TLLogger(s"L3_L2_$i", !debugOpts.FPGAPlatform && debugOpts.AlwaysBasicDB) :=* 331 TLBuffer() := 332 core_out 333 } 334 } 335 336 val clint = LazyModule(new CLINT(CLINTParams(0x38000000L), 8)) 337 if (enableCHI) { clint.node := device_xbar.get } 338 else { clint.node := peripheralXbar.get } 339 340 class IntSourceNodeToModule(val num: Int)(implicit p: Parameters) extends LazyModule { 341 val sourceNode = IntSourceNode(IntSourcePortSimple(num, ports = 1, sources = 1)) 342 class IntSourceNodeToModuleImp(wrapper: LazyModule) extends LazyModuleImp(wrapper) { 343 val in = IO(Input(Vec(num, Bool()))) 344 in.zip(sourceNode.out.head._1).foreach{ case (i, s) => s := i } 345 } 346 lazy val module = new IntSourceNodeToModuleImp(this) 347 } 348 349 val plic = LazyModule(new TLPLIC(PLICParams(0x3c000000L), 8)) 350 val plicSource = LazyModule(new IntSourceNodeToModule(NrExtIntr)) 351 352 plic.intnode := plicSource.sourceNode 353 if (enableCHI) { plic.node := device_xbar.get } 354 else { plic.node := peripheralXbar.get } 355 356 val pll_node = TLRegisterNode( 357 address = Seq(AddressSet(0x3a000000L, 0xfff)), 358 device = new SimpleDevice("pll_ctrl", Seq()), 359 beatBytes = 8, 360 concurrency = 1 361 ) 362 if (enableCHI) { pll_node := device_xbar.get } 363 else { pll_node := peripheralXbar.get } 364 365 val debugModule = LazyModule(new DebugModule(NumCores)(p)) 366 if (enableCHI) { 367 debugModule.debug.node := device_xbar.get 368 // TODO: l3_xbar 369 debugModule.debug.dmInner.dmInner.sb2tlOpt.foreach { sb2tl => 370 error_xbar.get := sb2tl.node 371 } 372 } else { 373 debugModule.debug.node := peripheralXbar.get 374 debugModule.debug.dmInner.dmInner.sb2tlOpt.foreach { sb2tl => 375 l3_xbar.get := TLBuffer() := sb2tl.node 376 } 377 } 378 379 val pma = LazyModule(new TLPMA) 380 if (enableCHI) { 381 pma.node := TLBuffer.chainNode(4) := device_xbar.get 382 } else { 383 pma.node := TLBuffer.chainNode(4) := peripheralXbar.get 384 } 385 386 class SoCMiscImp(wrapper: LazyModule) extends LazyModuleImp(wrapper) { 387 388 val debug_module_io = IO(new debugModule.DebugModuleIO) 389 val ext_intrs = IO(Input(UInt(NrExtIntr.W))) 390 val rtc_clock = IO(Input(Bool())) 391 val pll0_lock = IO(Input(Bool())) 392 val pll0_ctrl = IO(Output(Vec(6, UInt(32.W)))) 393 val cacheable_check = IO(new TLPMAIO) 394 val clintTime = IO(Output(ValidIO(UInt(64.W)))) 395 396 debugModule.module.io <> debug_module_io 397 398 // sync external interrupts 399 require(plicSource.module.in.length == ext_intrs.getWidth) 400 for ((plic_in, interrupt) <- plicSource.module.in.zip(ext_intrs.asBools)) { 401 val ext_intr_sync = RegInit(0.U(3.W)) 402 ext_intr_sync := Cat(ext_intr_sync(1, 0), interrupt) 403 plic_in := ext_intr_sync(2) 404 } 405 406 pma.module.io <> cacheable_check 407 408 // positive edge sampling of the lower-speed rtc_clock 409 val rtcTick = RegInit(0.U(3.W)) 410 rtcTick := Cat(rtcTick(1, 0), rtc_clock) 411 clint.module.io.rtcTick := rtcTick(1) && !rtcTick(2) 412 413 val pll_ctrl_regs = Seq.fill(6){ RegInit(0.U(32.W)) } 414 val pll_lock = RegNext(next = pll0_lock, init = false.B) 415 416 clintTime := clint.module.io.time 417 418 pll0_ctrl <> VecInit(pll_ctrl_regs) 419 420 pll_node.regmap( 421 0x000 -> RegFieldGroup( 422 "Pll", Some("PLL ctrl regs"), 423 pll_ctrl_regs.zipWithIndex.map{ 424 case (r, i) => RegField(32, r, RegFieldDesc( 425 s"PLL_ctrl_$i", 426 desc = s"PLL ctrl register #$i" 427 )) 428 } :+ RegField.r(32, Cat(0.U(31.W), pll_lock), RegFieldDesc( 429 "PLL_lock", 430 "PLL lock register" 431 )) 432 ) 433 ) 434 } 435 436 lazy val module = new SoCMiscImp(this) 437} 438 439class SoCMisc()(implicit p: Parameters) extends MemMisc 440 with HaveSlaveAXI4Port 441 442