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