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