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