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