xref: /XiangShan/src/main/scala/xiangshan/backend/issue/Scheduler.scala (revision 68d130856f32eb5a07b1be2c23b3724a5a590e46)
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 fromCtrlBlock = new Bundle {
45    val pcVec = Input(Vec(params.numPcReadPort, UInt(VAddrData().dataWidth.W)))
46    val targetVec = Input(Vec(params.numPcReadPort, UInt(VAddrData().dataWidth.W)))
47    val flush = Flipped(ValidIO(new Redirect))
48  }
49  val fromDispatch = new Bundle {
50    val allocPregs = Vec(RenameWidth, Input(new ResetPregStateReq))
51    val uops =  Vec(params.numUopIn, Flipped(DecoupledIO(new DynInst)))
52  }
53  val intWriteBack = MixedVec(Vec(backendParams.intPregParams.numWrite,
54    new RfWritePortWithConfig(backendParams.intPregParams.dataCfg, backendParams.intPregParams.addrWidth)))
55  val vfWriteBack = MixedVec(Vec(backendParams.vfPregParams.numWrite,
56    new RfWritePortWithConfig(backendParams.vfPregParams.dataCfg, backendParams.vfPregParams.addrWidth)))
57  val toDataPath: MixedVec[MixedVec[DecoupledIO[Bundles.IssueQueueIssueBundle]]] = MixedVec(params.issueBlockParams.map(_.genIssueDecoupledBundle))
58  val fromDataPath: MixedVec[MixedVec[Bundles.OGRespBundle]] = MixedVec(params.issueBlockParams.map(x => Flipped(x.genOGRespBundle)))
59
60  val memIO = if (params.isMemSchd) Some(new Bundle {
61    val feedbackIO = Flipped(Vec(params.StaCnt, new MemRSFeedbackIO))
62    val lsqEnqIO = Flipped(new LsqEnqIO)
63  }) else None
64  val fromMem = if (params.isMemSchd) Some(new Bundle {
65    val stIssuePtr = Input(new SqPtr())
66    val lcommit = Input(UInt(log2Up(CommitWidth + 1).W))
67    val scommit = Input(UInt(log2Ceil(EnsbufferWidth + 1).W)) // connected to `memBlock.io.sqDeq` instead of ROB
68    // from lsq
69    val lqCancelCnt = Input(UInt(log2Up(LoadQueueSize + 1).W))
70    val sqCancelCnt = Input(UInt(log2Up(StoreQueueSize + 1).W))
71    val memWaitUpdateReq = Flipped(new MemWaitUpdateReq)
72  }) else None
73  val toMem = if (params.isMemSchd) Some(new Bundle {
74    val loadFastMatch = Output(Vec(params.LduCnt, new IssueQueueLoadBundle))
75  }) else None
76}
77
78abstract class SchedulerImpBase(wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
79  extends LazyModuleImp(wrapper)
80    with HasXSParameter
81{
82  val io = IO(new SchedulerIO())
83
84  // alias
85  private val schdType = params.schdType
86  private val (numRfRead, numRfWrite) = params.numRfReadWrite.getOrElse((0, 0))
87  private val numPregs = params.numPregs
88
89  // Modules
90  val dispatch2Iq: Dispatch2IqImp = wrapper.dispatch2Iq.module
91  val issueQueues: Seq[IssueQueueImp] = wrapper.issueQueue.map(_.module)
92
93  // BusyTable Modules
94  val intBusyTable = schdType match {
95    case IntScheduler() | MemScheduler() => Some(Module(new BusyTable(dispatch2Iq.numIntStateRead, wrapper.numIntStateWrite)))
96    case _ => None
97  }
98
99  val vfBusyTable = schdType match {
100    case VfScheduler() | MemScheduler() => Some(Module(new BusyTable(dispatch2Iq.numVfStateRead, wrapper.numVfStateWrite)))
101    case _ => None
102  }
103
104  dispatch2Iq.io match { case dp2iq =>
105    dp2iq.redirect <> io.fromCtrlBlock.flush
106    dp2iq.in <> io.fromDispatch.uops
107    dp2iq.readIntState.foreach(_ <> intBusyTable.get.io.read)
108    dp2iq.readVfState.foreach(_ <> vfBusyTable.get.io.read)
109  }
110
111  intBusyTable match {
112    case Some(bt) =>
113      bt.io.allocPregs.zip(io.fromDispatch.allocPregs).foreach { case (btAllocPregs, dpAllocPregs) =>
114        btAllocPregs.valid := dpAllocPregs.isInt
115        btAllocPregs.bits := dpAllocPregs.preg
116      }
117      bt.io.wbPregs.zipWithIndex.foreach { case (wb, i) =>
118        wb.valid := io.intWriteBack(i).wen && io.intWriteBack(i).intWen
119        wb.bits := io.intWriteBack(i).addr
120      }
121    case None =>
122  }
123
124  vfBusyTable match {
125    case Some(bt) =>
126      bt.io.allocPregs.zip(io.fromDispatch.allocPregs).foreach { case (btAllocPregs, dpAllocPregs) =>
127        btAllocPregs.valid := dpAllocPregs.isFp
128        btAllocPregs.bits := dpAllocPregs.preg
129      }
130      bt.io.wbPregs.zipWithIndex.foreach { case (wb, i) =>
131        wb.valid := io.vfWriteBack(i).wen && (io.vfWriteBack(i).fpWen || io.vfWriteBack(i).vecWen)
132        wb.bits := io.vfWriteBack(i).addr
133      }
134    case None =>
135  }
136
137  val wakeupFromWBVec = Wire(Vec(params.numWakeupFromWB, ValidIO(new IssueQueueWakeUpBundle(params.pregIdxWidth))))
138  val writeback = params.schdType match {
139    case IntScheduler() => io.intWriteBack
140    case MemScheduler() => io.intWriteBack ++ io.vfWriteBack
141    case VfScheduler() => io.vfWriteBack
142    case _ => Seq()
143  }
144  wakeupFromWBVec.zip(writeback).foreach { case (sink, source) =>
145    sink.valid := source.wen
146    sink.bits.rfWen := source.intWen
147    sink.bits.fpWen := source.fpWen
148    sink.bits.vecWen := source.vecWen
149    sink.bits.pdest := source.addr
150  }
151
152  io.toDataPath.zipWithIndex.foreach { case (toDp, i) =>
153    toDp <> issueQueues(i).io.deq
154  }
155}
156
157class SchedulerArithImp(override val wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
158  extends SchedulerImpBase(wrapper)
159    with HasXSParameter
160{
161  println(s"[SchedulerArithImp] " +
162    s"has intBusyTable: ${intBusyTable.nonEmpty}, " +
163    s"has vfBusyTable: ${vfBusyTable.nonEmpty}")
164
165  issueQueues.zipWithIndex.foreach { case (iq, i) =>
166    iq.io.flush <> io.fromCtrlBlock.flush
167    iq.io.enq <> dispatch2Iq.io.out(i)
168    iq.io.wakeup := wakeupFromWBVec
169    iq.io.deqResp.zipWithIndex.foreach { case (deqResp, j) =>
170      deqResp.valid := iq.io.deq(j).valid && io.toDataPath(i)(j).ready
171      deqResp.bits.success := false.B
172      deqResp.bits.respType := RSFeedbackType.issueSuccess
173      deqResp.bits.addrOH := iq.io.deq(j).bits.addrOH
174    }
175    iq.io.og0Resp.zipWithIndex.foreach { case (og0Resp, j) =>
176      og0Resp.valid := io.fromDataPath(i)(j).og0resp.valid
177      og0Resp.bits.success := false.B // Todo: remove it
178      og0Resp.bits.respType := io.fromDataPath(i)(j).og0resp.bits.respType
179      og0Resp.bits.addrOH := io.fromDataPath(i)(j).og0resp.bits.addrOH
180    }
181    iq.io.og1Resp.zipWithIndex.foreach { case (og1Resp, j) =>
182      og1Resp.valid := io.fromDataPath(i)(j).og1resp.valid
183      og1Resp.bits.success := false.B
184      og1Resp.bits.respType := io.fromDataPath(i)(j).og1resp.bits.respType
185      og1Resp.bits.addrOH := io.fromDataPath(i)(j).og1resp.bits.addrOH
186    }
187  }
188
189  val iqJumpBundleVec: Seq[IssueQueueJumpBundle] = issueQueues.map {
190    case imp: IssueQueueIntImp => imp.io.enqJmp
191    case _ => None
192  }.filter(_.nonEmpty).flatMap(_.get)
193  println(s"[Scheduler] iqJumpBundleVec: ${iqJumpBundleVec}")
194
195  iqJumpBundleVec.zip(io.fromCtrlBlock.pcVec zip io.fromCtrlBlock.targetVec).foreach { case (iqJmp, (pc, target)) =>
196    iqJmp.pc := pc
197    iqJmp.target := target
198  }
199}
200
201class SchedulerMemImp(override val wrapper: Scheduler)(implicit params: SchdBlockParams, p: Parameters)
202  extends SchedulerImpBase(wrapper)
203    with HasXSParameter
204{
205  println(s"[SchedulerMemImp] " +
206    s"has intBusyTable: ${intBusyTable.nonEmpty}, " +
207    s"has vfBusyTable: ${vfBusyTable.nonEmpty}")
208
209  val memAddrIQs = issueQueues.filter(iq => iq.params.StdCnt == 0)
210  val stAddrIQs = issueQueues.filter(iq => iq.params.StaCnt > 0) // included in memAddrIQs
211  val stDataIQs = issueQueues.filter(iq => iq.params.StdCnt > 0)
212  require(memAddrIQs.nonEmpty && stDataIQs.nonEmpty)
213
214  issueQueues.zipWithIndex.foreach { case (iq, i) =>
215    iq.io.deqResp.zipWithIndex.foreach { case (deqResp, j) =>
216      deqResp.valid := iq.io.deq(j).valid && io.toDataPath(i)(j).ready
217      deqResp.bits.success := false.B
218      deqResp.bits.respType := RSFeedbackType.issueSuccess
219      deqResp.bits.addrOH := iq.io.deq(j).bits.addrOH
220    }
221    iq.io.og0Resp.zipWithIndex.foreach { case (og0Resp, j) =>
222      og0Resp.valid := io.fromDataPath(i)(j).og0resp.valid
223      og0Resp.bits.success := false.B // Todo: remove it
224      og0Resp.bits.respType := io.fromDataPath(i)(j).og0resp.bits.respType
225      og0Resp.bits.addrOH := io.fromDataPath(i)(j).og0resp.bits.addrOH
226    }
227    iq.io.og1Resp.zipWithIndex.foreach { case (og1Resp, j) =>
228      og1Resp.valid := io.fromDataPath(i)(j).og1resp.valid
229      og1Resp.bits.success := false.B
230      og1Resp.bits.respType := io.fromDataPath(i)(j).og1resp.bits.respType
231      og1Resp.bits.addrOH := io.fromDataPath(i)(j).og1resp.bits.addrOH
232    }
233  }
234
235  memAddrIQs.zipWithIndex.foreach { case (iq, i) =>
236    iq.io.flush <> io.fromCtrlBlock.flush
237    iq.io.enq <> dispatch2Iq.io.out(i)
238    iq.io.wakeup := wakeupFromWBVec
239  }
240
241
242  dispatch2Iq.io.out(1).zip(stAddrIQs(0).io.enq).zip(stDataIQs(0).io.enq).foreach{ case((di, staIQ), stdIQ) =>
243    val isAllReady = staIQ.ready && stdIQ.ready
244    di.ready := isAllReady
245    staIQ.valid := di.valid && isAllReady
246    stdIQ.valid := di.valid && isAllReady
247  }
248
249  require(stAddrIQs.size == stDataIQs.size, s"number of store address IQs(${stAddrIQs.size}) " +
250    s"should be equal to number of data IQs(${stDataIQs})")
251  stDataIQs.zip(stAddrIQs).zipWithIndex.foreach { case ((stdIQ, staIQ), i) =>
252    stdIQ.io.flush <> io.fromCtrlBlock.flush
253
254    stdIQ.io.enq.zip(staIQ.io.enq).foreach { case (stdIQEnq, staIQEnq) =>
255      stdIQEnq.bits  := staIQEnq.bits
256      // Store data reuses store addr src(1) in dispatch2iq
257      // [dispatch2iq] --src*------src*(0)--> [staIQ]
258      //                       \
259      //                        ---src*(1)--> [stdIQ]
260      // Since the src(1) of sta is easier to get, stdIQEnq.bits.src*(0) is assigned to staIQEnq.bits.src*(1)
261      // instead of dispatch2Iq.io.out(x).bits.src*(1)
262      stdIQEnq.bits.srcState(0) := staIQEnq.bits.srcState(1)
263      stdIQEnq.bits.srcType(0) := staIQEnq.bits.srcType(1)
264      stdIQEnq.bits.psrc(0) := staIQEnq.bits.psrc(1)
265      stdIQEnq.bits.sqIdx := staIQEnq.bits.sqIdx
266    }
267    stdIQ.io.wakeup := wakeupFromWBVec
268  }
269
270  val iqMemBundleVec = stAddrIQs.map {
271    case imp: IssueQueueMemAddrImp => imp.io.memIO
272    case _ => None
273  }.filter(_.nonEmpty).map(_.get)
274  println(s"[Scheduler] iqMemBundleVec: ${iqMemBundleVec}")
275
276  val lsqEnqCtrl = Module(new LsqEnqCtrl)
277
278  lsqEnqCtrl.io.redirect <> io.fromCtrlBlock.flush
279  lsqEnqCtrl.io.enq <> dispatch2Iq.io.enqLsqIO.get
280  lsqEnqCtrl.io.lcommit := io.fromMem.get.lcommit
281  lsqEnqCtrl.io.scommit := io.fromMem.get.scommit
282  lsqEnqCtrl.io.lqCancelCnt := io.fromMem.get.lqCancelCnt
283  lsqEnqCtrl.io.sqCancelCnt := io.fromMem.get.sqCancelCnt
284  io.memIO.get.lsqEnqIO <> lsqEnqCtrl.io.enqLsq
285  require(io.memIO.get.feedbackIO.size == iqMemBundleVec.map(_.feedbackIO.size).sum,
286    s"[SchedulerMemImp] io.memIO.feedbackIO.size(${io.memIO.get.feedbackIO.size}) " +
287      s"should be equal to sum of memIQ.io.feedbackIO.size(${iqMemBundleVec.map(_.feedbackIO.size).sum})")
288
289  val memIQFeedbackIO: Seq[MemRSFeedbackIO] = iqMemBundleVec.flatMap(_.feedbackIO)
290  io.memIO.get.feedbackIO <> memIQFeedbackIO
291}
292