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