xref: /XiangShan/src/main/scala/xiangshan/backend/rename/BusyTable.scala (revision dc4fac130426dbec49b49d778b9105d79b4a8eab)
1/***************************************************************************************
2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*
5* XiangShan is licensed under Mulan PSL v2.
6* You can use this software according to the terms and conditions of the Mulan PSL v2.
7* You may obtain a copy of Mulan PSL v2 at:
8*          http://license.coscl.org.cn/MulanPSL2
9*
10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*
14* See the Mulan PSL v2 for more details.
15***************************************************************************************/
16
17package xiangshan.backend.rename
18
19import org.chipsalliance.cde.config.Parameters
20import chisel3._
21import chisel3.util._
22import xiangshan._
23import utils._
24import utility._
25import xiangshan.backend.Bundles._
26import xiangshan.backend.datapath.WbConfig._
27import xiangshan.backend.issue.SchdBlockParams
28import xiangshan.backend.datapath.{DataSource}
29
30class BusyTableReadIO(implicit p: Parameters) extends XSBundle {
31  val req = Input(UInt(PhyRegIdxWidth.W))
32  val resp = Output(Bool())
33  val loadDependency = Vec(LoadPipelineWidth, Output(UInt(LoadDependencyWidth.W)))
34}
35
36class VlBusyTableReadIO(implicit p: Parameters) extends XSBundle {
37  val is_zero = Output(Bool())
38  val is_vlmax = Output(Bool())
39}
40
41class BusyTable(numReadPorts: Int, numWritePorts: Int, numPhyPregs: Int, pregWB: PregWB)(implicit p: Parameters, params: SchdBlockParams) extends XSModule with HasPerfEvents {
42  val io = IO(new Bundle() {
43    // set preg state to busy
44    val allocPregs = Vec(RenameWidth, Flipped(ValidIO(UInt(PhyRegIdxWidth.W))))
45    // set preg state to ready (write back regfile + rob walk)
46    val wbPregs = Vec(numWritePorts, Flipped(ValidIO(UInt(PhyRegIdxWidth.W))))
47    // fast wakeup
48    val wakeUp: MixedVec[ValidIO[IssueQueueIQWakeUpBundle]] = Flipped(params.genIQWakeUpInValidBundle)
49    // cancelFromDatapath
50    val og0Cancel = Input(ExuVec())
51    // cancelFromMem
52    val ldCancel = Vec(backendParams.LdExuCnt, Flipped(new LoadCancelIO))
53    // read preg state
54    val read = Vec(numReadPorts, new BusyTableReadIO)
55  })
56
57  val allExuParams = params.backendParam.allExuParams
58  val intBusyTableNeedLoadCancel = allExuParams.map(x =>
59    x.needLoadDependency && x.writeIntRf && x.iqWakeUpSourcePairs.map(y => y.sink.getExuParam(allExuParams).readIntRf).foldLeft(false)(_ || _)
60  ).reduce(_ || _)
61  val fpBusyTableNeedLoadCancel = allExuParams.map(x =>
62    x.needLoadDependency && x.writeFpRf && x.iqWakeUpSourcePairs.map(y => y.sink.getExuParam(allExuParams).readFpRf).foldLeft(false)(_ || _)
63  ).reduce(_ || _)
64  val vfBusyTableNeedLoadCancel = allExuParams.map(x =>
65    x.needLoadDependency && x.writeVfRf && x.iqWakeUpSourcePairs.map(y => y.sink.getExuParam(allExuParams).readVecRf).foldLeft(false)(_ || _)
66  ).reduce(_ || _)
67  val v0BusyTableNeedLoadCancel = allExuParams.map(x =>
68    x.needLoadDependency && x.writeV0Rf && x.iqWakeUpSourcePairs.map(y => y.sink.getExuParam(allExuParams).readVecRf).foldLeft(false)(_ || _)
69  ).reduce(_ || _)
70  val vlBusyTableNeedLoadCancel = allExuParams.map(x =>
71    x.needLoadDependency && x.writeVlRf && x.iqWakeUpSourcePairs.map(y => y.sink.getExuParam(allExuParams).readVlRf).foldLeft(false)(_ || _)
72  ).reduce(_ || _)
73  val needLoadCancel = pregWB match {
74    case IntWB(_, _) => intBusyTableNeedLoadCancel
75    case FpWB(_, _) => fpBusyTableNeedLoadCancel
76    case VfWB(_, _) => vfBusyTableNeedLoadCancel
77    case V0WB(_, _) => v0BusyTableNeedLoadCancel
78    case VlWB(_, _) => vlBusyTableNeedLoadCancel
79    case _ => throw new IllegalArgumentException(s"WbConfig ${pregWB} is not permitted")
80  }
81  if (!needLoadCancel) println(s"[BusyTable]: WbConfig ${pregWB} busyTable don't need loadCancel")
82  val loadCancel = if (needLoadCancel) io.ldCancel else 0.U.asTypeOf(io.ldCancel)
83  val wakeUpIn = pregWB match {
84    case IntWB(_, _) => io.wakeUp.filter(_.bits.params.writeIntRf)
85    case FpWB(_, _) => io.wakeUp.filter(_.bits.params.writeFpRf)
86    case VfWB(_, _) => io.wakeUp.filter(_.bits.params.writeVfRf)
87    case V0WB(_, _) => io.wakeUp.filter(_.bits.params.writeV0Rf)
88    case VlWB(_, _) => io.wakeUp.filter(_.bits.params.writeVlRf)
89    case _ => throw new IllegalArgumentException(s"WbConfig ${pregWB} is not permitted")
90  }
91  val loadDependency = RegInit(0.U.asTypeOf(Vec(numPhyPregs, Vec(LoadPipelineWidth, UInt(LoadDependencyWidth.W)))))
92  val shiftLoadDependency = Wire(Vec(wakeUpIn.size, Vec(LoadPipelineWidth, UInt(LoadDependencyWidth.W))))
93  val tableUpdate = Wire(Vec(numPhyPregs, Bool()))
94  val wakeupOHVec = Wire(Vec(numPhyPregs, UInt(wakeUpIn.size.W)))
95
96  def reqVecToMask(rVec: Vec[Valid[UInt]]): UInt = {
97    ParallelOR(rVec.map(v => Mux(v.valid, UIntToOH(v.bits), 0.U)))
98  }
99
100  shiftLoadDependency.zip(wakeUpIn).map{ case (deps, wakeup) =>
101    if (wakeup.bits.params.hasLoadExu) {
102      deps.zipWithIndex.map{ case (dep, i) =>
103        if (backendParams.getLdExuIdx(wakeup.bits.params) == i) dep := 1.U
104        else dep := 0.U
105      }
106    }
107    else {
108      deps.zip(wakeup.bits.loadDependency).map{ case (sink, source) =>
109        sink := source << 1
110      }
111    }
112  }
113
114  wakeupOHVec.zipWithIndex.foreach{ case (wakeupOH, idx) =>
115    val tmp = pregWB match {
116      case IntWB(_, _) => wakeUpIn.map(x => x.valid && x.bits.rfWen  && UIntToOH(x.bits.pdest)(idx) && !LoadShouldCancel(Some(x.bits.loadDependency), loadCancel) && !(x.bits.is0Lat && io.og0Cancel(x.bits.params.exuIdx)))
117      case FpWB(_, _)  => wakeUpIn.map(x => x.valid && x.bits.fpWen  && UIntToOH(x.bits.pdest)(idx) && !LoadShouldCancel(Some(x.bits.loadDependency), loadCancel) && !(x.bits.is0Lat && io.og0Cancel(x.bits.params.exuIdx)))
118      case VfWB(_, _)  => wakeUpIn.map(x => x.valid && x.bits.vecWen && UIntToOH(x.bits.pdest)(idx) && !LoadShouldCancel(Some(x.bits.loadDependency), loadCancel) && !(x.bits.is0Lat && io.og0Cancel(x.bits.params.exuIdx)))
119      case V0WB(_, _)  => wakeUpIn.map(x => x.valid && x.bits.v0Wen  && UIntToOH(x.bits.pdest)(idx) && !LoadShouldCancel(Some(x.bits.loadDependency), loadCancel) && !(x.bits.is0Lat && io.og0Cancel(x.bits.params.exuIdx)))
120      case VlWB(_, _)  => wakeUpIn.map(x => x.valid && x.bits.vlWen  && UIntToOH(x.bits.pdest)(idx) && !LoadShouldCancel(Some(x.bits.loadDependency), loadCancel) && !(x.bits.is0Lat && io.og0Cancel(x.bits.params.exuIdx)))
121      case _ => throw new IllegalArgumentException(s"WbConfig ${pregWB} is not permitted")
122    }
123    wakeupOH := (if (wakeUpIn.nonEmpty) VecInit(tmp.toSeq).asUInt else 0.U)
124  }
125  val wbMask = reqVecToMask(io.wbPregs)
126  val allocMask = reqVecToMask(io.allocPregs)
127  val wakeUpMask = VecInit(wakeupOHVec.map(_.orR).toSeq).asUInt
128  val ldCancelMask = loadDependency.map(x => LoadShouldCancel(Some(x), loadCancel))
129
130  loadDependency.zipWithIndex.foreach{ case (ldDp, idx) =>
131    when(wakeUpMask(idx)) {
132      ldDp := (if (wakeUpIn.nonEmpty) Mux1H(wakeupOHVec(idx), shiftLoadDependency) else 0.U.asTypeOf(ldDp))
133    }
134    .elsewhen(ldDp.map(x => x.orR).reduce(_ | _)) {
135      ldDp := VecInit(ldDp.map(x => x << 1))
136    }
137  }
138
139  /*
140  we can ensure that the following conditions are mutually exclusive
141  wakeUp and cancel (same pdest) may arrive at the same cycle
142  for a pdest:
143    rename alloc => wakeUp / cancel => ... => wakeUp / cancel => wakeUp
144  or
145    rename alloc => wbMask  //TODO we still need wbMask because wakeUp signal is partial now
146  in wakeUpMask, we filter ogCancel and loadTransCancel at the same cycle
147   */
148  val table = VecInit((0 until numPhyPregs).zip(tableUpdate).map{ case (idx, update) =>
149    RegEnable(update, 0.U(1.W), allocMask(idx) || ldCancelMask(idx) || wakeUpMask(idx) || wbMask(idx))
150  }).asUInt
151
152  tableUpdate.zipWithIndex.foreach{ case (update, idx) =>
153    when(wakeUpMask(idx) || wbMask(idx)) {
154      update := false.B                                   //ready
155    }
156    .elsewhen(allocMask(idx) || ldCancelMask(idx)) {
157      update := true.B                                    //busy
158      if (idx == 0 && pregWB.isInstanceOf[IntWB]) {
159          // Int RegFile 0 is always ready
160          update := false.B
161      }
162    }
163    .otherwise {
164      update := table(idx)
165    }
166  }
167
168  io.read.foreach{ case res =>
169    res.resp := !table(res.req)
170    res.loadDependency := loadDependency(res.req)
171  }
172
173  val oddTable = table.asBools.zipWithIndex.filter(_._2 % 2 == 1).map(_._1)
174  val evenTable = table.asBools.zipWithIndex.filter(_._2 % 2 == 0).map(_._1)
175  val busyCount = RegNext(RegNext(PopCount(oddTable)) + RegNext(PopCount(evenTable)))
176
177  XSPerfAccumulate("busy_count", PopCount(table))
178
179  val perfEvents = Seq(
180    ("bt_std_freelist_1_4_valid", busyCount < (numPhyPregs / 4).U                                        ),
181    ("bt_std_freelist_2_4_valid", busyCount > (numPhyPregs / 4).U && busyCount <= (numPhyPregs / 2).U    ),
182    ("bt_std_freelist_3_4_valid", busyCount > (numPhyPregs / 2).U && busyCount <= (numPhyPregs * 3 / 4).U),
183    ("bt_std_freelist_4_4_valid", busyCount > (numPhyPregs * 3 / 4).U                                    )
184  )
185  generatePerfEvent()
186}
187
188class VlBusyTable(numReadPorts: Int, numWritePorts: Int, numPhyPregs: Int, pregWB: PregWB)(implicit p: Parameters, params: SchdBlockParams) extends BusyTable(numReadPorts, numWritePorts, numPhyPregs, pregWB) {
189
190  val io_vl_Wb = IO(new Bundle() {
191    val vlWriteBackInfo = new Bundle {
192      val vlFromIntIsZero  = Input(Bool())
193      val vlFromIntIsVlmax = Input(Bool())
194      val vlFromVfIsZero   = Input(Bool())
195      val vlFromVfIsVlmax  = Input(Bool())
196    }
197  })
198  val io_vl_read = IO(new Bundle() {
199    val vlReadInfo = Vec(numReadPorts, new VlBusyTableReadIO)
200  })
201
202  var intSchdVlWbPort = p(XSCoreParamsKey).intSchdVlWbPort
203  var vfSchdVlWbPort = p(XSCoreParamsKey).vfSchdVlWbPort
204
205  val zeroTableUpdate = Wire(Vec(numPhyPregs, Bool()))
206  val vlmaxTableUpdate = Wire(Vec(numPhyPregs, Bool()))
207
208  val intVlWb = Mux(io.wbPregs(intSchdVlWbPort).valid, UIntToOH(io.wbPregs(intSchdVlWbPort).bits), 0.U)
209  val vfVlWb = Mux(io.wbPregs(vfSchdVlWbPort).valid, UIntToOH(io.wbPregs(vfSchdVlWbPort).bits), 0.U)
210
211  val zeroTable = VecInit((0 until numPhyPregs).zip(zeroTableUpdate).map{ case (idx, update) =>
212    RegEnable(update, 0.U(1.W), allocMask(idx) || ldCancelMask(idx) || intVlWb(idx) || vfVlWb(idx))
213  }).asUInt
214  val vlmaxTable = VecInit((0 until numPhyPregs).zip(vlmaxTableUpdate).map{ case (idx, update) =>
215    RegEnable(update, 0.U(1.W), allocMask(idx) || ldCancelMask(idx) || intVlWb(idx) || vfVlWb(idx))
216  }).asUInt
217
218
219  zeroTableUpdate.zipWithIndex.foreach{ case (update, idx) =>
220    when(intVlWb(idx)) {
221      // int schd vl write back, check whether the vl is zero
222      update := !io_vl_Wb.vlWriteBackInfo.vlFromIntIsZero
223    }.elsewhen(vfVlWb(idx)) {
224      // vf schd vl write back, check whether the vl is zero
225      update := !io_vl_Wb.vlWriteBackInfo.vlFromVfIsZero
226    }.elsewhen(allocMask(idx) || ldCancelMask(idx)) {
227      update := true.B
228    }.otherwise {
229      update := zeroTable(idx)
230    }
231  }
232
233  vlmaxTableUpdate.zipWithIndex.foreach{ case (update, idx) =>
234    when(intVlWb(idx)) {
235      // int schd vl write back, check whether the vl is vlmax
236      update := !io_vl_Wb.vlWriteBackInfo.vlFromIntIsVlmax
237    }.elsewhen(vfVlWb(idx)) {
238      // vf schd vl write back, check whether the vl is vlmax
239      update := !io_vl_Wb.vlWriteBackInfo.vlFromVfIsVlmax
240    }.elsewhen(allocMask(idx) || ldCancelMask(idx)) {
241      update := true.B
242    }.otherwise {
243      update := vlmaxTable(idx)
244    }
245  }
246
247  io_vl_read.vlReadInfo.zip(io.read).foreach{ case (vlRes, res) =>
248    vlRes.is_zero := !zeroTable(res.req)
249    vlRes.is_vlmax := !vlmaxTable(res.req)
250  }
251}
252