xref: /XiangShan/src/main/scala/xiangshan/XSCore.scala (revision f4b2089a918d093dcd57da84f0b8b6319ef987f9)
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.allocPregs <> ctrlBlock.io.allocPregs
264    exu.rfWriteback <> rfWriteback
265    exu.fastUopIn <> allFastUop1
266    exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc
267    exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target
268    exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr
269    exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat
270    exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat
271    exu.scheExtra.memWaitUpdateReq.staIssue.zip(memBlock.io.stIn).foreach{case (sink, src) => {
272      sink.bits := src.bits
273      sink.valid := src.valid && !csrioIn.customCtrl.storeset_no_fast_wakeup
274    }}
275    exu.scheExtra.memWaitUpdateReq.stdIssue.zip(stdIssue).foreach{case (sink, src) => {
276      sink.valid := src.valid
277      sink.bits := src.bits
278    }}
279  }
280  XSPerfHistogram("fastIn_count", PopCount(allFastUop1.map(_.valid)), true.B, 0, allFastUop1.length, 1)
281  XSPerfHistogram("wakeup_count", PopCount(rfWriteback.map(_.valid)), true.B, 0, rfWriteback.length, 1)
282
283  // TODO: connect rsPerf
284  val rsPerf = VecInit(exuBlocks.flatMap(_.io.scheExtra.perf))
285  dontTouch(rsPerf)
286
287  csrioIn.hartId <> io.hartId
288  csrioIn.perf <> DontCare
289  csrioIn.perf.retiredInstr <> ctrlBlock.io.robio.toCSR.perfinfo.retiredInstr
290  csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo
291  csrioIn.perf.memInfo <> memBlock.io.memInfo
292  csrioIn.perf.frontendInfo <> frontend.io.frontendInfo
293
294  csrioIn.fpu.fflags <> ctrlBlock.io.robio.toCSR.fflags
295  csrioIn.fpu.isIllegal := false.B
296  csrioIn.fpu.dirty_fs <> ctrlBlock.io.robio.toCSR.dirty_fs
297  csrioIn.fpu.frm <> exuBlocks(1).io.fuExtra.frm.get
298  csrioIn.exception <> ctrlBlock.io.robio.exception
299  csrioIn.isXRet <> ctrlBlock.io.robio.toCSR.isXRet
300  csrioIn.trapTarget <> ctrlBlock.io.robio.toCSR.trapTarget
301  csrioIn.interrupt <> ctrlBlock.io.robio.toCSR.intrBitSet
302  csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr
303
304  csrioIn.externalInterrupt.msip := outer.clint_int_sink.in.head._1(0)
305  csrioIn.externalInterrupt.mtip := outer.clint_int_sink.in.head._1(1)
306  csrioIn.externalInterrupt.meip := outer.plic_int_sink.in.head._1(0)
307  csrioIn.externalInterrupt.debug := outer.debug_int_sink.in.head._1(0)
308
309  fenceio.sfence <> memBlock.io.sfence
310  fenceio.sbuffer <> memBlock.io.fenceToSbuffer
311
312  memBlock.io.redirect <> ctrlBlock.io.redirect
313  memBlock.io.rsfeedback <> exuBlocks(0).io.scheExtra.feedback.get
314  memBlock.io.csrCtrl <> csrioIn.customCtrl
315  memBlock.io.tlbCsr <> csrioIn.tlb
316  memBlock.io.lsqio.rob <> ctrlBlock.io.robio.lsq
317  memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.robio.exception.bits.uop.lqIdx
318  memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.robio.exception.bits.uop.sqIdx
319  memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.uop.ctrl.commitType)
320
321  val itlbRepeater = Module(new PTWRepeater(2))
322  val dtlbRepeater = Module(new PTWFilter(LoadPipelineWidth + StorePipelineWidth, l2tlbParams.filterSize))
323  itlbRepeater.io.tlb <> frontend.io.ptw
324  dtlbRepeater.io.tlb <> memBlock.io.ptw
325  itlbRepeater.io.sfence <> fenceio.sfence
326  dtlbRepeater.io.sfence <> fenceio.sfence
327  ptw.io.tlb(0) <> itlbRepeater.io.ptw
328  ptw.io.tlb(1) <> dtlbRepeater.io.ptw
329  ptw.io.sfence <> fenceio.sfence
330  ptw.io.csr.tlb <> csrioIn.tlb
331  ptw.io.csr.distribute_csr <> csrioIn.customCtrl.distribute_csr
332
333  // if l2 prefetcher use stream prefetch, it should be placed in XSCore
334  io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable
335
336  val ptw_reset_gen = Module(new ResetGen(2, !debugOpts.FPGAPlatform))
337  ptw.reset := ptw_reset_gen.io.out
338  itlbRepeater.reset := ptw_reset_gen.io.out
339  dtlbRepeater.reset := ptw_reset_gen.io.out
340
341  val memBlock_reset_gen = Module(new ResetGen(3, !debugOpts.FPGAPlatform))
342  memBlock.reset := memBlock_reset_gen.io.out
343
344  val exuBlock_reset_gen = Module(new ResetGen(4, !debugOpts.FPGAPlatform))
345  exuBlocks.foreach(_.reset := exuBlock_reset_gen.io.out)
346
347  val ctrlBlock_reset_gen = Module(new ResetGen(6, !debugOpts.FPGAPlatform))
348  ctrlBlock.reset := ctrlBlock_reset_gen.io.out
349
350  val frontend_reset_gen = Module(new ResetGen(7, !debugOpts.FPGAPlatform))
351  frontend.reset := frontend_reset_gen.io.out
352}
353