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