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