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