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