xref: /XiangShan/src/main/scala/xiangshan/backend/Backend.scala (revision bc2314355d316f004e7c466e1d1f837b5c951485)
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._
19import utils.ParallelOR
20
21/** Backend Pipeline:
22  * Decode -> Rename -> Dispatch-1 -> Dispatch-2 -> Issue -> Exe
23  */
24class Backend extends XSModule
25  with NeedImpl {
26  val io = IO(new Bundle {
27    val frontend = Flipped(new FrontendToBackendIO)
28    val mem = Flipped(new MemToBackendIO)
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 exeUnits = jmpExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits)
40  exeUnits.foreach(_.io.exception := DontCare)
41  exeUnits.foreach(_.io.dmem := DontCare)
42  exeUnits.foreach(_.io.mcommit := DontCare)
43
44  val decode = Module(new DecodeStage)
45  val brq = Module(new Brq)
46  val decBuf = Module(new DecodeBuffer)
47  val rename = Module(new Rename)
48  val dispatch = Module(new Dispatch)
49  val roq = Module(new Roq)
50  val intRf = Module(new Regfile(
51    numReadPorts = NRIntReadPorts,
52    numWirtePorts = NRIntWritePorts,
53    hasZero = true
54  ))
55  val fpRf = Module(new Regfile(
56    numReadPorts = NRFpReadPorts,
57    numWirtePorts = NRFpWritePorts,
58    hasZero = false
59  ))
60  val memRf = Module(new Regfile(
61    numReadPorts = 2*exuParameters.StuCnt + exuParameters.LduCnt,
62    numWirtePorts = NRIntWritePorts,
63    hasZero = true,
64    isMemRf = true
65  ))
66
67  // backend redirect, flush pipeline
68  val redirect = Mux(
69    roq.io.redirect.valid,
70    roq.io.redirect,
71    Mux(
72      brq.io.redirect.valid,
73      brq.io.redirect,
74      io.mem.replayAll
75    )
76  )
77
78  io.frontend.redirect := redirect
79  io.frontend.redirect.valid := redirect.valid && !redirect.bits.isReplay
80
81  val memConfigs =
82    Seq.fill(exuParameters.LduCnt)(Exu.ldExeUnitCfg) ++
83    Seq.fill(exuParameters.StuCnt)(Exu.stExeUnitCfg)
84
85  val exuConfigs = exeUnits.map(_.config) ++ memConfigs
86
87  val exeWbReqs = exeUnits.map(_.io.out) ++ io.mem.ldout ++ io.mem.stout
88
89  def needWakeup(cfg: ExuConfig): Boolean =
90    (cfg.readIntRf && cfg.writeIntRf) || (cfg.readFpRf && cfg.writeFpRf)
91
92  def needData(a: ExuConfig, b: ExuConfig): Boolean =
93    (a.readIntRf && b.writeIntRf) || (a.readFpRf && b.writeFpRf)
94
95  val reservedStations = exeUnits.
96    zipWithIndex.
97    map({ case (exu, i) =>
98
99      val cfg = exu.config
100
101      val wakeUpDateVec = exuConfigs.zip(exeWbReqs).filter(x => needData(cfg, x._1)).map(_._2)
102      val bypassCnt = exuConfigs.count(c => c.enableBypass && needData(cfg, c) && cfg.enableBypass)
103
104      println(s"exu:${cfg.name} wakeupCnt:${wakeUpDateVec.length} bypassCnt:$bypassCnt")
105
106      val rs = Module(new ReservationStation(
107        cfg, wakeUpDateVec.length, bypassCnt, cfg.enableBypass, false
108      ))
109      rs.io.redirect <> redirect
110      rs.io.numExist <> dispatch.io.numExist(i)
111      rs.io.enqCtrl <> dispatch.io.enqIQCtrl(i)
112      rs.io.enqData <> dispatch.io.enqIQData(i)
113      for(
114        (wakeUpPort, exuOut) <-
115        rs.io.wakeUpPorts.zip(wakeUpDateVec)
116      ){
117        wakeUpPort.bits := exuOut.bits
118        wakeUpPort.valid := exuOut.valid
119      }
120
121      exu.io.in <> rs.io.deq
122      exu.io.redirect <> redirect
123      rs
124    })
125
126  for( rs <- reservedStations){
127    val bypassDataVec = exuConfigs.zip(exeWbReqs).
128      filter(x => x._1.enableBypass && needData(rs.exuCfg, x._1)).map(_._2)
129
130    if(rs.exuCfg.enableBypass) {
131      rs.io.bypassUops <> reservedStations.
132      filter(x => x.enableBypass && needData(rs.exuCfg, x.exuCfg)).
133      map(_.io.selectedUop)
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
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.
148        filter(r => r.exuCfg.enableBypass && needData(cfg, r.exuCfg)).map(_.io.selectedUop)
149      val bypassDataVec = exuConfigs.zip(exeWbReqs).
150        filter(x => x._1.enableBypass && needData(cfg, x._1)).map(_._2)
151
152      val iq = Module(new IssueQueue(
153        cfg, wakeUpDateVec.length, bypassUopVec.length
154      ))
155      println(s"exu:${cfg.name} wakeupCnt:${wakeUpDateVec.length} bypassCnt:${bypassUopVec.length}")
156      iq.io.redirect <> redirect
157      iq.io.tlbFeedback := io.mem.tlbFeedback(i - exuParameters.ExuCnt + exuParameters.LduCnt + exuParameters.StuCnt)
158      iq.io.enq <> dispatch.io.enqIQCtrl(i)
159      dispatch.io.numExist(i) := iq.io.numExist
160      for(
161        (wakeUpPort, exuOut) <-
162        iq.io.wakeUpPorts.zip(wakeUpDateVec)
163      ){
164        wakeUpPort.bits := exuOut.bits
165        wakeUpPort.valid := exuOut.fire() // data after arbit
166      }
167      iq.io.bypassUops <> bypassUopVec
168      for(i <- bypassDataVec.indices){
169        iq.io.bypassData(i).valid := bypassDataVec(i).valid
170        iq.io.bypassData(i).bits := bypassDataVec(i).bits
171      }
172      iq
173    })
174
175  io.mem.commits <> roq.io.commits
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 := ParallelOR(roq.io.commits.map(c => c.valid && c.bits.isWalk)) // 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
209  roq.io.memRedirect <> io.mem.replayAll
210  roq.io.brqRedirect <> brq.io.redirect
211  roq.io.dp1Req <> dispatch.io.toRoq
212  dispatch.io.roqIdxs <> roq.io.roqIdxs
213  io.mem.dp1Req <> dispatch.io.toLsroq
214  dispatch.io.lsroqIdxs <> io.mem.lsroqIdxs
215  dispatch.io.commits <> roq.io.commits
216
217  intRf.io.readPorts <> dispatch.io.readIntRf
218  fpRf.io.readPorts <> dispatch.io.readFpRf ++ issueQueues.flatMap(_.io.readFpRf)
219  memRf.io.readPorts <> issueQueues.flatMap(_.io.readIntRf)
220
221  io.mem.redirect <> redirect
222
223  val wbu = Module(new Wbu(exuConfigs))
224  wbu.io.in <> exeWbReqs
225
226  val wbIntResults = wbu.io.toIntRf
227  val wbFpResults = wbu.io.toFpRf
228
229  def exuOutToRfWrite(x: Valid[ExuOutput]): RfWritePort = {
230    val rfWrite = Wire(new RfWritePort)
231    rfWrite.wen := x.valid
232    rfWrite.addr := x.bits.uop.pdest
233    rfWrite.data := x.bits.data
234    rfWrite
235  }
236  val intRfWrite = wbIntResults.map(exuOutToRfWrite)
237  intRf.io.writePorts <> intRfWrite
238  memRf.io.writePorts <> intRfWrite
239  fpRf.io.writePorts <> wbFpResults.map(exuOutToRfWrite)
240
241  rename.io.wbIntResults <> wbIntResults
242  rename.io.wbFpResults <> wbFpResults
243
244  roq.io.exeWbResults.take(exeWbReqs.length).zip(wbu.io.toRoq).foreach(x => x._1 := x._2)
245  roq.io.exeWbResults.last := brq.io.out
246
247
248  // TODO: Remove sink and source
249  val tmp = WireInit(0.U)
250  val sinks = Array[String](
251    "DTLBFINISH",
252    "DTLBPF",
253    "DTLBENABLE",
254    "perfCntCondMdcacheLoss",
255    "perfCntCondMl2cacheLoss",
256    "perfCntCondMdcacheHit",
257    "lsuMMIO",
258    "perfCntCondMl2cacheHit",
259    "perfCntCondMl2cacheReq",
260    "mtip",
261    "perfCntCondMdcacheReq",
262    "meip"
263  )
264  for (s <- sinks) {
265    BoringUtils.addSink(tmp, s)
266  }
267
268  val debugIntReg, debugFpReg = WireInit(VecInit(Seq.fill(32)(0.U(XLEN.W))))
269  BoringUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG")
270  BoringUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG")
271  val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg))
272  if (!env.FPGAPlatform) {
273    BoringUtils.addSource(debugArchReg, "difftestRegs")
274  }
275
276}
277