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