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