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