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