xref: /XiangShan/src/main/scala/xiangshan/backend/issue/Scheduler.scala (revision 87b463aac27f0159c82c43fb0707fff00609545c)
1package xiangshan.backend.issue
2
3import org.chipsalliance.cde.config.Parameters
4import chisel3._
5import chisel3.util._
6import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
7import utility.HasPerfEvents
8import utils.OptionWrapper
9import xiangshan._
10import xiangshan.backend.Bundles._
11import xiangshan.backend.datapath.DataConfig._
12import xiangshan.backend.datapath.WbConfig._
13import xiangshan.backend.fu.FuType
14import xiangshan.backend.regfile.RfWritePortWithConfig
15import xiangshan.backend.rename.BusyTable
16import xiangshan.mem.{LsqEnqCtrl, LsqEnqIO, MemWaitUpdateReq, SqPtr, LqPtr}
17import xiangshan.backend.datapath.WbConfig.V0WB
18import xiangshan.backend.regfile.VlPregParams
19import xiangshan.backend.regcache.RegCacheTagTable
20
21sealed trait SchedulerType
22
23case class IntScheduler() extends SchedulerType
24case class FpScheduler() extends SchedulerType
25case class MemScheduler() extends SchedulerType
26case class VfScheduler() extends SchedulerType
27case class NoScheduler() extends SchedulerType
28
29class Scheduler(val params: SchdBlockParams)(implicit p: Parameters) extends LazyModule with HasXSParameter {
30  override def shouldBeInlined: Boolean = false
31
32  val numIntStateWrite = backendParams.numPregWb(IntData())
33  val numFpStateWrite = backendParams.numPregWb(FpData())
34  val numVfStateWrite = backendParams.numPregWb(VecData())
35  val numV0StateWrite = backendParams.numPregWb(V0Data())
36  val numVlStateWrite = backendParams.numPregWb(VlData())
37
38  val dispatch2Iq = LazyModule(new Dispatch2Iq(params))
39  val issueQueue = params.issueBlockParams.map(x => LazyModule(new IssueQueue(x).suggestName(x.getIQName)))
40
41  lazy val module: SchedulerImpBase = params.schdType match {
42    case IntScheduler() => new SchedulerArithImp(this)(params, p)
43    case FpScheduler()  => new SchedulerArithImp(this)(params, p)
44    case MemScheduler() => new SchedulerMemImp(this)(params, p)
45    case VfScheduler() => new SchedulerArithImp(this)(params, p)
46    case _ => null
47  }
48}
49
50class SchedulerIO()(implicit params: SchdBlockParams, p: Parameters) extends XSBundle {
51  // params alias
52  private val LoadQueueSize = VirtualLoadQueueSize
53
54  val fromTop = new Bundle {
55    val hartId = Input(UInt(8.W))
56  }
57  val fromWbFuBusyTable = new Bundle{
58    val fuBusyTableRead = MixedVec(params.issueBlockParams.map(x => Input(x.genWbFuBusyTableReadBundle)))
59  }
60  val wbFuBusyTable = MixedVec(params.issueBlockParams.map(x => Output(x.genWbFuBusyTableWriteBundle)))
61  val intIQValidNumVec = Output(MixedVec(backendParams.genIntIQValidNumBundle))
62  val fpIQValidNumVec = Output(MixedVec(backendParams.genFpIQValidNumBundle))
63
64  val fromCtrlBlock = new Bundle {
65    val flush = Flipped(ValidIO(new Redirect))
66  }
67  val fromDispatch = new Bundle {
68    val allocPregs = Vec(RenameWidth, Input(new ResetPregStateReq))
69    val uops =  Vec(params.numUopIn, Flipped(DecoupledIO(new DynInst)))
70  }
71  val intWriteBack = MixedVec(Vec(backendParams.numPregWb(IntData()),
72    new RfWritePortWithConfig(backendParams.intPregParams.dataCfg, backendParams.intPregParams.addrWidth)))
73  val fpWriteBack = MixedVec(Vec(backendParams.numPregWb(FpData()),
74    new RfWritePortWithConfig(backendParams.fpPregParams.dataCfg, backendParams.fpPregParams.addrWidth)))
75  val vfWriteBack = MixedVec(Vec(backendParams.numPregWb(VecData()),
76    new RfWritePortWithConfig(backendParams.vfPregParams.dataCfg, backendParams.vfPregParams.addrWidth)))
77  val v0WriteBack = MixedVec(Vec(backendParams.numPregWb(V0Data()),
78    new RfWritePortWithConfig(backendParams.v0PregParams.dataCfg, backendParams.v0PregParams.addrWidth)))
79  val vlWriteBack = MixedVec(Vec(backendParams.numPregWb(VlData()),
80    new RfWritePortWithConfig(backendParams.vlPregParams.dataCfg, backendParams.vlPregParams.addrWidth)))
81  val toDataPathAfterDelay: MixedVec[MixedVec[DecoupledIO[IssueQueueIssueBundle]]] = MixedVec(params.issueBlockParams.map(_.genIssueDecoupledBundle))
82
83  val vlWriteBackInfo = new Bundle {
84    val vlIsZero = Input(Bool())
85    val vlIsVlmax = Input(Bool())
86  }
87
88  val fromSchedulers = new Bundle {
89    val wakeupVec: MixedVec[ValidIO[IssueQueueIQWakeUpBundle]] = Flipped(params.genIQWakeUpInValidBundle)
90  }
91
92  val toSchedulers = new Bundle {
93    val wakeupVec: MixedVec[ValidIO[IssueQueueIQWakeUpBundle]] = params.genIQWakeUpOutValidBundle
94  }
95
96  val fromDataPath = new Bundle {
97    val resp: MixedVec[MixedVec[OGRespBundle]] = MixedVec(params.issueBlockParams.map(x => Flipped(x.genOGRespBundle)))
98    val og0Cancel = Input(ExuVec())
99    // Todo: remove this after no cancel signal from og1
100    val og1Cancel = Input(ExuVec())
101    // replace RCIdx to Wakeup Queue
102    val replaceRCIdx = OptionWrapper(params.needWriteRegCache, Vec(params.numWriteRegCache, Input(UInt(RegCacheIdxWidth.W))))
103    // just be compatible to old code
104    def apply(i: Int)(j: Int) = resp(i)(j)
105  }
106
107  val loadFinalIssueResp = MixedVec(params.issueBlockParams.map(x => MixedVec(Vec(x.LdExuCnt, Flipped(ValidIO(new IssueQueueDeqRespBundle()(p, x)))))))
108  val memAddrIssueResp = MixedVec(params.issueBlockParams.map(x => MixedVec(Vec(x.LdExuCnt, Flipped(ValidIO(new IssueQueueDeqRespBundle()(p, x)))))))
109  val vecLoadIssueResp = MixedVec(params.issueBlockParams.map(x => MixedVec(Vec(x.VlduCnt, Flipped(ValidIO(new IssueQueueDeqRespBundle()(p, x)))))))
110
111  val ldCancel = Vec(backendParams.LduCnt + backendParams.HyuCnt, Flipped(new LoadCancelIO))
112
113  val memIO = if (params.isMemSchd) Some(new Bundle {
114    val lsqEnqIO = Flipped(new LsqEnqIO)
115  }) else None
116  val fromMem = if (params.isMemSchd) Some(new Bundle {
117    val ldaFeedback = Flipped(Vec(params.LduCnt, new MemRSFeedbackIO))
118    val staFeedback = Flipped(Vec(params.StaCnt, new MemRSFeedbackIO))
119    val hyuFeedback = Flipped(Vec(params.HyuCnt, new MemRSFeedbackIO))
120    val vstuFeedback = Flipped(Vec(params.VstuCnt, new MemRSFeedbackIO(isVector = true)))
121    val vlduFeedback = Flipped(Vec(params.VlduCnt, new MemRSFeedbackIO(isVector = true)))
122    val stIssuePtr = Input(new SqPtr())
123    val lcommit = Input(UInt(log2Up(CommitWidth + 1).W))
124    val scommit = Input(UInt(log2Ceil(EnsbufferWidth + 1).W)) // connected to `memBlock.io.sqDeq` instead of ROB
125    val wakeup = Vec(params.LdExuCnt, Flipped(Valid(new DynInst)))
126    val lqDeqPtr = Input(new LqPtr)
127    val sqDeqPtr = Input(new SqPtr)
128    // from lsq
129    val lqCancelCnt = Input(UInt(log2Up(LoadQueueSize + 1).W))
130    val sqCancelCnt = Input(UInt(log2Up(StoreQueueSize + 1).W))
131    val memWaitUpdateReq = Flipped(new MemWaitUpdateReq)
132  }) else None
133  val toMem = if (params.isMemSchd) Some(new Bundle {
134    val loadFastMatch = Output(Vec(params.LduCnt, new IssueQueueLoadBundle))
135  }) else None
136  val fromOg2Resp = if(params.needOg2Resp) Some(MixedVec(params.issueBlockParams.filter(_.needOg2Resp).map(x => Flipped(x.genOG2RespBundle)))) else None
137}
138
139abstract class SchedulerImpBase(wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
140  extends LazyModuleImp(wrapper)
141    with HasXSParameter
142{
143  val io = IO(new SchedulerIO())
144
145  // alias
146  private val iqWakeUpInMap: Map[Int, ValidIO[IssueQueueIQWakeUpBundle]] =
147    io.fromSchedulers.wakeupVec.map(x => (x.bits.exuIdx, x)).toMap
148  private val schdType = params.schdType
149
150  // Modules
151  val dispatch2Iq: Dispatch2IqImp = wrapper.dispatch2Iq.module
152  val issueQueues: Seq[IssueQueueImp] = wrapper.issueQueue.map(_.module)
153  io.intIQValidNumVec := 0.U.asTypeOf(io.intIQValidNumVec)
154  io.fpIQValidNumVec := 0.U.asTypeOf(io.fpIQValidNumVec)
155  if (params.isIntSchd) {
156    dispatch2Iq.io.intIQValidNumVec.get := io.intIQValidNumVec
157    io.intIQValidNumVec := MixedVecInit(issueQueues.map(_.io.validCntDeqVec))
158  }
159  else if (params.isFpSchd) {
160    dispatch2Iq.io.fpIQValidNumVec.get := io.fpIQValidNumVec
161    io.fpIQValidNumVec := MixedVecInit(issueQueues.map(_.io.validCntDeqVec))
162  }
163
164  // valid count
165  dispatch2Iq.io.iqValidCnt := issueQueues.filter(_.params.StdCnt == 0).map(_.io.status.validCnt)
166
167  // BusyTable Modules
168  val intBusyTable = schdType match {
169    case IntScheduler() | MemScheduler() => Some(Module(new BusyTable(dispatch2Iq.numIntStateRead, wrapper.numIntStateWrite, IntPhyRegs, IntWB())))
170    case _ => None
171  }
172  val fpBusyTable = schdType match {
173    case FpScheduler() | MemScheduler() => Some(Module(new BusyTable(dispatch2Iq.numFpStateRead, wrapper.numFpStateWrite, FpPhyRegs, FpWB())))
174    case _ => None
175  }
176  val vfBusyTable = schdType match {
177    case VfScheduler() | MemScheduler() => Some(Module(new BusyTable(dispatch2Iq.numVfStateRead, wrapper.numVfStateWrite, VfPhyRegs, VfWB())))
178    case _ => None
179  }
180  val v0BusyTable = schdType match {
181    case VfScheduler() | MemScheduler() => Some(Module(new BusyTable(dispatch2Iq.numV0StateRead, wrapper.numV0StateWrite, V0PhyRegs, V0WB())))
182    case _ => None
183  }
184  val vlBusyTable = schdType match {
185    case VfScheduler() | MemScheduler() => Some(Module(new BusyTable(dispatch2Iq.numVlStateRead, wrapper.numVlStateWrite, VlPhyRegs, VlWB())))
186    case _ => None
187  }
188
189  // RegCacheTagTable Module
190  val rcTagTable = schdType match {
191    case IntScheduler() | MemScheduler() => Some(Module(new RegCacheTagTable(dispatch2Iq.numRCTagTableStateRead)))
192    case _ => None
193  }
194
195  dispatch2Iq.io match { case dp2iq =>
196    dp2iq.redirect <> io.fromCtrlBlock.flush
197    dp2iq.in <> io.fromDispatch.uops
198    dp2iq.readIntState.foreach(_ <> intBusyTable.get.io.read)
199    dp2iq.readFpState.foreach(_ <> fpBusyTable.get.io.read)
200    dp2iq.readVfState.foreach(_ <> vfBusyTable.get.io.read)
201    dp2iq.readV0State.foreach(_ <> v0BusyTable.get.io.read)
202    dp2iq.readVlState.foreach(_ <> vlBusyTable.get.io.read)
203    dp2iq.readRCTagTableState.foreach(_ <> rcTagTable.get.io.readPorts)
204  }
205
206  intBusyTable match {
207    case Some(bt) =>
208      bt.io.allocPregs.zip(io.fromDispatch.allocPregs).foreach { case (btAllocPregs, dpAllocPregs) =>
209        btAllocPregs.valid := dpAllocPregs.isInt
210        btAllocPregs.bits := dpAllocPregs.preg
211      }
212      bt.io.wbPregs.zipWithIndex.foreach { case (wb, i) =>
213        wb.valid := io.intWriteBack(i).wen && io.intWriteBack(i).intWen
214        wb.bits := io.intWriteBack(i).addr
215      }
216      bt.io.wakeUp := io.fromSchedulers.wakeupVec
217      bt.io.og0Cancel := io.fromDataPath.og0Cancel
218      bt.io.ldCancel := io.ldCancel
219    case None =>
220  }
221
222  fpBusyTable match {
223    case Some(bt) =>
224      bt.io.allocPregs.zip(io.fromDispatch.allocPregs).foreach { case (btAllocPregs, dpAllocPregs) =>
225        btAllocPregs.valid := dpAllocPregs.isFp
226        btAllocPregs.bits := dpAllocPregs.preg
227      }
228      bt.io.wbPregs.zipWithIndex.foreach { case (wb, i) =>
229        wb.valid := io.fpWriteBack(i).wen && io.fpWriteBack(i).fpWen
230        wb.bits := io.fpWriteBack(i).addr
231      }
232      bt.io.wakeUp := io.fromSchedulers.wakeupVec
233      bt.io.og0Cancel := io.fromDataPath.og0Cancel
234      bt.io.ldCancel := io.ldCancel
235    case None =>
236  }
237
238  vfBusyTable match {
239    case Some(bt) =>
240      bt.io.allocPregs.zip(io.fromDispatch.allocPregs).foreach { case (btAllocPregs, dpAllocPregs) =>
241        btAllocPregs.valid := dpAllocPregs.isVec
242        btAllocPregs.bits := dpAllocPregs.preg
243      }
244      bt.io.wbPregs.zipWithIndex.foreach { case (wb, i) =>
245        wb.valid := io.vfWriteBack(i).wen && io.vfWriteBack(i).vecWen
246        wb.bits := io.vfWriteBack(i).addr
247      }
248      bt.io.wakeUp := io.fromSchedulers.wakeupVec
249      bt.io.og0Cancel := io.fromDataPath.og0Cancel
250      bt.io.ldCancel := io.ldCancel
251    case None =>
252  }
253
254  v0BusyTable match {
255    case Some(bt) =>
256      bt.io.allocPregs.zip(io.fromDispatch.allocPregs).foreach { case (btAllocPregs, dpAllocPregs) =>
257        btAllocPregs.valid := dpAllocPregs.isV0
258        btAllocPregs.bits := dpAllocPregs.preg
259      }
260      bt.io.wbPregs.zipWithIndex.foreach { case (wb, i) =>
261        wb.valid := io.v0WriteBack(i).wen && io.v0WriteBack(i).v0Wen
262        wb.bits := io.v0WriteBack(i).addr
263      }
264      bt.io.wakeUp := io.fromSchedulers.wakeupVec
265      bt.io.og0Cancel := io.fromDataPath.og0Cancel
266      bt.io.ldCancel := io.ldCancel
267    case None =>
268  }
269
270  vlBusyTable match {
271    case Some(bt) =>
272      bt.io.allocPregs.zip(io.fromDispatch.allocPregs).foreach { case (btAllocPregs, dpAllocPregs) =>
273        btAllocPregs.valid := dpAllocPregs.isVl
274        btAllocPregs.bits := dpAllocPregs.preg
275      }
276      bt.io.wbPregs.zipWithIndex.foreach { case (wb, i) =>
277        wb.valid := io.vlWriteBack(i).wen && io.vlWriteBack(i).vlWen
278        wb.bits := io.vlWriteBack(i).addr
279      }
280      bt.io.wakeUp := io.fromSchedulers.wakeupVec
281      bt.io.og0Cancel := io.fromDataPath.og0Cancel
282      bt.io.ldCancel := io.ldCancel
283    case None =>
284  }
285
286  rcTagTable match {
287    case Some(rct) =>
288      rct.io.allocPregs.zip(io.fromDispatch.allocPregs).foreach { case (btAllocPregs, dpAllocPregs) =>
289        btAllocPregs.valid := dpAllocPregs.isInt
290        btAllocPregs.bits := dpAllocPregs.preg
291      }
292      rct.io.wakeupFromIQ := io.fromSchedulers.wakeupVec
293      rct.io.og0Cancel := io.fromDataPath.og0Cancel
294      rct.io.ldCancel := io.ldCancel
295    case None =>
296  }
297
298  val wakeupFromIntWBVec = Wire(params.genIntWBWakeUpSinkValidBundle)
299  val wakeupFromFpWBVec = Wire(params.genFpWBWakeUpSinkValidBundle)
300  val wakeupFromVfWBVec = Wire(params.genVfWBWakeUpSinkValidBundle)
301  val wakeupFromV0WBVec = Wire(params.genV0WBWakeUpSinkValidBundle)
302  val wakeupFromVlWBVec = Wire(params.genVlWBWakeUpSinkValidBundle)
303
304  wakeupFromIntWBVec.zip(io.intWriteBack).foreach { case (sink, source) =>
305    sink.valid := source.wen
306    sink.bits.rfWen := source.intWen
307    sink.bits.fpWen := source.fpWen
308    sink.bits.vecWen := source.vecWen
309    sink.bits.v0Wen := source.v0Wen
310    sink.bits.vlWen := source.vlWen
311    sink.bits.pdest := source.addr
312  }
313
314  wakeupFromFpWBVec.zip(io.fpWriteBack).foreach { case (sink, source) =>
315    sink.valid := source.wen
316    sink.bits.rfWen := source.intWen
317    sink.bits.fpWen := source.fpWen
318    sink.bits.vecWen := source.vecWen
319    sink.bits.v0Wen := source.v0Wen
320    sink.bits.vlWen := source.vlWen
321    sink.bits.pdest := source.addr
322  }
323
324  wakeupFromVfWBVec.zip(io.vfWriteBack).foreach { case (sink, source) =>
325    sink.valid := source.wen
326    sink.bits.rfWen := source.intWen
327    sink.bits.fpWen := source.fpWen
328    sink.bits.vecWen := source.vecWen
329    sink.bits.v0Wen := source.v0Wen
330    sink.bits.vlWen := source.vlWen
331    sink.bits.pdest := source.addr
332  }
333
334  wakeupFromV0WBVec.zip(io.v0WriteBack).foreach { case (sink, source) =>
335    sink.valid := source.wen
336    sink.bits.rfWen := source.intWen
337    sink.bits.fpWen := source.fpWen
338    sink.bits.vecWen := source.vecWen
339    sink.bits.v0Wen := source.v0Wen
340    sink.bits.vlWen := source.vlWen
341    sink.bits.pdest := source.addr
342  }
343
344  wakeupFromVlWBVec.zip(io.vlWriteBack).foreach { case (sink, source) =>
345    sink.valid := source.wen
346    sink.bits.rfWen := source.intWen
347    sink.bits.fpWen := source.fpWen
348    sink.bits.vecWen := source.vecWen
349    sink.bits.v0Wen := source.v0Wen
350    sink.bits.vlWen := source.vlWen
351    sink.bits.pdest := source.addr
352  }
353
354  // Connect bundles having the same wakeup source
355  issueQueues.zipWithIndex.foreach { case(iq, i) =>
356    iq.io.wakeupFromIQ.foreach { wakeUp =>
357      val wakeUpIn = iqWakeUpInMap(wakeUp.bits.exuIdx)
358      val exuIdx = wakeUp.bits.exuIdx
359      println(s"[Backend] Connect wakeup exuIdx ${exuIdx}")
360      connectSamePort(wakeUp,wakeUpIn)
361      backendParams.connectWakeup(exuIdx)
362      if (backendParams.isCopyPdest(exuIdx)) {
363        println(s"[Backend] exuIdx ${exuIdx} use pdestCopy ${backendParams.getCopyPdestIndex(exuIdx)}")
364        wakeUp.bits.pdest := wakeUpIn.bits.pdestCopy.get(backendParams.getCopyPdestIndex(exuIdx))
365        if (wakeUpIn.bits.rfWenCopy.nonEmpty) wakeUp.bits.rfWen := wakeUpIn.bits.rfWenCopy.get(backendParams.getCopyPdestIndex(exuIdx))
366        if (wakeUpIn.bits.fpWenCopy.nonEmpty) wakeUp.bits.fpWen := wakeUpIn.bits.fpWenCopy.get(backendParams.getCopyPdestIndex(exuIdx))
367        if (wakeUpIn.bits.vecWenCopy.nonEmpty) wakeUp.bits.vecWen := wakeUpIn.bits.vecWenCopy.get(backendParams.getCopyPdestIndex(exuIdx))
368        if (wakeUpIn.bits.v0WenCopy.nonEmpty) wakeUp.bits.v0Wen := wakeUpIn.bits.v0WenCopy.get(backendParams.getCopyPdestIndex(exuIdx))
369        if (wakeUpIn.bits.vlWenCopy.nonEmpty) wakeUp.bits.vlWen := wakeUpIn.bits.vlWenCopy.get(backendParams.getCopyPdestIndex(exuIdx))
370        if (wakeUpIn.bits.loadDependencyCopy.nonEmpty) wakeUp.bits.loadDependency := wakeUpIn.bits.loadDependencyCopy.get(backendParams.getCopyPdestIndex(exuIdx))
371      }
372      if (iq.params.numIntSrc == 0) wakeUp.bits.rfWen := false.B
373      if (iq.params.numFpSrc == 0)  wakeUp.bits.fpWen := false.B
374      if (iq.params.numVfSrc == 0)  wakeUp.bits.vecWen := false.B
375      if (iq.params.numV0Src == 0)  wakeUp.bits.v0Wen := false.B
376      if (iq.params.numVlSrc == 0)  wakeUp.bits.vlWen := false.B
377    }
378    iq.io.og0Cancel := io.fromDataPath.og0Cancel
379    iq.io.og1Cancel := io.fromDataPath.og1Cancel
380    if (iq.params.needLoadDependency)
381      iq.io.ldCancel := io.ldCancel
382    else
383      iq.io.ldCancel := 0.U.asTypeOf(io.ldCancel)
384  }
385
386  // connect the vl writeback informatino to the issue queues
387  issueQueues.zipWithIndex.foreach { case(iq, i) =>
388    iq.io.vlIsVlmax := io.vlWriteBackInfo.vlIsVlmax
389    iq.io.vlIsZero := io.vlWriteBackInfo.vlIsZero
390  }
391
392  private val iqWakeUpOutMap: Map[Int, ValidIO[IssueQueueIQWakeUpBundle]] =
393    issueQueues.flatMap(_.io.wakeupToIQ)
394      .map(x => (x.bits.exuIdx, x))
395      .toMap
396
397  // Connect bundles having the same wakeup source
398  io.toSchedulers.wakeupVec.foreach { wakeUp =>
399    wakeUp := iqWakeUpOutMap(wakeUp.bits.exuIdx)
400  }
401
402  io.toDataPathAfterDelay.zipWithIndex.foreach { case (toDpDy, i) =>
403    toDpDy <> issueQueues(i).io.deqDelay
404  }
405
406  // Response
407  issueQueues.zipWithIndex.foreach { case (iq, i) =>
408    iq.io.og0Resp.zipWithIndex.foreach { case (og0Resp, j) =>
409      og0Resp := io.fromDataPath(i)(j).og0resp
410    }
411    iq.io.og1Resp.zipWithIndex.foreach { case (og1Resp, j) =>
412      og1Resp := io.fromDataPath(i)(j).og1resp
413    }
414    iq.io.finalIssueResp.foreach(_.zipWithIndex.foreach { case (finalIssueResp, j) =>
415      if (io.loadFinalIssueResp(i).isDefinedAt(j)) {
416        finalIssueResp := io.loadFinalIssueResp(i)(j)
417      } else {
418        finalIssueResp := 0.U.asTypeOf(finalIssueResp)
419      }
420    })
421    iq.io.memAddrIssueResp.foreach(_.zipWithIndex.foreach { case (memAddrIssueResp, j) =>
422      if (io.memAddrIssueResp(i).isDefinedAt(j)) {
423        memAddrIssueResp := io.memAddrIssueResp(i)(j)
424      } else {
425        memAddrIssueResp := 0.U.asTypeOf(memAddrIssueResp)
426      }
427    })
428    iq.io.vecLoadIssueResp.foreach(_.zipWithIndex.foreach { case (resp, deqIdx) =>
429      resp := io.vecLoadIssueResp(i)(deqIdx)
430    })
431    iq.io.wbBusyTableRead := io.fromWbFuBusyTable.fuBusyTableRead(i)
432    io.wbFuBusyTable(i) := iq.io.wbBusyTableWrite
433    iq.io.replaceRCIdx.foreach(x => x := 0.U.asTypeOf(x))
434  }
435  if (params.needOg2Resp) {
436    issueQueues.filter(_.params.needOg2Resp).zip(io.fromOg2Resp.get).foreach{ case (iq, og2RespVec) =>
437      iq.io.og2Resp.get.zip(og2RespVec).foreach{ case (iqOg2Resp, og2Resp) =>
438        iqOg2Resp := og2Resp
439      }
440    }
441  }
442
443  // Connect each replace RCIdx to IQ
444  if (params.needWriteRegCache) {
445    val iqReplaceRCIdxVec = issueQueues.filter(_.params.needWriteRegCache).flatMap{ iq =>
446      iq.params.allExuParams.zip(iq.io.replaceRCIdx.get).filter(_._1.needWriteRegCache).map(_._2)
447    }
448    iqReplaceRCIdxVec.zip(io.fromDataPath.replaceRCIdx.get).foreach{ case (iq, in) =>
449      iq := in
450    }
451
452    println(s"[Scheduler] numWriteRegCache: ${params.numWriteRegCache}")
453    println(s"[Scheduler] iqReplaceRCIdxVec: ${iqReplaceRCIdxVec.size}")
454  }
455
456  // perfEvent
457  val lastCycleDp2IqOutFireVec = RegNext(VecInit(dispatch2Iq.io.out.flatten.map(_.fire)))
458  val lastCycleIqEnqFireVec    = RegNext(VecInit(issueQueues.map(_.io.enq.map(_.fire)).flatten))
459  val lastCycleIqFullVec       = RegNext(VecInit(issueQueues.map(_.io.enq.head.ready)))
460
461  val issueQueueFullVecPerf = issueQueues.zip(lastCycleIqFullVec)map{ case (iq, full) => (iq.params.getIQName + s"_full", full) }
462  val basePerfEvents = Seq(
463    ("dispatch2Iq_out_fire_cnt", PopCount(lastCycleDp2IqOutFireVec)                 ),
464    ("issueQueue_enq_fire_cnt",  PopCount(lastCycleIqEnqFireVec)                    )
465  )  ++ issueQueueFullVecPerf
466
467  println(s"[Scheduler] io.fromSchedulers.wakeupVec: ${io.fromSchedulers.wakeupVec.map(x => backendParams.getExuName(x.bits.exuIdx))}")
468  println(s"[Scheduler] iqWakeUpInKeys: ${iqWakeUpInMap.keys}")
469
470  println(s"[Scheduler] iqWakeUpOutKeys: ${iqWakeUpOutMap.keys}")
471  println(s"[Scheduler] io.toSchedulers.wakeupVec: ${io.toSchedulers.wakeupVec.map(x => backendParams.getExuName(x.bits.exuIdx))}")
472}
473
474class SchedulerArithImp(override val wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
475  extends SchedulerImpBase(wrapper)
476    with HasXSParameter
477    with HasPerfEvents
478{
479//  dontTouch(io.vfWbFuBusyTable)
480  println(s"[SchedulerArithImp] " +
481    s"has intBusyTable: ${intBusyTable.nonEmpty}, " +
482    s"has vfBusyTable: ${vfBusyTable.nonEmpty}")
483
484  issueQueues.zipWithIndex.foreach { case (iq, i) =>
485    iq.io.flush <> io.fromCtrlBlock.flush
486    iq.io.enq <> dispatch2Iq.io.out(i)
487    if (!iq.params.needLoadDependency) {
488      iq.io.enq.map(x => x.bits.srcLoadDependency := 0.U.asTypeOf(x.bits.srcLoadDependency))
489    }
490    val intWBIQ = params.schdType match {
491      case IntScheduler() => wakeupFromIntWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromIntWBPort.keys.toSeq.contains(x._2)).map(_._1)
492      case FpScheduler() => wakeupFromFpWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromFpWBPort.keys.toSeq.contains(x._2)).map(_._1)
493      case VfScheduler() => (wakeupFromVfWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromVfWBPort.keys.toSeq.contains(x._2)).map(_._1) ++
494                             wakeupFromV0WBVec.zipWithIndex.filter(x => iq.params.needWakeupFromV0WBPort.keys.toSeq.contains(x._2)).map(_._1) ++
495                             wakeupFromVlWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromVlWBPort.keys.toSeq.contains(x._2)).map(_._1))
496      case _ => null
497    }
498    iq.io.wakeupFromWB.zip(intWBIQ).foreach{ case (sink, source) => sink := source}
499  }
500
501  val perfEvents = basePerfEvents
502  generatePerfEvent()
503}
504
505// FIXME: Vector mem instructions may not be handled properly!
506class SchedulerMemImp(override val wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
507  extends SchedulerImpBase(wrapper)
508    with HasXSParameter
509    with HasPerfEvents
510{
511  println(s"[SchedulerMemImp] " +
512    s"has intBusyTable: ${intBusyTable.nonEmpty}, " +
513    s"has vfBusyTable: ${vfBusyTable.nonEmpty}")
514
515  val memAddrIQs = issueQueues.filter(_.params.isMemAddrIQ)
516  val stAddrIQs = issueQueues.filter(iq => iq.params.StaCnt > 0) // included in memAddrIQs
517  val ldAddrIQs = issueQueues.filter(iq => iq.params.LduCnt > 0)
518  val stDataIQs = issueQueues.filter(iq => iq.params.StdCnt > 0)
519  val vecMemIQs = issueQueues.filter(_.params.isVecMemIQ)
520  val (hyuIQs, hyuIQIdxs) = issueQueues.zipWithIndex.filter(_._1.params.HyuCnt > 0).unzip
521
522  println(s"[SchedulerMemImp] memAddrIQs.size: ${memAddrIQs.size}, enq.size: ${memAddrIQs.map(_.io.enq.size).sum}")
523  println(s"[SchedulerMemImp] stAddrIQs.size:  ${stAddrIQs.size }, enq.size: ${stAddrIQs.map(_.io.enq.size).sum}")
524  println(s"[SchedulerMemImp] ldAddrIQs.size:  ${ldAddrIQs.size }, enq.size: ${ldAddrIQs.map(_.io.enq.size).sum}")
525  println(s"[SchedulerMemImp] stDataIQs.size:  ${stDataIQs.size }, enq.size: ${stDataIQs.map(_.io.enq.size).sum}")
526  println(s"[SchedulerMemImp] hyuIQs.size:     ${hyuIQs.size    }, enq.size: ${hyuIQs.map(_.io.enq.size).sum}")
527  require(memAddrIQs.nonEmpty && stDataIQs.nonEmpty)
528
529  io.toMem.get.loadFastMatch := 0.U.asTypeOf(io.toMem.get.loadFastMatch) // TODO: is still needed?
530
531  private val loadWakeUp = issueQueues.filter(_.params.LdExuCnt > 0).map(_.asInstanceOf[IssueQueueMemAddrImp].io.memIO.get.loadWakeUp).flatten
532  require(loadWakeUp.length == io.fromMem.get.wakeup.length)
533  loadWakeUp.zip(io.fromMem.get.wakeup).foreach(x => x._1 := x._2)
534
535  memAddrIQs.zipWithIndex.foreach { case (iq, i) =>
536    iq.io.flush <> io.fromCtrlBlock.flush
537    iq.io.enq <> dispatch2Iq.io.out(i)
538    if (!iq.params.needLoadDependency) {
539      iq.io.enq.map(x => x.bits.srcLoadDependency := 0.U.asTypeOf(x.bits.srcLoadDependency))
540    }
541    iq.io.wakeupFromWB.zip(
542      wakeupFromIntWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromIntWBPort.keys.toSeq.contains(x._2)).map(_._1) ++
543      wakeupFromFpWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromFpWBPort.keys.toSeq.contains(x._2)).map(_._1) ++
544      wakeupFromVfWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromVfWBPort.keys.toSeq.contains(x._2)).map(_._1) ++
545      wakeupFromV0WBVec.zipWithIndex.filter(x => iq.params.needWakeupFromV0WBPort.keys.toSeq.contains(x._2)).map(_._1) ++
546      wakeupFromVlWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromVlWBPort.keys.toSeq.contains(x._2)).map(_._1)
547    ).foreach{ case (sink, source) => sink := source}
548  }
549
550  ldAddrIQs.zipWithIndex.foreach {
551    case (imp: IssueQueueMemAddrImp, i) =>
552      imp.io.memIO.get.feedbackIO.head := 0.U.asTypeOf(imp.io.memIO.get.feedbackIO.head)
553      imp.io.memIO.get.checkWait.stIssuePtr := io.fromMem.get.stIssuePtr
554      imp.io.memIO.get.checkWait.memWaitUpdateReq := io.fromMem.get.memWaitUpdateReq
555    case _ =>
556  }
557
558  stAddrIQs.zipWithIndex.foreach {
559    case (imp: IssueQueueMemAddrImp, i) =>
560      imp.io.memIO.get.feedbackIO.head := io.fromMem.get.staFeedback(i)
561      imp.io.memIO.get.checkWait.stIssuePtr := io.fromMem.get.stIssuePtr
562      imp.io.memIO.get.checkWait.memWaitUpdateReq := io.fromMem.get.memWaitUpdateReq
563    case _ =>
564  }
565
566  hyuIQs.zip(hyuIQIdxs).foreach {
567    case (imp: IssueQueueMemAddrImp, idx) =>
568      imp.io.memIO.get.feedbackIO.head := io.fromMem.get.hyuFeedback.head
569      imp.io.memIO.get.feedbackIO(1) := 0.U.asTypeOf(imp.io.memIO.get.feedbackIO(1))
570      imp.io.memIO.get.checkWait.stIssuePtr := io.fromMem.get.stIssuePtr
571      imp.io.memIO.get.checkWait.memWaitUpdateReq := io.fromMem.get.memWaitUpdateReq
572      // TODO: refactor ditry code
573      imp.io.deqDelay(1).ready := false.B
574      io.toDataPathAfterDelay(idx)(1).valid := false.B
575      io.toDataPathAfterDelay(idx)(1).bits := 0.U.asTypeOf(io.toDataPathAfterDelay(idx)(1).bits)
576    case _ =>
577  }
578
579  private val staIdxSeq = (stAddrIQs).map(iq => iq.params.idxInSchBlk)
580  private val hyaIdxSeq = (hyuIQs).map(iq => iq.params.idxInSchBlk)
581
582  println(s"[SchedulerMemImp] sta iq idx in memSchdBlock: $staIdxSeq")
583  println(s"[SchedulerMemImp] hya iq idx in memSchdBlock: $hyaIdxSeq")
584
585  private val staEnqs = stAddrIQs.map(_.io.enq).flatten
586  private val stdEnqs = stDataIQs.map(_.io.enq).flatten.take(staEnqs.size)
587  private val hyaEnqs = hyuIQs.map(_.io.enq).flatten
588  private val hydEnqs = stDataIQs.map(_.io.enq).flatten.drop(staEnqs.size)
589
590  require(staEnqs.size == stdEnqs.size, s"number of enq ports of store address IQs(${staEnqs.size}) " +
591  s"should be equal to number of enq ports of store data IQs(${stdEnqs.size})")
592
593  require(hyaEnqs.size == hydEnqs.size, s"number of enq ports of hybrid address IQs(${hyaEnqs.size}) " +
594  s"should be equal to number of enq ports of hybrid data IQs(${hydEnqs.size})")
595
596  val d2IqStaOut = dispatch2Iq.io.out.zipWithIndex.filter(staIdxSeq contains _._2).unzip._1.flatten
597  d2IqStaOut.zip(staEnqs).zip(stdEnqs).foreach{ case((dp, staIQ), stdIQ) =>
598    val isAllReady = staIQ.ready && stdIQ.ready
599    dp.ready := isAllReady
600    staIQ.valid := dp.valid && isAllReady
601    stdIQ.valid := dp.valid && isAllReady && FuType.FuTypeOrR(dp.bits.fuType, FuType.stu, FuType.mou)
602  }
603
604  val d2IqHyaOut = dispatch2Iq.io.out.zipWithIndex.filter(hyaIdxSeq contains _._2).unzip._1.flatten
605  d2IqHyaOut.zip(hyaEnqs).zip(hydEnqs).foreach{ case((dp, hyaIQ), hydIQ) =>
606    val isAllReady = hyaIQ.ready && hydIQ.ready
607    dp.ready := isAllReady
608    hyaIQ.valid := dp.valid && isAllReady
609    hydIQ.valid := dp.valid && isAllReady && FuType.FuTypeOrR(dp.bits.fuType, FuType.stu, FuType.mou)
610  }
611
612  stDataIQs.zipWithIndex.foreach { case (iq, i) =>
613    iq.io.flush <> io.fromCtrlBlock.flush
614    iq.io.wakeupFromWB.zip(
615      wakeupFromIntWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromIntWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
616      wakeupFromFpWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromFpWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
617      wakeupFromVfWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromVfWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
618      wakeupFromV0WBVec.zipWithIndex.filter(x => iq.params.needWakeupFromV0WBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
619      wakeupFromVlWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromVlWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq
620    ).foreach{ case (sink, source) => sink := source}
621  }
622
623  (stdEnqs ++ hydEnqs).zip(staEnqs ++ hyaEnqs).zipWithIndex.foreach { case ((stdIQEnq, staIQEnq), i) =>
624    stdIQEnq.bits  := staIQEnq.bits
625    // Store data reuses store addr src(1) in dispatch2iq
626    // [dispatch2iq] --src*------src*(0)--> [staIQ|hyaIQ]
627    //                       \
628    //                        ---src*(1)--> [stdIQ]
629    // Since the src(1) of sta is easier to get, stdIQEnq.bits.src*(0) is assigned to staIQEnq.bits.src*(1)
630    // instead of dispatch2Iq.io.out(x).bits.src*(1)
631    val stdIdx = 1
632    stdIQEnq.bits.srcState(0) := staIQEnq.bits.srcState(stdIdx)
633    stdIQEnq.bits.srcLoadDependency(0) := staIQEnq.bits.srcLoadDependency(stdIdx)
634    stdIQEnq.bits.srcType(0) := staIQEnq.bits.srcType(stdIdx)
635    stdIQEnq.bits.psrc(0) := staIQEnq.bits.psrc(stdIdx)
636    stdIQEnq.bits.sqIdx := staIQEnq.bits.sqIdx
637    stdIQEnq.bits.useRegCache(0) := staIQEnq.bits.useRegCache(stdIdx)
638    stdIQEnq.bits.regCacheIdx(0) := staIQEnq.bits.regCacheIdx(stdIdx)
639  }
640
641  vecMemIQs.foreach {
642    case imp: IssueQueueVecMemImp =>
643      imp.io.memIO.get.sqDeqPtr.foreach(_ := io.fromMem.get.sqDeqPtr)
644      imp.io.memIO.get.lqDeqPtr.foreach(_ := io.fromMem.get.lqDeqPtr)
645      // not used
646      //imp.io.memIO.get.feedbackIO.head := io.fromMem.get.vstuFeedback.head // only vector store replay
647      // maybe not used
648      imp.io.memIO.get.checkWait.stIssuePtr := io.fromMem.get.stIssuePtr
649      imp.io.memIO.get.checkWait.memWaitUpdateReq := io.fromMem.get.memWaitUpdateReq
650      imp.io.wakeupFromWB.zip(
651        wakeupFromIntWBVec.zipWithIndex.filter(x => imp.params.needWakeupFromIntWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
652        wakeupFromFpWBVec.zipWithIndex.filter(x => imp.params.needWakeupFromFpWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
653        wakeupFromVfWBVec.zipWithIndex.filter(x => imp.params.needWakeupFromVfWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
654        wakeupFromV0WBVec.zipWithIndex.filter(x => imp.params.needWakeupFromV0WBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
655        wakeupFromVlWBVec.zipWithIndex.filter(x => imp.params.needWakeupFromVlWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq
656      ).foreach{ case (sink, source) => sink := source}
657
658    case _ =>
659  }
660  val vecMemFeedbackIO: Seq[MemRSFeedbackIO] = vecMemIQs.map {
661    case imp: IssueQueueVecMemImp =>
662      imp.io.memIO.get.feedbackIO
663  }.flatten
664  assert(vecMemFeedbackIO.size == io.fromMem.get.vstuFeedback.size, "vecMemFeedback size dont match!")
665  vecMemFeedbackIO.zip(io.fromMem.get.vstuFeedback).foreach{
666    case (sink, source) =>
667      sink := source
668  }
669
670  val lsqEnqCtrl = Module(new LsqEnqCtrl)
671
672  lsqEnqCtrl.io.redirect <> io.fromCtrlBlock.flush
673  lsqEnqCtrl.io.enq <> dispatch2Iq.io.enqLsqIO.get
674  lsqEnqCtrl.io.lcommit := io.fromMem.get.lcommit
675  lsqEnqCtrl.io.scommit := io.fromMem.get.scommit
676  lsqEnqCtrl.io.lqCancelCnt := io.fromMem.get.lqCancelCnt
677  lsqEnqCtrl.io.sqCancelCnt := io.fromMem.get.sqCancelCnt
678  dispatch2Iq.io.lqFreeCount.get := lsqEnqCtrl.io.lqFreeCount
679  dispatch2Iq.io.sqFreeCount.get := lsqEnqCtrl.io.sqFreeCount
680  io.memIO.get.lsqEnqIO <> lsqEnqCtrl.io.enqLsq
681
682  dontTouch(io.vecLoadIssueResp)
683
684  val intBusyTablePerf = intBusyTable.get
685  val fpBusyTablePerf  = fpBusyTable.get
686  val vecBusyTablePerf = vfBusyTable.get
687  val v0BusyTablePerf  = v0BusyTable.get
688  val vlBusyTablePerf  = vlBusyTable.get
689
690  val perfEvents = basePerfEvents ++ Seq(intBusyTablePerf, fpBusyTablePerf, vecBusyTablePerf, v0BusyTablePerf, vlBusyTablePerf).flatten(_.getPerfEvents)
691  generatePerfEvent()
692}
693