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