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