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