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