xref: /XiangShan/src/main/scala/xiangshan/backend/Backend.scala (revision ccce3504dd794d72d8ff6263bcf3eac7bee7b1f9)
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
40  fmacExeUnits.foreach(_.frm := jmpExeUnit.frm)
41  fmiscExeUnits.foreach(_.frm := jmpExeUnit.frm)
42
43  val wbIntExus = exeUnits.filter(e => e.config.writeIntRf)
44  val wbFpExus = exeUnits.filter(e => e.config.writeFpRf)
45  // wb int exu + wb fp exu + ldu / stu + brq
46  val wbSize = wbIntExus.length + wbFpExus.length + exuParameters.LduCnt + exuParameters.StuCnt + 1
47
48  val ldExeUnitCfg = ExuConfig("LoadExu", Seq(lduCfg), wbIntPriority = 0, wbFpPriority = 0)
49  val stExeUnitCfg = ExuConfig("StoreExu", Seq(stuCfg, mouCfg), wbIntPriority = Int.MaxValue, wbFpPriority = Int.MaxValue)
50
51  val ldIntOut = io.mem.ldout.map(x => {
52    val raw = WireInit(x)
53    raw.valid := x.valid && x.bits.uop.ctrl.rfWen
54    raw
55  })
56
57  val ldFpOut = io.mem.ldout.map(x => {
58    val raw = WireInit(x)
59    raw.valid := x.valid && x.bits.uop.ctrl.fpWen
60    raw
61  })
62
63
64  val decode = Module(new DecodeStage)
65  val brq = Module(new Brq)
66  val decBuf = Module(new DecodeBuffer)
67  val rename = Module(new Rename)
68  val dispatch = Module(new Dispatch(
69    jmpExeUnit.config, aluExeUnits(0).config, mduExeUnits(0).config,
70    fmacExeUnits(0).config, fmiscExeUnits(0).config,
71    ldExeUnitCfg, stExeUnitCfg
72  ))
73  val roq = Module(new Roq(wbSize))
74  val intRf = Module(new Regfile(
75    numReadPorts = NRIntReadPorts,
76    numWirtePorts = NRIntWritePorts,
77    hasZero = true,
78    len = XLEN
79  ))
80  val fpRf = Module(new Regfile(
81    numReadPorts = NRFpReadPorts,
82    numWirtePorts = NRFpWritePorts,
83    hasZero = false,
84    len = XLEN + 1
85  ))
86
87  // backend redirect, flush pipeline
88  val redirect = Mux(
89    roq.io.redirect.valid,
90    roq.io.redirect,
91    Mux(
92      brq.io.redirect.valid,
93      brq.io.redirect,
94      io.mem.replayAll
95    )
96  )
97
98  io.frontend.redirect := redirect
99  io.frontend.redirect.valid := redirect.valid && !redirect.bits.isReplay
100
101
102  val ldConfigs = Seq.fill(exuParameters.LduCnt)(ldExeUnitCfg)
103  val stConfigs = Seq.fill(exuParameters.StuCnt)(stExeUnitCfg)
104  val memConfigs = ldConfigs ++ stConfigs
105
106  val exuConfigs = exeUnits.map(_.config) ++ memConfigs
107
108
109  def needWakeup(cfg: ExuConfig): Boolean =
110    (cfg.readIntRf && cfg.writeIntRf) || (cfg.readFpRf && cfg.writeFpRf)
111
112  def needData(a: ExuConfig, b: ExuConfig): Boolean =
113    (a.readIntRf && b.writeIntRf) || (a.readFpRf && b.writeFpRf)
114
115  val reservedStations = exuConfigs.zipWithIndex.map({ case (cfg, i) =>
116
117    // NOTE: exu could have certern and uncertaion latency
118    // but could not have multiple certern latency
119    var certainLatency = -1
120    if (cfg.hasCertainLatency) {
121      certainLatency = cfg.latency.latencyVal.get
122    }
123
124    val readIntRf = cfg.readIntRf
125    val readFpRf = cfg.readFpRf
126
127    val writeBackIntData = wbIntExus.filter(e => e.config.hasCertainLatency && readIntRf).map(_.io.toInt.bits.data)
128    val writeBackFpData = wbFpExus.filter(e => e.config.hasCertainLatency && readFpRf).map(_.io.toFp.bits.data)
129    val writeBackedData = writeBackIntData ++ writeBackFpData
130    val wakeupCnt = writeBackedData.length
131
132    val extraListenInt = wbIntExus.filter(e => e.config.hasUncertainlatency && readIntRf).map(_.io.toInt)
133    val extraListenFp = wbFpExus.filter(e => e.config.hasUncertainlatency && readFpRf).map(_.io.toFp)
134
135    val extraListenPorts = extraListenInt ++ extraListenFp ++ io.mem.ldout
136    val extraListenPortsCnt = extraListenPorts.length
137
138    val feedback = (cfg == ldExeUnitCfg) || (cfg == stExeUnitCfg)
139
140    println(s"${i}: exu:${cfg.name} wakeupCnt: ${wakeupCnt} extraListenPorts: ${extraListenPortsCnt} delay:${certainLatency} feedback:${feedback}")
141
142    val rs = Module(new ReservationStationNew(
143      cfg, wakeupCnt, extraListenPortsCnt, fixedDelay = certainLatency, feedback = feedback
144    ))
145
146    rs.io.redirect <> redirect
147    rs.io.numExist <> dispatch.io.numExist(i)
148    rs.io.enqCtrl <> dispatch.io.enqIQCtrl(i)
149    rs.io.enqData <> dispatch.io.enqIQData(i)
150
151    rs.io.writeBackedData <> writeBackedData
152    for ((x, y) <- rs.io.extraListenPorts.zip(extraListenPorts)) {
153      x.valid := y.fire()
154      x.bits := y.bits
155    }
156
157    cfg match {
158      case `ldExeUnitCfg` =>
159      case `stExeUnitCfg` =>
160      case otherCfg =>
161        if (cfg.readIntRf) {
162          exeUnits(i).io.fromInt <> rs.io.deq
163        } else {
164          exeUnits(i).io.fromFp <> rs.io.deq
165        }
166        exeUnits(i).io.redirect <> redirect
167        rs.io.tlbFeedback := DontCare
168    }
169
170    rs.suggestName(s"rs_${cfg.name}")
171
172    rs
173  })
174
175  for (rs <- reservedStations) {
176    val wbIntUops = reservedStations.filter(x =>
177      x.exuCfg.hasCertainLatency && x.exuCfg.writeIntRf && rs.exuCfg.readIntRf
178    ).map(x => {
179      val raw = WireInit(x.io.selectedUop)
180      raw.valid := x.io.selectedUop.valid && raw.bits.ctrl.rfWen
181      raw
182    })
183    val wbFpUops = reservedStations.filter(x =>
184      x.exuCfg.hasCertainLatency && x.exuCfg.writeFpRf && rs.exuCfg.readFpRf
185    ).map(x => {
186      val raw = WireInit(x.io.selectedUop)
187      raw.valid := x.io.selectedUop.valid && raw.bits.ctrl.fpWen
188      raw
189    })
190
191    rs.io.broadcastedUops <> wbIntUops ++ wbFpUops
192  }
193
194  io.mem.commits <> roq.io.commits
195  io.mem.roqDeqPtr := roq.io.roqDeqPtr
196
197  io.mem.ldin <> reservedStations.filter(_.exuCfg == ldExeUnitCfg).map(_.io.deq)
198  io.mem.stin <> reservedStations.filter(_.exuCfg == stExeUnitCfg).map(_.io.deq)
199  jmpExeUnit.csrOnly.exception.valid := roq.io.redirect.valid && roq.io.redirect.bits.isException
200  jmpExeUnit.csrOnly.exception.bits := roq.io.exception
201  jmpExeUnit.fflags := roq.io.csr.fflags
202  jmpExeUnit.dirty_fs := roq.io.csr.dirty_fs
203  jmpExeUnit.csrOnly.externalInterrupt := io.externalInterrupt
204  jmpExeUnit.csrOnly.memExceptionVAddr := io.mem.exceptionAddr.vaddr
205  jmpExeUnit.csrOnly.isInterrupt := DontCare // TODO: fix this
206  jmpExeUnit.fenceToSbuffer <> io.mem.fenceToSbuffer
207  io.mem.sfence <> jmpExeUnit.sfence
208  io.mem.csr <> jmpExeUnit.tlbCsrIO
209
210  io.mem.exceptionAddr.lsIdx.lsroqIdx := roq.io.exception.lsroqIdx
211  io.mem.exceptionAddr.lsIdx.lqIdx := roq.io.exception.lqIdx
212  io.mem.exceptionAddr.lsIdx.sqIdx := roq.io.exception.sqIdx
213  io.mem.exceptionAddr.isStore := CommitType.lsInstIsStore(roq.io.exception.ctrl.commitType)
214
215  io.mem.tlbFeedback <> reservedStations.filter(
216    x => x.exuCfg == ldExeUnitCfg || x.exuCfg == stExeUnitCfg
217  ).map(_.io.tlbFeedback)
218
219  io.frontend.outOfOrderBrInfo <> brq.io.outOfOrderBrInfo
220  io.frontend.inOrderBrInfo <> brq.io.inOrderBrInfo
221  io.frontend.sfence <> jmpExeUnit.sfence
222  io.frontend.tlbCsrIO <> jmpExeUnit.tlbCsrIO
223
224  io.fencei := jmpExeUnit.fencei
225  io.tlbCsrIO := jmpExeUnit.tlbCsrIO
226
227  decode.io.in <> io.frontend.cfVec
228  brq.io.roqRedirect <> roq.io.redirect
229  brq.io.memRedirect <> io.mem.replayAll
230  brq.io.bcommit := roq.io.bcommit
231  brq.io.enqReqs <> decode.io.toBrq
232  for ((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.config.hasRedirect))) {
233    x.bits := y.io.toInt.bits
234    x.valid := y.io.toInt.fire() && y.io.toInt.bits.redirectValid
235  }
236  decode.io.brTags <> brq.io.brTags
237  decBuf.io.isWalking := ParallelOR(roq.io.commits.map(c => c.valid && c.bits.isWalk)) // TODO: opt this
238  decBuf.io.redirect <> redirect
239  decBuf.io.in <> decode.io.out
240
241  rename.io.redirect <> redirect
242  rename.io.roqCommits <> roq.io.commits
243  rename.io.in <> decBuf.io.out
244  rename.io.intRfReadAddr <> dispatch.io.readIntRf.map(_.addr)
245  rename.io.intPregRdy <> dispatch.io.intPregRdy
246  rename.io.fpRfReadAddr <> dispatch.io.readFpRf.map(_.addr)
247  rename.io.fpPregRdy <> dispatch.io.fpPregRdy
248  rename.io.replayPregReq <> dispatch.io.replayPregReq
249  dispatch.io.redirect <> redirect
250  dispatch.io.fromRename <> rename.io.out
251
252  roq.io.memRedirect <> io.mem.replayAll
253  roq.io.brqRedirect <> brq.io.redirect
254  roq.io.dp1Req <> dispatch.io.toRoq
255  roq.io.csr.intrBitSet := jmpExeUnit.csrOnly.interrupt
256  roq.io.csr.trapTarget := jmpExeUnit.csrOnly.trapTarget
257  dispatch.io.roqIdxs <> roq.io.roqIdxs
258  io.mem.dp1Req <> dispatch.io.toLsroq
259  dispatch.io.lsIdxs <> io.mem.lsIdxs
260  dispatch.io.dequeueRoqIndex.valid := roq.io.commitRoqIndex.valid || io.mem.oldestStore.valid
261  // store writeback must be after commit roqIdx
262  dispatch.io.dequeueRoqIndex.bits := Mux(io.mem.oldestStore.valid, io.mem.oldestStore.bits, roq.io.commitRoqIndex.bits)
263
264
265  intRf.io.readPorts <> dispatch.io.readIntRf
266  fpRf.io.readPorts <> dispatch.io.readFpRf
267
268  io.mem.redirect <> redirect
269
270
271  val wbIntArbiter = Module(new Wb(
272    wbIntExus.map(_.config.wbIntPriority) ++ ldConfigs.map(_.wbIntPriority),
273    NRIntWritePorts,
274    wen = (e: ExuOutput)=>e.uop.ctrl.rfWen
275  ))
276
277  val wbFpArbiter = Module(new Wb(
278    wbFpExus.map(_.config.wbFpPriority) ++ ldConfigs.map(_.wbFpPriority),
279    NRFpWritePorts,
280    wen = (e: ExuOutput) => e.uop.ctrl.fpWen
281  ))
282
283  wbIntArbiter.io.in <> wbIntExus.map(_.io.toInt) ++ ldIntOut
284  wbFpArbiter.io.in <> wbFpExus.map(_.io.toFp) ++ ldFpOut
285
286  def exuOutToRfWrite(x: Valid[ExuOutput]): RfWritePort = {
287    val rfWrite = Wire(new RfWritePort)
288    rfWrite.wen := x.valid
289    rfWrite.addr := x.bits.uop.pdest
290    rfWrite.data := x.bits.data
291    rfWrite
292  }
293
294  intRf.io.writePorts <> wbIntArbiter.io.out.map(exuOutToRfWrite)
295  fpRf.io.writePorts <> wbFpArbiter.io.out.map(exuOutToRfWrite)
296
297  rename.io.wbIntResults <> wbIntArbiter.io.out
298  rename.io.wbFpResults <> wbFpArbiter.io.out
299
300  io.mem.stout.foreach(_.ready := true.B)
301  io.mem.ldout.foreach(_.ready := true.B)
302  roq.io.exeWbResults.take(wbSize - 1).zip(
303    wbIntExus.map(e => {
304      val toInt = WireInit(e.io.toInt)
305      if(e.config.hasRedirect){
306        toInt.valid := e.io.toInt.valid && !toInt.bits.redirectValid
307      }
308      toInt
309    }) ++ wbFpExus.map(_.io.toFp) ++ io.mem.ldout ++ io.mem.stout
310  ).foreach {
311    case (x, y) =>
312      x.bits := y.bits
313      x.valid := y.fire()
314  }
315  roq.io.exeWbResults.last := brq.io.out
316
317  val debugIntReg, debugFpReg = WireInit(VecInit(Seq.fill(32)(0.U(XLEN.W))))
318  ExcitingUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG", ExcitingUtils.Debug)
319  ExcitingUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG", ExcitingUtils.Debug)
320  val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg))
321  if (!env.FPGAPlatform) {
322    ExcitingUtils.addSource(debugArchReg, "difftestRegs", ExcitingUtils.Debug)
323  }
324
325}
326