xref: /XiangShan/src/main/scala/xiangshan/backend/Backend.scala (revision 79e6426b3546b2c6261bc7b623c697f6a53ea8ce)
1package xiangshan.backend
2
3import chisel3._
4import chisel3.util._
5import xiangshan._
6import xiangshan.backend.decode.{DecodeBuffer, DecodeStage}
7import xiangshan.backend.rename.Rename
8import xiangshan.backend.brq.Brq
9import xiangshan.backend.dispatch.Dispatch
10import xiangshan.backend.exu._
11import xiangshan.backend.issue.{ReservationStationCtrl, ReservationStationData}
12import xiangshan.backend.regfile.{Regfile, RfWritePort}
13import xiangshan.backend.roq.Roq
14import xiangshan.mem._
15import utils.ParallelOR
16import xiangshan.backend.fu.FunctionUnit.{lduCfg, mouCfg, stuCfg}
17
18/** Backend Pipeline:
19  * Decode -> Rename -> Dispatch-1 -> Dispatch-2 -> Issue -> Exe
20  */
21class Backend extends XSModule
22  with NeedImpl {
23  val io = IO(new Bundle {
24    val frontend = Flipped(new FrontendToBackendIO)
25    val mem = Flipped(new MemToBackendIO)
26    val externalInterrupt = new ExternalInterruptIO
27    val sfence = Output(new SfenceBundle)
28    val fencei = Output(Bool())
29    val tlbCsrIO = Output(new TlbCsrBundle)
30  })
31
32
33  val aluExeUnits =Array.tabulate(exuParameters.AluCnt)(_ => Module(new AluExeUnit))
34  val jmpExeUnit = Module(new JumpExeUnit)
35  val mduExeUnits = Array.tabulate(exuParameters.MduCnt)(_ => Module(new MulDivExeUnit))
36  val fmacExeUnits = Array.tabulate(exuParameters.FmacCnt)(_ => Module(new FmacExeUnit))
37  val fmiscExeUnits = Array.tabulate(exuParameters.FmiscCnt)(_ => Module(new FmiscExeUnit))
38  val exeUnits = jmpExeUnit +: (aluExeUnits ++ mduExeUnits ++ fmacExeUnits ++ fmiscExeUnits)
39  exeUnits.foreach(_.io.csrOnly := DontCare)
40  exeUnits.foreach(_.io.mcommit := DontCare)
41
42  fmacExeUnits.foreach(_.frm := jmpExeUnit.frm)
43  fmiscExeUnits.foreach(_.frm := jmpExeUnit.frm)
44
45  val ldExeUnitCfg = ExuConfig("LoadExu", Seq(lduCfg), wbIntPriority = 0, wbFpPriority = 0)
46  val stExeUnitCfg = ExuConfig("StoreExu", Seq(stuCfg, mouCfg), wbIntPriority = Int.MaxValue, wbFpPriority = Int.MaxValue)
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    jmpExeUnit.config, aluExeUnits(0).config, mduExeUnits(0).config,
54    fmacExeUnits(0).config, fmiscExeUnits(0).config,
55    ldExeUnitCfg, stExeUnitCfg
56  ))
57  val roq = Module(new Roq)
58  val intRf = Module(new Regfile(
59    numReadPorts = NRIntReadPorts,
60    numWirtePorts = NRIntWritePorts,
61    hasZero = true
62  ))
63  val fpRf = Module(new Regfile(
64    numReadPorts = NRFpReadPorts,
65    numWirtePorts = NRFpWritePorts,
66    hasZero = false
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
84
85  val memConfigs =
86    Seq.fill(exuParameters.LduCnt)(ldExeUnitCfg) ++
87    Seq.fill(exuParameters.StuCnt)(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 rs = exuConfigs.zipWithIndex.map({ case (cfg, i) =>
100
101    // NOTE: exu could have certern and uncertaion latency
102    // but could not have multiple certern latency
103    var certainLatency = -1
104    if(cfg.hasCertainLatency) { certainLatency = cfg.latency.latencyVal.get }
105
106    val writeBackedData = exuConfigs.zip(exeWbReqs).filter(x => x._1.hasCertainLatency && needData(cfg, x._1)).map(_._2.bits.data)
107    val wakeupCnt = writeBackedData.length
108
109    val extraListenPorts = exuConfigs
110      .zip(exeWbReqs)
111      .filter(x => x._1.hasUncertainlatency && needData(cfg, x._1))
112      .map(_._2)
113    val extraListenPortsCnt = extraListenPorts.length
114
115    val feedback = (cfg == ldExeUnitCfg) || (cfg == stExeUnitCfg)
116
117    println(s"${i}: exu:${cfg.name} wakeupCnt: ${wakeupCnt} extraListenPorts: ${extraListenPortsCnt} delay:${certainLatency} feedback:${feedback}")
118
119    val rs_ctrl = Module(new ReservationStationCtrl(cfg, wakeupCnt, extraListenPortsCnt, fixedDelay = certainLatency, feedback = feedback))
120    val rs_data = Module(new ReservationStationData(cfg, wakeupCnt, extraListenPortsCnt))
121
122    rs_ctrl.io.toData <> rs_data.io.fromCtrl
123    rs_ctrl.io.redirect <> redirect
124    rs_ctrl.io.numExist <> dispatch.io.numExist(i)
125    rs_ctrl.io.enqCtrl <> dispatch.io.enqIQCtrl(i)
126    rs_data.io.enqData <> dispatch.io.enqIQData(i)
127
128    rs_data.io.writeBackedData <> writeBackedData
129    for(((x, y), z) <- rs_ctrl.io.extraListenPorts.zip(rs_data.io.extraListenPorts).zip(extraListenPorts)){
130      x.valid := z.fire()
131      x.bits  := z.bits
132      y       := z.bits.data
133    }
134
135
136    cfg match {
137      case `ldExeUnitCfg` =>
138      case `stExeUnitCfg` =>
139      case otherCfg =>
140        exeUnits(i).io.in <> rs_ctrl.io.deq
141        exeUnits(i).io.in.bits := rs_data.io.deq
142        exeUnits(i).io.redirect <> redirect
143        rs_ctrl.io.tlbFeedback := DontCare
144    }
145
146    rs_ctrl.suggestName(s"rs_ctrl_${cfg.name}")
147    rs_data.suggestName(s"rs_data_${cfg.name}")
148    (rs_ctrl, rs_data)
149  })
150  val rsCtrls = rs.map(_._1)
151  val rsDatas = rs.map(_._2)
152
153  for(rs_ctrl <- rsCtrls) {
154    rs_ctrl.io.broadcastedUops <> rsCtrls.
155      filter(x => x.exuCfg.hasCertainLatency && needData(rs_ctrl.exuCfg, x.exuCfg)).
156      map(_.io.selectedUop)
157  }
158
159  io.mem.commits <> roq.io.commits
160  io.mem.roqDeqPtr := roq.io.roqDeqPtr
161
162  // io.mem.ldin <> reservedStations.filter(_.exuCfg == ldExeUnitCfg).map(_.io.deq)
163  // io.mem.stin <> reservedStations.filter(_.exuCfg == stExeUnitCfg).map(_.io.deq)
164  io.mem.ldin <> rsCtrls.filter(_.exuCfg == ldExeUnitCfg).map(_.io.deq)
165  io.mem.ldin.zip(rsDatas.filter(_.exuCfg == ldExeUnitCfg).map(_.io.deq)).map{
166    case (l,r) => l.bits := r
167  }
168  io.mem.stin <> rsCtrls.filter(_.exuCfg == stExeUnitCfg).map(_.io.deq)
169  io.mem.stin.zip(rsDatas.filter(_.exuCfg == stExeUnitCfg).map(_.io.deq)).map{
170    case (l,r) => l.bits := r
171  }
172  jmpExeUnit.io.csrOnly.exception.valid := roq.io.redirect.valid && roq.io.redirect.bits.isException
173  jmpExeUnit.io.csrOnly.exception.bits := roq.io.exception
174  jmpExeUnit.fflags := roq.io.fflags
175  jmpExeUnit.dirty_fs := roq.io.dirty_fs
176  jmpExeUnit.io.csrOnly.externalInterrupt := io.externalInterrupt
177  jmpExeUnit.io.csrOnly.memExceptionVAddr := io.mem.exceptionAddr.vaddr
178  jmpExeUnit.fenceToSbuffer <> io.mem.fenceToSbuffer
179  io.mem.sfence <> jmpExeUnit.sfence
180  io.mem.csr <> jmpExeUnit.tlbCsrIO
181
182  io.mem.exceptionAddr.lsIdx.lsroqIdx := roq.io.exception.lsroqIdx
183  io.mem.exceptionAddr.lsIdx.lqIdx := roq.io.exception.lqIdx
184  io.mem.exceptionAddr.lsIdx.sqIdx := roq.io.exception.sqIdx
185  io.mem.exceptionAddr.isStore := CommitType.lsInstIsStore(roq.io.exception.ctrl.commitType)
186
187  io.mem.tlbFeedback <> rsCtrls.filter(
188    x => x.exuCfg == ldExeUnitCfg || x.exuCfg == stExeUnitCfg
189  ).map(_.io.tlbFeedback)
190
191  io.frontend.outOfOrderBrInfo <> brq.io.outOfOrderBrInfo
192  io.frontend.inOrderBrInfo <> brq.io.inOrderBrInfo
193  io.frontend.sfence <> jmpExeUnit.sfence
194  io.frontend.tlbCsrIO <> jmpExeUnit.tlbCsrIO
195
196  io.fencei := jmpExeUnit.fencei
197  io.tlbCsrIO := jmpExeUnit.tlbCsrIO
198
199  decode.io.in <> io.frontend.cfVec
200  brq.io.roqRedirect <> roq.io.redirect
201  brq.io.memRedirect <> io.mem.replayAll
202  brq.io.bcommit := roq.io.bcommit
203  brq.io.enqReqs <> decode.io.toBrq
204  for ((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.config.hasRedirect))) {
205    x.bits := y.io.out.bits
206    x.valid := y.io.out.fire() && y.io.out.bits.redirectValid
207  }
208  decode.io.brTags <> brq.io.brTags
209  decBuf.io.isWalking := ParallelOR(roq.io.commits.map(c => c.valid && c.bits.isWalk)) // TODO: opt this
210  decBuf.io.redirect <> redirect
211  decBuf.io.in <> decode.io.out
212
213  rename.io.redirect <> redirect
214  rename.io.roqCommits <> roq.io.commits
215  rename.io.in <> decBuf.io.out
216  rename.io.intRfReadAddr <> dispatch.io.readIntRf.map(_.addr) ++ dispatch.io.memIntRf.map(_.addr)
217  rename.io.intPregRdy <> dispatch.io.intPregRdy ++ dispatch.io.intMemRegRdy
218  rename.io.fpRfReadAddr <> dispatch.io.readFpRf.map(_.addr) ++ dispatch.io.memFpRf.map(_.addr)
219  rename.io.fpPregRdy <> dispatch.io.fpPregRdy ++ dispatch.io.fpMemRegRdy
220  rename.io.replayPregReq <> dispatch.io.replayPregReq
221  dispatch.io.redirect <> redirect
222  dispatch.io.fromRename <> rename.io.out
223
224  roq.io.memRedirect <> io.mem.replayAll
225  roq.io.brqRedirect <> brq.io.redirect
226  roq.io.dp1Req <> dispatch.io.toRoq
227  roq.io.intrBitSet := jmpExeUnit.io.csrOnly.interrupt
228  roq.io.trapTarget := jmpExeUnit.io.csrOnly.trapTarget
229  dispatch.io.roqIdxs <> roq.io.roqIdxs
230  io.mem.dp1Req <> dispatch.io.toLsroq
231  dispatch.io.lsIdxs <> io.mem.lsIdxs
232  dispatch.io.dequeueRoqIndex.valid := roq.io.commitRoqIndex.valid || io.mem.oldestStore.valid
233  // store writeback must be after commit roqIdx
234  dispatch.io.dequeueRoqIndex.bits := Mux(io.mem.oldestStore.valid, io.mem.oldestStore.bits, roq.io.commitRoqIndex.bits)
235
236
237  intRf.io.readPorts <> dispatch.io.readIntRf ++ dispatch.io.memIntRf
238  fpRf.io.readPorts <> dispatch.io.readFpRf ++ dispatch.io.memFpRf
239
240  io.mem.redirect <> redirect
241
242  val wbu = Module(new Wbu(exuConfigs))
243  wbu.io.in <> exeWbReqs
244
245  val wbIntResults = wbu.io.toIntRf
246  val wbFpResults = wbu.io.toFpRf
247
248  def exuOutToRfWrite(x: Valid[ExuOutput]): RfWritePort = {
249    val rfWrite = Wire(new RfWritePort)
250    rfWrite.wen := x.valid
251    rfWrite.addr := x.bits.uop.pdest
252    rfWrite.data := x.bits.data
253    rfWrite
254  }
255  intRf.io.writePorts <> wbIntResults.map(exuOutToRfWrite)
256  fpRf.io.writePorts <> wbFpResults.map(exuOutToRfWrite)
257
258  rename.io.wbIntResults <> wbIntResults
259  rename.io.wbFpResults <> wbFpResults
260
261  roq.io.exeWbResults.take(exeWbReqs.length).zip(wbu.io.toRoq).foreach(x => x._1 := x._2)
262  roq.io.exeWbResults.last := brq.io.out
263
264
265  val debugIntReg, debugFpReg = WireInit(VecInit(Seq.fill(32)(0.U(XLEN.W))))
266  ExcitingUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG", ExcitingUtils.Debug)
267  ExcitingUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG", ExcitingUtils.Debug)
268  val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg))
269  if (!env.FPGAPlatform) {
270    ExcitingUtils.addSource(debugArchReg, "difftestRegs", ExcitingUtils.Debug)
271  }
272
273}
274