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