xref: /XiangShan/src/main/scala/xiangshan/backend/Backend.scala (revision 3fce4f48e1f4c43253ff1758dbd05b8b71627990)
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.ReservationStationNew
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 reservedStations  = 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 = Module(new ReservationStationNew(cfg, wakeupCnt, extraListenPortsCnt, fixedDelay = certainLatency, feedback = feedback))
120
121    rs.io.redirect <> redirect
122    rs.io.numExist <> dispatch.io.numExist(i)
123    rs.io.enqCtrl <> dispatch.io.enqIQCtrl(i)
124    rs.io.enqData <> dispatch.io.enqIQData(i)
125
126    rs.io.writeBackedData <> writeBackedData
127    for((x, y) <- rs.io.extraListenPorts.zip(extraListenPorts)){
128      x.valid := y.fire()
129      x.bits := y.bits
130    }
131
132    cfg match {
133      case `ldExeUnitCfg` =>
134      case `stExeUnitCfg` =>
135      case otherCfg =>
136        exeUnits(i).io.in <> rs.io.deq
137        exeUnits(i).io.redirect <> redirect
138        rs.io.tlbFeedback := DontCare
139    }
140
141    rs.suggestName(s"rs_${cfg.name}")
142
143    rs
144  })
145
146  for(rs <- reservedStations){
147    rs.io.broadcastedUops <> reservedStations.
148      filter(x => x.exuCfg.hasCertainLatency && needData(rs.exuCfg, x.exuCfg)).
149      map(_.io.selectedUop)
150  }
151
152  io.mem.commits <> roq.io.commits
153  io.mem.roqDeqPtr := roq.io.roqDeqPtr
154
155  io.mem.ldin <> reservedStations.filter(_.exuCfg == ldExeUnitCfg).map(_.io.deq)
156  io.mem.stin <> reservedStations.filter(_.exuCfg == stExeUnitCfg).map(_.io.deq)
157  jmpExeUnit.io.csrOnly.exception.valid := roq.io.redirect.valid && roq.io.redirect.bits.isException
158  jmpExeUnit.io.csrOnly.exception.bits := roq.io.exception
159  jmpExeUnit.fflags := roq.io.fflags
160  jmpExeUnit.dirty_fs := roq.io.dirty_fs
161  jmpExeUnit.io.csrOnly.externalInterrupt := io.externalInterrupt
162  jmpExeUnit.io.csrOnly.memExceptionVAddr := io.mem.exceptionAddr.vaddr
163  jmpExeUnit.fenceToSbuffer <> io.mem.fenceToSbuffer
164  io.mem.sfence <> jmpExeUnit.sfence
165  io.mem.csr <> jmpExeUnit.tlbCsrIO
166
167  io.mem.exceptionAddr.lsIdx.lsroqIdx := roq.io.exception.lsroqIdx
168  io.mem.exceptionAddr.lsIdx.lqIdx := roq.io.exception.lqIdx
169  io.mem.exceptionAddr.lsIdx.sqIdx := roq.io.exception.sqIdx
170  io.mem.exceptionAddr.isStore := CommitType.lsInstIsStore(roq.io.exception.ctrl.commitType)
171
172  io.mem.tlbFeedback <> reservedStations.filter(
173    x => x.exuCfg == ldExeUnitCfg || x.exuCfg == stExeUnitCfg
174  ).map(_.io.tlbFeedback)
175
176  io.frontend.outOfOrderBrInfo <> brq.io.outOfOrderBrInfo
177  io.frontend.inOrderBrInfo <> brq.io.inOrderBrInfo
178  io.frontend.sfence <> jmpExeUnit.sfence
179  io.frontend.tlbCsrIO <> jmpExeUnit.tlbCsrIO
180
181  io.fencei := jmpExeUnit.fencei
182  io.sfence := jmpExeUnit.sfence
183  io.tlbCsrIO := jmpExeUnit.tlbCsrIO
184
185  decode.io.in <> io.frontend.cfVec
186  brq.io.roqRedirect <> roq.io.redirect
187  brq.io.memRedirect <> io.mem.replayAll
188  brq.io.bcommit := roq.io.bcommit
189  brq.io.enqReqs <> decode.io.toBrq
190  for ((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.config.hasRedirect))) {
191    x.bits := y.io.out.bits
192    x.valid := y.io.out.fire() && y.io.out.bits.redirectValid
193  }
194  decode.io.brTags <> brq.io.brTags
195  decBuf.io.isWalking := ParallelOR(roq.io.commits.map(c => c.valid && c.bits.isWalk)) // TODO: opt this
196  decBuf.io.redirect <> redirect
197  decBuf.io.in <> decode.io.out
198
199  rename.io.redirect <> redirect
200  rename.io.roqCommits <> roq.io.commits
201  rename.io.in <> decBuf.io.out
202  rename.io.intRfReadAddr <> dispatch.io.readIntRf.map(_.addr) ++ dispatch.io.memIntRf.map(_.addr)
203  rename.io.intPregRdy <> dispatch.io.intPregRdy ++ dispatch.io.intMemRegRdy
204  rename.io.fpRfReadAddr <> dispatch.io.readFpRf.map(_.addr) ++ dispatch.io.memFpRf.map(_.addr)
205  rename.io.fpPregRdy <> dispatch.io.fpPregRdy ++ dispatch.io.fpMemRegRdy
206  rename.io.replayPregReq <> dispatch.io.replayPregReq
207  dispatch.io.redirect <> redirect
208  dispatch.io.fromRename <> rename.io.out
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.intrBitSet := jmpExeUnit.io.csrOnly.interrupt
214  roq.io.trapTarget := jmpExeUnit.io.csrOnly.trapTarget
215  dispatch.io.roqIdxs <> roq.io.roqIdxs
216  io.mem.dp1Req <> dispatch.io.toLsroq
217  dispatch.io.lsIdxs <> io.mem.lsIdxs
218  dispatch.io.dequeueRoqIndex.valid := roq.io.commitRoqIndex.valid || io.mem.oldestStore.valid
219  // store writeback must be after commit roqIdx
220  dispatch.io.dequeueRoqIndex.bits := Mux(io.mem.oldestStore.valid, io.mem.oldestStore.bits, roq.io.commitRoqIndex.bits)
221
222
223  intRf.io.readPorts <> dispatch.io.readIntRf ++ dispatch.io.memIntRf
224  fpRf.io.readPorts <> dispatch.io.readFpRf ++ dispatch.io.memFpRf
225
226  io.mem.redirect <> redirect
227
228  val wbu = Module(new Wbu(exuConfigs))
229  wbu.io.in <> exeWbReqs
230
231  val wbIntResults = wbu.io.toIntRf
232  val wbFpResults = wbu.io.toFpRf
233
234  def exuOutToRfWrite(x: Valid[ExuOutput]): RfWritePort = {
235    val rfWrite = Wire(new RfWritePort)
236    rfWrite.wen := x.valid
237    rfWrite.addr := x.bits.uop.pdest
238    rfWrite.data := x.bits.data
239    rfWrite
240  }
241  intRf.io.writePorts <> wbIntResults.map(exuOutToRfWrite)
242  fpRf.io.writePorts <> wbFpResults.map(exuOutToRfWrite)
243
244  rename.io.wbIntResults <> wbIntResults
245  rename.io.wbFpResults <> wbFpResults
246
247  roq.io.exeWbResults.take(exeWbReqs.length).zip(wbu.io.toRoq).foreach(x => x._1 := x._2)
248  roq.io.exeWbResults.last := brq.io.out
249
250
251  val debugIntReg, debugFpReg = WireInit(VecInit(Seq.fill(32)(0.U(XLEN.W))))
252  ExcitingUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG", ExcitingUtils.Debug)
253  ExcitingUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG", ExcitingUtils.Debug)
254  val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg))
255  if (!env.FPGAPlatform) {
256    ExcitingUtils.addSource(debugArchReg, "difftestRegs", ExcitingUtils.Debug)
257  }
258
259}
260