xref: /XiangShan/src/main/scala/xiangshan/backend/issue/Scheduler.scala (revision 94aa21c6009c2f39c5c5dae9c87260c78887efcc)
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.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 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  val fromDispatchUopNum = params.issueBlockParams.filter(x => x.StdCnt == 0).map(_.numEnq).sum
52  val allIssueParams = params.issueBlockParams.filter(_.StdCnt == 0)
53  val IssueQueueDeqSum = allIssueParams.map(_.numDeq).sum
54  val maxIQSize = allIssueParams.map(_.numEntries).max
55  val fromTop = new Bundle {
56    val hartId = Input(UInt(8.W))
57  }
58  val fromWbFuBusyTable = new Bundle{
59    val fuBusyTableRead = MixedVec(params.issueBlockParams.map(x => Input(x.genWbFuBusyTableReadBundle)))
60  }
61  val wbFuBusyTable = MixedVec(params.issueBlockParams.map(x => Output(x.genWbFuBusyTableWriteBundle)))
62  val IQValidNumVec = Output(Vec(IssueQueueDeqSum, UInt((maxIQSize).U.getWidth.W)))
63
64  val fromCtrlBlock = new Bundle {
65    val flush = Flipped(ValidIO(new Redirect))
66  }
67  val fromDispatch = new Bundle {
68    val uops =  Vec(fromDispatchUopNum, 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 intWriteBackDelayed = MixedVec(Vec(backendParams.numPregWb(IntData()),
81    new RfWritePortWithConfig(backendParams.intPregParams.dataCfg, backendParams.intPregParams.addrWidth)))
82  val fpWriteBackDelayed = MixedVec(Vec(backendParams.numPregWb(FpData()),
83    new RfWritePortWithConfig(backendParams.fpPregParams.dataCfg, backendParams.fpPregParams.addrWidth)))
84  val vfWriteBackDelayed = MixedVec(Vec(backendParams.numPregWb(VecData()),
85    new RfWritePortWithConfig(backendParams.vfPregParams.dataCfg, backendParams.vfPregParams.addrWidth)))
86  val v0WriteBackDelayed = MixedVec(Vec(backendParams.numPregWb(V0Data()),
87    new RfWritePortWithConfig(backendParams.v0PregParams.dataCfg, backendParams.v0PregParams.addrWidth)))
88  val vlWriteBackDelayed = MixedVec(Vec(backendParams.numPregWb(VlData()),
89    new RfWritePortWithConfig(backendParams.vlPregParams.dataCfg, backendParams.vlPregParams.addrWidth)))
90  val toDataPathAfterDelay: MixedVec[MixedVec[DecoupledIO[IssueQueueIssueBundle]]] = MixedVec(params.issueBlockParams.map(_.genIssueDecoupledBundle))
91
92  val vlWriteBackInfo = new Bundle {
93    val vlFromIntIsZero  = Input(Bool())
94    val vlFromIntIsVlmax = Input(Bool())
95    val vlFromVfIsZero   = Input(Bool())
96    val vlFromVfIsVlmax  = Input(Bool())
97  }
98
99  val fromSchedulers = new Bundle {
100    val wakeupVec: MixedVec[ValidIO[IssueQueueIQWakeUpBundle]] = Flipped(params.genIQWakeUpInValidBundle)
101    val wakeupVecDelayed: MixedVec[ValidIO[IssueQueueIQWakeUpBundle]] = Flipped(params.genIQWakeUpInValidBundle)
102  }
103
104  val toSchedulers = new Bundle {
105    val wakeupVec: MixedVec[ValidIO[IssueQueueIQWakeUpBundle]] = params.genIQWakeUpOutValidBundle
106  }
107
108  val fromDataPath = new Bundle {
109    val resp: MixedVec[MixedVec[OGRespBundle]] = MixedVec(params.issueBlockParams.map(x => Flipped(x.genOGRespBundle)))
110    val og0Cancel = Input(ExuVec())
111    // Todo: remove this after no cancel signal from og1
112    val og1Cancel = Input(ExuVec())
113    // replace RCIdx to Wakeup Queue
114    val replaceRCIdx = OptionWrapper(params.needWriteRegCache, Vec(params.numWriteRegCache, Input(UInt(RegCacheIdxWidth.W))))
115    // just be compatible to old code
116    def apply(i: Int)(j: Int) = resp(i)(j)
117  }
118
119  val loadFinalIssueResp = MixedVec(params.issueBlockParams.map(x => MixedVec(Vec(x.LdExuCnt, Flipped(ValidIO(new IssueQueueDeqRespBundle()(p, x)))))))
120  val vecLoadFinalIssueResp = MixedVec(params.issueBlockParams.map(x => MixedVec(Vec(x.VlduCnt, Flipped(ValidIO(new IssueQueueDeqRespBundle()(p, x)))))))
121  val memAddrIssueResp = MixedVec(params.issueBlockParams.map(x => MixedVec(Vec(x.LdExuCnt, Flipped(ValidIO(new IssueQueueDeqRespBundle()(p, x)))))))
122  val vecLoadIssueResp = MixedVec(params.issueBlockParams.map(x => MixedVec(Vec(x.VlduCnt, Flipped(ValidIO(new IssueQueueDeqRespBundle()(p, x)))))))
123
124  val ldCancel = Vec(backendParams.LduCnt + backendParams.HyuCnt, Flipped(new LoadCancelIO))
125
126  val fromMem = if (params.isMemSchd) Some(new Bundle {
127    val ldaFeedback = Flipped(Vec(params.LduCnt, new MemRSFeedbackIO))
128    val staFeedback = Flipped(Vec(params.StaCnt, new MemRSFeedbackIO))
129    val hyuFeedback = Flipped(Vec(params.HyuCnt, new MemRSFeedbackIO))
130    val vstuFeedback = Flipped(Vec(params.VstuCnt, new MemRSFeedbackIO(isVector = true)))
131    val vlduFeedback = Flipped(Vec(params.VlduCnt, new MemRSFeedbackIO(isVector = true)))
132    val stIssuePtr = Input(new SqPtr())
133    val lcommit = Input(UInt(log2Up(CommitWidth + 1).W))
134    val scommit = Input(UInt(log2Ceil(EnsbufferWidth + 1).W)) // connected to `memBlock.io.sqDeq` instead of ROB
135    val wakeup = Vec(params.LdExuCnt, Flipped(Valid(new DynInst)))
136    val lqDeqPtr = Input(new LqPtr)
137    val sqDeqPtr = Input(new SqPtr)
138    // from lsq
139    val lqCancelCnt = Input(UInt(log2Up(LoadQueueSize + 1).W))
140    val sqCancelCnt = Input(UInt(log2Up(StoreQueueSize + 1).W))
141    val memWaitUpdateReq = Flipped(new MemWaitUpdateReq)
142  }) else None
143  val toMem = if (params.isMemSchd) Some(new Bundle {
144    val loadFastMatch = Output(Vec(params.LduCnt, new IssueQueueLoadBundle))
145  }) else None
146  val fromOg2Resp = if(params.needOg2Resp) Some(MixedVec(params.issueBlockParams.filter(_.needOg2Resp).map(x => Flipped(x.genOG2RespBundle)))) else None
147}
148
149abstract class SchedulerImpBase(wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
150  extends LazyModuleImp(wrapper)
151    with HasXSParameter
152{
153  val io = IO(new SchedulerIO())
154
155  // alias
156  private val iqWakeUpInMap: Map[Int, ValidIO[IssueQueueIQWakeUpBundle]] =
157    io.fromSchedulers.wakeupVec.map(x => (x.bits.exuIdx, x)).toMap
158  private val iqWakeUpInMapDelayed: Map[Int, ValidIO[IssueQueueIQWakeUpBundle]] =
159    io.fromSchedulers.wakeupVecDelayed.map(x => (x.bits.exuIdx, x)).toMap
160  private val schdType = params.schdType
161
162  // Modules
163  val issueQueues: Seq[IssueQueueImp] = wrapper.issueQueue.map(_.module)
164
165  io.IQValidNumVec := issueQueues.filter(_.params.StdCnt == 0).map(_.io.validCntDeqVec).flatten
166  val wakeupFromIntWBVec = Wire(params.genIntWBWakeUpSinkValidBundle)
167  val wakeupFromFpWBVec = Wire(params.genFpWBWakeUpSinkValidBundle)
168  val wakeupFromVfWBVec = Wire(params.genVfWBWakeUpSinkValidBundle)
169  val wakeupFromV0WBVec = Wire(params.genV0WBWakeUpSinkValidBundle)
170  val wakeupFromVlWBVec = Wire(params.genVlWBWakeUpSinkValidBundle)
171  val wakeupFromIntWBVecDelayed = Wire(params.genIntWBWakeUpSinkValidBundle)
172  val wakeupFromFpWBVecDelayed = Wire(params.genFpWBWakeUpSinkValidBundle)
173  val wakeupFromVfWBVecDelayed = Wire(params.genVfWBWakeUpSinkValidBundle)
174  val wakeupFromV0WBVecDelayed = Wire(params.genV0WBWakeUpSinkValidBundle)
175  val wakeupFromVlWBVecDelayed = Wire(params.genVlWBWakeUpSinkValidBundle)
176
177  val wakeupFromWBVec = Seq(wakeupFromIntWBVec, wakeupFromFpWBVec, wakeupFromVfWBVec, wakeupFromV0WBVec, wakeupFromVlWBVec)
178  val allWriteBack = Seq(io.intWriteBack, io.fpWriteBack, io.vfWriteBack, io.v0WriteBack, io.vlWriteBack)
179  wakeupFromWBVec.zip(allWriteBack).map{ case (sinks, sources) =>
180    sinks.zip(sources).map{ case (sink, source) =>
181      sink.valid := source.wen
182      sink.bits.rfWen := source.intWen
183      sink.bits.fpWen := source.fpWen
184      sink.bits.vecWen := source.vecWen
185      sink.bits.v0Wen := source.v0Wen
186      sink.bits.vlWen := source.vlWen
187      sink.bits.pdest := source.addr
188    }
189  }
190
191  val wakeupFromWBVecDelayed = Seq(wakeupFromIntWBVecDelayed, wakeupFromFpWBVecDelayed, wakeupFromVfWBVecDelayed, wakeupFromV0WBVecDelayed, wakeupFromVlWBVecDelayed)
192  val allWriteBackDelayed = Seq(io.intWriteBackDelayed, io.fpWriteBackDelayed, io.vfWriteBackDelayed, io.v0WriteBackDelayed, io.vlWriteBackDelayed)
193  wakeupFromWBVecDelayed.zip(allWriteBackDelayed).map { case (sinks, sources) =>
194    sinks.zip(sources).map { case (sink, source) =>
195      sink.valid := source.wen
196      sink.bits.rfWen := source.intWen
197      sink.bits.fpWen := source.fpWen
198      sink.bits.vecWen := source.vecWen
199      sink.bits.v0Wen := source.v0Wen
200      sink.bits.vlWen := source.vlWen
201      sink.bits.pdest := source.addr
202    }
203  }
204  // Connect bundles having the same wakeup source
205  issueQueues.zipWithIndex.foreach { case(iq, i) =>
206    iq.io.wakeupFromIQ.foreach { wakeUp =>
207      val wakeUpIn = iqWakeUpInMap(wakeUp.bits.exuIdx)
208      val exuIdx = wakeUp.bits.exuIdx
209      println(s"[Backend] Connect wakeup exuIdx ${exuIdx}")
210      connectSamePort(wakeUp,wakeUpIn)
211      backendParams.connectWakeup(exuIdx)
212      if (backendParams.isCopyPdest(exuIdx)) {
213        println(s"[Backend] exuIdx ${exuIdx} use pdestCopy ${backendParams.getCopyPdestIndex(exuIdx)}")
214        wakeUp.bits.pdest := wakeUpIn.bits.pdestCopy.get(backendParams.getCopyPdestIndex(exuIdx))
215        if (wakeUpIn.bits.rfWenCopy.nonEmpty) wakeUp.bits.rfWen := wakeUpIn.bits.rfWenCopy.get(backendParams.getCopyPdestIndex(exuIdx))
216        if (wakeUpIn.bits.fpWenCopy.nonEmpty) wakeUp.bits.fpWen := wakeUpIn.bits.fpWenCopy.get(backendParams.getCopyPdestIndex(exuIdx))
217        if (wakeUpIn.bits.vecWenCopy.nonEmpty) wakeUp.bits.vecWen := wakeUpIn.bits.vecWenCopy.get(backendParams.getCopyPdestIndex(exuIdx))
218        if (wakeUpIn.bits.v0WenCopy.nonEmpty) wakeUp.bits.v0Wen := wakeUpIn.bits.v0WenCopy.get(backendParams.getCopyPdestIndex(exuIdx))
219        if (wakeUpIn.bits.vlWenCopy.nonEmpty) wakeUp.bits.vlWen := wakeUpIn.bits.vlWenCopy.get(backendParams.getCopyPdestIndex(exuIdx))
220        if (wakeUpIn.bits.loadDependencyCopy.nonEmpty) wakeUp.bits.loadDependency := wakeUpIn.bits.loadDependencyCopy.get(backendParams.getCopyPdestIndex(exuIdx))
221      }
222      if (iq.params.numIntSrc == 0) wakeUp.bits.rfWen := false.B
223      if (iq.params.numFpSrc == 0)  wakeUp.bits.fpWen := false.B
224      if (iq.params.numVfSrc == 0)  wakeUp.bits.vecWen := false.B
225      if (iq.params.numV0Src == 0)  wakeUp.bits.v0Wen := false.B
226      if (iq.params.numVlSrc == 0)  wakeUp.bits.vlWen := false.B
227    }
228    iq.io.wakeupFromIQDelayed.foreach { wakeUp =>
229      val wakeUpIn = iqWakeUpInMapDelayed(wakeUp.bits.exuIdx)
230      connectSamePort(wakeUp, wakeUpIn)
231      if (iq.params.numIntSrc == 0) wakeUp.bits.rfWen := false.B
232      if (iq.params.numFpSrc == 0) wakeUp.bits.fpWen := false.B
233      if (iq.params.numVfSrc == 0) wakeUp.bits.vecWen := false.B
234      if (iq.params.numV0Src == 0) wakeUp.bits.v0Wen := false.B
235      if (iq.params.numVlSrc == 0) wakeUp.bits.vlWen := false.B
236    }
237    iq.io.og0Cancel := io.fromDataPath.og0Cancel
238    iq.io.og1Cancel := io.fromDataPath.og1Cancel
239    if (iq.params.needLoadDependency)
240      iq.io.ldCancel := io.ldCancel
241    else
242      iq.io.ldCancel := 0.U.asTypeOf(io.ldCancel)
243  }
244
245  // connect the vl writeback informatino to the issue queues
246  issueQueues.zipWithIndex.foreach { case(iq, i) =>
247    iq.io.vlFromIntIsVlmax := io.vlWriteBackInfo.vlFromIntIsVlmax
248    iq.io.vlFromIntIsZero := io.vlWriteBackInfo.vlFromIntIsZero
249    iq.io.vlFromVfIsVlmax := io.vlWriteBackInfo.vlFromVfIsVlmax
250    iq.io.vlFromVfIsZero := io.vlWriteBackInfo.vlFromVfIsZero
251  }
252
253  private val iqWakeUpOutMap: Map[Int, ValidIO[IssueQueueIQWakeUpBundle]] =
254    issueQueues.flatMap(_.io.wakeupToIQ)
255      .map(x => (x.bits.exuIdx, x))
256      .toMap
257
258  // Connect bundles having the same wakeup source
259  io.toSchedulers.wakeupVec.foreach { wakeUp =>
260    wakeUp := iqWakeUpOutMap(wakeUp.bits.exuIdx)
261  }
262
263  io.toDataPathAfterDelay.zipWithIndex.foreach { case (toDpDy, i) =>
264    toDpDy <> issueQueues(i).io.deqDelay
265  }
266
267  // Response
268  issueQueues.zipWithIndex.foreach { case (iq, i) =>
269    iq.io.og0Resp.zipWithIndex.foreach { case (og0Resp, j) =>
270      og0Resp := io.fromDataPath(i)(j).og0resp
271    }
272    iq.io.og1Resp.zipWithIndex.foreach { case (og1Resp, j) =>
273      og1Resp := io.fromDataPath(i)(j).og1resp
274    }
275    iq.io.finalIssueResp.foreach(_.zipWithIndex.foreach { case (finalIssueResp, j) =>
276      if (io.loadFinalIssueResp(i).isDefinedAt(j) && iq.params.isLdAddrIQ) {
277        finalIssueResp := io.loadFinalIssueResp(i)(j)
278      } else if (io.vecLoadFinalIssueResp(i).isDefinedAt(j) && iq.params.isVecLduIQ) {
279        finalIssueResp := io.vecLoadFinalIssueResp(i)(j)
280      }
281      else {
282        finalIssueResp := 0.U.asTypeOf(finalIssueResp)
283      }
284    })
285    iq.io.memAddrIssueResp.foreach(_.zipWithIndex.foreach { case (memAddrIssueResp, j) =>
286      if (io.memAddrIssueResp(i).isDefinedAt(j)) {
287        memAddrIssueResp := io.memAddrIssueResp(i)(j)
288      } else {
289        memAddrIssueResp := 0.U.asTypeOf(memAddrIssueResp)
290      }
291    })
292    iq.io.vecLoadIssueResp.foreach(_.zipWithIndex.foreach { case (resp, deqIdx) =>
293      resp := io.vecLoadIssueResp(i)(deqIdx)
294    })
295    iq.io.wbBusyTableRead := io.fromWbFuBusyTable.fuBusyTableRead(i)
296    io.wbFuBusyTable(i) := iq.io.wbBusyTableWrite
297    iq.io.replaceRCIdx.foreach(x => x := 0.U.asTypeOf(x))
298  }
299  if (params.needOg2Resp) {
300    issueQueues.filter(_.params.needOg2Resp).zip(io.fromOg2Resp.get).foreach{ case (iq, og2RespVec) =>
301      iq.io.og2Resp.get.zip(og2RespVec).foreach{ case (iqOg2Resp, og2Resp) =>
302        iqOg2Resp := og2Resp
303      }
304    }
305  }
306
307  // Connect each replace RCIdx to IQ
308  if (params.needWriteRegCache) {
309    val iqReplaceRCIdxVec = issueQueues.filter(_.params.needWriteRegCache).flatMap{ iq =>
310      iq.params.allExuParams.zip(iq.io.replaceRCIdx.get).filter(_._1.needWriteRegCache).map(_._2)
311    }
312    iqReplaceRCIdxVec.zip(io.fromDataPath.replaceRCIdx.get).foreach{ case (iq, in) =>
313      iq := in
314    }
315
316    println(s"[Scheduler] numWriteRegCache: ${params.numWriteRegCache}")
317    println(s"[Scheduler] iqReplaceRCIdxVec: ${iqReplaceRCIdxVec.size}")
318  }
319
320  // perfEvent
321  val lastCycleIqEnqFireVec    = RegNext(VecInit(issueQueues.map(_.io.enq.map(_.fire)).flatten))
322  val lastCycleIqFullVec       = RegNext(VecInit(issueQueues.map(_.io.enq.head.ready)))
323
324  val issueQueueFullVecPerf = issueQueues.zip(lastCycleIqFullVec)map{ case (iq, full) => (iq.params.getIQName + s"_full", full) }
325  val basePerfEvents = Seq(
326    ("issueQueue_enq_fire_cnt",  PopCount(lastCycleIqEnqFireVec)                    )
327  )  ++ issueQueueFullVecPerf
328
329  println(s"[Scheduler] io.fromSchedulers.wakeupVec: ${io.fromSchedulers.wakeupVec.map(x => backendParams.getExuName(x.bits.exuIdx))}")
330  println(s"[Scheduler] iqWakeUpInKeys: ${iqWakeUpInMap.keys}")
331
332  println(s"[Scheduler] iqWakeUpOutKeys: ${iqWakeUpOutMap.keys}")
333  println(s"[Scheduler] io.toSchedulers.wakeupVec: ${io.toSchedulers.wakeupVec.map(x => backendParams.getExuName(x.bits.exuIdx))}")
334}
335
336class SchedulerArithImp(override val wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
337  extends SchedulerImpBase(wrapper)
338    with HasXSParameter
339    with HasPerfEvents
340{
341  val issueQueuesUopIn = issueQueues.map(_.io.enq).flatten
342  issueQueuesUopIn.zip(io.fromDispatch.uops).map(x => x._1 <> x._2)
343  issueQueues.zipWithIndex.foreach { case (iq, i) =>
344    iq.io.flush <> io.fromCtrlBlock.flush
345    if (!iq.params.needLoadDependency) {
346      iq.io.enq.map(x => x.bits.srcLoadDependency := 0.U.asTypeOf(x.bits.srcLoadDependency))
347    }
348    val intWBIQ = params.schdType match {
349      case IntScheduler() => wakeupFromIntWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromIntWBPort.keys.toSeq.contains(x._2)).map(_._1)
350      case FpScheduler() => wakeupFromFpWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromFpWBPort.keys.toSeq.contains(x._2)).map(_._1)
351      case VfScheduler() => (wakeupFromVfWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromVfWBPort.keys.toSeq.contains(x._2)).map(_._1) ++
352                             wakeupFromV0WBVec.zipWithIndex.filter(x => iq.params.needWakeupFromV0WBPort.keys.toSeq.contains(x._2)).map(_._1) ++
353                             wakeupFromVlWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromVlWBPort.keys.toSeq.contains(x._2)).map(_._1))
354      case _ => null
355    }
356    val intWBIQDelayed = params.schdType match {
357      case IntScheduler() => wakeupFromIntWBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromIntWBPort.keys.toSeq.contains(x._2)).map(_._1)
358      case FpScheduler() => wakeupFromFpWBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromFpWBPort.keys.toSeq.contains(x._2)).map(_._1)
359      case VfScheduler() => (wakeupFromVfWBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromVfWBPort.keys.toSeq.contains(x._2)).map(_._1) ++
360                             wakeupFromV0WBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromV0WBPort.keys.toSeq.contains(x._2)).map(_._1) ++
361                             wakeupFromVlWBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromVlWBPort.keys.toSeq.contains(x._2)).map(_._1))
362      case _ => null
363    }
364    iq.io.wakeupFromWB.zip(intWBIQ).foreach{ case (sink, source) => sink := source}
365    iq.io.wakeupFromWBDelayed.zip(intWBIQDelayed).foreach{ case (sink, source) => sink := source}
366  }
367
368  val perfEvents = basePerfEvents
369  generatePerfEvent()
370}
371
372// FIXME: Vector mem instructions may not be handled properly!
373class SchedulerMemImp(override val wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
374  extends SchedulerImpBase(wrapper)
375    with HasXSParameter
376    with HasPerfEvents
377{
378
379  val issueQueuesUopIn = issueQueues.filter(_.params.StdCnt == 0).map(_.io.enq).flatten
380  issueQueuesUopIn.zip(io.fromDispatch.uops).map(x => x._1 <> x._2)
381  val noStdExuParams = params.issueBlockParams.map(x => Seq.fill(x.numEnq)(x.exuBlockParams)).flatten.filter{x => x.map(!_.hasStdFu).reduce(_ && _)}
382  val staIdx = noStdExuParams.zipWithIndex.filter{x => x._1.map(_.hasStoreAddrFu).reduce(_ || _)}.map(_._2)
383  val staReady = issueQueues.filter(iq => iq.params.StaCnt > 0).map(_.io.enq.map(_.ready)).flatten
384  val stdReady = issueQueues.filter(iq => iq.params.StdCnt > 0).map(_.io.enq.map(_.ready)).flatten
385  staIdx.zipWithIndex.map{ case (sta, i) => {
386    io.fromDispatch.uops(sta).ready := staReady(i) && stdReady(i)
387  }}
388  issueQueues.filter(iq => iq.params.StaCnt > 0).map(_.io.enq).flatten.zipWithIndex.map{ case (iq, idx) =>
389    iq.valid := io.fromDispatch.uops(staIdx(idx)).valid && !io.fromDispatch.uops(staIdx(idx)).bits.isDropAmocasSta
390  }
391  val staValidFromDispatch = staIdx.map(idx => io.fromDispatch.uops(idx).valid)
392  val memAddrIQs = issueQueues.filter(_.params.isMemAddrIQ)
393  val stAddrIQs = issueQueues.filter(iq => iq.params.StaCnt > 0) // included in memAddrIQs
394  val ldAddrIQs = issueQueues.filter(iq => iq.params.LduCnt > 0)
395  val stDataIQs = issueQueues.filter(iq => iq.params.StdCnt > 0)
396  val vecMemIQs = issueQueues.filter(_.params.isVecMemIQ)
397  val (hyuIQs, hyuIQIdxs) = issueQueues.zipWithIndex.filter(_._1.params.HyuCnt > 0).unzip
398
399  println(s"[SchedulerMemImp] memAddrIQs.size: ${memAddrIQs.size}, enq.size: ${memAddrIQs.map(_.io.enq.size).sum}")
400  println(s"[SchedulerMemImp] stAddrIQs.size:  ${stAddrIQs.size }, enq.size: ${stAddrIQs.map(_.io.enq.size).sum}")
401  println(s"[SchedulerMemImp] ldAddrIQs.size:  ${ldAddrIQs.size }, enq.size: ${ldAddrIQs.map(_.io.enq.size).sum}")
402  println(s"[SchedulerMemImp] stDataIQs.size:  ${stDataIQs.size }, enq.size: ${stDataIQs.map(_.io.enq.size).sum}")
403  println(s"[SchedulerMemImp] hyuIQs.size:     ${hyuIQs.size    }, enq.size: ${hyuIQs.map(_.io.enq.size).sum}")
404  require(memAddrIQs.nonEmpty && stDataIQs.nonEmpty)
405
406  io.toMem.get.loadFastMatch := 0.U.asTypeOf(io.toMem.get.loadFastMatch) // TODO: is still needed?
407
408  private val loadWakeUp = issueQueues.filter(_.params.LdExuCnt > 0).map(_.asInstanceOf[IssueQueueMemAddrImp].io.memIO.get.loadWakeUp).flatten
409  require(loadWakeUp.length == io.fromMem.get.wakeup.length)
410  loadWakeUp.zip(io.fromMem.get.wakeup).foreach(x => x._1 := x._2)
411
412  memAddrIQs.zipWithIndex.foreach { case (iq, i) =>
413    iq.io.flush <> io.fromCtrlBlock.flush
414    if (!iq.params.needLoadDependency) {
415      iq.io.enq.map(x => x.bits.srcLoadDependency := 0.U.asTypeOf(x.bits.srcLoadDependency))
416    }
417    iq.io.wakeupFromWB.zip(
418      wakeupFromIntWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromIntWBPort.keys.toSeq.contains(x._2)).map(_._1) ++
419      wakeupFromFpWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromFpWBPort.keys.toSeq.contains(x._2)).map(_._1) ++
420      wakeupFromVfWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromVfWBPort.keys.toSeq.contains(x._2)).map(_._1) ++
421      wakeupFromV0WBVec.zipWithIndex.filter(x => iq.params.needWakeupFromV0WBPort.keys.toSeq.contains(x._2)).map(_._1) ++
422      wakeupFromVlWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromVlWBPort.keys.toSeq.contains(x._2)).map(_._1)
423    ).foreach{ case (sink, source) => sink := source}
424    iq.io.wakeupFromWBDelayed.zip(
425      wakeupFromIntWBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromIntWBPort.keys.toSeq.contains(x._2)).map(_._1) ++
426      wakeupFromFpWBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromFpWBPort.keys.toSeq.contains(x._2)).map(_._1) ++
427      wakeupFromVfWBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromVfWBPort.keys.toSeq.contains(x._2)).map(_._1) ++
428      wakeupFromV0WBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromV0WBPort.keys.toSeq.contains(x._2)).map(_._1) ++
429      wakeupFromVlWBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromVlWBPort.keys.toSeq.contains(x._2)).map(_._1)
430    ).foreach { case (sink, source) => sink := source }
431  }
432
433  ldAddrIQs.zipWithIndex.foreach {
434    case (imp: IssueQueueMemAddrImp, i) =>
435      imp.io.memIO.get.feedbackIO.head := 0.U.asTypeOf(imp.io.memIO.get.feedbackIO.head)
436      imp.io.memIO.get.checkWait.stIssuePtr := io.fromMem.get.stIssuePtr
437      imp.io.memIO.get.checkWait.memWaitUpdateReq := io.fromMem.get.memWaitUpdateReq
438    case _ =>
439  }
440
441  stAddrIQs.zipWithIndex.foreach {
442    case (imp: IssueQueueMemAddrImp, i) =>
443      imp.io.memIO.get.feedbackIO.head := io.fromMem.get.staFeedback(i)
444      imp.io.memIO.get.checkWait.stIssuePtr := io.fromMem.get.stIssuePtr
445      imp.io.memIO.get.checkWait.memWaitUpdateReq := io.fromMem.get.memWaitUpdateReq
446    case _ =>
447  }
448
449  hyuIQs.zip(hyuIQIdxs).foreach {
450    case (imp: IssueQueueMemAddrImp, idx) =>
451      imp.io.memIO.get.feedbackIO.head := io.fromMem.get.hyuFeedback.head
452      imp.io.memIO.get.feedbackIO(1) := 0.U.asTypeOf(imp.io.memIO.get.feedbackIO(1))
453      imp.io.memIO.get.checkWait.stIssuePtr := io.fromMem.get.stIssuePtr
454      imp.io.memIO.get.checkWait.memWaitUpdateReq := io.fromMem.get.memWaitUpdateReq
455      // TODO: refactor ditry code
456      imp.io.deqDelay(1).ready := false.B
457      io.toDataPathAfterDelay(idx)(1).valid := false.B
458      io.toDataPathAfterDelay(idx)(1).bits := 0.U.asTypeOf(io.toDataPathAfterDelay(idx)(1).bits)
459    case _ =>
460  }
461
462  private val staIdxSeq = (stAddrIQs).map(iq => iq.params.idxInSchBlk)
463  private val hyaIdxSeq = (hyuIQs).map(iq => iq.params.idxInSchBlk)
464
465  println(s"[SchedulerMemImp] sta iq idx in memSchdBlock: $staIdxSeq")
466  println(s"[SchedulerMemImp] hya iq idx in memSchdBlock: $hyaIdxSeq")
467
468  private val staEnqs = stAddrIQs.map(_.io.enq).flatten
469  private val stdEnqs = stDataIQs.map(_.io.enq).flatten.take(staEnqs.size)
470  private val hyaEnqs = hyuIQs.map(_.io.enq).flatten
471  private val hydEnqs = stDataIQs.map(_.io.enq).flatten.drop(staEnqs.size)
472
473  require(staEnqs.size == stdEnqs.size, s"number of enq ports of store address IQs(${staEnqs.size}) " +
474  s"should be equal to number of enq ports of store data IQs(${stdEnqs.size})")
475
476  require(hyaEnqs.size == hydEnqs.size, s"number of enq ports of hybrid address IQs(${hyaEnqs.size}) " +
477  s"should be equal to number of enq ports of hybrid data IQs(${hydEnqs.size})")
478
479  stDataIQs.zipWithIndex.foreach { case (iq, i) =>
480    iq.io.flush <> io.fromCtrlBlock.flush
481    iq.io.wakeupFromWB.zip(
482      wakeupFromIntWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromIntWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
483      wakeupFromFpWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromFpWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
484      wakeupFromVfWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromVfWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
485      wakeupFromV0WBVec.zipWithIndex.filter(x => iq.params.needWakeupFromV0WBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
486      wakeupFromVlWBVec.zipWithIndex.filter(x => iq.params.needWakeupFromVlWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq
487    ).foreach{ case (sink, source) => sink := source}
488    iq.io.wakeupFromWBDelayed.zip(
489      wakeupFromIntWBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromIntWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
490      wakeupFromFpWBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromFpWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
491      wakeupFromVfWBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromVfWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
492      wakeupFromV0WBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromV0WBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
493      wakeupFromVlWBVecDelayed.zipWithIndex.filter(x => iq.params.needWakeupFromVlWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq
494    ).foreach { case (sink, source) => sink := source }
495    // here disable fp load fast wakeup to std, and no FEX wakeup to std
496    iq.io.wakeupFromIQ.map(_.bits.fpWen := false.B)
497  }
498
499  (stdEnqs ++ hydEnqs).zip(staEnqs ++ hyaEnqs).zipWithIndex.foreach { case ((stdIQEnq, staIQEnq), i) =>
500    stdIQEnq.valid := staValidFromDispatch(i)
501    stdIQEnq.bits  := staIQEnq.bits
502    // Store data reuses store addr src(1) in dispatch2iq
503    // [dispatch2iq] --src*------src*(0)--> [staIQ|hyaIQ]
504    //                       \
505    //                        ---src*(1)--> [stdIQ]
506    // Since the src(1) of sta is easier to get, stdIQEnq.bits.src*(0) is assigned to staIQEnq.bits.src*(1)
507    // instead of dispatch2Iq.io.out(x).bits.src*(1)
508    val stdIdx = 1
509    stdIQEnq.bits.srcState(0) := staIQEnq.bits.srcState(stdIdx)
510    stdIQEnq.bits.srcLoadDependency(0) := staIQEnq.bits.srcLoadDependency(stdIdx)
511    stdIQEnq.bits.srcType(0) := staIQEnq.bits.srcType(stdIdx)
512    stdIQEnq.bits.psrc(0) := staIQEnq.bits.psrc(stdIdx)
513    stdIQEnq.bits.sqIdx := staIQEnq.bits.sqIdx
514    stdIQEnq.bits.useRegCache(0) := staIQEnq.bits.useRegCache(stdIdx)
515    stdIQEnq.bits.regCacheIdx(0) := staIQEnq.bits.regCacheIdx(stdIdx)
516  }
517
518  vecMemIQs.foreach {
519    case imp: IssueQueueVecMemImp =>
520      imp.io.memIO.get.sqDeqPtr.foreach(_ := io.fromMem.get.sqDeqPtr)
521      imp.io.memIO.get.lqDeqPtr.foreach(_ := io.fromMem.get.lqDeqPtr)
522      // not used
523      //imp.io.memIO.get.feedbackIO.head := io.fromMem.get.vstuFeedback.head // only vector store replay
524      // maybe not used
525      imp.io.memIO.get.checkWait.stIssuePtr := io.fromMem.get.stIssuePtr
526      imp.io.memIO.get.checkWait.memWaitUpdateReq := io.fromMem.get.memWaitUpdateReq
527      imp.io.wakeupFromWB.zip(
528        wakeupFromIntWBVec.zipWithIndex.filter(x => imp.params.needWakeupFromIntWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
529        wakeupFromFpWBVec.zipWithIndex.filter(x => imp.params.needWakeupFromFpWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
530        wakeupFromVfWBVec.zipWithIndex.filter(x => imp.params.needWakeupFromVfWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
531        wakeupFromV0WBVec.zipWithIndex.filter(x => imp.params.needWakeupFromV0WBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
532        wakeupFromVlWBVec.zipWithIndex.filter(x => imp.params.needWakeupFromVlWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq
533      ).foreach{ case (sink, source) => sink := source}
534      imp.io.wakeupFromWBDelayed.zip(
535        wakeupFromIntWBVecDelayed.zipWithIndex.filter(x => imp.params.needWakeupFromIntWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
536        wakeupFromFpWBVecDelayed.zipWithIndex.filter(x => imp.params.needWakeupFromFpWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
537        wakeupFromVfWBVecDelayed.zipWithIndex.filter(x => imp.params.needWakeupFromVfWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
538        wakeupFromV0WBVecDelayed.zipWithIndex.filter(x => imp.params.needWakeupFromV0WBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq ++
539        wakeupFromVlWBVecDelayed.zipWithIndex.filter(x => imp.params.needWakeupFromVlWBPort.keys.toSeq.contains(x._2)).map(_._1).toSeq
540      ).foreach { case (sink, source) => sink := source }
541
542    case _ =>
543  }
544  val vecMemFeedbackIO: Seq[MemRSFeedbackIO] = vecMemIQs.map {
545    case imp: IssueQueueVecMemImp =>
546      imp.io.memIO.get.feedbackIO
547  }.flatten
548  assert(vecMemFeedbackIO.size == io.fromMem.get.vstuFeedback.size, "vecMemFeedback size dont match!")
549  vecMemFeedbackIO.zip(io.fromMem.get.vstuFeedback).foreach{
550    case (sink, source) =>
551      sink := source
552  }
553
554  val perfEvents = basePerfEvents
555  generatePerfEvent()
556}
557