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