xref: /XiangShan/src/main/scala/xiangshan/XSCore.scala (revision d57bda64dd69dbc246bd52257ef7392f220149aa)
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, Wb}
24import xiangshan.frontend._
25import xiangshan.cache.mmu._
26import xiangshan.cache.L1plusCacheWrapper
27import chipsalliance.rocketchip.config
28import chipsalliance.rocketchip.config.Parameters
29import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
30import freechips.rocketchip.tile.HasFPUParameters
31import system.{HasSoCParameter, L1CacheErrorInfo, SoCParamsKey}
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  // outer facing nodes
67  val frontend = LazyModule(new Frontend())
68  val l1pluscache = LazyModule(new L1plusCacheWrapper())
69  val ptw = LazyModule(new PTWWrapper())
70
71  val intConfigs = exuConfigs.filter(_.writeIntRf)
72  val intArbiter = LazyModule(new Wb(intConfigs, NRIntWritePorts, isFp = false))
73  val intWbPorts = intArbiter.allConnections.map(c => c.map(intConfigs(_)))
74  val numIntWbPorts = intWbPorts.length
75
76  val fpConfigs = exuConfigs.filter(_.writeFpRf)
77  val fpArbiter = LazyModule(new Wb(fpConfigs, NRFpWritePorts, isFp = true))
78  val fpWbPorts = fpArbiter.allConnections.map(c => c.map(fpConfigs(_)))
79  val numFpWbPorts = fpWbPorts.length
80
81  // TODO: better RS organization
82  // generate rs according to number of function units
83  require(exuParameters.JmpCnt == 1)
84  require(exuParameters.MduCnt <= exuParameters.AluCnt && exuParameters.MduCnt > 0)
85  require(exuParameters.FmiscCnt <= exuParameters.FmacCnt && exuParameters.FmiscCnt > 0)
86  require(exuParameters.LduCnt == 2 && exuParameters.StuCnt == 2)
87
88  // one RS every 2 MDUs
89  val schedulePorts = Seq(
90    // exuCfg, numDeq, intFastWakeupTarget, fpFastWakeupTarget
91    Seq(
92      (AluExeUnitCfg, exuParameters.AluCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg, JumpCSRExeUnitCfg, LdExeUnitCfg, StExeUnitCfg), Seq())
93    ),
94    Seq(
95      (MulDivExeUnitCfg, exuParameters.MduCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg, JumpCSRExeUnitCfg, LdExeUnitCfg, StExeUnitCfg), Seq()),
96      (JumpCSRExeUnitCfg, 1, Seq(), Seq())
97    ),
98    Seq(
99      (FmacExeUnitCfg, exuParameters.FmacCnt, Seq(), Seq(FmacExeUnitCfg, FmiscExeUnitCfg)),
100      (FmiscExeUnitCfg, exuParameters.FmiscCnt, Seq(), Seq())
101    ),
102    Seq(
103      (LdExeUnitCfg, exuParameters.LduCnt, Seq(AluExeUnitCfg, LdExeUnitCfg), Seq()),
104      (StExeUnitCfg, exuParameters.StuCnt, Seq(), Seq())
105    )
106  )
107
108  // should do outer fast wakeup ports here
109  val otherFastPorts = schedulePorts.zipWithIndex.map { case (sche, i) =>
110    val otherCfg = schedulePorts.zipWithIndex.filter(_._2 != i).map(_._1).reduce(_ ++ _)
111    val outerPorts = sche.map(cfg => {
112      // exe units from this scheduler need fastUops from exeunits
113      val outerWakeupInSche = sche.filter(_._1.wakeupFromExu)
114      val intraIntScheOuter = outerWakeupInSche.filter(_._3.contains(cfg._1)).map(_._1)
115      val intraFpScheOuter = outerWakeupInSche.filter(_._4.contains(cfg._1)).map(_._1)
116      // exe units from other schedulers need fastUop from outside
117      val otherIntSource = otherCfg.filter(_._3.contains(cfg._1)).map(_._1)
118      val otherFpSource = otherCfg.filter(_._4.contains(cfg._1)).map(_._1)
119      val intSource = findInWbPorts(intWbPorts, intraIntScheOuter ++ otherIntSource)
120      val fpSource = findInWbPorts(fpWbPorts, intraFpScheOuter ++ otherFpSource)
121      getFastWakeupIndex(cfg._1, intSource, fpSource, numIntWbPorts).sorted
122    })
123    println(s"inter-scheduler wakeup sources for $i: $outerPorts")
124    outerPorts
125  }
126
127  // allow mdu and fmisc to have 2*numDeq enqueue ports
128  val intDpPorts = (0 until exuParameters.AluCnt).map(i => Seq((0, i)))
129  val int1DpPorts = (0 until 2*exuParameters.MduCnt).map(i => {
130    if (i < exuParameters.JmpCnt) Seq((0, i), (1, i))
131    else Seq((0, i))
132  })
133  val fpDpPorts = (0 until exuParameters.FmacCnt).map(i => {
134    if (i < 2*exuParameters.FmiscCnt) Seq((0, i), (1, i))
135    else Seq((1, i))
136  })
137  val lsDpPorts = Seq(
138    Seq((0, 0)),
139    Seq((0, 1)),
140    Seq((1, 0)),
141    Seq((1, 1))
142  )
143  val dispatchPorts = Seq(intDpPorts, int1DpPorts, fpDpPorts, lsDpPorts)
144
145  val exuBlocks = schedulePorts.zip(dispatchPorts).zip(otherFastPorts).reverse.drop(1).reverseMap { case ((sche, disp), other) =>
146    LazyModule(new ExuBlock(sche, disp, intWbPorts, fpWbPorts, other))
147  }
148
149  val memScheduler = LazyModule(new Scheduler(schedulePorts.last, dispatchPorts.last, intWbPorts, fpWbPorts, otherFastPorts.last))
150  val memBlock = LazyModule(new MemBlock()(p.alter((site, here, up) => {
151    case XSCoreParamsKey => up(XSCoreParamsKey).copy(
152      IssQueSize = memScheduler.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 l1pluscache = outer.l1pluscache.module
183  val ptw = outer.ptw.module
184  val exuBlocks = outer.exuBlocks.map(_.module)
185  val memScheduler = outer.memScheduler.module
186
187  val allWriteback = exuBlocks.map(_.io.fuWriteback).fold(Seq())(_ ++ _) ++ memBlock.io.writeback
188
189  val intWriteback = allWriteback.zip(exuConfigs).filter(_._2.writeIntRf).map(_._1)
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 <> l1pluscache.io.error
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
229  frontend.io.icacheMemAcq <> l1pluscache.io.req
230  l1pluscache.io.resp <> frontend.io.icacheMemGrant
231  l1pluscache.io.flush := frontend.io.l1plusFlush
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(2).io.allocate ++ memScheduler.io.allocate
251  for (i <- 0 until exuParameters.AluCnt) {
252    val rsIn = VecInit(Seq(exuBlocks(0).io.allocate(i), exuBlocks(1).io.allocate(i)))
253    val func1 = (op: MicroOp) => outer.exuBlocks(0).scheduler.canAccept(op.ctrl.fuType)
254    val func2 = (op: MicroOp) => outer.exuBlocks(1).scheduler.canAccept(op.ctrl.fuType)
255    val arbiterOut = DispatchArbiter(ctrlBlock.io.enqIQ(i), Seq(func1, func2))
256    rsIn <> arbiterOut
257  }
258  memScheduler.io.redirect <> ctrlBlock.io.redirect
259  memScheduler.io.flush <> ctrlBlock.io.flush
260  memScheduler.io.issue <> memBlock.io.issue
261  memScheduler.io.writeback <> rfWriteback
262  memScheduler.io.fastUopIn <> allFastUop1
263  memScheduler.io.extra.jumpPc <> ctrlBlock.io.jumpPc
264  memScheduler.io.extra.jalr_target <> ctrlBlock.io.jalr_target
265  memScheduler.io.extra.stIssuePtr <> memBlock.io.stIssuePtr
266  memScheduler.io.extra.debug_int_rat <> ctrlBlock.io.debug_int_rat
267  memScheduler.io.extra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat
268
269  exuBlocks.map(_.io).foreach { exu =>
270    exu.redirect <> ctrlBlock.io.redirect
271    exu.flush <> ctrlBlock.io.flush
272    exu.rfWriteback <> rfWriteback
273    exu.fastUopIn <> allFastUop1
274    exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc
275    exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target
276    exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr
277    exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat
278    exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat
279  }
280
281  csrioIn.hartId <> io.hartId
282  csrioIn.perf <> DontCare
283  csrioIn.perf.retiredInstr <> ctrlBlock.io.roqio.toCSR.perfinfo.retiredInstr
284  // csrioIn.perf.bpuInfo <> DontCare // TODO: reassign this
285  csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo
286  csrioIn.perf.memInfo <> memBlock.io.memInfo
287  csrioIn.perf.frontendInfo <> frontend.io.frontendInfo
288
289  csrioIn.fpu.fflags <> ctrlBlock.io.roqio.toCSR.fflags
290  csrioIn.fpu.isIllegal := false.B
291  csrioIn.fpu.dirty_fs <> ctrlBlock.io.roqio.toCSR.dirty_fs
292  csrioIn.fpu.frm <> exuBlocks(2).io.fuExtra.frm.get
293  csrioIn.exception <> ctrlBlock.io.roqio.exception
294  csrioIn.isXRet <> ctrlBlock.io.roqio.toCSR.isXRet
295  csrioIn.trapTarget <> ctrlBlock.io.roqio.toCSR.trapTarget
296  csrioIn.interrupt <> ctrlBlock.io.roqio.toCSR.intrBitSet
297  csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr
298  csrioIn.externalInterrupt <> io.externalInterrupt
299
300  fenceio.sfence <> memBlock.io.sfence
301  fenceio.sbuffer <> memBlock.io.fenceToSbuffer
302
303  memBlock.io.redirect <> ctrlBlock.io.redirect
304  memBlock.io.flush <> ctrlBlock.io.flush
305  memBlock.io.replay <> memScheduler.io.extra.feedback.get.map(_.replay)
306  memBlock.io.rsIdx <> memScheduler.io.extra.feedback.get.map(_.rsIdx)
307  memBlock.io.isFirstIssue <> memScheduler.io.extra.feedback.get.map(_.isFirstIssue)
308  memBlock.io.stData <> memScheduler.stData
309  memBlock.io.csrCtrl <> csrioIn.customCtrl
310  memBlock.io.tlbCsr <> csrioIn.tlb
311  memBlock.io.lsqio.roq <> ctrlBlock.io.roqio.lsq
312  memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.roqio.exception.bits.uop.lqIdx
313  memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.roqio.exception.bits.uop.sqIdx
314  memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.roqio.exception.bits.uop.ctrl.commitType)
315
316  val itlbRepeater = Module(new PTWRepeater(2))
317  val dtlbRepeater = if (usePTWRepeater) {
318    Module(new PTWRepeater(LoadPipelineWidth + StorePipelineWidth))
319  } else {
320    Module(new PTWFilter(LoadPipelineWidth + StorePipelineWidth, PtwMissQueueSize))
321  }
322  itlbRepeater.io.tlb <> frontend.io.ptw
323  dtlbRepeater.io.tlb <> memBlock.io.ptw
324  itlbRepeater.io.sfence <> fenceio.sfence
325  dtlbRepeater.io.sfence <> fenceio.sfence
326  ptw.io.tlb(0) <> itlbRepeater.io.ptw
327  ptw.io.tlb(1) <> dtlbRepeater.io.ptw
328  ptw.io.sfence <> fenceio.sfence
329  ptw.io.csr <> csrioIn.tlb
330
331  // if l2 prefetcher use stream prefetch, it should be placed in XSCore
332  assert(l2PrefetcherParameters._type == "bop")
333  io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable
334
335  val l1plus_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform))
336  l1pluscache.reset := l1plus_reset_gen.io.out
337
338  val ptw_reset_gen = Module(new ResetGen(2, !debugOpts.FPGAPlatform))
339  ptw.reset := ptw_reset_gen.io.out
340  itlbRepeater.reset := ptw_reset_gen.io.out
341  dtlbRepeater.reset := ptw_reset_gen.io.out
342
343  val memBlock_reset_gen = Module(new ResetGen(3, !debugOpts.FPGAPlatform))
344  memBlock.reset := memBlock_reset_gen.io.out
345
346  val exuBlock_reset_gen = Module(new ResetGen(4, !debugOpts.FPGAPlatform))
347  exuBlocks.foreach(_.reset := exuBlock_reset_gen.io.out)
348
349  val ctrlBlock_reset_gen = Module(new ResetGen(6, !debugOpts.FPGAPlatform))
350  ctrlBlock.reset := ctrlBlock_reset_gen.io.out
351
352  val frontend_reset_gen = Module(new ResetGen(7, !debugOpts.FPGAPlatform))
353  frontend.reset := frontend_reset_gen.io.out
354}
355