xref: /XiangShan/src/main/scala/xiangshan/XSCore.scala (revision 7154d65e61dadbebf64d138841a8804142559e30)
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    ),
94    Seq(
95      (FmacExeUnitCfg, exuParameters.FmacCnt, Seq(), Seq(FmacExeUnitCfg, FmiscExeUnitCfg)),
96      (FmiscExeUnitCfg, exuParameters.FmiscCnt, Seq(), Seq())
97    ),
98    Seq(
99      (LdExeUnitCfg, exuParameters.LduCnt, Seq(AluExeUnitCfg, LdExeUnitCfg), Seq()),
100      (StaExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()),
101      (StdExeUnitCfg, exuParameters.StuCnt, Seq(), Seq())
102    )
103  )
104
105  // should do outer fast wakeup ports here
106  val otherFastPorts = schedulePorts.zipWithIndex.map { case (sche, i) =>
107    val otherCfg = schedulePorts.zipWithIndex.filter(_._2 != i).map(_._1).reduce(_ ++ _)
108    val outerPorts = sche.map(cfg => {
109      // exe units from this scheduler need fastUops from exeunits
110      val outerWakeupInSche = sche.filter(_._1.wakeupFromExu)
111      val intraIntScheOuter = outerWakeupInSche.filter(_._3.contains(cfg._1)).map(_._1)
112      val intraFpScheOuter = outerWakeupInSche.filter(_._4.contains(cfg._1)).map(_._1)
113      // exe units from other schedulers need fastUop from outside
114      val otherIntSource = otherCfg.filter(_._3.contains(cfg._1)).map(_._1)
115      val otherFpSource = otherCfg.filter(_._4.contains(cfg._1)).map(_._1)
116      val intSource = findInWbPorts(intWbPorts, intraIntScheOuter ++ otherIntSource)
117      val fpSource = findInWbPorts(fpWbPorts, intraFpScheOuter ++ otherFpSource)
118      getFastWakeupIndex(cfg._1, intSource, fpSource, numIntWbPorts).sorted
119    })
120    println(s"inter-scheduler wakeup sources for $i: $outerPorts")
121    outerPorts
122  }
123
124  // allow mdu and fmisc to have 2*numDeq enqueue ports
125  val intDpPorts = (0 until exuParameters.AluCnt).map(i => {
126    if (i < exuParameters.JmpCnt) Seq((0, i), (1, i), (2, i))
127    else if (i < exuParameters.MduCnt) Seq((0, i), (1, i))
128    else Seq((0, i))
129  })
130  val lsDpPorts = Seq(
131    Seq((0, 0)),
132    Seq((0, 1)),
133    Seq((1, 0)),
134    Seq((1, 1))
135  ) ++ (0 until exuParameters.StuCnt).map(i => Seq((2, i)))
136  val fpDpPorts = (0 until exuParameters.FmacCnt).map(i => {
137    if (i < exuParameters.FmiscCnt) Seq((0, i), (1, i))
138    else Seq((0, i))
139  })
140
141  val dispatchPorts = Seq(intDpPorts, fpDpPorts, lsDpPorts)
142
143  val outIntRfReadPorts = Seq(6, 0, 0)
144  val outFpRfReadPorts = Seq(0, 2, 0)
145  val hasIntRf = Seq(true, false, false)
146  val hasFpRf = Seq(false, true, false)
147  val exuBlocks = schedulePorts.zip(dispatchPorts).zip(otherFastPorts).zipWithIndex.dropRight(1).map {
148    case (((sche, disp), other), i) =>
149      LazyModule(new ExuBlock(sche, disp, intWbPorts, fpWbPorts, other, outIntRfReadPorts(i), outFpRfReadPorts(i), hasIntRf(i), hasFpRf(i)))
150  }
151
152  val memScheduler = LazyModule(new Scheduler(schedulePorts.last, dispatchPorts.last, intWbPorts, fpWbPorts, otherFastPorts.last, outIntRfReadPorts.last, outFpRfReadPorts.last, hasIntRf.last, hasFpRf.last))
153  val memBlock = LazyModule(new MemBlock()(p.alter((site, here, up) => {
154    case XSCoreParamsKey => up(XSCoreParamsKey).copy(
155      IssQueSize = memScheduler.memRsEntries.max
156    )
157  })))
158}
159
160class XSCore()(implicit p: config.Parameters) extends XSCoreBase
161  with HasXSDts
162{
163  lazy val module = new XSCoreImp(this)
164}
165
166class XSCoreImp(outer: XSCoreBase) extends LazyModuleImp(outer)
167  with HasXSParameter
168  with HasSoCParameter
169  with HasExeBlockHelper {
170  val io = IO(new Bundle {
171    val hartId = Input(UInt(64.W))
172    val externalInterrupt = new ExternalInterruptIO
173    val l2_pf_enable = Output(Bool())
174    val l1plus_error, icache_error, dcache_error = Output(new L1CacheErrorInfo)
175  })
176
177  println(s"FPGAPlatform:${env.FPGAPlatform} EnableDebug:${env.EnableDebug}")
178  AddressSpace.checkMemmap()
179  AddressSpace.printMemmap()
180
181  val ctrlBlock = Module(new CtrlBlock)
182
183  val frontend = outer.frontend.module
184  val memBlock = outer.memBlock.module
185  val ptw = outer.ptw.module
186  val exuBlocks = outer.exuBlocks.map(_.module)
187  val memScheduler = outer.memScheduler.module
188
189  val allWriteback = exuBlocks.map(_.io.fuWriteback).fold(Seq())(_ ++ _) ++ memBlock.io.writeback
190
191  val intWriteback = allWriteback.zip(exuConfigs).filter(_._2.writeIntRf).map(_._1)
192  require(exuConfigs.length == allWriteback.length, s"${exuConfigs.length} != ${allWriteback.length}")
193
194  // set default value for ready
195  exuBlocks.foreach(_.io.fuWriteback.foreach(_.ready := true.B))
196  memBlock.io.writeback.foreach(_.ready := true.B)
197
198  val intArbiter = outer.intArbiter.module
199  intArbiter.io.in.zip(intWriteback).foreach { case (arb, wb) =>
200    arb.valid := wb.valid && !wb.bits.uop.ctrl.fpWen
201    arb.bits := wb.bits
202    when (arb.valid) {
203      wb.ready := arb.ready
204    }
205  }
206
207  val fpArbiter = outer.fpArbiter.module
208  val fpWriteback = allWriteback.zip(exuConfigs).filter(_._2.writeFpRf).map(_._1)
209  fpArbiter.io.in.zip(fpWriteback).foreach{ case (arb, wb) =>
210    arb.valid := wb.valid && wb.bits.uop.ctrl.fpWen
211    arb.bits := wb.bits
212    when (arb.valid) {
213      wb.ready := arb.ready
214    }
215  }
216
217  val rfWriteback = VecInit(intArbiter.io.out ++ fpArbiter.io.out)
218
219  io.l1plus_error <> DontCare
220  io.icache_error <> frontend.io.error
221  io.dcache_error <> memBlock.io.error
222
223  require(exuBlocks.count(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)) == 1)
224  val csrFenceMod = exuBlocks.filter(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)).head
225  val csrioIn = csrFenceMod.io.fuExtra.csrio.get
226  val fenceio = csrFenceMod.io.fuExtra.fenceio.get
227
228  frontend.io.backend <> ctrlBlock.io.frontend
229  frontend.io.sfence <> fenceio.sfence
230  frontend.io.tlbCsr <> csrioIn.tlb
231  frontend.io.csrCtrl <> csrioIn.customCtrl
232  frontend.io.fencei := fenceio.fencei
233
234  ctrlBlock.io.csrCtrl <> csrioIn.customCtrl
235  val redirectBlocks = exuBlocks.reverse.filter(_.fuConfigs.map(_._1).map(_.hasRedirect).reduce(_ || _))
236  ctrlBlock.io.exuRedirect <> redirectBlocks.map(_.io.fuExtra.exuRedirect).fold(Seq())(_ ++ _)
237  ctrlBlock.io.stIn <> memBlock.io.stIn
238  ctrlBlock.io.stOut <> memBlock.io.stOut
239  ctrlBlock.io.memoryViolation <> memBlock.io.memoryViolation
240  ctrlBlock.io.enqLsq <> memBlock.io.enqLsq
241  ctrlBlock.io.writeback <> rfWriteback
242
243  val allFastUop = exuBlocks.map(_.io.fastUopOut).fold(Seq())(_ ++ _) ++ memBlock.io.otherFastWakeup
244  val intFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeIntRf).map(_._1)
245  val fpFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeFpRf).map(_._1)
246  val intFastUop1 = outer.intArbiter.allConnections.map(c => intFastUop(c.head))
247  val fpFastUop1 = outer.fpArbiter.allConnections.map(c => fpFastUop(c.head))
248  val allFastUop1 = intFastUop1 ++ fpFastUop1
249
250  ctrlBlock.io.enqIQ <> exuBlocks(0).io.allocate ++ exuBlocks(1).io.allocate ++ memScheduler.io.allocate.take(4)
251
252  val stdAllocate = memScheduler.io.allocate.takeRight(2)
253  val staAllocate = memScheduler.io.allocate.slice(2, 4)
254  stdAllocate.zip(staAllocate).zip(ctrlBlock.io.enqIQ.takeRight(2)).zipWithIndex.foreach{ case (((std, sta), enq), i) =>
255    std.valid := enq.valid && sta.ready
256    sta.valid := enq.valid && std.ready
257    std.bits := enq.bits
258    sta.bits := enq.bits
259    std.bits.ctrl.lsrc(0) := enq.bits.ctrl.lsrc(1)
260    std.bits.psrc(0) := enq.bits.psrc(1)
261    std.bits.srcState(0) := enq.bits.srcState(1)
262    std.bits.ctrl.srcType(0) := enq.bits.ctrl.srcType(1)
263    enq.ready := sta.ready && std.ready
264    XSPerfAccumulate(s"st_rs_not_ready_$i", enq.valid && !enq.ready)
265    XSPerfAccumulate(s"sta_rs_not_ready_$i", sta.valid && !sta.ready)
266    XSPerfAccumulate(s"std_rs_not_ready_$i", std.valid && !std.ready)
267  }
268  memScheduler.io.extra.fpRfReadIn.get <> exuBlocks(1).io.scheExtra.fpRfReadOut.get
269  memScheduler.io.extra.intRfReadIn.get <> exuBlocks(0).io.scheExtra.intRfReadOut.get
270
271  memScheduler.io.redirect <> ctrlBlock.io.redirect
272  memScheduler.io.flush <> ctrlBlock.io.flush
273  memBlock.io.issue <> memScheduler.io.issue
274  // By default, instructions do not have exceptions when they enter the function units.
275  memBlock.io.issue.map(_.bits.uop.clearExceptions())
276  memScheduler.io.writeback <> rfWriteback
277  memScheduler.io.fastUopIn <> allFastUop1
278  memScheduler.io.extra.jumpPc <> ctrlBlock.io.jumpPc
279  memScheduler.io.extra.jalr_target <> ctrlBlock.io.jalr_target
280  memScheduler.io.extra.stIssuePtr <> memBlock.io.stIssuePtr
281  memScheduler.io.extra.loadFastMatch.get <> memBlock.io.loadFastMatch
282  memScheduler.io.extra.debug_int_rat <> ctrlBlock.io.debug_int_rat
283  memScheduler.io.extra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat
284
285  exuBlocks.map(_.io).foreach { exu =>
286    exu.redirect <> ctrlBlock.io.redirect
287    exu.flush <> ctrlBlock.io.flush
288    exu.rfWriteback <> rfWriteback
289    exu.fastUopIn <> allFastUop1
290    exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc
291    exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target
292    exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr
293    exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat
294    exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat
295  }
296  XSPerfHistogram("fastIn_count", PopCount(allFastUop1.map(_.valid)), true.B, 0, allFastUop1.length, 1)
297  XSPerfHistogram("wakeup_count", PopCount(rfWriteback.map(_.valid)), true.B, 0, rfWriteback.length, 1)
298
299  csrioIn.hartId <> io.hartId
300  csrioIn.perf <> DontCare
301  csrioIn.perf.retiredInstr <> ctrlBlock.io.robio.toCSR.perfinfo.retiredInstr
302  csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo
303  csrioIn.perf.memInfo <> memBlock.io.memInfo
304  csrioIn.perf.frontendInfo <> frontend.io.frontendInfo
305
306  csrioIn.fpu.fflags <> ctrlBlock.io.robio.toCSR.fflags
307  csrioIn.fpu.isIllegal := false.B
308  csrioIn.fpu.dirty_fs <> ctrlBlock.io.robio.toCSR.dirty_fs
309  csrioIn.fpu.frm <> exuBlocks(1).io.fuExtra.frm.get
310  csrioIn.exception <> ctrlBlock.io.robio.exception
311  csrioIn.isXRet <> ctrlBlock.io.robio.toCSR.isXRet
312  csrioIn.trapTarget <> ctrlBlock.io.robio.toCSR.trapTarget
313  csrioIn.interrupt <> ctrlBlock.io.robio.toCSR.intrBitSet
314  csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr
315  csrioIn.externalInterrupt <> io.externalInterrupt
316
317  fenceio.sfence <> memBlock.io.sfence
318  fenceio.sbuffer <> memBlock.io.fenceToSbuffer
319
320  memBlock.io.redirect <> ctrlBlock.io.redirect
321  memBlock.io.flush <> ctrlBlock.io.flush
322  memBlock.io.replay <> memScheduler.io.extra.feedback.get.map(_.replay)
323  memBlock.io.rsIdx <> memScheduler.io.extra.feedback.get.map(_.rsIdx)
324  memBlock.io.isFirstIssue <> memScheduler.io.extra.feedback.get.map(_.isFirstIssue)
325  memBlock.io.csrCtrl <> csrioIn.customCtrl
326  memBlock.io.tlbCsr <> csrioIn.tlb
327  memBlock.io.lsqio.rob <> ctrlBlock.io.robio.lsq
328  memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.robio.exception.bits.uop.lqIdx
329  memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.robio.exception.bits.uop.sqIdx
330  memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.uop.ctrl.commitType)
331
332  val itlbRepeater = Module(new PTWRepeater(2))
333  val dtlbRepeater = Module(new PTWFilter(LoadPipelineWidth + StorePipelineWidth, l2tlbParams.missQueueSize - 1))
334  itlbRepeater.io.tlb <> frontend.io.ptw
335  dtlbRepeater.io.tlb <> memBlock.io.ptw
336  itlbRepeater.io.sfence <> fenceio.sfence
337  dtlbRepeater.io.sfence <> fenceio.sfence
338  ptw.io.tlb(0) <> itlbRepeater.io.ptw
339  ptw.io.tlb(1) <> dtlbRepeater.io.ptw
340  ptw.io.sfence <> fenceio.sfence
341  ptw.io.csr <> csrioIn.tlb
342
343  // if l2 prefetcher use stream prefetch, it should be placed in XSCore
344  io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable
345
346  val ptw_reset_gen = Module(new ResetGen(2, !debugOpts.FPGAPlatform))
347  ptw.reset := ptw_reset_gen.io.out
348  itlbRepeater.reset := ptw_reset_gen.io.out
349  dtlbRepeater.reset := ptw_reset_gen.io.out
350
351  val memBlock_reset_gen = Module(new ResetGen(3, !debugOpts.FPGAPlatform))
352  memBlock.reset := memBlock_reset_gen.io.out
353  memScheduler.reset := memBlock_reset_gen.io.out
354
355  val exuBlock_reset_gen = Module(new ResetGen(4, !debugOpts.FPGAPlatform))
356  exuBlocks.foreach(_.reset := exuBlock_reset_gen.io.out)
357
358  val ctrlBlock_reset_gen = Module(new ResetGen(6, !debugOpts.FPGAPlatform))
359  ctrlBlock.reset := ctrlBlock_reset_gen.io.out
360
361  val frontend_reset_gen = Module(new ResetGen(7, !debugOpts.FPGAPlatform))
362  frontend.reset := frontend_reset_gen.io.out
363}
364