xref: /XiangShan/src/main/scala/xiangshan/backend/issue/Scheduler.scala (revision 8d29ec3240ecfd2ed29ce59c324e78e62693faf8)
1package xiangshan.backend.issue
2
3import chipsalliance.rocketchip.config.Parameters
4import chisel3._
5import chisel3.util._
6import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
7import xiangshan._
8import xiangshan.backend.Bundles
9import xiangshan.backend.datapath.DataConfig.VAddrData
10import xiangshan.backend.regfile.RfWritePortWithConfig
11import xiangshan.backend.rename.BusyTable
12import xiangshan.mem.{LsqEnqCtrl, LsqEnqIO, MemWaitUpdateReq, SqPtr}
13import xiangshan.backend.Bundles.{DynInst, IssueQueueWakeUpBundle}
14
15sealed trait SchedulerType
16
17case class IntScheduler() extends SchedulerType
18case class MemScheduler() extends SchedulerType
19case class VfScheduler() extends SchedulerType
20case class NoScheduler() extends SchedulerType
21
22class Scheduler(val params: SchdBlockParams)(implicit p: Parameters) extends LazyModule with HasXSParameter {
23  val numIntStateWrite = backendParams.numIntWb
24  val numVfStateWrite = backendParams.numVfWb
25
26  val dispatch2Iq = LazyModule(new Dispatch2Iq(params))
27  val issueQueue = params.issueBlockParams.map(x => LazyModule(new IssueQueue(x).suggestName(x.getIQName)))
28
29  lazy val module = params.schdType match {
30    case IntScheduler() => new SchedulerArithImp(this)(params, p)
31    case MemScheduler() => new SchedulerMemImp(this)(params, p)
32    case VfScheduler() => new SchedulerArithImp(this)(params, p)
33    case _ => null
34  }
35}
36
37class SchedulerIO()(implicit params: SchdBlockParams, p: Parameters) extends XSBundle {
38  // params alias
39  private val LoadQueueSize = VirtualLoadQueueSize
40
41  val fromTop = new Bundle {
42    val hartId = Input(UInt(8.W))
43  }
44  val wbFuBusyTable = new Bundle{
45    val fuBusyTableWrite = MixedVec(params.issueBlockParams.map(x => x.genFuBusyTableWriteBundle))
46    val fuBusyTableRead = MixedVec(params.issueBlockParams.map(x => Input(x.genFuBusyTableReadBundle)))
47  }
48  val fromCtrlBlock = new Bundle {
49    val pcVec = Input(Vec(params.numPcReadPort, UInt(VAddrData().dataWidth.W)))
50    val targetVec = Input(Vec(params.numPcReadPort, UInt(VAddrData().dataWidth.W)))
51    val flush = Flipped(ValidIO(new Redirect))
52  }
53  val fromDispatch = new Bundle {
54    val allocPregs = Vec(RenameWidth, Input(new ResetPregStateReq))
55    val uops =  Vec(params.numUopIn, Flipped(DecoupledIO(new DynInst)))
56  }
57  val intWriteBack = MixedVec(Vec(backendParams.intPregParams.numWrite,
58    new RfWritePortWithConfig(backendParams.intPregParams.dataCfg, backendParams.intPregParams.addrWidth)))
59  val vfWriteBack = MixedVec(Vec(backendParams.vfPregParams.numWrite,
60    new RfWritePortWithConfig(backendParams.vfPregParams.dataCfg, backendParams.vfPregParams.addrWidth)))
61  val toDataPath: MixedVec[MixedVec[DecoupledIO[Bundles.IssueQueueIssueBundle]]] = MixedVec(params.issueBlockParams.map(_.genIssueDecoupledBundle))
62  val fromDataPath: MixedVec[MixedVec[Bundles.OGRespBundle]] = MixedVec(params.issueBlockParams.map(x => Flipped(x.genOGRespBundle)))
63
64  val memIO = if (params.isMemSchd) Some(new Bundle {
65    val lsqEnqIO = Flipped(new LsqEnqIO)
66  }) else None
67  val fromMem = if (params.isMemSchd) Some(new Bundle {
68    val ldaFeedback = Flipped(Vec(params.LduCnt, new MemRSFeedbackIO))
69    val staFeedback = Flipped(Vec(params.StaCnt, new MemRSFeedbackIO))
70    val stIssuePtr = Input(new SqPtr())
71    val lcommit = Input(UInt(log2Up(CommitWidth + 1).W))
72    val scommit = Input(UInt(log2Ceil(EnsbufferWidth + 1).W)) // connected to `memBlock.io.sqDeq` instead of ROB
73    // from lsq
74    val lqCancelCnt = Input(UInt(log2Up(LoadQueueSize + 1).W))
75    val sqCancelCnt = Input(UInt(log2Up(StoreQueueSize + 1).W))
76    val memWaitUpdateReq = Flipped(new MemWaitUpdateReq)
77  }) else None
78  val toMem = if (params.isMemSchd) Some(new Bundle {
79    val loadFastMatch = Output(Vec(params.LduCnt, new IssueQueueLoadBundle))
80  }) else None
81}
82
83abstract class SchedulerImpBase(wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
84  extends LazyModuleImp(wrapper)
85    with HasXSParameter
86{
87  val io = IO(new SchedulerIO())
88
89  // alias
90  private val schdType = params.schdType
91  private val (numRfRead, numRfWrite) = params.numRfReadWrite.getOrElse((0, 0))
92  private val numPregs = params.numPregs
93
94  // Modules
95  val dispatch2Iq: Dispatch2IqImp = wrapper.dispatch2Iq.module
96  val issueQueues: Seq[IssueQueueImp] = wrapper.issueQueue.map(_.module)
97
98  // BusyTable Modules
99  val intBusyTable = schdType match {
100    case IntScheduler() | MemScheduler() => Some(Module(new BusyTable(dispatch2Iq.numIntStateRead, wrapper.numIntStateWrite)))
101    case _ => None
102  }
103
104  val vfBusyTable = schdType match {
105    case VfScheduler() | MemScheduler() => Some(Module(new BusyTable(dispatch2Iq.numVfStateRead, wrapper.numVfStateWrite)))
106    case _ => None
107  }
108
109  dispatch2Iq.io match { case dp2iq =>
110    dp2iq.redirect <> io.fromCtrlBlock.flush
111    dp2iq.in <> io.fromDispatch.uops
112    dp2iq.readIntState.foreach(_ <> intBusyTable.get.io.read)
113    dp2iq.readVfState.foreach(_ <> vfBusyTable.get.io.read)
114  }
115
116  intBusyTable match {
117    case Some(bt) =>
118      bt.io.allocPregs.zip(io.fromDispatch.allocPregs).foreach { case (btAllocPregs, dpAllocPregs) =>
119        btAllocPregs.valid := dpAllocPregs.isInt
120        btAllocPregs.bits := dpAllocPregs.preg
121      }
122      bt.io.wbPregs.zipWithIndex.foreach { case (wb, i) =>
123        wb.valid := io.intWriteBack(i).wen && io.intWriteBack(i).intWen
124        wb.bits := io.intWriteBack(i).addr
125      }
126    case None =>
127  }
128
129  vfBusyTable match {
130    case Some(bt) =>
131      bt.io.allocPregs.zip(io.fromDispatch.allocPregs).foreach { case (btAllocPregs, dpAllocPregs) =>
132        btAllocPregs.valid := dpAllocPregs.isFp
133        btAllocPregs.bits := dpAllocPregs.preg
134      }
135      bt.io.wbPregs.zipWithIndex.foreach { case (wb, i) =>
136        wb.valid := io.vfWriteBack(i).wen && (io.vfWriteBack(i).fpWen || io.vfWriteBack(i).vecWen)
137        wb.bits := io.vfWriteBack(i).addr
138      }
139    case None =>
140  }
141
142  val wakeupFromWBVec = Wire(Vec(params.numWakeupFromWB, ValidIO(new IssueQueueWakeUpBundle(params.pregIdxWidth))))
143  val writeback = params.schdType match {
144    case IntScheduler() => io.intWriteBack
145    case MemScheduler() => io.intWriteBack ++ io.vfWriteBack
146    case VfScheduler() => io.vfWriteBack
147    case _ => Seq()
148  }
149  wakeupFromWBVec.zip(writeback).foreach { case (sink, source) =>
150    sink.valid := source.wen
151    sink.bits.rfWen := source.intWen
152    sink.bits.fpWen := source.fpWen
153    sink.bits.vecWen := source.vecWen
154    sink.bits.pdest := source.addr
155  }
156
157  io.toDataPath.zipWithIndex.foreach { case (toDp, i) =>
158    toDp <> issueQueues(i).io.deq
159  }
160}
161
162class SchedulerArithImp(override val wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
163  extends SchedulerImpBase(wrapper)
164    with HasXSParameter
165{
166  println(s"[SchedulerArithImp] " +
167    s"has intBusyTable: ${intBusyTable.nonEmpty}, " +
168    s"has vfBusyTable: ${vfBusyTable.nonEmpty}")
169
170  issueQueues.zipWithIndex.foreach { case (iq, i) =>
171    iq.io.flush <> io.fromCtrlBlock.flush
172    iq.io.enq <> dispatch2Iq.io.out(i)
173    iq.io.wakeup := wakeupFromWBVec
174    iq.io.deqResp.zipWithIndex.foreach { case (deqResp, j) =>
175      deqResp.valid := iq.io.deq(j).valid && io.toDataPath(i)(j).ready
176      deqResp.bits.success := false.B
177      deqResp.bits.respType := RSFeedbackType.issueSuccess
178      deqResp.bits.addrOH := iq.io.deq(j).bits.addrOH
179      deqResp.bits.rfWen := iq.io.deq(j).bits.common.rfWen.getOrElse(false.B)
180      deqResp.bits.fuType := iq.io.deq(j).bits.common.fuType
181
182      io.wbFuBusyTable.fuBusyTableWrite(i)(j).deqResp.valid := iq.io.deq(j).valid && io.toDataPath(i)(j).ready
183      io.wbFuBusyTable.fuBusyTableWrite(i)(j).deqResp.bits.fuType := iq.io.deq(j).bits.common.fuType
184      io.wbFuBusyTable.fuBusyTableWrite(i)(j).deqResp.bits.respType := RSFeedbackType.issueSuccess
185      io.wbFuBusyTable.fuBusyTableWrite(i)(j).deqResp.bits.rfWen := iq.io.deq(j).bits.common.rfWen.getOrElse(false.B)
186    }
187    iq.io.og0Resp.zipWithIndex.foreach { case (og0Resp, j) =>
188      og0Resp.valid := io.fromDataPath(i)(j).og0resp.valid
189      og0Resp.bits.success := false.B // Todo: remove it
190      og0Resp.bits.respType := io.fromDataPath(i)(j).og0resp.bits.respType
191      og0Resp.bits.addrOH := io.fromDataPath(i)(j).og0resp.bits.addrOH
192      og0Resp.bits.rfWen := io.fromDataPath(i)(j).og0resp.bits.rfWen
193      og0Resp.bits.fuType := io.fromDataPath(i)(j).og0resp.bits.fuType
194
195      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og0Resp.valid := io.fromDataPath(i)(j).og0resp.valid
196      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og0Resp.bits.fuType := io.fromDataPath(i)(j).og0resp.bits.fuType
197      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og0Resp.bits.respType := io.fromDataPath(i)(j).og0resp.bits.respType
198      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og0Resp.bits.rfWen := io.fromDataPath(i)(j).og0resp.bits.rfWen
199    }
200    iq.io.og1Resp.zipWithIndex.foreach { case (og1Resp, j) =>
201      og1Resp.valid := io.fromDataPath(i)(j).og1resp.valid
202      og1Resp.bits.success := false.B
203      og1Resp.bits.respType := io.fromDataPath(i)(j).og1resp.bits.respType
204      og1Resp.bits.addrOH := io.fromDataPath(i)(j).og1resp.bits.addrOH
205      og1Resp.bits.rfWen := io.fromDataPath(i)(j).og1resp.bits.rfWen
206      og1Resp.bits.fuType := io.fromDataPath(i)(j).og1resp.bits.fuType
207
208      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og1Resp.valid := io.fromDataPath(i)(j).og1resp.valid
209      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og1Resp.bits.fuType := io.fromDataPath(i)(j).og1resp.bits.fuType
210      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og1Resp.bits.respType := io.fromDataPath(i)(j).og1resp.bits.respType
211      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og1Resp.bits.rfWen := io.fromDataPath(i)(j).og1resp.bits.rfWen
212    }
213    iq.io.wbBusyRead := io.wbFuBusyTable.fuBusyTableRead(i)
214  }
215
216  val iqJumpBundleVec: Seq[IssueQueueJumpBundle] = issueQueues.map {
217    case imp: IssueQueueIntImp => imp.io.enqJmp
218    case _ => None
219  }.filter(_.nonEmpty).flatMap(_.get)
220  println(s"[Scheduler] iqJumpBundleVec: ${iqJumpBundleVec}")
221
222  iqJumpBundleVec.zip(io.fromCtrlBlock.pcVec zip io.fromCtrlBlock.targetVec).foreach { case (iqJmp, (pc, target)) =>
223    iqJmp.pc := pc
224    iqJmp.target := target
225  }
226}
227
228class SchedulerMemImp(override val wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
229  extends SchedulerImpBase(wrapper)
230    with HasXSParameter
231{
232  println(s"[SchedulerMemImp] " +
233    s"has intBusyTable: ${intBusyTable.nonEmpty}, " +
234    s"has vfBusyTable: ${vfBusyTable.nonEmpty}")
235
236  val memAddrIQs = issueQueues.filter(iq => iq.params.StdCnt == 0)
237  val stAddrIQs = issueQueues.filter(iq => iq.params.StaCnt > 0) // included in memAddrIQs
238  val ldAddrIQs = issueQueues.filter(iq => iq.params.LduCnt > 0)
239  val stDataIQs = issueQueues.filter(iq => iq.params.StdCnt > 0)
240  require(memAddrIQs.nonEmpty && stDataIQs.nonEmpty)
241
242  issueQueues.zipWithIndex.foreach { case (iq, i) =>
243    iq.io.deqResp.zipWithIndex.foreach { case (deqResp, j) =>
244      deqResp.valid := iq.io.deq(j).valid && io.toDataPath(i)(j).ready
245      deqResp.bits.success := false.B
246      deqResp.bits.respType := RSFeedbackType.issueSuccess
247      deqResp.bits.addrOH := iq.io.deq(j).bits.addrOH
248      deqResp.bits.rfWen := iq.io.deq(j).bits.common.rfWen.getOrElse(false.B)
249      deqResp.bits.fuType := iq.io.deq(j).bits.common.fuType
250
251      io.wbFuBusyTable.fuBusyTableWrite(i)(j).deqResp.valid := iq.io.deq(j).valid && io.toDataPath(i)(j).ready
252      io.wbFuBusyTable.fuBusyTableWrite(i)(j).deqResp.bits.fuType := iq.io.deq(j).bits.common.fuType
253      io.wbFuBusyTable.fuBusyTableWrite(i)(j).deqResp.bits.respType := RSFeedbackType.issueSuccess
254      io.wbFuBusyTable.fuBusyTableWrite(i)(j).deqResp.bits.rfWen := iq.io.deq(j).bits.common.rfWen.getOrElse(false.B)
255    }
256    iq.io.og0Resp.zipWithIndex.foreach { case (og0Resp, j) =>
257      og0Resp.valid := io.fromDataPath(i)(j).og0resp.valid
258      og0Resp.bits.success := false.B // Todo: remove it
259      og0Resp.bits.respType := io.fromDataPath(i)(j).og0resp.bits.respType
260      og0Resp.bits.addrOH := io.fromDataPath(i)(j).og0resp.bits.addrOH
261      og0Resp.bits.rfWen := io.fromDataPath(i)(j).og0resp.bits.rfWen
262      og0Resp.bits.fuType := io.fromDataPath(i)(j).og0resp.bits.fuType
263
264      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og0Resp.valid := io.fromDataPath(i)(j).og0resp.valid
265      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og0Resp.bits.fuType := io.fromDataPath(i)(j).og0resp.bits.fuType
266      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og0Resp.bits.respType := io.fromDataPath(i)(j).og0resp.bits.respType
267      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og0Resp.bits.rfWen := io.fromDataPath(i)(j).og0resp.bits.rfWen
268    }
269    iq.io.og1Resp.zipWithIndex.foreach { case (og1Resp, j) =>
270      og1Resp.valid := io.fromDataPath(i)(j).og1resp.valid
271      og1Resp.bits.success := false.B
272      og1Resp.bits.respType := io.fromDataPath(i)(j).og1resp.bits.respType
273      og1Resp.bits.addrOH := io.fromDataPath(i)(j).og1resp.bits.addrOH
274      og1Resp.bits.rfWen := io.fromDataPath(i)(j).og1resp.bits.rfWen
275      og1Resp.bits.fuType := io.fromDataPath(i)(j).og1resp.bits.fuType
276
277      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og1Resp.valid := io.fromDataPath(i)(j).og1resp.valid
278      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og1Resp.bits.fuType := io.fromDataPath(i)(j).og1resp.bits.fuType
279      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og1Resp.bits.respType := io.fromDataPath(i)(j).og1resp.bits.respType
280      io.wbFuBusyTable.fuBusyTableWrite(i)(j).og1Resp.bits.rfWen := io.fromDataPath(i)(j).og1resp.bits.rfWen
281    }
282  }
283
284  memAddrIQs.zipWithIndex.foreach { case (iq, i) =>
285    iq.io.flush <> io.fromCtrlBlock.flush
286    iq.io.enq <> dispatch2Iq.io.out(i)
287    iq.io.wakeup := wakeupFromWBVec
288  }
289
290  ldAddrIQs.foreach {
291    case imp: IssueQueueMemAddrImp => imp.io.memIO.get.feedbackIO <> io.fromMem.get.ldaFeedback
292    case _ =>
293  }
294
295  stAddrIQs.foreach {
296    case imp: IssueQueueMemAddrImp => imp.io.memIO.get.feedbackIO <> io.fromMem.get.staFeedback
297    case _ =>
298  }
299
300  dispatch2Iq.io.out(1).zip(stAddrIQs(0).io.enq).zip(stDataIQs(0).io.enq).foreach{ case((di, staIQ), stdIQ) =>
301    val isAllReady = staIQ.ready && stdIQ.ready
302    di.ready := isAllReady
303    staIQ.valid := di.valid && isAllReady
304    stdIQ.valid := di.valid && isAllReady
305  }
306
307  require(stAddrIQs.size == stDataIQs.size, s"number of store address IQs(${stAddrIQs.size}) " +
308    s"should be equal to number of data IQs(${stDataIQs})")
309  stDataIQs.zip(stAddrIQs).zipWithIndex.foreach { case ((stdIQ, staIQ), i) =>
310    stdIQ.io.flush <> io.fromCtrlBlock.flush
311
312    stdIQ.io.enq.zip(staIQ.io.enq).foreach { case (stdIQEnq, staIQEnq) =>
313      stdIQEnq.bits  := staIQEnq.bits
314      // Store data reuses store addr src(1) in dispatch2iq
315      // [dispatch2iq] --src*------src*(0)--> [staIQ]
316      //                       \
317      //                        ---src*(1)--> [stdIQ]
318      // Since the src(1) of sta is easier to get, stdIQEnq.bits.src*(0) is assigned to staIQEnq.bits.src*(1)
319      // instead of dispatch2Iq.io.out(x).bits.src*(1)
320      stdIQEnq.bits.srcState(0) := staIQEnq.bits.srcState(1)
321      stdIQEnq.bits.srcType(0) := staIQEnq.bits.srcType(1)
322      stdIQEnq.bits.psrc(0) := staIQEnq.bits.psrc(1)
323      stdIQEnq.bits.sqIdx := staIQEnq.bits.sqIdx
324    }
325    stdIQ.io.wakeup := wakeupFromWBVec
326  }
327
328  val lsqEnqCtrl = Module(new LsqEnqCtrl)
329
330  lsqEnqCtrl.io.redirect <> io.fromCtrlBlock.flush
331  lsqEnqCtrl.io.enq <> dispatch2Iq.io.enqLsqIO.get
332  lsqEnqCtrl.io.lcommit := io.fromMem.get.lcommit
333  lsqEnqCtrl.io.scommit := io.fromMem.get.scommit
334  lsqEnqCtrl.io.lqCancelCnt := io.fromMem.get.lqCancelCnt
335  lsqEnqCtrl.io.sqCancelCnt := io.fromMem.get.sqCancelCnt
336  io.memIO.get.lsqEnqIO <> lsqEnqCtrl.io.enqLsq
337}
338