xref: /XiangShan/src/main/scala/xiangshan/backend/Backend.scala (revision d077b11804222346941c6a7dc7188e89b46579a4)
1package xiangshan.backend
2
3import bus.simplebus.SimpleBusUC
4import chisel3._
5import chisel3.util._
6import chisel3.util.experimental.BoringUtils
7import noop.MemMMUIO
8import xiangshan._
9import xiangshan.backend.decode.{DecodeBuffer, DecodeStage}
10import xiangshan.backend.rename.Rename
11import xiangshan.backend.brq.Brq
12import xiangshan.backend.dispatch.Dispatch
13import xiangshan.backend.exu._
14import xiangshan.backend.fu.FunctionUnit
15import xiangshan.backend.issue.IssueQueue
16import xiangshan.backend.regfile.{Regfile, RfWritePort}
17import xiangshan.backend.roq.Roq
18import utils.ParallelOR
19
20/** Backend Pipeline:
21  * Decode -> Rename -> Dispatch-1 -> Dispatch-2 -> Issue -> Exe
22  */
23class Backend extends XSModule
24  with NeedImpl {
25  val io = IO(new Bundle {
26    val dmem = new SimpleBusUC(addrBits = VAddrBits)
27    val memMMU = Flipped(new MemMMUIO)
28    val frontend = Flipped(new FrontendToBackendIO)
29  })
30
31
32  val aluExeUnits = Array.tabulate(exuParameters.AluCnt)(_ => Module(new AluExeUnit))
33  val jmpExeUnit = Module(new JmpExeUnit)
34  val mulExeUnits = Array.tabulate(exuParameters.MulCnt)(_ => Module(new MulExeUnit))
35  val mduExeUnits = Array.tabulate(exuParameters.MduCnt)(_ => Module(new MulDivExeUnit))
36  //  val fmacExeUnits = Array.tabulate(exuParameters.FmacCnt)(_ => Module(new Fmac))
37  //  val fmiscExeUnits = Array.tabulate(exuParameters.FmiscCnt)(_ => Module(new Fmisc))
38  //  val fmiscDivSqrtExeUnits = Array.tabulate(exuParameters.FmiscDivSqrtCnt)(_ => Module(new FmiscDivSqrt))
39  val lsuExeUnits = Array.tabulate(exuParameters.StuCnt)(_ => Module(new LsExeUnit))
40  val exeUnits = jmpExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits ++ lsuExeUnits)
41  exeUnits.foreach(_.io.exception := DontCare)
42  exeUnits.foreach(_.io.dmem := DontCare)
43  exeUnits.foreach(_.io.scommit := DontCare)
44
45  val decode = Module(new DecodeStage)
46  val brq = Module(new Brq)
47  val decBuf = Module(new DecodeBuffer)
48  val rename = Module(new Rename)
49  val dispatch = Module(new Dispatch(exeUnits.map(_.config)))
50  val roq = Module(new Roq)
51  val intRf = Module(new Regfile(
52    numReadPorts = NRReadPorts,
53    numWirtePorts = NRWritePorts,
54    hasZero = true
55  ))
56  val fpRf = Module(new Regfile(
57    numReadPorts = NRReadPorts,
58    numWirtePorts = NRWritePorts,
59    hasZero = false
60  ))
61
62  // backend redirect, flush pipeline
63  val redirect = Mux(roq.io.redirect.valid, roq.io.redirect, brq.io.redirect)
64
65  io.frontend.redirect <> redirect
66
67  var iqInfo = new StringBuilder
68  val issueQueues = exeUnits.zipWithIndex.map({ case (eu, i) =>
69    def needBypass(cfg: ExuConfig): Boolean = cfg.enableBypass
70
71    val bypassCnt = exeUnits.map(_.config).count(needBypass)
72    def needWakeup(cfg: ExuConfig): Boolean =
73      (cfg.readIntRf && cfg.writeIntRf) || (cfg.readFpRf && cfg.writeFpRf)
74
75    val wakeupCnt = exeUnits.map(_.config).count(needWakeup)
76    assert(!(needBypass(eu.config) && !needWakeup(eu.config))) // needBypass but dont needWakeup is not allowed
77    val iq = Module(new IssueQueue(
78      eu.config,
79      wakeupCnt,
80      bypassCnt,
81      eu.config.enableBypass,
82      fifo = eu.config.supportedFuncUnits.contains(FunctionUnit.lsuCfg)
83    ))
84    iq.io.redirect <> redirect
85    iq.io.numExist <> dispatch.io.numExist(i)
86    iq.io.enqCtrl <> dispatch.io.enqIQCtrl(i)
87    iq.io.enqData <> dispatch.io.enqIQData(i)
88    for(
89      (wakeUpPort, exuOut) <-
90      iq.io.wakeUpPorts.zip(exeUnits.filter(e => needWakeup(e.config)).map(_.io.out))
91    ){
92      wakeUpPort.bits := exuOut.bits
93      wakeUpPort.valid := exuOut.valid
94    }
95    iqInfo ++= {
96      s"[$i] ${eu.name} Queue wakeupCnt:$wakeupCnt bypassCnt:$bypassCnt" +
97        s" Supported Function:[" +
98        s"${
99          eu.config.supportedFuncUnits.map(
100            fu => FuType.functionNameMap(fu.fuType.litValue())).mkString(", "
101          )
102        }]\n"
103    }
104    eu.io.in <> iq.io.deq
105    eu.io.redirect <> redirect
106    iq
107  })
108
109  val bypassQueues = issueQueues.filter(_.enableBypass)
110  val bypassUnits = exeUnits.filter(_.config.enableBypass)
111  issueQueues.foreach(iq => {
112    for (i <- iq.io.bypassUops.indices) {
113      iq.io.bypassData(i).bits := bypassUnits(i).io.out.bits
114      iq.io.bypassData(i).valid := bypassUnits(i).io.out.valid
115    }
116    iq.io.bypassUops <> bypassQueues.map(_.io.selectedUop)
117  })
118
119  lsuExeUnits.foreach(_.io.dmem <> io.dmem)
120  lsuExeUnits.foreach(_.io.scommit <> roq.io.scommit)
121  jmpExeUnit.io.exception.valid := roq.io.redirect.valid
122  jmpExeUnit.io.exception.bits := roq.io.exception
123
124  io.frontend.outOfOrderBrInfo <> brq.io.outOfOrderBrInfo
125  io.frontend.inOrderBrInfo <> brq.io.inOrderBrInfo
126
127  decode.io.in <> io.frontend.cfVec
128  brq.io.roqRedirect <> roq.io.redirect
129  brq.io.bcommit := roq.io.bcommit
130  brq.io.enqReqs <> decode.io.toBrq
131  for ((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.config.hasRedirect))) {
132    x.bits := y.io.out.bits
133    x.valid := y.io.out.fire() && y.io.out.bits.redirectValid
134  }
135  decode.io.brTags <> brq.io.brTags
136  decBuf.io.isWalking := ParallelOR(roq.io.commits.map(c => c.valid && c.bits.isWalk)) // TODO: opt this
137  decBuf.io.redirect <> redirect
138  decBuf.io.in <> decode.io.out
139
140  rename.io.redirect <> redirect
141  rename.io.roqCommits <> roq.io.commits
142  rename.io.in <> decBuf.io.out
143  rename.io.intRfReadAddr <> dispatch.io.readIntRf.map(_.addr)
144  rename.io.fpRfReadAddr <> dispatch.io.readFpRf.map(_.addr)
145  rename.io.intPregRdy <> dispatch.io.intPregRdy
146  rename.io.fpPregRdy <> dispatch.io.fpPregRdy
147
148  dispatch.io.redirect <> redirect
149  dispatch.io.fromRename <> rename.io.out
150
151  roq.io.brqRedirect <> brq.io.redirect
152  roq.io.dp1Req <> dispatch.io.toRoq
153  dispatch.io.roqIdxs <> roq.io.roqIdxs
154
155  intRf.io.readPorts <> dispatch.io.readIntRf
156  fpRf.io.readPorts <> dispatch.io.readFpRf
157
158  val exeWbReqs = exeUnits.map(_.io.out)
159
160  val wbIntIdx = exeUnits.zipWithIndex.filter(_._1.config.writeIntRf).map(_._2)
161  val wbFpIdx = exeUnits.zipWithIndex.filter(_._1.config.writeFpRf).map(_._2)
162
163  val wbu = Module(new Wbu(wbIntIdx, wbFpIdx))
164  wbu.io.in <> exeWbReqs
165
166  val wbIntResults = wbu.io.toIntRf
167  val wbFpResults = wbu.io.toFpRf
168
169  def exuOutToRfWrite(x: Valid[ExuOutput]): RfWritePort = {
170    val rfWrite = Wire(new RfWritePort)
171    rfWrite.wen := x.valid
172    rfWrite.addr := x.bits.uop.pdest
173    rfWrite.data := x.bits.data
174    rfWrite
175  }
176
177  intRf.io.writePorts <> wbIntResults.map(exuOutToRfWrite)
178  fpRf.io.writePorts <> wbFpResults.map(exuOutToRfWrite)
179
180  rename.io.wbIntResults <> wbIntResults
181  rename.io.wbFpResults <> wbFpResults
182
183  roq.io.exeWbResults.take(exeWbReqs.length).zip(wbu.io.toRoq).foreach(x => x._1 := x._2)
184  roq.io.exeWbResults.last := brq.io.out
185
186
187  // TODO: Remove sink and source
188  val tmp = WireInit(0.U)
189  val sinks = Array[String](
190    "DTLBFINISH",
191    "DTLBPF",
192    "DTLBENABLE",
193    "perfCntCondMdcacheLoss",
194    "perfCntCondMl2cacheLoss",
195    "perfCntCondMdcacheHit",
196    "lsuMMIO",
197    "perfCntCondMl2cacheHit",
198    "perfCntCondMl2cacheReq",
199    "mtip",
200    "perfCntCondMdcacheReq",
201    "meip"
202  )
203  for (s <- sinks) {
204    BoringUtils.addSink(tmp, s)
205  }
206
207  val debugIntReg, debugFpReg = WireInit(VecInit(Seq.fill(32)(0.U(XLEN.W))))
208  BoringUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG")
209  BoringUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG")
210  val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg))
211  if (!env.FPGAPlatform) {
212    BoringUtils.addSource(debugArchReg, "difftestRegs")
213  }
214
215  print(iqInfo)
216
217}
218