xref: /XiangShan/src/main/scala/xiangshan/backend/rename/BusyTable.scala (revision 83ba63b34cf09b33c0a9e1b3203138e51af4491b)
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.{IntWB, VfWB, PregWB}
27import xiangshan.backend.issue.SchdBlockParams
28import xiangshan.backend.datapath.{DataSource}
29
30object RegStatus {
31  val busy = "b11".U
32  val bypass = "b10".U
33  val regFile = "b00".U
34
35  def apply() = UInt(2.W)
36}
37
38class BusyTableReadIO(implicit p: Parameters) extends XSBundle {
39  val req = Input(UInt(PhyRegIdxWidth.W))
40  val resp = Output(Bool())
41  val dataSource = Output(DataSource())
42  val l1ExuOH = Output(ExuVec())
43}
44
45class BusyTable(numReadPorts: Int, numWritePorts: Int, numPhyPregs: Int, pregWB: PregWB)(implicit p: Parameters, params: SchdBlockParams) extends XSModule with HasPerfEvents {
46  val io = IO(new Bundle() {
47    // set preg state to busy
48    val allocPregs = Vec(RenameWidth, Flipped(ValidIO(UInt(PhyRegIdxWidth.W))))
49    // set preg state to ready (write back regfile + rob walk)
50    val wbPregs = Vec(numWritePorts, Flipped(ValidIO(UInt(PhyRegIdxWidth.W))))
51    // fast wakeup
52    val wakeUp: MixedVec[ValidIO[IssueQueueIQWakeUpBundle]] = Flipped(params.genIQWakeUpInValidBundle)
53    // cancelFromDatapath
54    val cancel = Vec(backendParams.numExu, Flipped(ValidIO(new CancelSignal)))
55    // read preg state
56    val read = Vec(numReadPorts, new BusyTableReadIO)
57  })
58
59  val wakeUpReg = Reg(params.genIQWakeUpInValidBundle)
60  val table = RegInit(VecInit(Seq.fill(numPhyPregs)(0.U(2.W))))
61  val tableUpdate = Wire(Vec(numPhyPregs, RegStatus()))
62  val wakeUpFilterLS = io.wakeUp.filter(x => (x.bits.exuIdx != backendParams.getExuIdx("LDU0")) && (x.bits.exuIdx != backendParams.getExuIdx("LDU1")) ) //TODO
63
64  def reqVecToMask(rVec: Vec[Valid[UInt]]): UInt = {
65    ParallelOR(rVec.map(v => Mux(v.valid, UIntToOH(v.bits), 0.U)))
66  }
67
68  val wbMask = reqVecToMask(io.wbPregs)
69  val allocMask = reqVecToMask(io.allocPregs)
70  val wakeUpMask = pregWB match {
71    case _: IntWB => ParallelOR(wakeUpFilterLS.map(x => Mux(x.valid && x.bits.rfWen && !x.bits.loadDependency.asUInt.orR, UIntToOH(x.bits.pdest), 0.U)).toSeq) //TODO: dont implement "load -> wakeUp other -> wakeUp BusyTable" now
72    case _: VfWB => ParallelOR(wakeUpFilterLS.map(x => Mux(x.valid && (x.bits.fpWen || x.bits.vecWen) && !x.bits.loadDependency.asUInt.orR, UIntToOH(x.bits.pdest), 0.U)).toSeq)
73  }
74  val cancelMask = pregWB match {
75    case _: IntWB => ParallelOR(io.cancel.map(x => Mux(x.valid && x.bits.rfWen, UIntToOH(x.bits.pdest), 0.U)))
76    case _: VfWB => ParallelOR(io.cancel.map(x => Mux(x.valid && (x.bits.fpWen || x.bits.vecWen), UIntToOH(x.bits.pdest), 0.U)))
77  }
78
79  /*
80  we can ensure that the following conditions are mutually exclusive
81  wakeUp and cancel (same pdest) would not arrive at the same cycle
82  for a pdest:
83    rename alloc => wakeUp => cancel => ... => wakeUp => cancel => wakeUp
84  or
85    rename alloc => wbMask  //TODO we still need wbMask because wakeUp signal is partial now
86  the bypass state lasts for a maximum of one cycle, cancel(=> busy) or else(=> regFile)
87   */
88  tableUpdate.zipWithIndex.foreach{ case (update, idx) =>
89    when(allocMask(idx)) {
90      update := RegStatus.busy
91    }.elsewhen(wakeUpMask(idx)) {
92      update := RegStatus.bypass
93    }.elsewhen(cancelMask(idx)) {
94      update := RegStatus.busy
95    }.elsewhen((table(idx) === RegStatus.bypass) || wbMask(idx)) {
96      update := RegStatus.regFile
97    }.otherwise {
98      update := table(idx)
99    }
100  }
101
102  io.read.foreach{ case res =>
103    res.resp := Mux(!cancelMask(res.req), !table(res.req).andR, false.B)
104    res.dataSource.value := Mux(table(res.req) === DataSource.bypass, DataSource.bypass, DataSource.reg)
105    val wakeUpExuOHVec = wakeUpReg.map{ case x =>
106      val v: Bool = pregWB match {
107        case _: IntWB => x.valid && x.bits.rfWen
108        case _: VfWB => x.valid && (x.bits.fpWen || x.bits.vecWen)
109      }
110      val pdestHit = res.req === x.bits.pdest
111      val isBypass = table(res.req) === DataSource.bypass
112      Mux(v && pdestHit && isBypass, MathUtils.IntToOH(x.bits.exuIdx).U(backendParams.numExu.W), 0.U)
113    }
114    res.l1ExuOH := Mux(table(res.req) === DataSource.bypass, ParallelOR(wakeUpExuOHVec.toSeq), 0.U).asBools
115  }
116
117  table := tableUpdate
118  wakeUpReg := io.wakeUp
119
120  val oddTable = table.zipWithIndex.filter(_._2 % 2 == 1).map(!_._1.orR)
121  val evenTable = table.zipWithIndex.filter(_._2 % 2 == 0).map(!_._1.orR)
122  val busyCount = RegNext(RegNext(PopCount(oddTable)) + RegNext(PopCount(evenTable)))
123
124  XSPerfAccumulate("busy_count", PopCount(table.map(_.andR)))
125
126  val perfEvents = Seq(
127    ("std_freelist_1_4_valid", busyCount < (numPhyPregs / 4).U                                      ),
128    ("std_freelist_2_4_valid", busyCount > (numPhyPregs / 4).U && busyCount <= (numPhyPregs / 2).U    ),
129    ("std_freelist_3_4_valid", busyCount > (numPhyPregs / 2).U && busyCount <= (numPhyPregs * 3 / 4).U),
130    ("std_freelist_4_4_valid", busyCount > (numPhyPregs * 3 / 4).U                                  )
131  )
132  generatePerfEvent()
133}
134