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