xref: /XiangShan/src/main/scala/xiangshan/backend/issue/Scheduler.scala (revision 9896b9c4876c8030f9576af41840cc739c3f49a1)
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    iq.io.wbBusyRead := io.wbFuBusyTable.fuBusyTableRead(i)
283  }
284
285  memAddrIQs.zipWithIndex.foreach { case (iq, i) =>
286    iq.io.flush <> io.fromCtrlBlock.flush
287    iq.io.enq <> dispatch2Iq.io.out(i)
288    iq.io.wakeup := wakeupFromWBVec
289  }
290
291  ldAddrIQs.foreach {
292    case imp: IssueQueueMemAddrImp => imp.io.memIO.get.feedbackIO <> io.fromMem.get.ldaFeedback
293    case _ =>
294  }
295
296  stAddrIQs.foreach {
297    case imp: IssueQueueMemAddrImp => imp.io.memIO.get.feedbackIO <> io.fromMem.get.staFeedback
298    case _ =>
299  }
300
301  dispatch2Iq.io.out(1).zip(stAddrIQs(0).io.enq).zip(stDataIQs(0).io.enq).foreach{ case((di, staIQ), stdIQ) =>
302    val isAllReady = staIQ.ready && stdIQ.ready
303    di.ready := isAllReady
304    staIQ.valid := di.valid && isAllReady
305    stdIQ.valid := di.valid && isAllReady
306  }
307
308  require(stAddrIQs.size == stDataIQs.size, s"number of store address IQs(${stAddrIQs.size}) " +
309    s"should be equal to number of data IQs(${stDataIQs})")
310  stDataIQs.zip(stAddrIQs).zipWithIndex.foreach { case ((stdIQ, staIQ), i) =>
311    stdIQ.io.flush <> io.fromCtrlBlock.flush
312
313    stdIQ.io.enq.zip(staIQ.io.enq).foreach { case (stdIQEnq, staIQEnq) =>
314      stdIQEnq.bits  := staIQEnq.bits
315      // Store data reuses store addr src(1) in dispatch2iq
316      // [dispatch2iq] --src*------src*(0)--> [staIQ]
317      //                       \
318      //                        ---src*(1)--> [stdIQ]
319      // Since the src(1) of sta is easier to get, stdIQEnq.bits.src*(0) is assigned to staIQEnq.bits.src*(1)
320      // instead of dispatch2Iq.io.out(x).bits.src*(1)
321      stdIQEnq.bits.srcState(0) := staIQEnq.bits.srcState(1)
322      stdIQEnq.bits.srcType(0) := staIQEnq.bits.srcType(1)
323      stdIQEnq.bits.psrc(0) := staIQEnq.bits.psrc(1)
324      stdIQEnq.bits.sqIdx := staIQEnq.bits.sqIdx
325    }
326    stdIQ.io.wakeup := wakeupFromWBVec
327  }
328
329  val lsqEnqCtrl = Module(new LsqEnqCtrl)
330
331  lsqEnqCtrl.io.redirect <> io.fromCtrlBlock.flush
332  lsqEnqCtrl.io.enq <> dispatch2Iq.io.enqLsqIO.get
333  lsqEnqCtrl.io.lcommit := io.fromMem.get.lcommit
334  lsqEnqCtrl.io.scommit := io.fromMem.get.scommit
335  lsqEnqCtrl.io.lqCancelCnt := io.fromMem.get.lqCancelCnt
336  lsqEnqCtrl.io.sqCancelCnt := io.fromMem.get.sqCancelCnt
337  io.memIO.get.lsqEnqIO <> lsqEnqCtrl.io.enqLsq
338}
339