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