xref: /XiangShan/src/main/scala/xiangshan/XSCore.scala (revision a273862e37f1d43bee748f2a6353320a2f52f6f4)
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 xiangshan
18
19import chisel3._
20import chisel3.util._
21import xiangshan.backend._
22import xiangshan.backend.fu.HasExceptionNO
23import xiangshan.backend.exu.{ExuConfig, WbArbiter, WbArbiterWrapper}
24import xiangshan.frontend._
25import xiangshan.cache.mmu._
26import chipsalliance.rocketchip.config
27import chipsalliance.rocketchip.config.Parameters
28import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
29import freechips.rocketchip.interrupts.{IntSinkNode, IntSinkPortSimple}
30import freechips.rocketchip.tile.HasFPUParameters
31import system.HasSoCParameter
32import utils._
33
34abstract class XSModule(implicit val p: Parameters) extends MultiIOModule
35  with HasXSParameter
36  with HasExceptionNO
37  with HasFPUParameters {
38  def io: Record
39}
40
41//remove this trait after impl module logic
42trait NeedImpl {
43  this: RawModule =>
44  override protected def IO[T <: Data](iodef: T): T = {
45    println(s"[Warn]: (${this.name}) please reomve 'NeedImpl' after implement this module")
46    val io = chisel3.experimental.IO(iodef)
47    io <> DontCare
48    io
49  }
50}
51
52abstract class XSBundle(implicit val p: Parameters) extends Bundle
53  with HasXSParameter
54
55case class EnviromentParameters
56(
57  FPGAPlatform: Boolean = true,
58  EnableDebug: Boolean = false,
59  EnablePerfDebug: Boolean = true,
60  DualCore: Boolean = false
61)
62
63abstract class XSCoreBase()(implicit p: config.Parameters) extends LazyModule
64  with HasXSParameter with HasExuWbMappingHelper
65{
66  // interrupt sinks
67  val clint_int_sink = IntSinkNode(IntSinkPortSimple(1, 2))
68  val debug_int_sink = IntSinkNode(IntSinkPortSimple(1, 1))
69  val plic_int_sink = IntSinkNode(IntSinkPortSimple(1, 1))
70  // outer facing nodes
71  val frontend = LazyModule(new Frontend())
72  val ptw = LazyModule(new PTWWrapper())
73
74  val wbArbiter = LazyModule(new WbArbiterWrapper(exuConfigs, NRIntWritePorts, NRFpWritePorts))
75  val intWbPorts = wbArbiter.intWbPorts
76  val fpWbPorts = wbArbiter.fpWbPorts
77
78  // TODO: better RS organization
79  // generate rs according to number of function units
80  require(exuParameters.JmpCnt == 1)
81  require(exuParameters.MduCnt <= exuParameters.AluCnt && exuParameters.MduCnt > 0)
82  require(exuParameters.FmiscCnt <= exuParameters.FmacCnt && exuParameters.FmiscCnt > 0)
83  require(exuParameters.LduCnt == 2 && exuParameters.StuCnt == 2)
84
85  // one RS every 2 MDUs
86  val schedulePorts = Seq(
87    // exuCfg, numDeq, intFastWakeupTarget, fpFastWakeupTarget
88    Seq(
89      (AluExeUnitCfg, exuParameters.AluCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg, JumpCSRExeUnitCfg, LdExeUnitCfg, StaExeUnitCfg), Seq()),
90      (MulDivExeUnitCfg, exuParameters.MduCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg), Seq()),
91      (JumpCSRExeUnitCfg, 1, Seq(), Seq()),
92      (LdExeUnitCfg, exuParameters.LduCnt, Seq(AluExeUnitCfg, LdExeUnitCfg), Seq()),
93      (StaExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()),
94      (StdExeUnitCfg, exuParameters.StuCnt, Seq(), Seq())
95    ),
96    Seq(
97      (FmacExeUnitCfg, exuParameters.FmacCnt, Seq(), Seq(FmacExeUnitCfg, FmiscExeUnitCfg)),
98      (FmiscExeUnitCfg, exuParameters.FmiscCnt, Seq(), Seq())
99    )
100  )
101
102  // should do outer fast wakeup ports here
103  val otherFastPorts = schedulePorts.zipWithIndex.map { case (sche, i) =>
104    val otherCfg = schedulePorts.zipWithIndex.filter(_._2 != i).map(_._1).reduce(_ ++ _)
105    val outerPorts = sche.map(cfg => {
106      // exe units from this scheduler need fastUops from exeunits
107      val outerWakeupInSche = sche.filter(_._1.wakeupFromExu)
108      val intraIntScheOuter = outerWakeupInSche.filter(_._3.contains(cfg._1)).map(_._1)
109      val intraFpScheOuter = outerWakeupInSche.filter(_._4.contains(cfg._1)).map(_._1)
110      // exe units from other schedulers need fastUop from outside
111      val otherIntSource = otherCfg.filter(_._3.contains(cfg._1)).map(_._1)
112      val otherFpSource = otherCfg.filter(_._4.contains(cfg._1)).map(_._1)
113      val intSource = findInWbPorts(intWbPorts, intraIntScheOuter ++ otherIntSource)
114      val fpSource = findInWbPorts(fpWbPorts, intraFpScheOuter ++ otherFpSource)
115      getFastWakeupIndex(cfg._1, intSource, fpSource, intWbPorts.length).sorted
116    })
117    println(s"inter-scheduler wakeup sources for $i: $outerPorts")
118    outerPorts
119  }
120
121  // allow mdu and fmisc to have 2*numDeq enqueue ports
122  val intDpPorts = (0 until exuParameters.AluCnt).map(i => {
123    if (i < exuParameters.JmpCnt) Seq((0, i), (1, i), (2, i))
124    else if (i < 2 * exuParameters.MduCnt) Seq((0, i), (1, i))
125    else Seq((0, i))
126  })
127  val lsDpPorts = Seq(
128    Seq((3, 0)),
129    Seq((3, 1)),
130    Seq((4, 0)),
131    Seq((4, 1))
132  ) ++ (0 until exuParameters.StuCnt).map(i => Seq((5, i)))
133  val fpDpPorts = (0 until exuParameters.FmacCnt).map(i => {
134    if (i < 2 * exuParameters.FmiscCnt) Seq((0, i), (1, i))
135    else Seq((0, i))
136  })
137
138  val dispatchPorts = Seq(intDpPorts ++ lsDpPorts, fpDpPorts)
139
140  val outIntRfReadPorts = Seq(0, 0)
141  val outFpRfReadPorts = Seq(0, 2)
142  val hasIntRf = Seq(true, false)
143  val hasFpRf = Seq(false, true)
144  val exuBlocks = schedulePorts.zip(dispatchPorts).zip(otherFastPorts).zipWithIndex.map {
145    case (((sche, disp), other), i) =>
146      LazyModule(new ExuBlock(sche, disp, intWbPorts, fpWbPorts, other, outIntRfReadPorts(i), outFpRfReadPorts(i), hasIntRf(i), hasFpRf(i)))
147  }
148
149  val memBlock = LazyModule(new MemBlock()(p.alter((site, here, up) => {
150    case XSCoreParamsKey => up(XSCoreParamsKey).copy(
151      IssQueSize = exuBlocks.head.scheduler.memRsEntries.max
152    )
153  })))
154}
155
156class XSCore()(implicit p: config.Parameters) extends XSCoreBase
157  with HasXSDts
158{
159  lazy val module = new XSCoreImp(this)
160}
161
162class XSCoreImp(outer: XSCoreBase) extends LazyModuleImp(outer)
163  with HasXSParameter
164  with HasSoCParameter
165  with HasExeBlockHelper {
166  val io = IO(new Bundle {
167    val hartId = Input(UInt(64.W))
168    val l2_pf_enable = Output(Bool())
169    val perfEvents = Vec(numPCntHc * coreParams.L2NBanks,(Input(UInt(6.W))))
170    val beu_errors = Output(new XSL1BusErrors())
171  })
172
173  println(s"FPGAPlatform:${env.FPGAPlatform} EnableDebug:${env.EnableDebug}")
174  AddressSpace.checkMemmap()
175  AddressSpace.printMemmap()
176
177  val ctrlBlock = Module(new CtrlBlock)
178
179  val frontend = outer.frontend.module
180  val memBlock = outer.memBlock.module
181  val ptw = outer.ptw.module
182  val exuBlocks = outer.exuBlocks.map(_.module)
183
184  val allWriteback = exuBlocks.flatMap(_.io.fuWriteback) ++ memBlock.io.writeback
185  require(exuConfigs.length == allWriteback.length, s"${exuConfigs.length} != ${allWriteback.length}")
186  outer.wbArbiter.module.io.in <> allWriteback
187  val rfWriteback = outer.wbArbiter.module.io.out
188
189  io.beu_errors.icache <> frontend.io.error
190  io.beu_errors.dcache <> memBlock.io.error
191
192  require(exuBlocks.count(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)) == 1)
193  val csrFenceMod = exuBlocks.filter(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)).head
194  val csrioIn = csrFenceMod.io.fuExtra.csrio.get
195  val fenceio = csrFenceMod.io.fuExtra.fenceio.get
196
197  frontend.io.backend <> ctrlBlock.io.frontend
198  frontend.io.sfence <> fenceio.sfence
199  frontend.io.tlbCsr <> csrioIn.tlb
200  frontend.io.csrCtrl <> csrioIn.customCtrl
201  frontend.io.fencei := fenceio.fencei
202
203  ctrlBlock.io.csrCtrl <> csrioIn.customCtrl
204  val redirectBlocks = exuBlocks.reverse.filter(_.fuConfigs.map(_._1).map(_.hasRedirect).reduce(_ || _))
205  ctrlBlock.io.exuRedirect <> redirectBlocks.flatMap(_.io.fuExtra.exuRedirect)
206  ctrlBlock.io.stIn <> memBlock.io.stIn
207  ctrlBlock.io.stOut <> memBlock.io.stOut
208  ctrlBlock.io.memoryViolation <> memBlock.io.memoryViolation
209  exuBlocks.head.io.scheExtra.enqLsq.get <> memBlock.io.enqLsq
210  ctrlBlock.io.writeback <> rfWriteback
211
212  val allFastUop = exuBlocks.flatMap(b => b.io.fastUopOut.dropRight(b.numOutFu)) ++ memBlock.io.otherFastWakeup
213  require(allFastUop.length == exuConfigs.length, s"${allFastUop.length} != ${exuConfigs.length}")
214  val intFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeIntRf).map(_._1)
215  val fpFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeFpRf).map(_._1)
216  val intFastUop1 = outer.wbArbiter.intConnections.map(c => intFastUop(c.head))
217  val fpFastUop1 = outer.wbArbiter.fpConnections.map(c => fpFastUop(c.head))
218  val allFastUop1 = intFastUop1 ++ fpFastUop1
219
220  ctrlBlock.io.dispatch <> exuBlocks.flatMap(_.io.in)
221
222  exuBlocks(0).io.scheExtra.fpRfReadIn.get <> exuBlocks(1).io.scheExtra.fpRfReadOut.get
223  exuBlocks(0).io.scheExtra.fpStateReadIn.get <> exuBlocks(1).io.scheExtra.fpStateReadOut.get
224
225  memBlock.io.issue <> exuBlocks(0).io.issue.get
226  // By default, instructions do not have exceptions when they enter the function units.
227  memBlock.io.issue.map(_.bits.uop.clearExceptions())
228  exuBlocks(0).io.scheExtra.loadFastMatch.get <> memBlock.io.loadFastMatch
229
230  val stdIssue = exuBlocks(0).io.issue.get.takeRight(exuParameters.StuCnt)
231  exuBlocks.map(_.io).foreach { exu =>
232    exu.redirect <> ctrlBlock.io.redirect
233    exu.allocPregs <> ctrlBlock.io.allocPregs
234    exu.rfWriteback <> rfWriteback
235    exu.fastUopIn <> allFastUop1
236    exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc
237    exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target
238    exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr
239    exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat
240    exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat
241    exu.scheExtra.memWaitUpdateReq.staIssue.zip(memBlock.io.stIn).foreach{case (sink, src) => {
242      sink.bits := src.bits
243      sink.valid := src.valid
244    }}
245    exu.scheExtra.memWaitUpdateReq.stdIssue.zip(stdIssue).foreach{case (sink, src) => {
246      sink.valid := src.valid
247      sink.bits := src.bits
248    }}
249  }
250  XSPerfHistogram("fastIn_count", PopCount(allFastUop1.map(_.valid)), true.B, 0, allFastUop1.length, 1)
251  XSPerfHistogram("wakeup_count", PopCount(rfWriteback.map(_.valid)), true.B, 0, rfWriteback.length, 1)
252
253  // TODO: connect rsPerf
254  val rsPerf = VecInit(exuBlocks.flatMap(_.io.scheExtra.perf))
255  val rs_perf = Wire(new PerfEventsBundle(rsPerf.length))
256  val rs_cnt = rs_perf.length
257  for (i <- 0 until rs_cnt){
258    rs_perf.perf_events(i).incr_step := rsPerf(i).asUInt
259  }
260  dontTouch(rsPerf)
261  exuBlocks(0).perfinfo.perfEvents <> ctrlBlock.perfinfo.perfEventsEu0
262  exuBlocks(1).perfinfo.perfEvents <> ctrlBlock.perfinfo.perfEventsEu1
263  memBlock.perfinfo.perfEventsPTW <> ptw.perfinfo.perfEvents
264  ctrlBlock.perfinfo.perfEventsRs := rs_perf
265
266  csrioIn.hartId <> io.hartId
267  csrioIn.perf <> DontCare
268  csrioIn.perf.retiredInstr <> ctrlBlock.io.robio.toCSR.perfinfo.retiredInstr
269  csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo
270  csrioIn.perf.memInfo <> memBlock.io.memInfo
271  csrioIn.perf.frontendInfo <> frontend.io.frontendInfo
272
273  csrioIn.perf.perfEventsFrontend <> frontend.perfinfo.perfEvents
274  csrioIn.perf.perfEventsCtrl     <> ctrlBlock.perfinfo.perfEvents
275  csrioIn.perf.perfEventsLsu      <> memBlock.perfinfo.perfEvents
276  csrioIn.perf.perfEventsHc       <> io.perfEvents
277
278  csrioIn.fpu.fflags <> ctrlBlock.io.robio.toCSR.fflags
279  csrioIn.fpu.isIllegal := false.B
280  csrioIn.fpu.dirty_fs <> ctrlBlock.io.robio.toCSR.dirty_fs
281  csrioIn.fpu.frm <> exuBlocks(1).io.fuExtra.frm.get
282  csrioIn.exception <> ctrlBlock.io.robio.exception
283  csrioIn.isXRet <> ctrlBlock.io.robio.toCSR.isXRet
284  csrioIn.trapTarget <> ctrlBlock.io.robio.toCSR.trapTarget
285  csrioIn.interrupt <> ctrlBlock.io.robio.toCSR.intrBitSet
286  csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr
287
288  csrioIn.externalInterrupt.msip := outer.clint_int_sink.in.head._1(0)
289  csrioIn.externalInterrupt.mtip := outer.clint_int_sink.in.head._1(1)
290  csrioIn.externalInterrupt.meip := outer.plic_int_sink.in.head._1(0)
291  csrioIn.externalInterrupt.debug := outer.debug_int_sink.in.head._1(0)
292
293  csrioIn.distributedUpdate <> memBlock.io.csrUpdate // TODO
294
295  fenceio.sfence <> memBlock.io.sfence
296  fenceio.sbuffer <> memBlock.io.fenceToSbuffer
297
298  memBlock.io.redirect <> ctrlBlock.io.redirect
299  memBlock.io.rsfeedback <> exuBlocks(0).io.scheExtra.feedback.get
300  memBlock.io.csrCtrl <> csrioIn.customCtrl
301  memBlock.io.tlbCsr <> csrioIn.tlb
302  memBlock.io.lsqio.rob <> ctrlBlock.io.robio.lsq
303  memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.robio.exception.bits.uop.lqIdx
304  memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.robio.exception.bits.uop.sqIdx
305  memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.uop.ctrl.commitType)
306
307  val itlbRepeater1 = PTWRepeater(frontend.io.ptw, fenceio.sfence, csrioIn.tlb)
308  val itlbRepeater2 = PTWRepeater(itlbRepeater1.io.ptw, ptw.io.tlb(0), fenceio.sfence, csrioIn.tlb)
309  val dtlbRepeater  = PTWFilter(memBlock.io.ptw, ptw.io.tlb(1), fenceio.sfence, csrioIn.tlb, l2tlbParams.filterSize)
310  ptw.io.sfence <> fenceio.sfence
311  ptw.io.csr.tlb <> csrioIn.tlb
312  ptw.io.csr.distribute_csr <> csrioIn.customCtrl.distribute_csr
313
314  // if l2 prefetcher use stream prefetch, it should be placed in XSCore
315  io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable
316
317  // Modules are reset one by one
318  // reset --> SYNC ----> SYNC ------> SYNC -----> SYNC -----> SYNC ---
319  //                  |          |            |           |           |
320  //                  v          v            v           v           v
321  //                 PTW  {MemBlock, dtlb}  ExuBlocks  CtrlBlock  {Frontend, itlb}
322  val resetChain = Seq(
323    Seq(ptw),
324    Seq(memBlock, dtlbRepeater),
325    // Note: arbiters don't actually have reset ports
326    exuBlocks ++ Seq(outer.wbArbiter.module),
327    Seq(ctrlBlock),
328    Seq(frontend, itlbRepeater1, itlbRepeater2)
329  )
330  ResetGen(resetChain, reset.asBool, !debugOpts.FPGAPlatform)
331}
332