xref: /XiangShan/src/main/scala/xiangshan/XSCore.scala (revision f973ab00f36a43196f948e67b30d0eff5b65d055)
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.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 intConfigs = exuConfigs.filter(_.writeIntRf)
75  val intArbiter = LazyModule(new WbArbiter(intConfigs, NRIntWritePorts, isFp = false))
76  val intWbPorts = intArbiter.allConnections.map(c => c.map(intConfigs(_)))
77  val numIntWbPorts = intWbPorts.length
78
79  val fpConfigs = exuConfigs.filter(_.writeFpRf)
80  val fpArbiter = LazyModule(new WbArbiter(fpConfigs, NRFpWritePorts, isFp = true))
81  val fpWbPorts = fpArbiter.allConnections.map(c => c.map(fpConfigs(_)))
82  val numFpWbPorts = fpWbPorts.length
83
84  // TODO: better RS organization
85  // generate rs according to number of function units
86  require(exuParameters.JmpCnt == 1)
87  require(exuParameters.MduCnt <= exuParameters.AluCnt && exuParameters.MduCnt > 0)
88  require(exuParameters.FmiscCnt <= exuParameters.FmacCnt && exuParameters.FmiscCnt > 0)
89  require(exuParameters.LduCnt == 2 && exuParameters.StuCnt == 2)
90
91  // one RS every 2 MDUs
92  val schedulePorts = Seq(
93    // exuCfg, numDeq, intFastWakeupTarget, fpFastWakeupTarget
94    Seq(
95      (AluExeUnitCfg, exuParameters.AluCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg, JumpCSRExeUnitCfg, LdExeUnitCfg, StaExeUnitCfg), Seq()),
96      (MulDivExeUnitCfg, exuParameters.MduCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg), Seq()),
97      (JumpCSRExeUnitCfg, 1, Seq(), Seq()),
98      (LdExeUnitCfg, exuParameters.LduCnt, Seq(AluExeUnitCfg, LdExeUnitCfg), Seq()),
99      (StaExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()),
100      (StdExeUnitCfg, exuParameters.StuCnt, Seq(), Seq())
101    ),
102    Seq(
103      (FmacExeUnitCfg, exuParameters.FmacCnt, Seq(), Seq(FmacExeUnitCfg, FmiscExeUnitCfg)),
104      (FmiscExeUnitCfg, exuParameters.FmiscCnt, 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 => {
129    if (i < exuParameters.JmpCnt) Seq((0, i), (1, i), (2, i))
130    else if (i < 2 * exuParameters.MduCnt) Seq((0, i), (1, i))
131    else Seq((0, i))
132  })
133  val lsDpPorts = Seq(
134    Seq((3, 0)),
135    Seq((3, 1)),
136    Seq((4, 0)),
137    Seq((4, 1))
138  ) ++ (0 until exuParameters.StuCnt).map(i => Seq((5, i)))
139  val fpDpPorts = (0 until exuParameters.FmacCnt).map(i => {
140    if (i < 2 * exuParameters.FmiscCnt) Seq((0, i), (1, i))
141    else Seq((0, i))
142  })
143
144  val dispatchPorts = Seq(intDpPorts ++ lsDpPorts, fpDpPorts)
145
146  val outIntRfReadPorts = Seq(0, 0)
147  val outFpRfReadPorts = Seq(0, 2)
148  val hasIntRf = Seq(true, false)
149  val hasFpRf = Seq(false, true)
150  val exuBlocks = schedulePorts.zip(dispatchPorts).zip(otherFastPorts).zipWithIndex.map {
151    case (((sche, disp), other), i) =>
152      LazyModule(new ExuBlock(sche, disp, intWbPorts, fpWbPorts, other, outIntRfReadPorts(i), outFpRfReadPorts(i), hasIntRf(i), hasFpRf(i)))
153  }
154
155  val memBlock = LazyModule(new MemBlock()(p.alter((site, here, up) => {
156    case XSCoreParamsKey => up(XSCoreParamsKey).copy(
157      IssQueSize = exuBlocks.head.scheduler.memRsEntries.max
158    )
159  })))
160}
161
162class XSCore()(implicit p: config.Parameters) extends XSCoreBase
163  with HasXSDts
164{
165  lazy val module = new XSCoreImp(this)
166}
167
168class XSCoreImp(outer: XSCoreBase) extends LazyModuleImp(outer)
169  with HasXSParameter
170  with HasSoCParameter
171  with HasExeBlockHelper {
172  val io = IO(new Bundle {
173    val hartId = Input(UInt(64.W))
174    val l2_pf_enable = Output(Bool())
175    val beu_errors = Output(new XSL1BusErrors())
176  })
177
178  println(s"FPGAPlatform:${env.FPGAPlatform} EnableDebug:${env.EnableDebug}")
179  AddressSpace.checkMemmap()
180  AddressSpace.printMemmap()
181
182  val ctrlBlock = Module(new CtrlBlock)
183
184  val frontend = outer.frontend.module
185  val memBlock = outer.memBlock.module
186  val ptw = outer.ptw.module
187  val exuBlocks = outer.exuBlocks.map(_.module)
188
189  val allWriteback = exuBlocks.flatMap(_.io.fuWriteback) ++ 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.beu_errors.icache <> frontend.io.error
220  io.beu_errors.dcache <> memBlock.io.error
221
222  require(exuBlocks.count(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)) == 1)
223  val csrFenceMod = exuBlocks.filter(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)).head
224  val csrioIn = csrFenceMod.io.fuExtra.csrio.get
225  val fenceio = csrFenceMod.io.fuExtra.fenceio.get
226
227  frontend.io.backend <> ctrlBlock.io.frontend
228  frontend.io.sfence <> fenceio.sfence
229  frontend.io.tlbCsr <> csrioIn.tlb
230  frontend.io.csrCtrl <> csrioIn.customCtrl
231  frontend.io.fencei := fenceio.fencei
232
233  ctrlBlock.io.csrCtrl <> csrioIn.customCtrl
234  val redirectBlocks = exuBlocks.reverse.filter(_.fuConfigs.map(_._1).map(_.hasRedirect).reduce(_ || _))
235  ctrlBlock.io.exuRedirect <> redirectBlocks.flatMap(_.io.fuExtra.exuRedirect)
236  ctrlBlock.io.stIn <> memBlock.io.stIn
237  ctrlBlock.io.stOut <> memBlock.io.stOut
238  ctrlBlock.io.memoryViolation <> memBlock.io.memoryViolation
239  ctrlBlock.io.enqLsq <> memBlock.io.enqLsq
240  ctrlBlock.io.writeback <> rfWriteback
241
242  val allFastUop = exuBlocks.flatMap(b => b.io.fastUopOut.dropRight(b.numOutFu)) ++ memBlock.io.otherFastWakeup
243  require(allFastUop.length == exuConfigs.length, s"${allFastUop.length} != ${exuConfigs.length}")
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.dispatch <> exuBlocks.flatMap(_.io.in)
251
252  exuBlocks(0).io.scheExtra.fpRfReadIn.get <> exuBlocks(1).io.scheExtra.fpRfReadOut.get
253  exuBlocks(0).io.scheExtra.fpStateReadIn.get <> exuBlocks(1).io.scheExtra.fpStateReadOut.get
254
255  memBlock.io.issue <> exuBlocks(0).io.issue.get
256  // By default, instructions do not have exceptions when they enter the function units.
257  memBlock.io.issue.map(_.bits.uop.clearExceptions())
258  exuBlocks(0).io.scheExtra.loadFastMatch.get <> memBlock.io.loadFastMatch
259
260  val stdIssue = exuBlocks(0).io.issue.get.takeRight(exuParameters.StuCnt)
261  exuBlocks.map(_.io).foreach { exu =>
262    exu.redirect <> ctrlBlock.io.redirect
263    exu.flush <> ctrlBlock.io.flush
264    exu.allocPregs <> ctrlBlock.io.allocPregs
265    exu.rfWriteback <> rfWriteback
266    exu.fastUopIn <> allFastUop1
267    exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc
268    exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target
269    exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr
270    exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat
271    exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat
272    exu.scheExtra.memWaitUpdateReq.staIssue.zip(memBlock.io.stIn).foreach{case (sink, src) => {
273      sink.bits := src.bits
274      sink.valid := src.valid && !csrioIn.customCtrl.storeset_no_fast_wakeup
275    }}
276    exu.scheExtra.memWaitUpdateReq.stdIssue.zip(stdIssue).foreach{case (sink, src) => {
277      sink.valid := src.valid
278      sink.bits := src.bits
279    }}
280  }
281  XSPerfHistogram("fastIn_count", PopCount(allFastUop1.map(_.valid)), true.B, 0, allFastUop1.length, 1)
282  XSPerfHistogram("wakeup_count", PopCount(rfWriteback.map(_.valid)), true.B, 0, rfWriteback.length, 1)
283
284  // TODO: connect rsPerf
285  val rsPerf = VecInit(exuBlocks.flatMap(_.io.scheExtra.perf))
286  dontTouch(rsPerf)
287
288  csrioIn.hartId <> io.hartId
289  csrioIn.perf <> DontCare
290  csrioIn.perf.retiredInstr <> ctrlBlock.io.robio.toCSR.perfinfo.retiredInstr
291  csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo
292  csrioIn.perf.memInfo <> memBlock.io.memInfo
293  csrioIn.perf.frontendInfo <> frontend.io.frontendInfo
294
295  csrioIn.fpu.fflags <> ctrlBlock.io.robio.toCSR.fflags
296  csrioIn.fpu.isIllegal := false.B
297  csrioIn.fpu.dirty_fs <> ctrlBlock.io.robio.toCSR.dirty_fs
298  csrioIn.fpu.frm <> exuBlocks(1).io.fuExtra.frm.get
299  csrioIn.exception <> ctrlBlock.io.robio.exception
300  csrioIn.isXRet <> ctrlBlock.io.robio.toCSR.isXRet
301  csrioIn.trapTarget <> ctrlBlock.io.robio.toCSR.trapTarget
302  csrioIn.interrupt <> ctrlBlock.io.robio.toCSR.intrBitSet
303  csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr
304
305  csrioIn.externalInterrupt.msip := outer.clint_int_sink.in.head._1(0)
306  csrioIn.externalInterrupt.mtip := outer.clint_int_sink.in.head._1(1)
307  csrioIn.externalInterrupt.meip := outer.plic_int_sink.in.head._1(0)
308  csrioIn.externalInterrupt.debug := outer.debug_int_sink.in.head._1(0)
309
310  fenceio.sfence <> memBlock.io.sfence
311  fenceio.sbuffer <> memBlock.io.fenceToSbuffer
312
313  memBlock.io.redirect <> ctrlBlock.io.redirect
314  memBlock.io.flush <> ctrlBlock.io.flush
315  memBlock.io.rsfeedback <> exuBlocks(0).io.scheExtra.feedback.get
316  memBlock.io.csrCtrl <> csrioIn.customCtrl
317  memBlock.io.tlbCsr <> csrioIn.tlb
318  memBlock.io.lsqio.rob <> ctrlBlock.io.robio.lsq
319  memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.robio.exception.bits.uop.lqIdx
320  memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.robio.exception.bits.uop.sqIdx
321  memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.uop.ctrl.commitType)
322
323  val itlbRepeater = Module(new PTWRepeater(2))
324  val dtlbRepeater = Module(new PTWFilter(LoadPipelineWidth + StorePipelineWidth, l2tlbParams.missQueueSize - 1))
325  itlbRepeater.io.tlb <> frontend.io.ptw
326  dtlbRepeater.io.tlb <> memBlock.io.ptw
327  itlbRepeater.io.sfence <> fenceio.sfence
328  dtlbRepeater.io.sfence <> fenceio.sfence
329  ptw.io.tlb(0) <> itlbRepeater.io.ptw
330  ptw.io.tlb(1) <> dtlbRepeater.io.ptw
331  ptw.io.sfence <> fenceio.sfence
332  ptw.io.csr.tlb <> csrioIn.tlb
333  ptw.io.csr.distribute_csr <> csrioIn.customCtrl.distribute_csr
334
335  // if l2 prefetcher use stream prefetch, it should be placed in XSCore
336  io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable
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