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