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