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