xref: /XiangShan/src/main/scala/xiangshan/backend/issue/Scheduler.scala (revision ea0f92d8a18e593ddd63d932eaff3d3099c091c0)
1730cfbc0SXuan Hupackage xiangshan.backend.issue
2730cfbc0SXuan Hu
3730cfbc0SXuan Huimport chipsalliance.rocketchip.config.Parameters
4730cfbc0SXuan Huimport chisel3._
5730cfbc0SXuan Huimport chisel3.util._
6730cfbc0SXuan Huimport freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
7730cfbc0SXuan Huimport xiangshan._
8730cfbc0SXuan Huimport xiangshan.backend.Bundles
9730cfbc0SXuan Huimport xiangshan.backend.datapath.DataConfig.VAddrData
10730cfbc0SXuan Huimport xiangshan.backend.regfile.RfWritePortWithConfig
11730cfbc0SXuan Huimport xiangshan.backend.rename.BusyTable
12730cfbc0SXuan Huimport xiangshan.mem.{LsqEnqCtrl, LsqEnqIO, MemWaitUpdateReq, SqPtr}
13730cfbc0SXuan Huimport xiangshan.backend.Bundles.{DynInst, IssueQueueWakeUpBundle}
14730cfbc0SXuan Hu
15730cfbc0SXuan Husealed trait SchedulerType
16730cfbc0SXuan Hu
17730cfbc0SXuan Hucase class IntScheduler() extends SchedulerType
18730cfbc0SXuan Hucase class MemScheduler() extends SchedulerType
19730cfbc0SXuan Hucase class VfScheduler() extends SchedulerType
20730cfbc0SXuan Hucase class NoScheduler() extends SchedulerType
21730cfbc0SXuan Hu
22730cfbc0SXuan Huclass Scheduler(val params: SchdBlockParams)(implicit p: Parameters) extends LazyModule with HasXSParameter {
23730cfbc0SXuan Hu  val numIntStateWrite = backendParams.numIntWb
24730cfbc0SXuan Hu  val numVfStateWrite = backendParams.numVfWb
25730cfbc0SXuan Hu
26730cfbc0SXuan Hu  val dispatch2Iq = LazyModule(new Dispatch2Iq(params))
27730cfbc0SXuan Hu  val issueQueue = params.issueBlockParams.map(x => LazyModule(new IssueQueue(x).suggestName(x.getIQName)))
28730cfbc0SXuan Hu
29730cfbc0SXuan Hu  lazy val module = params.schdType match {
30730cfbc0SXuan Hu    case IntScheduler() => new SchedulerArithImp(this)(params, p)
31730cfbc0SXuan Hu    case MemScheduler() => new SchedulerMemImp(this)(params, p)
32730cfbc0SXuan Hu    case VfScheduler() => new SchedulerArithImp(this)(params, p)
33730cfbc0SXuan Hu    case _ => null
34730cfbc0SXuan Hu  }
35730cfbc0SXuan Hu}
36730cfbc0SXuan Hu
37730cfbc0SXuan Huclass SchedulerIO()(implicit params: SchdBlockParams, p: Parameters) extends XSBundle {
38730cfbc0SXuan Hu  val fromTop = new Bundle {
39730cfbc0SXuan Hu    val hartId = Input(UInt(8.W))
40730cfbc0SXuan Hu  }
41730cfbc0SXuan Hu  val fromCtrlBlock = new Bundle {
42730cfbc0SXuan Hu    val pcVec = Input(Vec(params.numPcReadPort, UInt(VAddrData().dataWidth.W)))
43730cfbc0SXuan Hu    val targetVec = Input(Vec(params.numPcReadPort, UInt(VAddrData().dataWidth.W)))
44730cfbc0SXuan Hu    val flush = Flipped(ValidIO(new Redirect))
45730cfbc0SXuan Hu  }
46730cfbc0SXuan Hu  val fromDispatch = new Bundle {
47730cfbc0SXuan Hu    val allocPregs = Vec(RenameWidth, Input(new ResetPregStateReq))
48730cfbc0SXuan Hu    val uops =  Vec(params.numUopIn, Flipped(DecoupledIO(new DynInst)))
49730cfbc0SXuan Hu  }
50730cfbc0SXuan Hu  val intWriteBack = MixedVec(Vec(backendParams.intPregParams.numWrite,
51730cfbc0SXuan Hu    new RfWritePortWithConfig(backendParams.intPregParams.dataCfg, backendParams.intPregParams.addrWidth)))
52730cfbc0SXuan Hu  val vfWriteBack = MixedVec(Vec(backendParams.vfPregParams.numWrite,
53730cfbc0SXuan Hu    new RfWritePortWithConfig(backendParams.vfPregParams.dataCfg, backendParams.vfPregParams.addrWidth)))
54730cfbc0SXuan Hu  val toDataPath: MixedVec[MixedVec[DecoupledIO[Bundles.IssueQueueIssueBundle]]] = MixedVec(params.issueBlockParams.map(_.genIssueDecoupledBundle))
55730cfbc0SXuan Hu  val fromDataPath: MixedVec[MixedVec[Bundles.OGRespBundle]] = MixedVec(params.issueBlockParams.map(x => Flipped(x.genOGRespBundle)))
56730cfbc0SXuan Hu
57730cfbc0SXuan Hu  val memIO = if (params.isMemSchd) Some(new Bundle {
58730cfbc0SXuan Hu    val feedbackIO = Flipped(Vec(params.StaCnt, new MemRSFeedbackIO))
59730cfbc0SXuan Hu    val lsqEnqIO = Flipped(new LsqEnqIO)
60730cfbc0SXuan Hu  }) else None
61730cfbc0SXuan Hu  val fromMem = if (params.isMemSchd) Some(new Bundle {
62730cfbc0SXuan Hu    val stIssuePtr = Input(new SqPtr())
63730cfbc0SXuan Hu    val lcommit = Input(UInt(log2Up(CommitWidth + 1).W))
64730cfbc0SXuan Hu    val scommit = Input(UInt(log2Ceil(EnsbufferWidth + 1).W)) // connected to `memBlock.io.sqDeq` instead of ROB
65730cfbc0SXuan Hu    // from lsq
66730cfbc0SXuan Hu    val lqCancelCnt = Input(UInt(log2Up(LoadQueueSize + 1).W))
67730cfbc0SXuan Hu    val sqCancelCnt = Input(UInt(log2Up(StoreQueueSize + 1).W))
68730cfbc0SXuan Hu    val memWaitUpdateReq = Flipped(new MemWaitUpdateReq)
69730cfbc0SXuan Hu  }) else None
70730cfbc0SXuan Hu  val toMem = if (params.isMemSchd) Some(new Bundle {
71730cfbc0SXuan Hu    val loadFastMatch = Output(Vec(params.LduCnt, new IssueQueueLoadBundle))
72730cfbc0SXuan Hu  }) else None
73730cfbc0SXuan Hu}
74730cfbc0SXuan Hu
75730cfbc0SXuan Huabstract class SchedulerImpBase(wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
76730cfbc0SXuan Hu  extends LazyModuleImp(wrapper)
77730cfbc0SXuan Hu    with HasXSParameter
78730cfbc0SXuan Hu{
79730cfbc0SXuan Hu  val io = IO(new SchedulerIO())
80730cfbc0SXuan Hu
81730cfbc0SXuan Hu  // alias
82730cfbc0SXuan Hu  private val schdType = params.schdType
83730cfbc0SXuan Hu  private val (numRfRead, numRfWrite) = params.numRfReadWrite.getOrElse((0, 0))
84730cfbc0SXuan Hu  private val numPregs = params.numPregs
85730cfbc0SXuan Hu
86730cfbc0SXuan Hu  // Modules
87730cfbc0SXuan Hu  val dispatch2Iq: Dispatch2IqImp = wrapper.dispatch2Iq.module
88730cfbc0SXuan Hu  val issueQueues: Seq[IssueQueueImp] = wrapper.issueQueue.map(_.module)
89730cfbc0SXuan Hu
90730cfbc0SXuan Hu  // BusyTable Modules
91730cfbc0SXuan Hu  val intBusyTable = schdType match {
92730cfbc0SXuan Hu    case IntScheduler() | MemScheduler() => Some(Module(new BusyTable(dispatch2Iq.numIntStateRead, wrapper.numIntStateWrite)))
93730cfbc0SXuan Hu    case _ => None
94730cfbc0SXuan Hu  }
95730cfbc0SXuan Hu
96730cfbc0SXuan Hu  val vfBusyTable = schdType match {
97730cfbc0SXuan Hu    case VfScheduler() | MemScheduler() => Some(Module(new BusyTable(dispatch2Iq.numVfStateRead, wrapper.numVfStateWrite)))
98730cfbc0SXuan Hu    case _ => None
99730cfbc0SXuan Hu  }
100730cfbc0SXuan Hu
101730cfbc0SXuan Hu  dispatch2Iq.io match { case dp2iq =>
102730cfbc0SXuan Hu    dp2iq.redirect <> io.fromCtrlBlock.flush
103730cfbc0SXuan Hu    dp2iq.in <> io.fromDispatch.uops
104730cfbc0SXuan Hu    dp2iq.readIntState.foreach(_ <> intBusyTable.get.io.read)
105730cfbc0SXuan Hu    dp2iq.readVfState.foreach(_ <> vfBusyTable.get.io.read)
106730cfbc0SXuan Hu  }
107730cfbc0SXuan Hu
108730cfbc0SXuan Hu  intBusyTable match {
109730cfbc0SXuan Hu    case Some(bt) =>
110730cfbc0SXuan Hu      bt.io.allocPregs.zip(io.fromDispatch.allocPregs).foreach { case (btAllocPregs, dpAllocPregs) =>
111730cfbc0SXuan Hu        btAllocPregs.valid := dpAllocPregs.isInt
112730cfbc0SXuan Hu        btAllocPregs.bits := dpAllocPregs.preg
113730cfbc0SXuan Hu      }
114730cfbc0SXuan Hu      bt.io.wbPregs.zipWithIndex.foreach { case (wb, i) =>
115730cfbc0SXuan Hu        wb.valid := io.intWriteBack(i).wen && io.intWriteBack(i).intWen
116730cfbc0SXuan Hu        wb.bits := io.intWriteBack(i).addr
117730cfbc0SXuan Hu      }
118730cfbc0SXuan Hu    case None =>
119730cfbc0SXuan Hu  }
120730cfbc0SXuan Hu
121730cfbc0SXuan Hu  vfBusyTable match {
122730cfbc0SXuan Hu    case Some(bt) =>
123730cfbc0SXuan Hu      bt.io.allocPregs.zip(io.fromDispatch.allocPregs).foreach { case (btAllocPregs, dpAllocPregs) =>
124730cfbc0SXuan Hu        btAllocPregs.valid := dpAllocPregs.isFp
125730cfbc0SXuan Hu        btAllocPregs.bits := dpAllocPregs.preg
126730cfbc0SXuan Hu      }
127730cfbc0SXuan Hu      bt.io.wbPregs.zipWithIndex.foreach { case (wb, i) =>
128730cfbc0SXuan Hu        wb.valid := io.vfWriteBack(i).wen && (io.vfWriteBack(i).fpWen || io.vfWriteBack(i).vecWen)
129730cfbc0SXuan Hu        wb.bits := io.vfWriteBack(i).addr
130730cfbc0SXuan Hu      }
131730cfbc0SXuan Hu    case None =>
132730cfbc0SXuan Hu  }
133730cfbc0SXuan Hu
134730cfbc0SXuan Hu  val wakeupFromWBVec = Wire(Vec(params.numWakeupFromWB, ValidIO(new IssueQueueWakeUpBundle(params.pregIdxWidth))))
135730cfbc0SXuan Hu  val writeback = params.schdType match {
136730cfbc0SXuan Hu    case IntScheduler() => io.intWriteBack
137730cfbc0SXuan Hu    case MemScheduler() => io.intWriteBack ++ io.vfWriteBack
138730cfbc0SXuan Hu    case VfScheduler() => io.vfWriteBack
139730cfbc0SXuan Hu    case _ => Seq()
140730cfbc0SXuan Hu  }
141730cfbc0SXuan Hu  wakeupFromWBVec.zip(writeback).foreach { case (sink, source) =>
142730cfbc0SXuan Hu    sink.valid := source.wen
143730cfbc0SXuan Hu    sink.bits.rfWen := source.intWen
144730cfbc0SXuan Hu    sink.bits.fpWen := source.fpWen
145730cfbc0SXuan Hu    sink.bits.vecWen := source.vecWen
146730cfbc0SXuan Hu    sink.bits.pdest := source.addr
147730cfbc0SXuan Hu  }
148730cfbc0SXuan Hu
149730cfbc0SXuan Hu  io.toDataPath.zipWithIndex.foreach { case (toDp, i) =>
150730cfbc0SXuan Hu    toDp <> issueQueues(i).io.deq
151730cfbc0SXuan Hu  }
152730cfbc0SXuan Hu}
153730cfbc0SXuan Hu
154730cfbc0SXuan Huclass SchedulerArithImp(override val wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
155730cfbc0SXuan Hu  extends SchedulerImpBase(wrapper)
156730cfbc0SXuan Hu    with HasXSParameter
157730cfbc0SXuan Hu{
158730cfbc0SXuan Hu  println(s"[SchedulerArithImp] " +
159730cfbc0SXuan Hu    s"has intBusyTable: ${intBusyTable.nonEmpty}, " +
160730cfbc0SXuan Hu    s"has vfBusyTable: ${vfBusyTable.nonEmpty}")
161730cfbc0SXuan Hu
162730cfbc0SXuan Hu  issueQueues.zipWithIndex.foreach { case (iq, i) =>
163730cfbc0SXuan Hu    iq.io.flush <> io.fromCtrlBlock.flush
164730cfbc0SXuan Hu    iq.io.enq <> dispatch2Iq.io.out(i)
165730cfbc0SXuan Hu    iq.io.wakeup := wakeupFromWBVec
166730cfbc0SXuan Hu    iq.io.deqResp.zipWithIndex.foreach { case (deqResp, j) =>
167*ea0f92d8Sczw      deqResp.valid := iq.io.deq(j).valid && io.toDataPath(i)(j).ready
168730cfbc0SXuan Hu      deqResp.bits.success := false.B
169*ea0f92d8Sczw      deqResp.bits.respType := RSFeedbackType.issueSuccess
170730cfbc0SXuan Hu      deqResp.bits.addrOH := iq.io.deq(j).bits.addrOH
171730cfbc0SXuan Hu    }
172730cfbc0SXuan Hu    iq.io.og0Resp.zipWithIndex.foreach { case (og0Resp, j) =>
173730cfbc0SXuan Hu      og0Resp.valid := io.fromDataPath(i)(j).og0resp.valid
174730cfbc0SXuan Hu      og0Resp.bits.success := false.B // Todo: remove it
175730cfbc0SXuan Hu      og0Resp.bits.respType := io.fromDataPath(i)(j).og0resp.bits.respType
176730cfbc0SXuan Hu      og0Resp.bits.addrOH := io.fromDataPath(i)(j).og0resp.bits.addrOH
177730cfbc0SXuan Hu    }
178730cfbc0SXuan Hu    iq.io.og1Resp.zipWithIndex.foreach { case (og1Resp, j) =>
179730cfbc0SXuan Hu      og1Resp.valid := io.fromDataPath(i)(j).og1resp.valid
180730cfbc0SXuan Hu      og1Resp.bits.success := false.B
181730cfbc0SXuan Hu      og1Resp.bits.respType := io.fromDataPath(i)(j).og1resp.bits.respType
182730cfbc0SXuan Hu      og1Resp.bits.addrOH := io.fromDataPath(i)(j).og1resp.bits.addrOH
183730cfbc0SXuan Hu    }
184730cfbc0SXuan Hu  }
185730cfbc0SXuan Hu
186730cfbc0SXuan Hu  val iqJumpBundleVec: Seq[IssueQueueJumpBundle] = issueQueues.map {
187730cfbc0SXuan Hu    case imp: IssueQueueIntImp => imp.io.enqJmp
188730cfbc0SXuan Hu    case _ => None
189730cfbc0SXuan Hu  }.filter(_.nonEmpty).flatMap(_.get)
190730cfbc0SXuan Hu  println(s"[Scheduler] iqJumpBundleVec: ${iqJumpBundleVec}")
191730cfbc0SXuan Hu
192730cfbc0SXuan Hu  iqJumpBundleVec.zip(io.fromCtrlBlock.pcVec zip io.fromCtrlBlock.targetVec).foreach { case (iqJmp, (pc, target)) =>
193730cfbc0SXuan Hu    iqJmp.pc := pc
194730cfbc0SXuan Hu    iqJmp.target := target
195730cfbc0SXuan Hu  }
196730cfbc0SXuan Hu}
197730cfbc0SXuan Hu
198730cfbc0SXuan Huclass SchedulerMemImp(override val wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
199730cfbc0SXuan Hu  extends SchedulerImpBase(wrapper)
200730cfbc0SXuan Hu    with HasXSParameter
201730cfbc0SXuan Hu{
202730cfbc0SXuan Hu  println(s"[SchedulerMemImp] " +
203730cfbc0SXuan Hu    s"has intBusyTable: ${intBusyTable.nonEmpty}, " +
204730cfbc0SXuan Hu    s"has vfBusyTable: ${vfBusyTable.nonEmpty}")
205730cfbc0SXuan Hu
206730cfbc0SXuan Hu  val memAddrIQs = issueQueues.filter(iq => iq.params.StdCnt == 0)
207730cfbc0SXuan Hu  val stAddrIQs = issueQueues.filter(iq => iq.params.StaCnt > 0) // included in memAddrIQs
208730cfbc0SXuan Hu  val stDataIQs = issueQueues.filter(iq => iq.params.StdCnt > 0)
209730cfbc0SXuan Hu  require(memAddrIQs.nonEmpty && stDataIQs.nonEmpty)
210730cfbc0SXuan Hu
211730cfbc0SXuan Hu  issueQueues.zipWithIndex.foreach { case (iq, i) =>
212730cfbc0SXuan Hu    iq.io.deqResp.zipWithIndex.foreach { case (deqResp, j) =>
213*ea0f92d8Sczw      deqResp.valid := iq.io.deq(j).valid && io.toDataPath(i)(j).ready
214730cfbc0SXuan Hu      deqResp.bits.success := false.B
215*ea0f92d8Sczw      deqResp.bits.respType := RSFeedbackType.issueSuccess
216730cfbc0SXuan Hu      deqResp.bits.addrOH := iq.io.deq(j).bits.addrOH
217730cfbc0SXuan Hu    }
218730cfbc0SXuan Hu    iq.io.og0Resp.zipWithIndex.foreach { case (og0Resp, j) =>
219730cfbc0SXuan Hu      og0Resp.valid := io.fromDataPath(i)(j).og0resp.valid
220730cfbc0SXuan Hu      og0Resp.bits.success := false.B // Todo: remove it
221730cfbc0SXuan Hu      og0Resp.bits.respType := io.fromDataPath(i)(j).og0resp.bits.respType
222730cfbc0SXuan Hu      og0Resp.bits.addrOH := io.fromDataPath(i)(j).og0resp.bits.addrOH
223730cfbc0SXuan Hu    }
224730cfbc0SXuan Hu    iq.io.og1Resp.zipWithIndex.foreach { case (og1Resp, j) =>
225730cfbc0SXuan Hu      og1Resp.valid := io.fromDataPath(i)(j).og1resp.valid
226730cfbc0SXuan Hu      og1Resp.bits.success := false.B
227730cfbc0SXuan Hu      og1Resp.bits.respType := io.fromDataPath(i)(j).og1resp.bits.respType
228730cfbc0SXuan Hu      og1Resp.bits.addrOH := io.fromDataPath(i)(j).og1resp.bits.addrOH
229730cfbc0SXuan Hu    }
230730cfbc0SXuan Hu  }
231730cfbc0SXuan Hu
232730cfbc0SXuan Hu  memAddrIQs.zipWithIndex.foreach { case (iq, i) =>
233730cfbc0SXuan Hu    iq.io.flush <> io.fromCtrlBlock.flush
234730cfbc0SXuan Hu    iq.io.enq <> dispatch2Iq.io.out(i)
235730cfbc0SXuan Hu    iq.io.wakeup := wakeupFromWBVec
236730cfbc0SXuan Hu  }
237730cfbc0SXuan Hu
238730cfbc0SXuan Hu
239730cfbc0SXuan Hu  dispatch2Iq.io.out(1).zip(stAddrIQs(0).io.enq).zip(stDataIQs(0).io.enq).foreach{ case((di, staIQ), stdIQ) =>
240730cfbc0SXuan Hu    val isAllReady = staIQ.ready && stdIQ.ready
241730cfbc0SXuan Hu    di.ready := isAllReady
242730cfbc0SXuan Hu    staIQ.valid := di.valid && isAllReady
243730cfbc0SXuan Hu    stdIQ.valid := di.valid && isAllReady
244730cfbc0SXuan Hu  }
245730cfbc0SXuan Hu
246730cfbc0SXuan Hu  require(stAddrIQs.size == stDataIQs.size, s"number of store address IQs(${stAddrIQs.size}) " +
247730cfbc0SXuan Hu    s"should be equal to number of data IQs(${stDataIQs})")
248730cfbc0SXuan Hu  stDataIQs.zip(stAddrIQs).zipWithIndex.foreach { case ((stdIQ, staIQ), i) =>
249730cfbc0SXuan Hu    stdIQ.io.flush <> io.fromCtrlBlock.flush
250730cfbc0SXuan Hu
251730cfbc0SXuan Hu    stdIQ.io.enq.zip(staIQ.io.enq).foreach { case (stdIQEnq, staIQEnq) =>
252730cfbc0SXuan Hu      stdIQEnq.bits  := staIQEnq.bits
253730cfbc0SXuan Hu      // Store data reuses store addr src(1) in dispatch2iq
254730cfbc0SXuan Hu      // [dispatch2iq] --src*------src*(0)--> [staIQ]
255730cfbc0SXuan Hu      //                       \
256730cfbc0SXuan Hu      //                        ---src*(1)--> [stdIQ]
257730cfbc0SXuan Hu      // Since the src(1) of sta is easier to get, stdIQEnq.bits.src*(0) is assigned to staIQEnq.bits.src*(1)
258730cfbc0SXuan Hu      // instead of dispatch2Iq.io.out(x).bits.src*(1)
259730cfbc0SXuan Hu      stdIQEnq.bits.srcState(0) := staIQEnq.bits.srcState(1)
260730cfbc0SXuan Hu      stdIQEnq.bits.srcType(0) := staIQEnq.bits.srcType(1)
261730cfbc0SXuan Hu      stdIQEnq.bits.psrc(0) := staIQEnq.bits.psrc(1)
262730cfbc0SXuan Hu      stdIQEnq.bits.sqIdx := staIQEnq.bits.sqIdx
263730cfbc0SXuan Hu    }
264730cfbc0SXuan Hu    stdIQ.io.wakeup := wakeupFromWBVec
265730cfbc0SXuan Hu  }
266730cfbc0SXuan Hu
267730cfbc0SXuan Hu  val iqMemBundleVec = stAddrIQs.map {
268730cfbc0SXuan Hu    case imp: IssueQueueMemAddrImp => imp.io.memIO
269730cfbc0SXuan Hu    case _ => None
270730cfbc0SXuan Hu  }.filter(_.nonEmpty).map(_.get)
271730cfbc0SXuan Hu  println(s"[Scheduler] iqMemBundleVec: ${iqMemBundleVec}")
272730cfbc0SXuan Hu
273730cfbc0SXuan Hu  val lsqEnqCtrl = Module(new LsqEnqCtrl)
274730cfbc0SXuan Hu
275730cfbc0SXuan Hu  lsqEnqCtrl.io.redirect <> io.fromCtrlBlock.flush
276730cfbc0SXuan Hu  lsqEnqCtrl.io.enq <> dispatch2Iq.io.enqLsqIO.get
277730cfbc0SXuan Hu  lsqEnqCtrl.io.lcommit := io.fromMem.get.lcommit
278730cfbc0SXuan Hu  lsqEnqCtrl.io.scommit := io.fromMem.get.scommit
279730cfbc0SXuan Hu  lsqEnqCtrl.io.lqCancelCnt := io.fromMem.get.lqCancelCnt
280730cfbc0SXuan Hu  lsqEnqCtrl.io.sqCancelCnt := io.fromMem.get.sqCancelCnt
281730cfbc0SXuan Hu  io.memIO.get.lsqEnqIO <> lsqEnqCtrl.io.enqLsq
282730cfbc0SXuan Hu  require(io.memIO.get.feedbackIO.size == iqMemBundleVec.map(_.feedbackIO.size).sum,
283730cfbc0SXuan Hu    s"[SchedulerMemImp] io.memIO.feedbackIO.size(${io.memIO.get.feedbackIO.size}) " +
284730cfbc0SXuan Hu      s"should be equal to sum of memIQ.io.feedbackIO.size(${iqMemBundleVec.map(_.feedbackIO.size).sum})")
285730cfbc0SXuan Hu
286730cfbc0SXuan Hu  val memIQFeedbackIO: Seq[MemRSFeedbackIO] = iqMemBundleVec.flatMap(_.feedbackIO)
287730cfbc0SXuan Hu  io.memIO.get.feedbackIO <> memIQFeedbackIO
288730cfbc0SXuan Hu}
289