xref: /XiangShan/src/main/scala/xiangshan/backend/Backend.scala (revision ef74f7cb51e51469daf849b3d8ed7fbed106fcba)
1package xiangshan.backend
2
3import chisel3._
4import chisel3.util._
5import chisel3.util.experimental.BoringUtils
6import xiangshan._
7import xiangshan.backend.decode.{DecodeBuffer, DecodeStage}
8import xiangshan.backend.rename.Rename
9import xiangshan.backend.brq.Brq
10import xiangshan.backend.dispatch.Dispatch
11import xiangshan.backend.exu._
12import xiangshan.backend.fu.FunctionUnit
13import xiangshan.backend.issue.{IssueQueue, ReservationStation}
14import xiangshan.backend.regfile.{Regfile, RfWritePort}
15import xiangshan.backend.roq.Roq
16import xiangshan.mem._
17import utils.ParallelOR
18
19/** Backend Pipeline:
20  * Decode -> Rename -> Dispatch-1 -> Dispatch-2 -> Issue -> Exe
21  */
22class Backend extends XSModule
23  with NeedImpl {
24  val io = IO(new Bundle {
25    val frontend = Flipped(new FrontendToBackendIO)
26    val mem = Flipped(new MemToBackendIO)
27    val externalInterrupt = new ExternalInterruptIO
28  })
29
30
31  val aluExeUnits =Array.tabulate(exuParameters.AluCnt)(_ => Module(new AluExeUnit))
32  val jmpExeUnit = Module(new JmpExeUnit)
33  val mulExeUnits = Array.tabulate(exuParameters.MulCnt)(_ => Module(new MulExeUnit))
34  val mduExeUnits = Array.tabulate(exuParameters.MduCnt)(_ => Module(new MulDivExeUnit))
35  val fmacExeUnits = Array.tabulate(exuParameters.FmacCnt)(_ => Module(new FmacExeUnit))
36  val fmiscExeUnits = Array.tabulate(exuParameters.FmiscCnt)(_ => Module(new FmiscExeUnit))
37  // val fmiscDivSqrtExeUnits = Array.tabulate(exuParameters.FmiscDivSqrtCnt)(_ => Module(new FmiscDivSqrtExeUnit))
38  val exeUnits = jmpExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits ++ fmacExeUnits ++ fmiscExeUnits)
39  exeUnits.foreach(_.io.csrOnly := DontCare)
40  exeUnits.foreach(_.io.mcommit := DontCare)
41
42  val decode = Module(new DecodeStage)
43  val brq = Module(new Brq)
44  val decBuf = Module(new DecodeBuffer)
45  val rename = Module(new Rename)
46  val dispatch = Module(new Dispatch)
47  val roq = Module(new Roq)
48  val intRf = Module(new Regfile(
49    numReadPorts = NRIntReadPorts,
50    numWirtePorts = NRIntWritePorts,
51    hasZero = true
52  ))
53  val fpRf = Module(new Regfile(
54    numReadPorts = NRFpReadPorts,
55    numWirtePorts = NRFpWritePorts,
56    hasZero = false
57  ))
58  val memRf = Module(new Regfile(
59    numReadPorts = 2*exuParameters.StuCnt + exuParameters.LduCnt,
60    numWirtePorts = NRIntWritePorts,
61    hasZero = true,
62    isMemRf = true
63  ))
64
65  // backend redirect, flush pipeline
66  val redirect = Mux(
67    roq.io.redirect.valid,
68    roq.io.redirect,
69    Mux(
70      brq.io.redirect.valid,
71      brq.io.redirect,
72      io.mem.replayAll
73    )
74  )
75
76  io.frontend.redirect := redirect
77  io.frontend.redirect.valid := redirect.valid && !redirect.bits.isReplay
78
79  val memConfigs =
80    Seq.fill(exuParameters.LduCnt)(Exu.ldExeUnitCfg) ++
81    Seq.fill(exuParameters.StuCnt)(Exu.stExeUnitCfg)
82
83  val exuConfigs = exeUnits.map(_.config) ++ memConfigs
84
85  val exeWbReqs = exeUnits.map(_.io.out) ++ io.mem.ldout ++ io.mem.stout
86
87  def needWakeup(cfg: ExuConfig): Boolean =
88    (cfg.readIntRf && cfg.writeIntRf) || (cfg.readFpRf && cfg.writeFpRf)
89
90  def needData(a: ExuConfig, b: ExuConfig): Boolean =
91    (a.readIntRf && b.writeIntRf) || (a.readFpRf && b.writeFpRf)
92
93  val reservedStations = exeUnits.
94    zipWithIndex.
95    map({ case (exu, i) =>
96
97      val cfg = exu.config
98
99      val wakeUpDateVec = exuConfigs.zip(exeWbReqs).filter(x => needData(cfg, x._1)).map(_._2)
100      val bypassCnt = exuConfigs.count(c => c.enableBypass && needData(cfg, c))
101
102      println(s"exu:${cfg.name} wakeupCnt:${wakeUpDateVec.length} bypassCnt:$bypassCnt")
103
104      val rs = Module(new ReservationStation(
105        cfg, wakeUpDateVec.length, bypassCnt, cfg.enableBypass, false
106      ))
107      rs.io.redirect <> redirect
108      rs.io.numExist <> dispatch.io.numExist(i)
109      rs.io.enqCtrl <> dispatch.io.enqIQCtrl(i)
110      rs.io.enqData <> dispatch.io.enqIQData(i)
111      for(
112        (wakeUpPort, exuOut) <-
113        rs.io.wakeUpPorts.zip(wakeUpDateVec)
114      ){
115        wakeUpPort.bits := exuOut.bits
116        wakeUpPort.valid := exuOut.valid
117      }
118
119      exu.io.in <> rs.io.deq
120      exu.io.redirect <> redirect
121      rs
122    })
123
124  for( rs <- reservedStations){
125    val bypassDataVec = exuConfigs.zip(exeWbReqs).
126      filter(x => x._1.enableBypass && needData(rs.exuCfg, x._1)).map(_._2)
127
128    rs.io.bypassUops <> reservedStations.
129    filter(x => x.enableBypass && needData(rs.exuCfg, x.exuCfg)).
130    map(_.io.selectedUop)
131
132    for(i <- bypassDataVec.indices){
133      rs.io.bypassData(i).valid := bypassDataVec(i).valid
134      rs.io.bypassData(i).bits := bypassDataVec(i).bits
135    }
136  }
137
138  val issueQueues = exuConfigs.
139    zipWithIndex.
140    takeRight(exuParameters.LduCnt + exuParameters.StuCnt).
141    map({case (cfg, i) =>
142      val wakeUpDateVec = exuConfigs.zip(exeWbReqs).filter(x => needData(cfg, x._1)).map(_._2)
143      val bypassUopVec = reservedStations.
144        filter(r => r.exuCfg.enableBypass && needData(cfg, r.exuCfg)).map(_.io.selectedUop)
145      val bypassDataVec = exuConfigs.zip(exeWbReqs).
146        filter(x => x._1.enableBypass && needData(cfg, x._1)).map(_._2)
147
148      val iq = Module(new IssueQueue(
149        cfg, wakeUpDateVec.length, bypassUopVec.length
150      ))
151      println(s"exu:${cfg.name} wakeupCnt:${wakeUpDateVec.length} bypassCnt:${bypassUopVec.length}")
152      iq.io.redirect <> redirect
153      iq.io.tlbFeedback := io.mem.tlbFeedback(i - exuParameters.ExuCnt + exuParameters.LduCnt + exuParameters.StuCnt)
154      iq.io.enq <> dispatch.io.enqIQCtrl(i)
155      dispatch.io.numExist(i) := iq.io.numExist
156      for(
157        (wakeUpPort, exuOut) <-
158        iq.io.wakeUpPorts.zip(wakeUpDateVec)
159      ){
160        wakeUpPort.bits := exuOut.bits
161        wakeUpPort.valid := exuOut.fire() // data after arbit
162      }
163      iq.io.bypassUops <> bypassUopVec
164      for(i <- bypassDataVec.indices){
165        iq.io.bypassData(i).valid := bypassDataVec(i).valid
166        iq.io.bypassData(i).bits := bypassDataVec(i).bits
167      }
168      iq
169    })
170
171  io.mem.commits <> roq.io.commits
172  io.mem.roqDeqPtr := roq.io.roqDeqPtr
173  io.mem.ldin <> issueQueues.filter(_.exuCfg == Exu.ldExeUnitCfg).map(_.io.deq)
174  io.mem.stin <> issueQueues.filter(_.exuCfg == Exu.stExeUnitCfg).map(_.io.deq)
175  jmpExeUnit.io.csrOnly.exception.valid := roq.io.redirect.valid && roq.io.redirect.bits.isException
176  jmpExeUnit.io.csrOnly.exception.bits := roq.io.exception
177
178  jmpExeUnit.io.csrOnly.memExceptionVAddr := io.mem.exceptionAddr.vaddr
179  io.mem.exceptionAddr.lsIdx.lsroqIdx := roq.io.exception.lsroqIdx
180  io.mem.exceptionAddr.lsIdx.lqIdx := roq.io.exception.lqIdx
181  io.mem.exceptionAddr.lsIdx.sqIdx := roq.io.exception.sqIdx
182  io.mem.exceptionAddr.isStore := CommitType.lsInstIsStore(roq.io.exception.ctrl.commitType)
183
184  io.frontend.outOfOrderBrInfo <> brq.io.outOfOrderBrInfo
185  io.frontend.inOrderBrInfo <> brq.io.inOrderBrInfo
186
187  decode.io.in <> io.frontend.cfVec
188  brq.io.roqRedirect <> roq.io.redirect
189  brq.io.memRedirect <> io.mem.replayAll
190  brq.io.bcommit := roq.io.bcommit
191  brq.io.enqReqs <> decode.io.toBrq
192  for ((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.config.hasRedirect))) {
193    x.bits := y.io.out.bits
194    x.valid := y.io.out.fire() && y.io.out.bits.redirectValid
195  }
196  decode.io.brTags <> brq.io.brTags
197  decBuf.io.isWalking := ParallelOR(roq.io.commits.map(c => c.valid && c.bits.isWalk)) // TODO: opt this
198  decBuf.io.redirect <> redirect
199  decBuf.io.in <> decode.io.out
200
201  rename.io.redirect <> redirect
202  rename.io.roqCommits <> roq.io.commits
203  rename.io.in <> decBuf.io.out
204  rename.io.intRfReadAddr <> dispatch.io.readIntRf.map(_.addr) ++ dispatch.io.intMemRegAddr
205  rename.io.intPregRdy <> dispatch.io.intPregRdy ++ dispatch.io.intMemRegRdy
206  rename.io.fpRfReadAddr <> dispatch.io.readFpRf.map(_.addr) ++ dispatch.io.fpMemRegAddr
207  rename.io.fpPregRdy <> dispatch.io.fpPregRdy ++ dispatch.io.fpMemRegRdy
208  rename.io.replayPregReq <> dispatch.io.replayPregReq
209  dispatch.io.redirect <> redirect
210  dispatch.io.fromRename <> rename.io.out
211
212  roq.io.memRedirect <> io.mem.replayAll
213  roq.io.brqRedirect <> brq.io.redirect
214  roq.io.dp1Req <> dispatch.io.toRoq
215  roq.io.intrBitSet := jmpExeUnit.io.csrOnly.interrupt
216  roq.io.trapTarget := jmpExeUnit.io.csrOnly.trapTarget
217  dispatch.io.roqIdxs <> roq.io.roqIdxs
218  io.mem.dp1Req <> dispatch.io.toLsroq
219  dispatch.io.lsIdxs <> io.mem.lsIdxs
220  dispatch.io.dequeueRoqIndex.valid := roq.io.commitRoqIndex.valid || io.mem.oldestStore.valid
221  // store writeback must be after commit roqIdx
222  dispatch.io.dequeueRoqIndex.bits := Mux(io.mem.oldestStore.valid, io.mem.oldestStore.bits, roq.io.commitRoqIndex.bits)
223
224
225  intRf.io.readPorts <> dispatch.io.readIntRf
226  fpRf.io.readPorts <> dispatch.io.readFpRf ++ issueQueues.flatMap(_.io.readFpRf)
227  memRf.io.readPorts <> issueQueues.flatMap(_.io.readIntRf)
228
229  io.mem.redirect <> redirect
230
231  val wbu = Module(new Wbu(exuConfigs))
232  wbu.io.in <> exeWbReqs
233
234  val wbIntResults = wbu.io.toIntRf
235  val wbFpResults = wbu.io.toFpRf
236
237  def exuOutToRfWrite(x: Valid[ExuOutput]): RfWritePort = {
238    val rfWrite = Wire(new RfWritePort)
239    rfWrite.wen := x.valid
240    rfWrite.addr := x.bits.uop.pdest
241    rfWrite.data := x.bits.data
242    rfWrite
243  }
244  val intRfWrite = wbIntResults.map(exuOutToRfWrite)
245  intRf.io.writePorts <> intRfWrite
246  memRf.io.writePorts <> intRfWrite
247  fpRf.io.writePorts <> wbFpResults.map(exuOutToRfWrite)
248
249  rename.io.wbIntResults <> wbIntResults
250  rename.io.wbFpResults <> wbFpResults
251
252  roq.io.exeWbResults.take(exeWbReqs.length).zip(wbu.io.toRoq).foreach(x => x._1 := x._2)
253  roq.io.exeWbResults.last := brq.io.out
254
255
256  // TODO: Remove sink and source
257  val tmp = WireInit(0.U)
258  val sinks = Array[String](
259    "DTLBFINISH",
260    "DTLBPF",
261    "DTLBENABLE",
262    "perfCntCondMdcacheLoss",
263    "perfCntCondMl2cacheLoss",
264    "perfCntCondMdcacheHit",
265    "lsuMMIO",
266    "perfCntCondMl2cacheHit",
267    "perfCntCondMl2cacheReq",
268    "mtip",
269    "perfCntCondMdcacheReq",
270    "meip"
271  )
272  for (s <- sinks) {
273    BoringUtils.addSink(tmp, s)
274  }
275
276  val debugIntReg, debugFpReg = WireInit(VecInit(Seq.fill(32)(0.U(XLEN.W))))
277  BoringUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG")
278  BoringUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG")
279  val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg))
280  if (!env.FPGAPlatform) {
281    BoringUtils.addSource(debugArchReg, "difftestRegs")
282  }
283
284}
285