xref: /XiangShan/src/main/scala/xiangshan/XSCore.scala (revision d6477c69bc3348d63058f8f4cebbf80cad7ca1e0)
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.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  outer.wbArbiter.module.io.redirect <> ctrlBlock.io.redirect
182  val allWriteback = exuBlocks.flatMap(_.io.fuWriteback) ++ memBlock.io.writeback
183  require(exuConfigs.length == allWriteback.length, s"${exuConfigs.length} != ${allWriteback.length}")
184  outer.wbArbiter.module.io.in <> allWriteback
185  val rfWriteback = outer.wbArbiter.module.io.out
186
187  io.beu_errors.icache <> frontend.io.error
188  io.beu_errors.dcache <> memBlock.io.error
189
190  require(exuBlocks.count(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)) == 1)
191  val csrFenceMod = exuBlocks.filter(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)).head
192  val csrioIn = csrFenceMod.io.fuExtra.csrio.get
193  val fenceio = csrFenceMod.io.fuExtra.fenceio.get
194
195  frontend.io.backend <> ctrlBlock.io.frontend
196  frontend.io.sfence <> fenceio.sfence
197  frontend.io.tlbCsr <> csrioIn.tlb
198  frontend.io.csrCtrl <> csrioIn.customCtrl
199  frontend.io.fencei := fenceio.fencei
200
201  ctrlBlock.io.csrCtrl <> csrioIn.customCtrl
202  val redirectBlocks = exuBlocks.reverse.filter(_.fuConfigs.map(_._1).map(_.hasRedirect).reduce(_ || _))
203  ctrlBlock.io.exuRedirect <> redirectBlocks.flatMap(_.io.fuExtra.exuRedirect)
204  ctrlBlock.io.stIn <> memBlock.io.stIn
205  ctrlBlock.io.stOut <> memBlock.io.stOut
206  ctrlBlock.io.memoryViolation <> memBlock.io.memoryViolation
207  exuBlocks.head.io.scheExtra.enqLsq.get <> memBlock.io.enqLsq
208  val intWriteback = rfWriteback.take(outer.wbArbiter.intArbiter.numOutPorts)
209  val fpWriteback = rfWriteback.drop(outer.wbArbiter.intArbiter.numOutPorts)
210  val fpWritbackNoLoad = fpWriteback.zip(outer.wbArbiter.fpWbPorts).filterNot(_._2.contains(LdExeUnitCfg)).map(_._1)
211  require(fpWritbackNoLoad.length + intWriteback.length == ctrlBlock.io.writeback.length)
212  ctrlBlock.io.writeback <> VecInit(intWriteback ++ fpWritbackNoLoad)
213  // Load Int and Fp have the same bits and we can re-use the write-back ports
214  for (i <- 0 until exuParameters.LduCnt) {
215    ctrlBlock.io.writeback(exuParameters.AluCnt + i).valid := memBlock.io.writeback(i).valid
216  }
217
218  val allFastUop = exuBlocks.flatMap(b => b.io.fastUopOut.dropRight(b.numOutFu)) ++ memBlock.io.otherFastWakeup
219  require(allFastUop.length == exuConfigs.length, s"${allFastUop.length} != ${exuConfigs.length}")
220  val intFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeIntRf).map(_._1)
221  val fpFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeFpRf).map(_._1)
222  val intFastUop1 = outer.wbArbiter.intConnections.map(c => intFastUop(c.head))
223  val fpFastUop1 = outer.wbArbiter.fpConnections.map(c => fpFastUop(c.head))
224  val allFastUop1 = intFastUop1 ++ fpFastUop1
225
226  ctrlBlock.io.dispatch <> exuBlocks.flatMap(_.io.in)
227
228  exuBlocks(0).io.scheExtra.fpRfReadIn.get <> exuBlocks(1).io.scheExtra.fpRfReadOut.get
229  exuBlocks(0).io.scheExtra.fpStateReadIn.get <> exuBlocks(1).io.scheExtra.fpStateReadOut.get
230
231  memBlock.io.issue <> exuBlocks(0).io.issue.get
232  // By default, instructions do not have exceptions when they enter the function units.
233  memBlock.io.issue.map(_.bits.uop.clearExceptions())
234  exuBlocks(0).io.scheExtra.loadFastMatch.get <> memBlock.io.loadFastMatch
235
236  val stdIssue = exuBlocks(0).io.issue.get.takeRight(exuParameters.StuCnt)
237  exuBlocks.map(_.io).foreach { exu =>
238    exu.redirect <> ctrlBlock.io.redirect
239    exu.allocPregs <> ctrlBlock.io.allocPregs
240    exu.rfWriteback <> rfWriteback
241    exu.fastUopIn <> allFastUop1
242    exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc
243    exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target
244    exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr
245    exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat
246    exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat
247    exu.scheExtra.memWaitUpdateReq.staIssue.zip(memBlock.io.stIn).foreach{case (sink, src) => {
248      sink.bits := src.bits
249      sink.valid := src.valid
250    }}
251    exu.scheExtra.memWaitUpdateReq.stdIssue.zip(stdIssue).foreach{case (sink, src) => {
252      sink.valid := src.valid
253      sink.bits := src.bits
254    }}
255  }
256  XSPerfHistogram("fastIn_count", PopCount(allFastUop1.map(_.valid)), true.B, 0, allFastUop1.length, 1)
257  XSPerfHistogram("wakeup_count", PopCount(rfWriteback.map(_.valid)), true.B, 0, rfWriteback.length, 1)
258
259  // TODO: connect rsPerf
260  val rsPerf = VecInit(exuBlocks.flatMap(_.io.scheExtra.perf))
261  val rs_perf = Wire(new PerfEventsBundle(rsPerf.length))
262  val rs_cnt = rs_perf.length
263  for (i <- 0 until rs_cnt){
264    rs_perf.perf_events(i).incr_step := rsPerf(i).asUInt
265  }
266  dontTouch(rsPerf)
267  exuBlocks(0).perfinfo.perfEvents <> ctrlBlock.perfinfo.perfEventsEu0
268  exuBlocks(1).perfinfo.perfEvents <> ctrlBlock.perfinfo.perfEventsEu1
269  memBlock.perfinfo.perfEventsPTW <> ptw.perfinfo.perfEvents
270  ctrlBlock.perfinfo.perfEventsRs := rs_perf
271
272  csrioIn.hartId <> io.hartId
273  csrioIn.perf <> DontCare
274  csrioIn.perf.retiredInstr <> ctrlBlock.io.robio.toCSR.perfinfo.retiredInstr
275  csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo
276  csrioIn.perf.memInfo <> memBlock.io.memInfo
277  csrioIn.perf.frontendInfo <> frontend.io.frontendInfo
278
279  csrioIn.perf.perfEventsFrontend <> frontend.perfinfo.perfEvents
280  csrioIn.perf.perfEventsCtrl     <> ctrlBlock.perfinfo.perfEvents
281  csrioIn.perf.perfEventsLsu      <> memBlock.perfinfo.perfEvents
282  csrioIn.perf.perfEventsHc       <> io.perfEvents
283
284  csrioIn.fpu.fflags <> ctrlBlock.io.robio.toCSR.fflags
285  csrioIn.fpu.isIllegal := false.B
286  csrioIn.fpu.dirty_fs <> ctrlBlock.io.robio.toCSR.dirty_fs
287  csrioIn.fpu.frm <> exuBlocks(1).io.fuExtra.frm.get
288  csrioIn.exception <> ctrlBlock.io.robio.exception
289  csrioIn.isXRet <> ctrlBlock.io.robio.toCSR.isXRet
290  csrioIn.trapTarget <> ctrlBlock.io.robio.toCSR.trapTarget
291  csrioIn.interrupt <> ctrlBlock.io.robio.toCSR.intrBitSet
292  csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr
293
294  csrioIn.externalInterrupt.msip := outer.clint_int_sink.in.head._1(0)
295  csrioIn.externalInterrupt.mtip := outer.clint_int_sink.in.head._1(1)
296  csrioIn.externalInterrupt.meip := outer.plic_int_sink.in.head._1(0)
297  csrioIn.externalInterrupt.seip := outer.plic_int_sink.in.last._1(0)
298  csrioIn.externalInterrupt.debug := outer.debug_int_sink.in.head._1(0)
299
300  csrioIn.distributedUpdate <> memBlock.io.csrUpdate // TODO
301
302  fenceio.sfence <> memBlock.io.sfence
303  fenceio.sbuffer <> memBlock.io.fenceToSbuffer
304
305  memBlock.io.redirect <> ctrlBlock.io.redirect
306  memBlock.io.rsfeedback <> exuBlocks(0).io.scheExtra.feedback.get
307  memBlock.io.csrCtrl <> csrioIn.customCtrl
308  memBlock.io.tlbCsr <> csrioIn.tlb
309  memBlock.io.lsqio.rob <> ctrlBlock.io.robio.lsq
310  memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.uop.ctrl.commitType)
311
312  val itlbRepeater1 = PTWRepeater(frontend.io.ptw, fenceio.sfence, csrioIn.tlb)
313  val itlbRepeater2 = PTWRepeater(itlbRepeater1.io.ptw, ptw.io.tlb(0), fenceio.sfence, csrioIn.tlb)
314  val dtlbRepeater1  = PTWFilter(memBlock.io.ptw, fenceio.sfence, csrioIn.tlb, l2tlbParams.filterSize)
315  val dtlbRepeater2  = PTWRepeaterNB(passReady = false, dtlbRepeater1.io.ptw, ptw.io.tlb(1), fenceio.sfence, csrioIn.tlb)
316  ptw.io.sfence <> fenceio.sfence
317  ptw.io.csr.tlb <> csrioIn.tlb
318  ptw.io.csr.distribute_csr <> csrioIn.customCtrl.distribute_csr
319
320  // if l2 prefetcher use stream prefetch, it should be placed in XSCore
321  io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable
322
323  // Modules are reset one by one
324  // reset --> SYNC ----> SYNC ------> SYNC -----> SYNC -----> SYNC ---
325  //                  |          |            |           |           |
326  //                  v          v            v           v           v
327  //                 PTW  {MemBlock, dtlb}  ExuBlocks  CtrlBlock  {Frontend, itlb}
328  val resetChain = Seq(
329    Seq(memBlock, dtlbRepeater1, dtlbRepeater2),
330    Seq(exuBlocks.head),
331    // Note: arbiters don't actually have reset ports
332    exuBlocks.tail ++ Seq(outer.wbArbiter.module),
333    Seq(ctrlBlock),
334    Seq(ptw),
335    Seq(frontend, itlbRepeater1, itlbRepeater2)
336  )
337  ResetGen(resetChain, reset.asBool, !debugOpts.FPGAPlatform)
338}
339