xref: /XiangShan/src/main/scala/top/Top.scala (revision a58e33519795596dc4f85fe66907cbc7dde2d66a)
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    l3_xbar := TLBuffer() := TLLogger(s"L3_L2_$i") := core_with_l2(i).memory_port
258  }
259
260  val clint = LazyModule(new CLINT(CLINTParams(0x38000000L), 8))
261  clint.node := peripheralXbar
262
263  val clintIntSinks = Array.fill(NumCores){
264    val clintSink = LazyModule(new IntSinkNodeToModule(2))
265    clintSink.sinkNode := clint.intnode
266    clintSink
267  }
268
269  val fakeTreeNode = new GenericLogicalTreeNode
270  val beu = LazyModule(
271    new BusErrorUnit(new XSL1BusErrors(NumCores), BusErrorUnitParams(0x38010000), fakeTreeNode))
272  beu.node := peripheralXbar
273
274  class IntSinkNodeToModule(val sinks: Int)(implicit p: Parameters) extends LazyModule {
275    val sinkNode = IntSinkNode(IntSinkPortSimple(1, sinks))
276    lazy val module = new LazyModuleImp(this){
277      val out = IO(Output(Vec(sinks, Bool())))
278      out.zip(sinkNode.in.head._1).foreach{ case (o, i) => o := i }
279    }
280  }
281
282  class IntSourceNodeToModule(val num: Int)(implicit p: Parameters) extends LazyModule {
283    val sourceNode = IntSourceNode(IntSourcePortSimple(num, ports = 1, sources = 1))
284    lazy val module = new LazyModuleImp(this){
285      val in = IO(Input(Vec(num, Bool())))
286      in.zip(sourceNode.out.head._1).foreach{ case (i, s) => s := i }
287    }
288  }
289
290  val plic = LazyModule(new TLPLIC(PLICParams(0x3c000000L), 8))
291  val plicSource = LazyModule(new IntSourceNodeToModule(NrExtIntr))
292  val plicIntSinks = Array.fill(NumCores){
293    val plicSink = LazyModule(new IntSinkNodeToModule(1))
294    plicSink.sinkNode := plic.intnode
295    plicSink
296  }
297  plic.intnode := beu.intNode
298  plic.intnode := plicSource.sourceNode
299
300  plic.node := peripheralXbar
301
302  val l3cache = if(useFakeL3Cache) null else LazyModule(new HuanCun()(new Config((_, _, _) => {
303    case HCCacheParamsKey => soc.L3CacheParams
304  })))
305
306  val l3Ignore = if (useFakeL3Cache) TLIgnoreNode() else null
307
308  if (useFakeL3Cache) {
309    bankedNode :*= l3Ignore :*= l3_xbar
310  }
311  else {
312    bankedNode :*= TLLogger("MEM_L3") :*= l3cache.node :*= BusPerfMonitor(enable = true) :*= TLBuffer() :*= l3_xbar
313  }
314
315  val debugModule = LazyModule(new DebugModule(NumCores)(p))
316  debugModule.debug.node := peripheralXbar
317  val debugIntSink = LazyModule(new IntSinkNodeToModule(NumCores))
318  debugIntSink.sinkNode := debugModule.debug.dmOuter.dmOuter.intnode
319  debugModule.debug.dmInner.dmInner.sb2tlOpt.foreach { sb2tl  =>
320    l3_xbar := TLBuffer() := TLWidthWidget(1) := sb2tl.node
321  }
322
323  lazy val module = new LazyRawModuleImp(this) {
324    ElaborationArtefacts.add("dts", dts)
325    ElaborationArtefacts.add("graphml", graphML)
326    ElaborationArtefacts.add("json", json)
327    ElaborationArtefacts.add("plusArgs", freechips.rocketchip.util.PlusArgArtefacts.serialize_cHeader())
328
329    val io = IO(new Bundle {
330      val clock = Input(Bool())
331      val reset = Input(Bool())
332      val sram_config = Input(UInt(5.W))
333      val osc_clock = Input(Bool())
334      val pll_output = Output(UInt(14.W))
335      val extIntrs = Input(UInt(NrExtIntr.W))
336      // val meip = Input(Vec(NumCores, Bool()))
337      val ila = if(debugOpts.FPGAPlatform && EnableILA) Some(Output(new ILABundle)) else None
338      val systemjtag = new Bundle {
339        val jtag = Flipped(new JTAGIO(hasTRSTn = false))
340        val reset = Input(Bool()) // No reset allowed on top
341        val mfr_id = Input(UInt(11.W))
342        val part_number = Input(UInt(16.W))
343        val version = Input(UInt(4.W))
344      }
345      // val resetCtrl = new ResetCtrlIO(NumCores)(p)
346    })
347    io.pll_output := DontCare
348    dontTouch(io.sram_config)
349    dontTouch(io.osc_clock)
350    dontTouch(io.pll_output)
351    childClock := io.clock.asClock()
352
353    withClockAndReset(childClock, io.reset) {
354      val resetGen = Module(new ResetGen(1, !debugOpts.FPGAPlatform))
355      resetGen.suggestName("top_reset_gen")
356      childReset := resetGen.io.out | debugModule.module.io.debugIO.ndreset
357    }
358
359    withClockAndReset(childClock, childReset) {
360      plicSource.module.in := io.extIntrs.asBools()
361
362      for (i <- 0 until NumCores) {
363        val core_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform))
364        core_reset_gen.suggestName(s"core_${i}_reset_gen")
365        core_with_l2(i).module.reset := core_reset_gen.io.out
366        core_with_l2(i).module.io.hartId := i.U
367        core_with_l2(i).module.io.externalInterrupt.msip := clintIntSinks(i).module.out(0)
368        core_with_l2(i).module.io.externalInterrupt.mtip := clintIntSinks(i).module.out(1)
369        core_with_l2(i).module.io.externalInterrupt.meip := plicIntSinks(i).module.out(0)
370        core_with_l2(i).module.io.externalInterrupt.debug := debugIntSink.module.out(i)
371        beu.module.io.errors.l1plus(i) := core_with_l2(i).module.io.l1plus_error
372        beu.module.io.errors.icache(i) := core_with_l2(i).module.io.icache_error
373        beu.module.io.errors.dcache(i) := core_with_l2(i).module.io.dcache_error
374      }
375
376      if (!useFakeL3Cache) {
377        val l3_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform))
378        l3_reset_gen.suggestName("l3_reset_gen")
379        l3cache.module.reset := l3_reset_gen.io.out
380      }
381      // TODO: wrap this in a module
382      val freq = 100
383      val cnt = RegInit(freq.U)
384      val tick = cnt === 0.U
385      cnt := Mux(tick, freq.U, cnt - 1.U)
386      clint.module.io.rtcTick := tick
387
388      debugModule.module.io.resetCtrl.hartIsInReset.foreach {x => x := childReset.asBool() }
389      debugModule.module.io.clock := io.clock
390      debugModule.module.io.reset := io.reset
391
392      debugModule.module.io.debugIO.reset := io.systemjtag.reset // TODO: use synchronizer?
393      debugModule.module.io.debugIO.clock := childClock
394      debugModule.module.io.debugIO.dmactiveAck  := debugModule.module.io.debugIO.dmactive // TODO: delay 3 cycles?
395      // jtag connector
396      debugModule.module.io.debugIO.systemjtag.foreach { x =>
397        x.jtag <> io.systemjtag.jtag
398        x.reset  := io.systemjtag.reset
399        x.mfr_id := io.systemjtag.mfr_id
400        x.part_number := io.systemjtag.part_number
401        x.version := io.systemjtag.version
402      }
403    }
404  }
405}
406
407object TopMain extends App with HasRocketChipStageUtils {
408  override def main(args: Array[String]): Unit = {
409    val (config, firrtlOpts) = ArgParser.parse(args)
410    XiangShanStage.execute(firrtlOpts, Seq(
411      ChiselGeneratorAnnotation(() => {
412        val soc = LazyModule(new XSTop()(config))
413        soc.module
414      })
415    ))
416    ElaborationArtefacts.files.foreach{ case (extension, contents) =>
417      writeOutputFile("./build", s"XSTop.${extension}", contents())
418    }
419  }
420}
421