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