xref: /XiangShan/src/main/scala/xiangshan/XSCore.scala (revision 5eb4af5ba4d9ec70191944b8386c8983f355d751)
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 2*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.AluCnt) {
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  val stdAllocate = exuBlocks(1).io.allocate.takeRight(2)
262  val staAllocate = memScheduler.io.allocate.takeRight(2)
263  stdAllocate.zip(staAllocate).zip(ctrlBlock.io.enqIQ.takeRight(2)).zipWithIndex.foreach{ case (((std, sta), enq), i) =>
264    std.valid := enq.valid && sta.ready
265    sta.valid := enq.valid && std.ready
266    std.bits := enq.bits
267    sta.bits := enq.bits
268    std.bits.ctrl.lsrc(0) := enq.bits.ctrl.lsrc(1)
269    std.bits.psrc(0) := enq.bits.psrc(1)
270    std.bits.srcState(0) := enq.bits.srcState(1)
271    std.bits.ctrl.srcType(0) := enq.bits.ctrl.srcType(1)
272    enq.ready := sta.ready && std.ready
273    XSPerfAccumulate(s"st_not_ready_$i", enq.valid && !enq.ready)
274    XSPerfAccumulate(s"sta_not_ready_$i", sta.valid && !sta.ready)
275    XSPerfAccumulate(s"std_not_ready_$i", std.valid && !std.ready)
276  }
277  exuBlocks(1).io.scheExtra.fpRfReadIn.get <> exuBlocks(2).io.scheExtra.fpRfReadOut.get
278
279  memScheduler.io.redirect <> ctrlBlock.io.redirect
280  memScheduler.io.flush <> ctrlBlock.io.flush
281  memBlock.io.issue <> memScheduler.io.issue
282  memScheduler.io.writeback <> rfWriteback
283  memScheduler.io.fastUopIn <> allFastUop1
284  memScheduler.io.extra.jumpPc <> ctrlBlock.io.jumpPc
285  memScheduler.io.extra.jalr_target <> ctrlBlock.io.jalr_target
286  memScheduler.io.extra.stIssuePtr <> memBlock.io.stIssuePtr
287  memScheduler.io.extra.debug_int_rat <> ctrlBlock.io.debug_int_rat
288  memScheduler.io.extra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat
289
290  exuBlocks.map(_.io).foreach { exu =>
291    exu.redirect <> ctrlBlock.io.redirect
292    exu.flush <> ctrlBlock.io.flush
293    exu.rfWriteback <> rfWriteback
294    exu.fastUopIn <> allFastUop1
295    exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc
296    exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target
297    exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr
298    exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat
299    exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat
300  }
301
302  csrioIn.hartId <> io.hartId
303  csrioIn.perf <> DontCare
304  csrioIn.perf.retiredInstr <> ctrlBlock.io.roqio.toCSR.perfinfo.retiredInstr
305  csrioIn.perf.bpuInfo <> ctrlBlock.io.perfInfo.bpuInfo
306  csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo
307  csrioIn.perf.memInfo <> memBlock.io.memInfo
308  csrioIn.perf.frontendInfo <> frontend.io.frontendInfo
309
310  csrioIn.fpu.fflags <> ctrlBlock.io.roqio.toCSR.fflags
311  csrioIn.fpu.isIllegal := false.B
312  csrioIn.fpu.dirty_fs <> ctrlBlock.io.roqio.toCSR.dirty_fs
313  csrioIn.fpu.frm <> exuBlocks(2).io.fuExtra.frm.get
314  csrioIn.exception <> ctrlBlock.io.roqio.exception
315  csrioIn.isXRet <> ctrlBlock.io.roqio.toCSR.isXRet
316  csrioIn.trapTarget <> ctrlBlock.io.roqio.toCSR.trapTarget
317  csrioIn.interrupt <> ctrlBlock.io.roqio.toCSR.intrBitSet
318  csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr
319  csrioIn.externalInterrupt <> io.externalInterrupt
320
321  fenceio.sfence <> memBlock.io.sfence
322  fenceio.sbuffer <> memBlock.io.fenceToSbuffer
323
324  memBlock.io.redirect <> ctrlBlock.io.redirect
325  memBlock.io.flush <> ctrlBlock.io.flush
326  memBlock.io.replay <> memScheduler.io.extra.feedback.get.map(_.replay)
327  memBlock.io.rsIdx <> memScheduler.io.extra.feedback.get.map(_.rsIdx)
328  memBlock.io.isFirstIssue <> memScheduler.io.extra.feedback.get.map(_.isFirstIssue)
329  val stData = exuBlocks.map(_.io.fuExtra.stData.getOrElse(Seq())).reduce(_ ++ _)
330  memBlock.io.stData := stData
331  memBlock.io.csrCtrl <> csrioIn.customCtrl
332  memBlock.io.tlbCsr <> csrioIn.tlb
333  memBlock.io.lsqio.roq <> ctrlBlock.io.roqio.lsq
334  memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.roqio.exception.bits.uop.lqIdx
335  memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.roqio.exception.bits.uop.sqIdx
336  memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.roqio.exception.bits.uop.ctrl.commitType)
337
338  val itlbRepeater = Module(new PTWRepeater())
339  val dtlbRepeater = Module(new PTWFilter(LoadPipelineWidth + StorePipelineWidth, PtwMissQueueSize))
340  itlbRepeater.io.tlb <> frontend.io.ptw
341  dtlbRepeater.io.tlb <> memBlock.io.ptw
342  itlbRepeater.io.sfence <> fenceio.sfence
343  dtlbRepeater.io.sfence <> fenceio.sfence
344  ptw.io.tlb(0) <> itlbRepeater.io.ptw
345  ptw.io.tlb(1) <> dtlbRepeater.io.ptw
346  ptw.io.sfence <> fenceio.sfence
347  ptw.io.csr <> csrioIn.tlb
348
349  // if l2 prefetcher use stream prefetch, it should be placed in XSCore
350  assert(l2PrefetcherParameters._type == "bop")
351  io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable
352
353  val l1plus_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform))
354  l1pluscache.reset := l1plus_reset_gen.io.out
355
356  val ptw_reset_gen = Module(new ResetGen(2, !debugOpts.FPGAPlatform))
357  ptw.reset := ptw_reset_gen.io.out
358  itlbRepeater.reset := ptw_reset_gen.io.out
359  dtlbRepeater.reset := ptw_reset_gen.io.out
360
361  val memBlock_reset_gen = Module(new ResetGen(3, !debugOpts.FPGAPlatform))
362  memBlock.reset := memBlock_reset_gen.io.out
363
364  val exuBlock_reset_gen = Module(new ResetGen(4, !debugOpts.FPGAPlatform))
365  exuBlocks.foreach(_.reset := exuBlock_reset_gen.io.out)
366
367  val ctrlBlock_reset_gen = Module(new ResetGen(6, !debugOpts.FPGAPlatform))
368  ctrlBlock.reset := ctrlBlock_reset_gen.io.out
369
370  val frontend_reset_gen = Module(new ResetGen(7, !debugOpts.FPGAPlatform))
371  frontend.reset := frontend_reset_gen.io.out
372}
373