xref: /XiangShan/src/main/scala/xiangshan/backend/Backend.scala (revision bf44d6491c7790e1355b9d5174775c10ab8496c6)
1package xiangshan.backend
2
3import chipsalliance.rocketchip.config.Parameters
4import chisel3._
5import chisel3.util._
6import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
7import utility.{PipelineConnect, ZeroExt}
8import xiangshan._
9import xiangshan.backend.Bundles.{DynInst, MemExuInput, MemExuOutput}
10import xiangshan.backend.ctrlblock.CtrlBlock
11import xiangshan.backend.datapath.WbConfig._
12import xiangshan.backend.datapath.{DataPath, NewPipelineConnect, WbDataPath}
13import xiangshan.backend.exu.ExuBlock
14import xiangshan.backend.fu.vector.Bundles.{VConfig, VType}
15import xiangshan.backend.fu.{FenceIO, FenceToSbuffer, FuConfig, PerfCounterIO}
16import xiangshan.backend.issue.{Scheduler, IntScheduler, MemScheduler, VfScheduler}
17import xiangshan.backend.rob.RobLsqIO
18import xiangshan.frontend.{FtqPtr, FtqRead}
19import xiangshan.mem.{LqPtr, LsqEnqIO, SqPtr}
20
21class Backend(val params: BackendParams)(implicit p: Parameters) extends LazyModule
22  with HasXSParameter {
23
24  println("[Backend] ExuConfigs:")
25  for (exuCfg <- params.allExuParams) {
26    val fuConfigs = exuCfg.fuConfigs
27    val wbPortConfigs = exuCfg.wbPortConfigs
28    val immType = exuCfg.immType
29
30    println("[Backend]   " +
31      s"${exuCfg.name}: " +
32      s"${ fuConfigs.map(_.name).mkString("fu(s): {", ",", "}") }, " +
33      s"${ wbPortConfigs.mkString("wb: {", ",", "}") }, " +
34      s"${ immType.map(SelImm.mkString(_)).mkString("imm: {", "," , "}") }, " +
35      s"latMax(${exuCfg.latencyValMax}), ${exuCfg.fuLatancySet.mkString("lat: {",",","}")}, ")
36    require(wbPortConfigs.collectFirst { case x: IntWB => x }.nonEmpty ==
37      fuConfigs.map(_.writeIntRf).reduce(_ || _),
38      "int wb port has no priority" )
39    require(wbPortConfigs.collectFirst { case x: VfWB => x }.nonEmpty ==
40      fuConfigs.map(x => x.writeFpRf || x.writeVecRf).reduce(_ || _),
41      "vec wb port has no priority" )
42  }
43
44  for (cfg <- FuConfig.allConfigs) {
45    println(s"[Backend] $cfg")
46  }
47
48  val ctrlBlock = LazyModule(new CtrlBlock(params))
49  val intScheduler = params.intSchdParams.map(x => LazyModule(new Scheduler(x)))
50  val vfScheduler = params.vfSchdParams.map(x => LazyModule(new Scheduler(x)))
51  val memScheduler = params.memSchdParams.map(x => LazyModule(new Scheduler(x)))
52  val dataPath = LazyModule(new DataPath(params))
53  val intExuBlock = params.intSchdParams.map(x => LazyModule(new ExuBlock(x)))
54  val vfExuBlock = params.vfSchdParams.map(x => LazyModule(new ExuBlock(x)))
55
56  lazy val module = new BackendImp(this)
57}
58
59class BackendImp(override val wrapper: Backend)(implicit p: Parameters) extends LazyModuleImp(wrapper)
60  with HasXSParameter{
61  implicit private val params = wrapper.params
62  val io = IO(new BackendIO()(p, wrapper.params))
63
64  private val ctrlBlock = wrapper.ctrlBlock.module
65  private val intScheduler = wrapper.intScheduler.get.module
66  private val vfScheduler = wrapper.vfScheduler.get.module
67  private val memScheduler = wrapper.memScheduler.get.module
68  private val dataPath = wrapper.dataPath.module
69  private val intExuBlock = wrapper.intExuBlock.get.module
70  private val vfExuBlock = wrapper.vfExuBlock.get.module
71  private val wbDataPath = Module(new WbDataPath(params))
72
73  private val (intRespWrite, vfRespWrite, memRespWrite) = (intScheduler.io.toWbFuBusyTable.intFuBusyTableWrite,
74    vfScheduler.io.toWbFuBusyTable.intFuBusyTableWrite,
75    memScheduler.io.toWbFuBusyTable.intFuBusyTableWrite)
76  private val (intRespRead, vfRespRead, memRespRead) = (intScheduler.io.fromWbFuBusyTable.fuBusyTableRead,
77    vfScheduler.io.fromWbFuBusyTable.fuBusyTableRead,
78    memScheduler.io.fromWbFuBusyTable.fuBusyTableRead)
79  private val intAllRespWrite = (intRespWrite ++ vfRespWrite ++ memRespWrite).flatten
80  private val intAllRespRead = (intRespRead ++ vfRespRead ++ memRespRead).flatten.map(_.intWbBusyTable)
81  private val intAllWbConflictFlag = dataPath.io.wbConfictRead.flatten.flatten.map(_.intConflict)
82
83  private val (vfIntRespWrite, vfVfRespWrite, vfMemRespWrite) = (intScheduler.io.toWbFuBusyTable.vfFuBusyTableWrite,
84    vfScheduler.io.toWbFuBusyTable.vfFuBusyTableWrite,
85    memScheduler.io.toWbFuBusyTable.vfFuBusyTableWrite)
86
87  private val vfAllRespWrite = (vfIntRespWrite ++ vfVfRespWrite ++ vfMemRespWrite).flatten
88  private val vfAllRespRead = (intRespRead ++ vfRespRead ++ memRespRead).flatten.map(_.vfWbBusyTable)
89  private val vfAllWbConflictFlag = dataPath.io.wbConfictRead.flatten.flatten.map(_.vfConflict)
90
91  wbDataPath.io.fromIntExu.flatten.filter(x => x.bits.params.writeIntRf)
92  private val allExuParams = params.allExuParams
93  private val intRespWriteWithParams = intAllRespWrite.zip(allExuParams)
94  println(s"[intRespWriteWithParams] is ${intRespWriteWithParams}")
95  intRespWriteWithParams.foreach{ case(l,r) =>
96    println(s"FuBusyTableWriteBundle is ${l}, ExeUnitParams is ${r}")
97  }
98  private val vfRespWriteWithParams = vfAllRespWrite.zip(allExuParams)
99
100  private val intWBAllFuGroup = params.getIntWBExeGroup.map{ case(groupId, exeUnit) => (groupId, exeUnit.flatMap(_.fuConfigs)) }
101  private val intWBFuGroup = params.getIntWBExeGroup.map{ case(groupId, exeUnit) => (groupId, exeUnit.flatMap(_.fuConfigs).filter(_.writeIntRf)) }
102  private val intLatencyCertains = intWBAllFuGroup.map{case (k,v) => (k, v.map(_.latency.latencyVal.nonEmpty).reduce(_ && _))}
103  private val intWBFuLatencyMap = intLatencyCertains.map{case (k, latencyCertain) =>
104    if (latencyCertain) Some(intWBFuGroup(k).map(y => (y.fuType, y.latency.latencyVal.get)))
105    else None
106  }.toSeq
107  private val intWBFuLatencyValMax = intWBFuLatencyMap.map(latencyMap=> latencyMap.map(x => x.map(_._2).max))
108
109  private val vfWBAllFuGroup = params.getVfWBExeGroup.map{ case(groupId, exeUnit) => (groupId, exeUnit.flatMap(_.fuConfigs)) }
110  private val vfWBFuGroup = params.getVfWBExeGroup.map{ case(groupId, exeUnit) => (groupId, exeUnit.flatMap(_.fuConfigs).filter(x => x.writeFpRf || x.writeVecRf)) }
111  private val vfLatencyCertains = vfWBAllFuGroup.map{case (k,v) => (k, v.map(_.latency.latencyVal.nonEmpty).reduce(_ && _))}
112  val vfWBFuLatencyMap = vfLatencyCertains.map { case (k, latencyCertain) =>
113    if (latencyCertain) Some(vfWBFuGroup(k).map(y => (y.fuType, y.latency.latencyVal.get)))
114    else None
115  }.toSeq
116  private val vfWBFuLatencyValMax = vfWBFuLatencyMap.map(latencyMap => latencyMap.map(x => x.map(_._2).max))
117
118  private val intWBFuBusyTable = intWBFuLatencyValMax.map { case y => if (y.getOrElse(0)>0) Some(Reg(UInt(y.getOrElse(1).W))) else None }
119  println(s"[intWBFuBusyTable] is ${intWBFuBusyTable.map(x => x) }")
120  private val vfWBFuBusyTable = vfWBFuLatencyValMax.map { case y => if (y.getOrElse(0)>0) Some(Reg(UInt(y.getOrElse(1).W))) else None }
121  println(s"[vfWBFuBusyTable] is ${vfWBFuBusyTable.map(x => x) }")
122
123  private val intWBPortConflictFlag = intWBFuLatencyValMax.map { case y => if (y.getOrElse(0) > 0) Some(Reg(Bool())) else None }
124  private val vfWBPortConflictFlag = vfWBFuLatencyValMax.map { case y => if (y.getOrElse(0) > 0) Some(Reg(Bool())) else None }
125
126  intWBPortConflictFlag.foreach(x => if(x.isDefined) dontTouch((x.get)))
127  vfWBPortConflictFlag.foreach(x => if(x.isDefined) dontTouch((x.get)))
128
129
130  intWBFuBusyTable.map(x => x.map(dontTouch(_)))
131  vfWBFuBusyTable.map(x => x.map(dontTouch(_)))
132
133
134  private val intWBFuBusyTableWithPort = intWBFuBusyTable.zip(intWBFuGroup.map(_._1))
135  private val intWBPortConflictFlagWithPort = intWBPortConflictFlag.zip(intWBFuGroup.map(_._1))
136  // intWBFuBusyTable write
137  intWBFuBusyTableWithPort.zip(intWBPortConflictFlag).zip(intWBFuLatencyValMax).foreach {
138    case (((busyTable, wbPort), wbPortConflictFlag), maxLatency) =>
139      if (busyTable.nonEmpty) {
140      val maskWidth = maxLatency.getOrElse(0)
141      val defaultMask = ((1 << maskWidth) - 1).U
142      val deqWbFuBusyTableValue = intRespWriteWithParams.zipWithIndex.filter { case ((r, p), idx) =>
143        (p.wbPortConfigs.collectFirst{ case x: IntWB => x.port }.getOrElse(-1)) == wbPort
144      }.map{case ((r, p), idx) =>
145        val resps = Seq(r.deqResp, r.og0Resp, r.og1Resp)
146        Mux(resps(0).valid && resps(0).bits.respType === RSFeedbackType.issueSuccess,
147          VecInit((0 until maxLatency.getOrElse(0) + 1).map { case latency =>
148          val latencyNumFuType = p.writeIntFuConfigs.filter(_.latency.latencyVal.getOrElse(-1) == latency).map(_.fuType)
149          val isLatencyNum = Cat(latencyNumFuType.map(futype => resps(0).bits.fuType === futype.U)).asUInt().orR() // The latency of the deqResp inst is Num
150            isLatencyNum
151          }).asUInt,
152          0.U)
153      }
154//        deqWbFuBusyTableValue.foreach(x => dontTouch(x))
155      val deqIsLatencyNumMask = (deqWbFuBusyTableValue.reduce(_ | _) >> 1).asUInt
156      wbPortConflictFlag.get := deqWbFuBusyTableValue.reduce(_ & _).orR
157
158      val og0IsLatencyNumMask = WireInit(defaultMask)
159      og0IsLatencyNumMask := intRespWriteWithParams.zipWithIndex.map { case ((r, p), idx) =>
160        val resps = Seq(r.deqResp, r.og0Resp, r.og1Resp)
161        val matchI = (p.wbPortConfigs.collectFirst { case x: IntWB => x.port }.getOrElse(-1)) == wbPort
162        if (matchI) {
163          Mux(resps(1).valid && resps(1).bits.respType === RSFeedbackType.rfArbitFail,
164            (~(Cat(VecInit((0 until maxLatency.getOrElse(0)).map { case num =>
165              val latencyNumFuType = p.writeIntFuConfigs.filter(_.latency.latencyVal.getOrElse(-1) == num + 1).map(_.fuType)
166              val isLatencyNum = Cat(latencyNumFuType.map(futype => resps(1).bits.fuType === futype.U)).asUInt().orR() // The latency of the deqResp inst is Num
167              isLatencyNum
168            }).asUInt, 0.U(1.W)))).asUInt,
169            defaultMask)
170        } else defaultMask
171      }.reduce(_&_)
172      val og1IsLatencyNumMask = WireInit(defaultMask)
173      og1IsLatencyNumMask := intRespWriteWithParams.zipWithIndex.map { case ((r, p), idx) =>
174        val resps = Seq(r.deqResp, r.og0Resp, r.og1Resp)
175        val matchI = (p.wbPortConfigs.collectFirst { case x: IntWB => x.port }.getOrElse(-1)) == wbPort
176        if (matchI && resps.length==3) {
177          Mux(resps(2).valid && resps(2).bits.respType === RSFeedbackType.fuBusy,
178            (~(Cat(VecInit((0 until maxLatency.getOrElse(0)).map { case num =>
179              val latencyNumFuType = p.writeIntFuConfigs.filter(_.latency.latencyVal.getOrElse(-1) == num + 1).map(_.fuType)
180              val isLatencyNum = Cat(latencyNumFuType.map(futype => resps(2).bits.fuType === futype.U)).asUInt().orR() // The latency of the deqResp inst is Num
181              isLatencyNum
182            }).asUInt, 0.U(2.W)))).asUInt,
183            defaultMask)
184        } else defaultMask
185      }.reduce(_ & _)
186      dontTouch(deqIsLatencyNumMask)
187      dontTouch(og0IsLatencyNumMask)
188      dontTouch(og1IsLatencyNumMask)
189      busyTable.get := ((busyTable.get >> 1.U).asUInt() | deqIsLatencyNumMask) & og0IsLatencyNumMask.asUInt() & og1IsLatencyNumMask.asUInt()
190    }
191  }
192  // intWBFuBusyTable read
193  for(i <- 0 until intAllRespRead.size){
194    if(intAllRespRead(i).isDefined){
195      intAllRespRead(i).get := intWBFuBusyTableWithPort.map { case (busyTable, wbPort) =>
196        val matchI = (allExuParams(i).wbPortConfigs.collectFirst { case x: IntWB => x.port }.getOrElse(-1)) == wbPort
197        if (busyTable.nonEmpty && matchI) {
198          busyTable.get.asTypeOf(intAllRespRead(i).get)
199        } else {
200          0.U.asTypeOf(intAllRespRead(i).get)
201        }
202      }.reduce(_ | _)
203    }
204
205    if (intAllWbConflictFlag(i).isDefined) {
206      intAllWbConflictFlag(i).get := intWBPortConflictFlagWithPort.map { case (conflictFlag, wbPort) =>
207        val matchI = (allExuParams(i).wbPortConfigs.collectFirst { case x: IntWB => x.port }.getOrElse(-1)) == wbPort
208        if (conflictFlag.nonEmpty && matchI) {
209          conflictFlag.get
210        } else false.B
211      }.reduce(_ | _)
212    }
213  }
214
215  private val vfWBFuBusyTableWithPort = vfWBFuBusyTable.zip(vfWBFuGroup.map(_._1))
216  private val vfWBPortConflictFlagWithPort = vfWBPortConflictFlag.zip(vfWBFuGroup.map(_._1))
217  // vfWBFuBusyTable write
218  vfWBFuBusyTableWithPort.zip(vfWBPortConflictFlag).zip(vfWBFuLatencyValMax).foreach{
219    case(((busyTable, wbPort), wbPortConflictFlag), maxLatency) =>
220      if(busyTable.nonEmpty){
221        val maskWidth = maxLatency.getOrElse(0)
222        val defaultMask = ((1 << maskWidth) - 1).U
223        val deqWbFuBusyTableValue = vfRespWriteWithParams.zipWithIndex.filter { case ((_, p), _) =>
224          (p.wbPortConfigs.collectFirst { case x: VfWB => x.port }.getOrElse(-1)) == wbPort
225        }.map { case ((r, p), _) =>
226          val resps = Seq(r.deqResp, r.og0Resp, r.og1Resp)
227          Mux(resps(0).valid && resps(0).bits.respType === RSFeedbackType.issueSuccess,
228            VecInit((0 until maxLatency.getOrElse(0) + 1).map { case latency =>
229              val latencyNumFuType = p.writeVfFuConfigs.filter(_.latency.latencyVal.getOrElse(-1) == latency).map(_.fuType)
230              val isLatencyNum = Cat(latencyNumFuType.map(futype => resps(0).bits.fuType === futype.U)).asUInt.orR // The latency of the deqResp inst is Num
231              isLatencyNum
232            }).asUInt,
233            0.U)
234        }
235        val deqIsLatencyNumMask = (deqWbFuBusyTableValue.reduce(_ | _) >> 1).asUInt
236        wbPortConflictFlag.get := deqWbFuBusyTableValue.reduce(_ & _).orR
237
238        val og0IsLatencyNumMask = WireInit(defaultMask)
239        og0IsLatencyNumMask := vfRespWriteWithParams.zipWithIndex.map { case ((r, p), idx) =>
240          val resps = Seq(r.deqResp, r.og0Resp, r.og1Resp)
241          val matchI = (p.wbPortConfigs.collectFirst { case x: VfWB => x.port }.getOrElse(-1)) == wbPort
242          if (matchI) {
243            Mux(resps(1).valid && resps(1).bits.respType === RSFeedbackType.rfArbitFail,
244              (~(Cat(VecInit((0 until maxLatency.getOrElse(0)).map { case num =>
245                val latencyNumFuType = p.writeVfFuConfigs.filter(_.latency.latencyVal.getOrElse(-1) == num + 1).map(_.fuType)
246                val isLatencyNum = Cat(latencyNumFuType.map(futype => resps(1).bits.fuType === futype.U)).asUInt.orR // The latency of the deqResp inst is Num
247                isLatencyNum
248              }).asUInt, 0.U(1.W)))).asUInt,
249              defaultMask)
250          } else defaultMask
251        }.reduce(_ & _)
252        val og1IsLatencyNumMask = WireInit(defaultMask)
253        og1IsLatencyNumMask := vfRespWriteWithParams.zipWithIndex.map { case ((r, p), idx) =>
254          val resps = Seq(r.deqResp, r.og0Resp, r.og1Resp)
255
256          val matchI = (p.wbPortConfigs.collectFirst { case x: VfWB => x.port }.getOrElse(-1)) == wbPort
257          if (matchI && resps.length == 3) {
258            Mux(resps(2).valid && resps(2).bits.respType === RSFeedbackType.fuBusy,
259              (~(Cat(VecInit((0 until maxLatency.getOrElse(0)).map { case num =>
260                val latencyNumFuType = p.writeVfFuConfigs.filter(_.latency.latencyVal.getOrElse(-1) == num + 1).map(_.fuType)
261                val isLatencyNum = Cat(latencyNumFuType.map(futype => resps(2).bits.fuType === futype.U)).asUInt.orR // The latency of the deqResp inst is Num
262                isLatencyNum
263              }).asUInt, 0.U(2.W)))).asUInt,
264              defaultMask)
265          } else defaultMask
266        }.reduce(_ & _)
267        dontTouch(deqIsLatencyNumMask)
268        dontTouch(og0IsLatencyNumMask)
269        dontTouch(og1IsLatencyNumMask)
270        busyTable.get := ((busyTable.get >> 1.U).asUInt | deqIsLatencyNumMask) & og0IsLatencyNumMask.asUInt & og1IsLatencyNumMask.asUInt
271      }
272  }
273
274  // vfWBFuBusyTable read
275  for (i <- 0 until vfAllRespRead.size) {
276    if(vfAllRespRead(i).isDefined){
277      vfAllRespRead(i).get := vfWBFuBusyTableWithPort.map { case (busyTable, wbPort) =>
278        val matchI = (allExuParams(i).wbPortConfigs.collectFirst { case x: VfWB => x.port }.getOrElse(-1)) == wbPort
279        if (busyTable.nonEmpty && matchI) {
280          busyTable.get.asTypeOf(vfAllRespRead(i).get)
281        } else {
282          0.U.asTypeOf(vfAllRespRead(i).get)
283        }
284      }.reduce(_ | _)
285    }
286
287    if(vfAllWbConflictFlag(i).isDefined){
288      vfAllWbConflictFlag(i).get := vfWBPortConflictFlagWithPort.map { case (conflictFlag, wbPort) =>
289        val matchI = (allExuParams(i).wbPortConfigs.collectFirst { case x: VfWB => x.port }.getOrElse(-1)) == wbPort
290        if (conflictFlag.nonEmpty && matchI) {
291          conflictFlag.get
292        } else false.B
293      }.reduce(_ | _)
294    }
295  }
296
297  private val vconfig = dataPath.io.vconfigReadPort.data
298
299  ctrlBlock.io.fromTop.hartId := io.fromTop.hartId
300  ctrlBlock.io.frontend <> io.frontend
301  ctrlBlock.io.fromWB.wbData <> wbDataPath.io.toCtrlBlock.writeback
302  ctrlBlock.io.fromMem.stIn <> io.mem.stIn
303  ctrlBlock.io.fromMem.violation <> io.mem.memoryViolation
304  ctrlBlock.io.csrCtrl <> intExuBlock.io.csrio.get.customCtrl
305  ctrlBlock.io.robio.csr.intrBitSet := intExuBlock.io.csrio.get.interrupt
306  ctrlBlock.io.robio.csr.trapTarget := intExuBlock.io.csrio.get.trapTarget
307  ctrlBlock.io.robio.csr.isXRet := intExuBlock.io.csrio.get.isXRet
308  ctrlBlock.io.robio.csr.wfiEvent := intExuBlock.io.csrio.get.wfi_event
309  ctrlBlock.io.robio.lsq <> io.mem.robLsqIO
310  ctrlBlock.io.fromDataPath.vtype := vconfig(7, 0).asTypeOf(new VType)
311
312  intScheduler.io.fromTop.hartId := io.fromTop.hartId
313  intScheduler.io.fromCtrlBlock.flush := ctrlBlock.io.toIssueBlock.flush
314  intScheduler.io.fromCtrlBlock.pcVec := ctrlBlock.io.toIssueBlock.pcVec
315  intScheduler.io.fromCtrlBlock.targetVec := ctrlBlock.io.toIssueBlock.targetVec
316  intScheduler.io.fromDispatch.allocPregs <> ctrlBlock.io.toIssueBlock.allocPregs
317  intScheduler.io.fromDispatch.uops <> ctrlBlock.io.toIssueBlock.intUops
318  intScheduler.io.intWriteBack := wbDataPath.io.toIntPreg
319  intScheduler.io.vfWriteBack := 0.U.asTypeOf(intScheduler.io.vfWriteBack)
320  intScheduler.io.fromDataPath := dataPath.io.toIntIQ
321
322  memScheduler.io.fromTop.hartId := io.fromTop.hartId
323  memScheduler.io.fromCtrlBlock.flush := ctrlBlock.io.toIssueBlock.flush
324  memScheduler.io.fromDispatch.allocPregs <> ctrlBlock.io.toIssueBlock.allocPregs
325  memScheduler.io.fromDispatch.uops <> ctrlBlock.io.toIssueBlock.memUops
326  memScheduler.io.intWriteBack := wbDataPath.io.toIntPreg
327  memScheduler.io.vfWriteBack := wbDataPath.io.toVfPreg
328  memScheduler.io.fromMem.get.scommit := io.mem.sqDeq
329  memScheduler.io.fromMem.get.lcommit := io.mem.lqDeq
330  memScheduler.io.fromMem.get.sqCancelCnt := io.mem.sqCancelCnt
331  memScheduler.io.fromMem.get.lqCancelCnt := io.mem.lqCancelCnt
332  memScheduler.io.fromMem.get.stIssuePtr := io.mem.stIssuePtr
333  memScheduler.io.fromMem.get.memWaitUpdateReq.staIssue.zip(io.mem.stIn).foreach { case (sink, source) =>
334    sink.valid := source.valid
335    sink.bits.uop := 0.U.asTypeOf(sink.bits.uop)
336    sink.bits.uop.robIdx := source.bits.robIdx
337  }
338  memScheduler.io.fromDataPath := dataPath.io.toMemIQ
339  memScheduler.io.fromMem.get.ldaFeedback := io.mem.ldaIqFeedback
340  memScheduler.io.fromMem.get.staFeedback := io.mem.staIqFeedback
341
342  vfScheduler.io.fromTop.hartId := io.fromTop.hartId
343  vfScheduler.io.fromCtrlBlock.flush := ctrlBlock.io.toIssueBlock.flush
344  vfScheduler.io.fromDispatch.allocPregs <> ctrlBlock.io.toIssueBlock.allocPregs
345  vfScheduler.io.fromDispatch.uops <> ctrlBlock.io.toIssueBlock.vfUops
346  vfScheduler.io.intWriteBack := 0.U.asTypeOf(vfScheduler.io.intWriteBack)
347  vfScheduler.io.vfWriteBack := wbDataPath.io.toVfPreg
348  vfScheduler.io.fromDataPath := dataPath.io.toVfIQ
349
350  dataPath.io.flush := ctrlBlock.io.toDataPath.flush
351  dataPath.io.vconfigReadPort.addr := ctrlBlock.io.toDataPath.vtypeAddr
352
353  for (i <- 0 until dataPath.io.fromIntIQ.length) {
354    for (j <- 0 until dataPath.io.fromIntIQ(i).length) {
355      NewPipelineConnect(intScheduler.io.toDataPath(i)(j), dataPath.io.fromIntIQ(i)(j), dataPath.io.fromIntIQ(i)(j).valid,
356        intScheduler.io.toDataPath(i)(j).bits.common.robIdx.needFlush(ctrlBlock.io.toDataPath.flush), Option("intScheduler2DataPathPipe"))
357    }
358  }
359
360  for (i <- 0 until dataPath.io.fromVfIQ.length) {
361    for (j <- 0 until dataPath.io.fromVfIQ(i).length) {
362      NewPipelineConnect(vfScheduler.io.toDataPath(i)(j), dataPath.io.fromVfIQ(i)(j), dataPath.io.fromVfIQ(i)(j).valid,
363        vfScheduler.io.toDataPath(i)(j).bits.common.robIdx.needFlush(ctrlBlock.io.toDataPath.flush), Option("vfScheduler2DataPathPipe"))
364    }
365  }
366
367  for (i <- 0 until dataPath.io.fromMemIQ.length) {
368    for (j <- 0 until dataPath.io.fromMemIQ(i).length) {
369      NewPipelineConnect(memScheduler.io.toDataPath(i)(j), dataPath.io.fromMemIQ(i)(j), dataPath.io.fromMemIQ(i)(j).valid,
370        memScheduler.io.toDataPath(i)(j).bits.common.robIdx.needFlush(ctrlBlock.io.toDataPath.flush), Option("memScheduler2DataPathPipe"))
371    }
372  }
373
374  println(s"[Backend] wbDataPath.io.toIntPreg: ${wbDataPath.io.toIntPreg.size}, dataPath.io.fromIntWb: ${dataPath.io.fromIntWb.size}")
375  println(s"[Backend] wbDataPath.io.toVfPreg: ${wbDataPath.io.toVfPreg.size}, dataPath.io.fromFpWb: ${dataPath.io.fromVfWb.size}")
376  dataPath.io.fromIntWb := wbDataPath.io.toIntPreg
377  dataPath.io.fromVfWb := wbDataPath.io.toVfPreg
378  dataPath.io.debugIntRat := ctrlBlock.io.debug_int_rat
379  dataPath.io.debugFpRat := ctrlBlock.io.debug_fp_rat
380  dataPath.io.debugVecRat := ctrlBlock.io.debug_vec_rat
381  dataPath.io.debugVconfigRat := ctrlBlock.io.debug_vconfig_rat
382
383  intExuBlock.io.flush := ctrlBlock.io.toExuBlock.flush
384  for (i <- 0 until intExuBlock.io.in.length) {
385    for (j <- 0 until intExuBlock.io.in(i).length) {
386      NewPipelineConnect(dataPath.io.toIntExu(i)(j), intExuBlock.io.in(i)(j), intExuBlock.io.in(i)(j).fire,
387        Mux(dataPath.io.toIntExu(i)(j).fire,
388          dataPath.io.toIntExu(i)(j).bits.robIdx.needFlush(ctrlBlock.io.toExuBlock.flush),
389          intExuBlock.io.in(i)(j).bits.robIdx.needFlush(ctrlBlock.io.toExuBlock.flush)))
390    }
391  }
392
393  private val csrio = intExuBlock.io.csrio.get
394  csrio.hartId := io.fromTop.hartId
395  csrio.perf.retiredInstr <> ctrlBlock.io.robio.csr.perfinfo.retiredInstr
396  csrio.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo
397  csrio.perf.perfEventsCtrl <> ctrlBlock.getPerf
398  csrio.fpu.fflags := ctrlBlock.io.robio.csr.fflags
399  csrio.fpu.isIllegal := false.B // Todo: remove it
400  csrio.fpu.dirty_fs := ctrlBlock.io.robio.csr.dirty_fs
401  csrio.vpu <> 0.U.asTypeOf(csrio.vpu) // Todo
402
403  val debugVconfig = dataPath.io.debugVconfig.asTypeOf(new VConfig)
404  val debugVtype = VType.toVtypeStruct(debugVconfig.vtype).asUInt
405  val debugVl = debugVconfig.vl
406  csrio.vpu.set_vxsat := ctrlBlock.io.robio.csr.vxsat
407  csrio.vpu.set_vstart.valid := ctrlBlock.io.robio.csr.vcsrFlag
408  csrio.vpu.set_vstart.bits := 0.U
409  csrio.vpu.set_vtype.valid := ctrlBlock.io.robio.csr.vcsrFlag
410  csrio.vpu.set_vtype.bits := ZeroExt(debugVtype, XLEN)
411  csrio.vpu.set_vl.valid := ctrlBlock.io.robio.csr.vcsrFlag
412  csrio.vpu.set_vl.bits := ZeroExt(debugVl, XLEN)
413  csrio.exception := ctrlBlock.io.robio.exception
414  csrio.memExceptionVAddr := io.mem.exceptionVAddr
415  csrio.externalInterrupt := io.fromTop.externalInterrupt
416  csrio.distributedUpdate(0) := io.mem.csrDistributedUpdate
417  csrio.distributedUpdate(1) := io.frontendCsrDistributedUpdate
418  csrio.perf <> io.perf
419  private val fenceio = intExuBlock.io.fenceio.get
420  fenceio.disableSfence := csrio.disableSfence
421  io.fenceio <> fenceio
422
423  vfExuBlock.io.flush := ctrlBlock.io.toExuBlock.flush
424  for (i <- 0 until vfExuBlock.io.in.size) {
425    for (j <- 0 until vfExuBlock.io.in(i).size) {
426      NewPipelineConnect(dataPath.io.toFpExu(i)(j), vfExuBlock.io.in(i)(j), vfExuBlock.io.in(i)(j).fire,
427        Mux(dataPath.io.toFpExu(i)(j).fire,
428          dataPath.io.toFpExu(i)(j).bits.robIdx.needFlush(ctrlBlock.io.toExuBlock.flush),
429          vfExuBlock.io.in(i)(j).bits.robIdx.needFlush(ctrlBlock.io.toExuBlock.flush)))
430    }
431  }
432  vfExuBlock.io.frm.foreach(_ := csrio.fpu.frm)
433
434  wbDataPath.io.flush := ctrlBlock.io.redirect
435  wbDataPath.io.fromTop.hartId := io.fromTop.hartId
436  wbDataPath.io.fromIntExu <> intExuBlock.io.out
437  wbDataPath.io.fromVfExu <> vfExuBlock.io.out
438  wbDataPath.io.fromMemExu.flatten.zip(io.mem.writeBack).foreach { case (sink, source) =>
439    sink.valid := source.valid
440    source.ready := sink.ready
441    sink.bits.data   := source.bits.data
442    sink.bits.pdest  := source.bits.uop.pdest
443    sink.bits.robIdx := source.bits.uop.robIdx
444    sink.bits.intWen.foreach(_ := source.bits.uop.rfWen)
445    sink.bits.fpWen.foreach(_ := source.bits.uop.fpWen)
446    sink.bits.vecWen.foreach(_ := source.bits.uop.vecWen)
447    sink.bits.exceptionVec.foreach(_ := source.bits.uop.exceptionVec)
448    sink.bits.flushPipe.foreach(_ := source.bits.uop.flushPipe)
449    sink.bits.replay.foreach(_ := source.bits.uop.replayInst)
450    sink.bits.debug := source.bits.debug
451    sink.bits.debugInfo := 0.U.asTypeOf(sink.bits.debugInfo)
452    sink.bits.lqIdx.foreach(_ := source.bits.uop.lqIdx)
453    sink.bits.sqIdx.foreach(_ := source.bits.uop.sqIdx)
454    sink.bits.ftqIdx.foreach(_ := source.bits.uop.ftqPtr)
455    sink.bits.ftqOffset.foreach(_ := source.bits.uop.ftqOffset)
456  }
457
458  // to mem
459  io.mem.redirect := ctrlBlock.io.redirect
460  io.mem.issueUops.zip(dataPath.io.toMemExu.flatten).foreach { case (sink, source) =>
461    sink.valid := source.valid
462    source.ready := sink.ready
463    sink.bits.iqIdx         := source.bits.iqIdx
464    sink.bits.isFirstIssue  := source.bits.isFirstIssue
465    sink.bits.uop           := 0.U.asTypeOf(sink.bits.uop)
466    sink.bits.src           := 0.U.asTypeOf(sink.bits.src)
467    sink.bits.src.zip(source.bits.src).foreach { case (l, r) => l := r}
468    sink.bits.uop.fuType    := source.bits.fuType
469    sink.bits.uop.fuOpType  := source.bits.fuOpType
470    sink.bits.uop.imm       := source.bits.imm
471    sink.bits.uop.robIdx    := source.bits.robIdx
472    sink.bits.uop.pdest     := source.bits.pdest
473    sink.bits.uop.rfWen     := source.bits.rfWen.getOrElse(false.B)
474    sink.bits.uop.fpWen     := source.bits.fpWen.getOrElse(false.B)
475    sink.bits.uop.vecWen    := source.bits.vecWen.getOrElse(false.B)
476    sink.bits.uop.flushPipe := source.bits.flushPipe.getOrElse(false.B)
477    sink.bits.uop.pc        := source.bits.pc.getOrElse(0.U)
478    sink.bits.uop.lqIdx     := source.bits.lqIdx.getOrElse(0.U.asTypeOf(new LqPtr))
479    sink.bits.uop.sqIdx     := source.bits.sqIdx.getOrElse(0.U.asTypeOf(new SqPtr))
480    sink.bits.uop.ftqPtr    := source.bits.ftqIdx.getOrElse(0.U.asTypeOf(new FtqPtr))
481    sink.bits.uop.ftqOffset := source.bits.ftqOffset.getOrElse(0.U)
482  }
483  io.mem.loadFastMatch := memScheduler.io.toMem.get.loadFastMatch.map(_.fastMatch)
484  io.mem.loadFastImm := memScheduler.io.toMem.get.loadFastMatch.map(_.fastImm)
485  io.mem.tlbCsr := csrio.tlb
486  io.mem.csrCtrl := csrio.customCtrl
487  io.mem.sfence := fenceio.sfence
488  io.mem.isStoreException := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.commitType)
489  require(io.mem.loadPcRead.size == params.LduCnt)
490  io.mem.loadPcRead.zipWithIndex.foreach { case (loadPcRead, i) =>
491    loadPcRead.data := ctrlBlock.io.memLdPcRead(i).data
492    ctrlBlock.io.memLdPcRead(i).ptr := loadPcRead.ptr
493    ctrlBlock.io.memLdPcRead(i).offset := loadPcRead.offset
494  }
495  // mem io
496  io.mem.lsqEnqIO <> memScheduler.io.memIO.get.lsqEnqIO
497  io.mem.robLsqIO <> ctrlBlock.io.robio.lsq
498  io.mem.toSbuffer <> fenceio.sbuffer
499
500  io.frontendSfence := fenceio.sfence
501  io.frontendTlbCsr := csrio.tlb
502  io.frontendCsrCtrl := csrio.customCtrl
503
504  io.tlb <> csrio.tlb
505
506  io.csrCustomCtrl := csrio.customCtrl
507
508  dontTouch(memScheduler.io)
509  dontTouch(io.mem)
510  dontTouch(dataPath.io.toMemExu)
511  dontTouch(wbDataPath.io.fromMemExu)
512}
513
514class BackendMemIO(implicit p: Parameters, params: BackendParams) extends XSBundle {
515  // params alias
516  private val LoadQueueSize = VirtualLoadQueueSize
517  // In/Out // Todo: split it into one-direction bundle
518  val lsqEnqIO = Flipped(new LsqEnqIO)
519  val robLsqIO = new RobLsqIO
520  val toSbuffer = new FenceToSbuffer
521  val ldaIqFeedback = Vec(params.LduCnt, Flipped(new MemRSFeedbackIO))
522  val staIqFeedback = Vec(params.StaCnt, Flipped(new MemRSFeedbackIO))
523  val loadPcRead = Vec(params.LduCnt, Flipped(new FtqRead(UInt(VAddrBits.W))))
524
525  // Input
526  val writeBack = MixedVec(Seq.fill(params.LduCnt + params.StaCnt * 2)(Flipped(DecoupledIO(new MemExuOutput()))) ++ Seq.fill(params.VlduCnt)(Flipped(DecoupledIO(new MemExuOutput(true)))))
527
528  val s3_delayed_load_error = Input(Vec(LoadPipelineWidth, Bool()))
529  val stIn = Input(Vec(params.StaCnt, ValidIO(new DynInst())))
530  val memoryViolation = Flipped(ValidIO(new Redirect))
531  val exceptionVAddr = Input(UInt(VAddrBits.W))
532  val sqDeq = Input(UInt(log2Ceil(EnsbufferWidth + 1).W))
533  val lqDeq = Input(UInt(log2Up(CommitWidth + 1).W))
534
535  val lqCancelCnt = Input(UInt(log2Up(VirtualLoadQueueSize + 1).W))
536  val sqCancelCnt = Input(UInt(log2Up(StoreQueueSize + 1).W))
537
538  val otherFastWakeup = Flipped(Vec(params.LduCnt + 2 * params.StaCnt, ValidIO(new DynInst)))
539  val stIssuePtr = Input(new SqPtr())
540
541  val csrDistributedUpdate = Flipped(new DistributedCSRUpdateReq)
542
543  // Output
544  val redirect = ValidIO(new Redirect)   // rob flush MemBlock
545  val issueUops = MixedVec(Seq.fill(params.LduCnt + params.StaCnt * 2)(DecoupledIO(new MemExuInput())) ++ Seq.fill(params.VlduCnt)(DecoupledIO(new MemExuInput(true))))
546  val loadFastMatch = Vec(params.LduCnt, Output(UInt(params.LduCnt.W)))
547  val loadFastImm   = Vec(params.LduCnt, Output(UInt(12.W))) // Imm_I
548
549  val tlbCsr = Output(new TlbCsrBundle)
550  val csrCtrl = Output(new CustomCSRCtrlIO)
551  val sfence = Output(new SfenceBundle)
552  val isStoreException = Output(Bool())
553}
554
555class BackendIO(implicit p: Parameters, params: BackendParams) extends XSBundle {
556  val fromTop = new Bundle {
557    val hartId = Input(UInt(8.W))
558    val externalInterrupt = new ExternalInterruptIO
559  }
560
561  val toTop = new Bundle {
562    val cpuHalted = Output(Bool())
563  }
564
565  val fenceio = new FenceIO
566  // Todo: merge these bundles into BackendFrontendIO
567  val frontend = Flipped(new FrontendToCtrlIO)
568  val frontendSfence = Output(new SfenceBundle)
569  val frontendCsrCtrl = Output(new CustomCSRCtrlIO)
570  val frontendTlbCsr = Output(new TlbCsrBundle)
571  // distributed csr write
572  val frontendCsrDistributedUpdate = Flipped(new DistributedCSRUpdateReq)
573
574  val mem = new BackendMemIO
575
576  val perf = Input(new PerfCounterIO)
577
578  val tlb = Output(new TlbCsrBundle)
579
580  val csrCustomCtrl = Output(new CustomCSRCtrlIO)
581}
582