xref: /XiangShan/src/main/scala/top/Top.scala (revision 20edb3f77a5240aaf6070eed3b4288cb6a91f8a4)
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 device._
25import chisel3.stage.ChiselGeneratorAnnotation
26import chipsalliance.rocketchip.config._
27import device.{AXI4Plic, DebugModule, TLTimer}
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.jtag.JTAGIO
35import freechips.rocketchip.tile.{BusErrorUnit, BusErrorUnitParams, XLen}
36import freechips.rocketchip.tilelink
37import freechips.rocketchip.util.{ElaborationArtefacts, HasRocketChipStageUtils}
38import huancun.debug.TLLogger
39import huancun.{HCCacheParamsKey, HuanCun}
40import freechips.rocketchip.devices.debug.{DebugIO, ResetCtrlIO}
41
42class XSCoreWithL2()(implicit p: Parameters) extends LazyModule
43  with HasXSParameter with HasSoCParameter {
44  private val core = LazyModule(new XSCore)
45  private val busPMU = BusPerfMonitor(enable = !debugOpts.FPGAPlatform)
46  private val l2cacheOpt = coreParams.L2CacheParamsOpt.map(l2param =>
47    LazyModule(new HuanCun()(new Config((_, _, _) => {
48      case HCCacheParamsKey => l2param
49    })))
50  )
51  // (icache/ptw/dcache) => l2 or mem
52  private val l1_xbar = TLXbar()
53
54  val memory_port = TLIdentityNode()
55  val uncache = TLXbar()
56
57  if (coreParams.dcacheParametersOpt.nonEmpty) {
58    busPMU := TLLogger(s"L2_L1D_$hardId", !debugOpts.FPGAPlatform) := core.memBlock.dcache.clientNode
59  }
60  busPMU := core.frontend.icache.clientNode
61  if (!coreParams.softPTW) {
62    busPMU := core.ptw.node
63  }
64  l1_xbar :=* busPMU
65  l2cacheOpt match {
66    case Some(l2) =>
67      val l2_binder = BankBinder(coreParams.L2NBanks, 64)
68      memory_port :=* l2_binder :*= l2.node :*= l1_xbar
69    case None =>
70      memory_port := l1_xbar
71  }
72
73  uncache := TLBuffer() := core.frontend.instrUncache.clientNode
74  uncache := TLBuffer() := core.memBlock.uncache.clientNode
75
76  lazy val module = new LazyModuleImp(this) {
77    val io = IO(new Bundle {
78      val hartId = Input(UInt(64.W))
79      val externalInterrupt = new ExternalInterruptIO
80      val l1plus_error, icache_error, dcache_error = new L1CacheErrorInfo
81    })
82
83    core.module.io.hartId := io.hartId
84    core.module.io.externalInterrupt := io.externalInterrupt
85
86    io.l1plus_error <> core.module.io.l1plus_error
87    io.icache_error <> core.module.io.icache_error
88    io.dcache_error <> core.module.io.dcache_error
89
90    val core_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform))
91    core.module.reset := core_reset_gen.io.out
92
93    val l2_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform))
94    l2cacheOpt.foreach( _.module.reset := l2_reset_gen.io.out)
95  }
96}
97
98abstract class BaseXSSoc()(implicit p: Parameters) extends LazyModule
99  with HasSoCParameter
100  with BindingScope
101{
102  val bankedNode = BankBinder(L3NBanks, L3BlockSize)
103  val peripheralXbar = TLXbar()
104  val l3_xbar = TLXbar()
105  lazy val dts = DTS(bindingTree)
106  lazy val json = JSON(bindingTree)
107}
108
109// We adapt the following three traits from rocket-chip.
110// Source: rocket-chip/src/main/scala/subsystem/Ports.scala
111trait HaveSlaveAXI4Port {
112  this: BaseXSSoc =>
113
114  val idBits = 14
115
116  val l3FrontendAXI4Node = AXI4MasterNode(Seq(AXI4MasterPortParameters(
117    Seq(AXI4MasterParameters(
118      name = "dma",
119      id = IdRange(0, 1 << idBits)
120    ))
121  )))
122  private val errorDevice = LazyModule(new TLError(
123    params = DevNullParams(
124      address = Seq(AddressSet(0x0, 0x7fffffffL)),
125      maxAtomic = 8,
126      maxTransfer = 64),
127    beatBytes = L3InnerBusWidth / 8
128  ))
129  private val error_xbar = TLXbar()
130
131  error_xbar :=
132    TLFIFOFixer() :=
133    TLWidthWidget(16) :=
134    AXI4ToTL() :=
135    AXI4UserYanker(Some(1)) :=
136    AXI4Fragmenter() :=
137    AXI4IdIndexer(1) :=
138    l3FrontendAXI4Node
139  errorDevice.node := error_xbar
140  l3_xbar :=
141    TLBuffer() :=
142    error_xbar
143
144  val dma = InModuleBody {
145    l3FrontendAXI4Node.makeIOs()
146  }
147}
148
149trait HaveAXI4MemPort {
150  this: BaseXSSoc =>
151  val device = new MemoryDevice
152  // 40-bit physical address
153  val memRange = AddressSet(0x00000000L, 0xffffffffffL).subtract(AddressSet(0x0L, 0x7fffffffL))
154  val memAXI4SlaveNode = AXI4SlaveNode(Seq(
155    AXI4SlavePortParameters(
156      slaves = Seq(
157        AXI4SlaveParameters(
158          address = memRange,
159          regionType = RegionType.UNCACHED,
160          executable = true,
161          supportsRead = TransferSizes(1, L3BlockSize),
162          supportsWrite = TransferSizes(1, L3BlockSize),
163          interleavedId = Some(0),
164          resources = device.reg("mem")
165        )
166      ),
167      beatBytes = L3OuterBusWidth / 8
168    )
169  ))
170
171  val mem_xbar = TLXbar()
172  mem_xbar :=* TLBuffer() :=* TLCacheCork() :=* bankedNode
173  memAXI4SlaveNode :=
174    AXI4UserYanker() :=
175    AXI4Deinterleaver(L3BlockSize) :=
176    TLToAXI4() :=
177    TLWidthWidget(L3OuterBusWidth / 8) :=
178    mem_xbar
179
180  val memory = InModuleBody {
181    memAXI4SlaveNode.makeIOs()
182  }
183}
184
185
186trait HaveAXI4PeripheralPort { this: BaseXSSoc =>
187  // on-chip devices: 0x3800_0000 - 0x3fff_ffff 0x0000_0000 - 0x0000_0fff
188  val onChipPeripheralRange = AddressSet(0x38000000L, 0x07ffffffL)
189  val uartRange = AddressSet(0x40600000, 0xf)
190  val uartDevice = new SimpleDevice("serial", Seq("xilinx,uartlite"))
191  val uartParams = AXI4SlaveParameters(
192    address = Seq(uartRange),
193    regionType = RegionType.UNCACHED,
194    supportsRead = TransferSizes(1, 8),
195    supportsWrite = TransferSizes(1, 8),
196    resources = uartDevice.reg
197  )
198  val peripheralRange = AddressSet(
199    0x0, 0x7fffffff
200  ).subtract(onChipPeripheralRange).flatMap(x => x.subtract(uartRange))
201  val peripheralNode = AXI4SlaveNode(Seq(AXI4SlavePortParameters(
202    Seq(AXI4SlaveParameters(
203      address = peripheralRange,
204      regionType = RegionType.UNCACHED,
205      supportsRead = TransferSizes(1, 8),
206      supportsWrite = TransferSizes(1, 8),
207      interleavedId = Some(0)
208    ), uartParams),
209    beatBytes = 8
210  )))
211
212  peripheralNode :=
213    AXI4UserYanker() :=
214    AXI4Deinterleaver(8) :=
215    TLToAXI4() :=
216    peripheralXbar
217
218  val peripheral = InModuleBody {
219    peripheralNode.makeIOs()
220  }
221
222}
223
224class XSTop()(implicit p: Parameters) extends XSTopWithoutDMA
225  with HaveSlaveAXI4Port
226
227class XSTopWithoutDMA()(implicit p: Parameters) extends BaseXSSoc()
228  with HaveAXI4MemPort
229  with HaveAXI4PeripheralPort
230{
231  ResourceBinding {
232    val width = ResourceInt(2)
233    val model = "freechips,rocketchip-unknown"
234    Resource(ResourceAnchors.root, "model").bind(ResourceString(model))
235    Resource(ResourceAnchors.root, "compat").bind(ResourceString(model + "-dev"))
236    Resource(ResourceAnchors.soc, "compat").bind(ResourceString(model + "-soc"))
237    Resource(ResourceAnchors.root, "width").bind(width)
238    Resource(ResourceAnchors.soc, "width").bind(width)
239    Resource(ResourceAnchors.cpus, "width").bind(ResourceInt(1))
240    def bindManagers(xbar: TLNexusNode) = {
241      ManagerUnification(xbar.edges.in.head.manager.managers).foreach{ manager =>
242        manager.resources.foreach(r => r.bind(manager.toResource))
243      }
244    }
245    bindManagers(l3_xbar.asInstanceOf[TLNexusNode])
246    bindManagers(peripheralXbar.asInstanceOf[TLNexusNode])
247  }
248
249  println(s"FPGASoC cores: $NumCores banks: $L3NBanks block size: $L3BlockSize bus size: $L3OuterBusWidth")
250
251  val core_with_l2 = soc.cores.map(coreParams =>
252    LazyModule(new XSCoreWithL2()(p.alterPartial({
253      case XSCoreParamsKey => coreParams
254    })))
255  )
256
257  for (i <- 0 until NumCores) {
258    peripheralXbar := TLBuffer() := core_with_l2(i).uncache
259    val l2_l3_pmu = BusPerfMonitor(enable = !debugOpts.FPGAPlatform)
260    l3_xbar :=* TLBuffer() :=* TLLogger(s"L3_L2_$i", !debugOpts.FPGAPlatform) :=* l2_l3_pmu :=* core_with_l2(i).memory_port
261  }
262
263  val clint = LazyModule(new CLINT(CLINTParams(0x38000000L), 8))
264  clint.node := peripheralXbar
265
266  val clintIntSinks = Array.fill(NumCores){
267    val clintSink = LazyModule(new IntSinkNodeToModule(2))
268    clintSink.sinkNode := clint.intnode
269    clintSink
270  }
271
272  val fakeTreeNode = new GenericLogicalTreeNode
273  val beu = LazyModule(
274    new BusErrorUnit(new XSL1BusErrors(NumCores), BusErrorUnitParams(0x38010000), fakeTreeNode))
275  beu.node := peripheralXbar
276
277  class IntSinkNodeToModule(val sinks: Int)(implicit p: Parameters) extends LazyModule {
278    val sinkNode = IntSinkNode(IntSinkPortSimple(1, sinks))
279    lazy val module = new LazyModuleImp(this){
280      val out = IO(Output(Vec(sinks, Bool())))
281      out.zip(sinkNode.in.head._1).foreach{ case (o, i) => o := i }
282    }
283  }
284
285  class IntSourceNodeToModule(val num: Int)(implicit p: Parameters) extends LazyModule {
286    val sourceNode = IntSourceNode(IntSourcePortSimple(num, ports = 1, sources = 1))
287    lazy val module = new LazyModuleImp(this){
288      val in = IO(Input(Vec(num, Bool())))
289      in.zip(sourceNode.out.head._1).foreach{ case (i, s) => s := i }
290    }
291  }
292
293  val plic = LazyModule(new TLPLIC(PLICParams(0x3c000000L), 8))
294  val plicSource = LazyModule(new IntSourceNodeToModule(NrExtIntr))
295  val plicIntSinks = Array.fill(NumCores){
296    val plicSink = LazyModule(new IntSinkNodeToModule(1))
297    plicSink.sinkNode := plic.intnode
298    plicSink
299  }
300  plic.intnode := beu.intNode
301  plic.intnode := plicSource.sourceNode
302
303  plic.node := peripheralXbar
304
305  val l3cacheOpt = soc.L3CacheParamsOpt.map(l3param =>
306    LazyModule(new HuanCun()(new Config((_, _, _) => {
307      case HCCacheParamsKey => l3param
308    })))
309  )
310  val l3_mem_pmu = BusPerfMonitor(enable = !debugOpts.FPGAPlatform)
311
312  l3cacheOpt match {
313    case Some(l3) =>
314      bankedNode :*= TLLogger("MEM_L3", !debugOpts.FPGAPlatform) :*= l3_mem_pmu :*= l3.node :*= TLBuffer() :*= l3_xbar
315    case None => bankedNode :*= TLAdapterNode() :*= l3_xbar
316  }
317
318  val debugModule = LazyModule(new DebugModule(NumCores)(p))
319  debugModule.debug.node := peripheralXbar
320  val debugIntSink = Array.fill(NumCores){
321    val debugSink = LazyModule(new IntSinkNodeToModule(1))
322    debugSink.sinkNode := debugModule.debug.dmOuter.dmOuter.intnode
323    debugSink
324  }
325  debugModule.debug.dmInner.dmInner.sb2tlOpt.foreach { sb2tl  =>
326    l3_xbar := TLBuffer() := TLWidthWidget(1) := sb2tl.node
327  }
328
329  lazy val module = new LazyRawModuleImp(this) {
330    ElaborationArtefacts.add("dts", dts)
331    ElaborationArtefacts.add("graphml", graphML)
332    ElaborationArtefacts.add("json", json)
333    ElaborationArtefacts.add("plusArgs", freechips.rocketchip.util.PlusArgArtefacts.serialize_cHeader())
334
335    val io = IO(new Bundle {
336      val clock = Input(Bool())
337      val reset = Input(Bool())
338      val sram_config = Input(UInt(5.W))
339      val osc_clock = Input(Bool())
340      val pll_output = Output(UInt(14.W))
341      val extIntrs = Input(UInt(NrExtIntr.W))
342      // val meip = Input(Vec(NumCores, Bool()))
343      val ila = if(debugOpts.FPGAPlatform && EnableILA) Some(Output(new ILABundle)) else None
344      val systemjtag = new Bundle {
345        val jtag = Flipped(new JTAGIO(hasTRSTn = false))
346        val reset = Input(Bool()) // No reset allowed on top
347        val mfr_id = Input(UInt(11.W))
348        val part_number = Input(UInt(16.W))
349        val version = Input(UInt(4.W))
350      }
351      // val resetCtrl = new ResetCtrlIO(NumCores)(p)
352    })
353    io.pll_output := DontCare
354    dontTouch(io.sram_config)
355    dontTouch(io.osc_clock)
356    dontTouch(io.pll_output)
357    childClock := io.clock.asClock()
358
359    withClockAndReset(childClock, io.reset) {
360      val resetGen = Module(new ResetGen(1, !debugOpts.FPGAPlatform))
361      resetGen.suggestName("top_reset_gen")
362      childReset := resetGen.io.out | debugModule.module.io.debugIO.ndreset
363    }
364
365    withClockAndReset(childClock, childReset) {
366      plicSource.module.in := io.extIntrs.asBools()
367
368      for (i <- 0 until NumCores) {
369        val core_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform))
370        core_reset_gen.suggestName(s"core_${i}_reset_gen")
371        core_with_l2(i).module.reset := core_reset_gen.io.out
372        core_with_l2(i).module.io.hartId := i.U
373        core_with_l2(i).module.io.externalInterrupt.msip := clintIntSinks(i).module.out(0)
374        core_with_l2(i).module.io.externalInterrupt.mtip := clintIntSinks(i).module.out(1)
375        core_with_l2(i).module.io.externalInterrupt.meip := plicIntSinks(i).module.out(0)
376        core_with_l2(i).module.io.externalInterrupt.debug := debugIntSink(i).module.out(0)
377        beu.module.io.errors.l1plus(i) := core_with_l2(i).module.io.l1plus_error
378        beu.module.io.errors.icache(i) := core_with_l2(i).module.io.icache_error
379        beu.module.io.errors.dcache(i) := core_with_l2(i).module.io.dcache_error
380      }
381
382      if (l3cacheOpt.nonEmpty) {
383        val l3_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform))
384        l3_reset_gen.suggestName("l3_reset_gen")
385        l3cacheOpt.get.module.reset := l3_reset_gen.io.out
386      }
387      // TODO: wrap this in a module
388      val freq = 100
389      val cnt = RegInit(freq.U)
390      val tick = cnt === 0.U
391      cnt := Mux(tick, freq.U, cnt - 1.U)
392      clint.module.io.rtcTick := tick
393
394      debugModule.module.io.resetCtrl.hartIsInReset.foreach {x => x := childReset.asBool() }
395      debugModule.module.io.clock := io.clock
396      debugModule.module.io.reset := io.reset
397
398      debugModule.module.io.debugIO.reset := io.systemjtag.reset // TODO: use synchronizer?
399      debugModule.module.io.debugIO.clock := childClock
400      debugModule.module.io.debugIO.dmactiveAck  := debugModule.module.io.debugIO.dmactive // TODO: delay 3 cycles?
401      // jtag connector
402      debugModule.module.io.debugIO.systemjtag.foreach { x =>
403        x.jtag <> io.systemjtag.jtag
404        x.reset  := io.systemjtag.reset
405        x.mfr_id := io.systemjtag.mfr_id
406        x.part_number := io.systemjtag.part_number
407        x.version := io.systemjtag.version
408      }
409    }
410  }
411}
412
413object TopMain extends App with HasRocketChipStageUtils {
414  override def main(args: Array[String]): Unit = {
415    val (config, firrtlOpts) = ArgParser.parse(args)
416    val soc = DisableMonitors(p => LazyModule(new XSTop()(p)))(config)
417    XiangShanStage.execute(firrtlOpts, Seq(
418      ChiselGeneratorAnnotation(() => {
419        soc.module
420      })
421    ))
422    ElaborationArtefacts.files.foreach{ case (extension, contents) =>
423      writeOutputFile("./build", s"XSTop.${extension}", contents())
424    }
425  }
426}
427