xref: /XiangShan/src/main/scala/system/SoC.scala (revision 8a020714df826c6ac860308700137855ecd6ba07)
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