1package xiangshan.cache.wpu 2 3import org.chipsalliance.cde.config.Parameters 4import chisel3._ 5import chisel3.util._ 6import utility.XSPerfAccumulate 7import xiangshan._ 8import xiangshan.cache.{DCacheModule, HasDCacheParameters} 9import xiangshan.frontend.icache.HasICacheParameters 10 11class ReplayCarry(nWays: Int)(implicit p: Parameters) extends XSBundle { 12 val real_way_en = UInt(nWays.W) 13 val valid = Bool() 14} 15 16object ReplayCarry{ 17 def apply(nWays: Int, rwe: UInt = 0.U, v: Bool = false.B)(implicit p: Parameters): ReplayCarry = { 18 val rcry = Wire(new ReplayCarry(nWays)) 19 rcry.real_way_en := rwe 20 rcry.valid := v 21 rcry 22 } 23 24 def init(nWays: Int)(implicit p: Parameters): ReplayCarry = { 25 val rcry = Wire(new ReplayCarry(nWays)) 26 rcry.real_way_en := 0.U 27 rcry.valid := false.B 28 rcry 29 } 30} 31 32class WPUBaseReq(implicit p: Parameters) extends BaseWPUBundle{ 33 val vaddr = UInt(VAddrBits.W) 34} 35 36class WPUReplayedReq(nWays: Int)(implicit p: Parameters) extends WPUBaseReq { 37 val replayCarry = new ReplayCarry(nWays) 38} 39 40class WPUResp(nWays:Int)(implicit p:Parameters) extends BaseWPUBundle{ 41 val s0_pred_way_en = UInt(nWays.W) 42} 43 44class WPUUpdate(nWays:Int)(implicit p:Parameters) extends BaseWPUBundle{ 45 val vaddr = UInt(VAddrBits.W) 46 val s1_real_way_en = UInt(nWays.W) 47} 48 49class WPUUpdateLookup(nWays:Int)(implicit p:Parameters) extends WPUUpdate(nWays){ 50 val s1_pred_way_en = UInt(nWays.W) 51} 52 53class ConflictPredictIO(nWays:Int)(implicit p:Parameters) extends BaseWPUBundle{ 54 // pred 55 val s0_vaddr = Input(UInt(VAddrBits.W)) 56 // update 57 val s1_vaddr = Input(UInt(VAddrBits.W)) 58 val s1_dm_hit = Input(Bool()) 59} 60 61class IwpuBaseIO(nWays:Int, nPorts: Int)(implicit p:Parameters) extends BaseWPUBundle{ 62 val req = Vec(nPorts, Flipped(Decoupled(new WPUBaseReq))) 63 val resp = Vec(nPorts, ValidIO(new WPUResp(nWays))) 64 val lookup_upd = Vec(nPorts, Flipped(ValidIO(new WPUUpdateLookup(nWays)))) 65} 66 67class IwpuIO(nWays:Int, nPorts: Int)(implicit p:Parameters) extends IwpuBaseIO(nWays, nPorts){ 68 val tagwrite_upd = Flipped(ValidIO(new WPUUpdate(nWays))) 69} 70 71class DwpuBaseIO(nWays:Int, nPorts: Int)(implicit p:Parameters) extends BaseWPUBundle{ 72 val req = Vec(nPorts, Flipped(Decoupled(new WPUReplayedReq(nWays)))) 73 val resp = Vec(nPorts, ValidIO(new WPUResp(nWays))) 74 val lookup_upd = Vec(nPorts, Flipped(ValidIO(new WPUUpdateLookup(nWays)))) 75 val cfpred = Vec(nPorts, new ConflictPredictIO(nWays)) 76} 77 78class DwpuIO(nWays:Int, nPorts:Int)(implicit p:Parameters) extends DwpuBaseIO(nWays, nPorts){ 79 val tagwrite_upd = Flipped(ValidIO(new WPUUpdate(nWays))) 80} 81 82class DCacheWpuWrapper (nPorts: Int = 1) (implicit p:Parameters) extends DCacheModule with HasWPUParameters { 83 val wpu = AlgoWPUMap(dwpuParam, nPorts) 84 val io = IO(new DwpuIO(nWays, nPorts)) 85 86 /** pred */ 87 val s0_dmSel = Wire(Vec(nPorts, Bool())) 88 val s0_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W))) 89 val s1_lookup_valid = Wire(Vec(nPorts, Bool())) 90 val s1_dmSel = Wire(Vec(nPorts, Bool())) 91 val s1_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W))) 92 val s1_pred_fail = Wire(Vec(nPorts, Bool())) 93 val s1_hit = Wire(Vec(nPorts, Bool())) 94 95 for(i <- 0 until nPorts){ 96 s0_dmSel(i) := false.B 97 wpu.io.predVec(i).en := io.req(i).valid 98 wpu.io.predVec(i).vaddr := io.req(i).bits.vaddr 99 when(io.req(i).bits.replayCarry.valid) { 100 // replay carry 101 s0_pred_way_en(i) := io.req(i).bits.replayCarry.real_way_en 102 }.otherwise { 103 // way prediction 104 s0_pred_way_en(i) := wpu.io.predVec(i).way_en 105 } 106 107 /** check and update in s1 */ 108 s1_lookup_valid(i) := io.lookup_upd(i).valid 109 s1_dmSel(i) := RegNext(s0_dmSel(i)) 110 s1_pred_way_en(i) := io.lookup_upd(i).bits.s1_pred_way_en 111 s1_pred_fail(i) := io.lookup_upd(i).valid && s1_pred_way_en(i) =/= io.lookup_upd(i).bits.s1_real_way_en 112 s1_hit(i) := !s1_pred_fail(i) && s1_pred_way_en(i).orR 113 114 val s0_replay_upd = Wire(new BaseWpuUpdateBundle(nWays)) 115 s0_replay_upd.en := io.req(i).valid && io.req(i).bits.replayCarry.valid 116 s0_replay_upd.vaddr := io.req(i).bits.vaddr 117 s0_replay_upd.way_en := io.req(i).bits.replayCarry.real_way_en 118 val s1_replay_upd = RegEnable(s0_replay_upd, io.req(i).valid) 119 120 121 // look up res 122 wpu.io.updLookup(i).en := io.lookup_upd(i).valid 123 wpu.io.updLookup(i).vaddr := io.lookup_upd(i).bits.vaddr 124 wpu.io.updLookup(i).way_en := io.lookup_upd(i).bits.s1_real_way_en 125 wpu.io.updLookup(i).pred_way_en := io.lookup_upd(i).bits.s1_pred_way_en 126 127 // which will update in look up pred fail 128 wpu.io.updReplaycarry(i) := s1_replay_upd 129 130 // replace / tag write 131 wpu.io.updTagwrite(i) := DontCare 132 133 /** predict and response in s0 */ 134 io.req(i).ready := true.B 135 if (dwpuParam.enWPU) { 136 io.resp(i).valid := io.req(i).valid 137 } else { 138 io.resp(i).valid := false.B 139 } 140 io.resp(i).bits.s0_pred_way_en := s0_pred_way_en(i) 141 assert(PopCount(io.resp(i).bits.s0_pred_way_en) <= 1.U, "tag should not match with more than 1 way") 142 } 143 wpu.io.updTagwrite(0).en := io.tagwrite_upd.valid 144 wpu.io.updTagwrite(0).vaddr := io.tagwrite_upd.bits.vaddr 145 wpu.io.updTagwrite(0).way_en := io.tagwrite_upd.bits.s1_real_way_en 146 // PerfLog 147 // pred situation 148 XSPerfAccumulate("wpu_pred_total", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i)))) 149 XSPerfAccumulate("wpu_pred_succ", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i) && !s1_pred_fail(i)))) 150 XSPerfAccumulate("wpu_pred_fail", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i) && s1_pred_fail(i)))) 151 XSPerfAccumulate("wpu_pred_miss", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i) && !s1_pred_way_en(i).orR))) 152 XSPerfAccumulate("wpu_real_miss", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i) && !io.lookup_upd(i).bits.s1_real_way_en.orR))) 153 // pred component 154 XSPerfAccumulate("wpu_pred_replayCarry", PopCount((0 until nPorts).map(i => io.req(i).valid && io.req(i).bits.replayCarry.valid))) 155 XSPerfAccumulate("wpu_pred_wayPrediction", PopCount((0 until nPorts).map(i => io.req(i).valid && !io.req(i).bits.replayCarry.valid))) 156 157 /* selective direct mapping */ 158 if(dwpuParam.enCfPred){ 159 val wayConflictPredictor = Module(new WayConflictPredictor(nPorts)) 160 val s0_pred_way_conflict = Wire(Vec(nPorts, Bool())) 161 for(i <- 0 until nPorts){ 162 wayConflictPredictor.io.pred(i).en := io.req(i).valid 163 wayConflictPredictor.io.pred(i).vaddr := io.cfpred(i).s0_vaddr 164 s0_pred_way_conflict(i) := wayConflictPredictor.io.pred(i).way_conflict 165 when(!s0_pred_way_conflict(i)) { 166 s0_pred_way_en(i) := UIntToOH(get_direct_map_way(io.req(i).bits.vaddr)) 167 s0_dmSel(i) := true.B 168 } 169 wayConflictPredictor.io.update(i).en := io.lookup_upd(i).valid 170 wayConflictPredictor.io.update(i).vaddr := io.cfpred(i).s1_vaddr 171 wayConflictPredictor.io.update(i).dm_hit := s1_dmSel(i) && io.cfpred(i).s1_dm_hit 172 wayConflictPredictor.io.update(i).sa_hit := !s1_dmSel(i) && s1_hit(i) 173 } 174 XSPerfAccumulate("wpu_pred_from_prediction", PopCount((0 until nPorts).map(i => io.req(i).valid && !io.req(i).bits.replayCarry.valid && s0_pred_way_conflict(i)))) 175 XSPerfAccumulate("wpu_pred_from_directMap", PopCount((0 until nPorts).map(i => io.req(i).valid && !io.req(i).bits.replayCarry.valid && !s0_pred_way_conflict(i)))) 176 // dm situation 177 XSPerfAccumulate("direct_map_all", PopCount((0 until nPorts).map(i => io.lookup_upd(i).valid))) 178 XSPerfAccumulate("direct_map_ok", PopCount((0 until nPorts).map(i => io.lookup_upd(i).valid && io.cfpred(i).s1_dm_hit))) 179 } 180} 181 182 183class ICacheWpuWrapper (nPorts: Int) (implicit p:Parameters) extends WPUModule with HasICacheParameters { 184 val wpu = AlgoWPUMap(iwpuParam, nPorts) 185 val io = IO(new IwpuIO(nWays, nPorts)) 186 187 val s1_pred_fail = Wire(Vec(nPorts, Bool())) 188 val s0_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W))) 189 val s1_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W))) 190 val s1_real_way_en = Wire(Vec(nPorts, UInt(nWays.W))) 191 /** pred in s0*/ 192 for (i <- 0 until nPorts){ 193 wpu.io.predVec(i).en := io.req(i).valid 194 wpu.io.predVec(i).vaddr := io.req(i).bits.vaddr 195 s0_pred_way_en(i) := wpu.io.predVec(i).way_en 196 // io 197 io.req(i).ready := true.B 198 if (iwpuParam.enWPU) { 199 io.resp(i).valid := io.req(i).valid 200 } else { 201 io.resp(i).valid := false.B 202 } 203 io.resp(i).bits.s0_pred_way_en := s0_pred_way_en(i) 204 assert(PopCount(io.resp(i).bits.s0_pred_way_en) <= 1.U, "tag should not match with more than 1 way") 205 206 /** update in s1 */ 207 s1_pred_way_en(i) := io.lookup_upd(i).bits.s1_pred_way_en 208 s1_real_way_en(i) := io.lookup_upd(i).bits.s1_real_way_en 209 s1_pred_fail(i) := io.lookup_upd(i).valid && s1_pred_way_en(i) =/= s1_real_way_en(i) 210 // look up res 211 wpu.io.updLookup(i).en := io.lookup_upd(i).valid 212 wpu.io.updLookup(i).vaddr := io.lookup_upd(i).bits.vaddr 213 wpu.io.updLookup(i).way_en := io.lookup_upd(i).bits.s1_real_way_en 214 wpu.io.updLookup(i).pred_way_en := io.lookup_upd(i).bits.s1_pred_way_en 215 // which will update in look up pred fail 216 wpu.io.updReplaycarry := DontCare 217 // replace / tag write 218 wpu.io.updTagwrite := DontCare 219 } 220 wpu.io.updTagwrite.head.en := io.tagwrite_upd.valid 221 wpu.io.updTagwrite.head.vaddr := io.tagwrite_upd.bits.vaddr 222 wpu.io.updTagwrite.head.way_en := io.tagwrite_upd.bits.s1_real_way_en 223 224 XSPerfAccumulate("wpu_pred_total", PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid})) 225 XSPerfAccumulate("wpu_pred_succ", PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid && !s1_pred_fail(i)})) 226 XSPerfAccumulate("wpu_pred_fail", PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid && s1_pred_fail(i)})) 227 XSPerfAccumulate("wpu_pred_miss", PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid && !RegNext(s0_pred_way_en(i)).orR})) 228 XSPerfAccumulate("wpu_real_miss", PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid && !RegNext(s1_real_way_en(i)).orR})) 229} 230 231/** IdealWPU: 232 * req in s1 and resp in s1 233 */ 234class IdealWPU(implicit p:Parameters) extends WPUModule with HasDCacheParameters { 235 val io = IO(new Bundle{ 236 val req = Output(new Bundle { 237 val valid = Bool() 238 val s1_real_way_en = UInt(nWays.W) 239 }) 240 val resp = Output(new Bundle{ 241 val valid = Bool() 242 val s1_pred_way_en = UInt(nWays.W) 243 }) 244 }) 245 246 val s1_pred_way_en = io.req.s1_real_way_en 247 248 if(dwpuParam.enWPU){ 249 io.resp.valid := io.req.valid 250 }else{ 251 io.resp.valid := false.B 252 } 253 io.resp.s1_pred_way_en := s1_pred_way_en 254}