1package xiangshan.cache.wpu 2 3import org.chipsalliance.cde.config.Parameters 4import chisel3._ 5import chisel3.util._ 6import utils.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 wayConflictPredictor = Module(new WayConflictPredictor(nPorts)) 85 val io = IO(new DwpuIO(nWays, nPorts)) 86 87 /** pred */ 88 val s0_dmSel = Wire(Vec(nPorts, Bool())) 89 val s0_pred_way_conflict = Wire(Vec(nPorts, Bool())) 90 val s0_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W))) 91 val s1_lookup_valid = Wire(Vec(nPorts, Bool())) 92 val s1_dmSel = Wire(Vec(nPorts, Bool())) 93 val s1_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W))) 94 val s1_pred_fail = Wire(Vec(nPorts, Bool())) 95 val s1_hit = Wire(Vec(nPorts, Bool())) 96 97 for(i <- 0 until nPorts){ 98 wayConflictPredictor.io.pred(i).en := io.req(i).valid 99 wayConflictPredictor.io.pred(i).vaddr := io.cfpred(i).s0_vaddr 100 s0_pred_way_conflict(i) := wayConflictPredictor.io.pred(i).way_conflict 101 102 s0_dmSel(i) := false.B 103 wpu.io.predVec(i).en := io.req(i).valid 104 wpu.io.predVec(i).vaddr := io.req(i).bits.vaddr 105 when(io.req(i).bits.replayCarry.valid) { 106 // replay carry 107 s0_pred_way_en(i) := io.req(i).bits.replayCarry.real_way_en 108 }.otherwise { 109 // way prediction 110 s0_pred_way_en(i) := wpu.io.predVec(i).way_en 111 112 if (dwpuParam.enCfPred) { 113 // selective direct mapping 114 when(!s0_pred_way_conflict(i)) { 115 s0_pred_way_en(i) := UIntToOH(get_direct_map_way(io.req(i).bits.vaddr)) 116 s0_dmSel(i) := true.B 117 } 118 } 119 } 120 121 /** check and update in s1 */ 122 s1_lookup_valid(i) := io.lookup_upd(i).valid 123 s1_dmSel(i) := RegNext(s0_dmSel(i)) 124 s1_pred_way_en(i) := io.lookup_upd(i).bits.s1_pred_way_en 125 s1_pred_fail(i) := io.lookup_upd(i).valid && s1_pred_way_en(i) =/= io.lookup_upd(i).bits.s1_real_way_en 126 s1_hit(i) := !s1_pred_fail(i) && s1_pred_way_en(i).orR 127 128 val s0_replay_upd = Wire(new BaseWpuUpdateBundle(nWays)) 129 s0_replay_upd.en := io.req(i).valid && io.req(i).bits.replayCarry.valid 130 s0_replay_upd.vaddr := io.req(i).bits.vaddr 131 s0_replay_upd.way_en := io.req(i).bits.replayCarry.real_way_en 132 val s1_replay_upd = RegNext(s0_replay_upd) 133 134 wayConflictPredictor.io.update(i).en := io.lookup_upd(i).valid 135 wayConflictPredictor.io.update(i).vaddr := io.cfpred(i).s1_vaddr 136 wayConflictPredictor.io.update(i).dm_hit := s1_dmSel(i) && io.cfpred(i).s1_dm_hit 137 wayConflictPredictor.io.update(i).sa_hit := !s1_dmSel(i) && s1_hit(i) 138 139 // look up res 140 wpu.io.updLookup(i).en := io.lookup_upd(i).valid 141 wpu.io.updLookup(i).vaddr := io.lookup_upd(i).bits.vaddr 142 wpu.io.updLookup(i).way_en := io.lookup_upd(i).bits.s1_real_way_en 143 wpu.io.updLookup(i).pred_way_en := io.lookup_upd(i).bits.s1_pred_way_en 144 145 // which will update in look up pred fail 146 wpu.io.updReplaycarry(i) := s1_replay_upd 147 148 // replace / tag write 149 wpu.io.updTagwrite(i) := DontCare 150 151 /** predict and response in s0 */ 152 io.req(i).ready := true.B 153 if (dwpuParam.enWPU) { 154 io.resp(i).valid := io.req(i).valid 155 } else { 156 io.resp(i).valid := false.B 157 } 158 io.resp(i).bits.s0_pred_way_en := s0_pred_way_en(i) 159 assert(PopCount(io.resp(i).bits.s0_pred_way_en) <= 1.U, "tag should not match with more than 1 way") 160 } 161 wpu.io.updTagwrite(0).en := io.tagwrite_upd.valid 162 wpu.io.updTagwrite(0).vaddr := io.tagwrite_upd.bits.vaddr 163 wpu.io.updTagwrite(0).way_en := io.tagwrite_upd.bits.s1_real_way_en 164 165 // PerfLog 166 // pred situation 167 XSPerfAccumulate("wpu_pred_total", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i)))) 168 XSPerfAccumulate("wpu_pred_succ", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i) && !s1_pred_fail(i)))) 169 XSPerfAccumulate("wpu_pred_fail", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i) && s1_pred_fail(i)))) 170 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))) 171 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))) 172 // pred component 173 XSPerfAccumulate("wpu_pred_replayCarry", PopCount((0 until nPorts).map(i => io.req(i).valid && io.req(i).bits.replayCarry.valid))) 174 if(!dwpuParam.enCfPred){ 175 XSPerfAccumulate("wpu_pred_wayPrediction", PopCount((0 until nPorts).map(i => io.req(i).valid && !io.req(i).bits.replayCarry.valid))) 176 }else{ 177 XSPerfAccumulate("wpu_pred_wayPrediction", PopCount((0 until nPorts).map(i => io.req(i).valid && !io.req(i).bits.replayCarry.valid && s0_pred_way_conflict(i)))) 178 XSPerfAccumulate("wpu_pred_directMap", PopCount((0 until nPorts).map(i => io.req(i).valid && !io.req(i).bits.replayCarry.valid && !s0_pred_way_conflict(i)))) 179 // dm situation 180 XSPerfAccumulate("direct_map_all", PopCount((0 until nPorts).map(i => io.lookup_upd(i).valid))) 181 XSPerfAccumulate("direct_map_ok", PopCount((0 until nPorts).map(i => io.lookup_upd(i).valid && io.cfpred(i).s1_dm_hit))) 182 } 183} 184 185 186class ICacheWpuWrapper (nPorts: Int) (implicit p:Parameters) extends WPUModule with HasICacheParameters { 187 val wpu = AlgoWPUMap(iwpuParam, nPorts) 188 val io = IO(new IwpuIO(nWays, nPorts)) 189 190 val s1_pred_fail = Wire(Vec(nPorts, Bool())) 191 val s0_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W))) 192 val s1_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W))) 193 val s1_real_way_en = Wire(Vec(nPorts, UInt(nWays.W))) 194 /** pred in s0*/ 195 for (i <- 0 until nPorts){ 196 wpu.io.predVec(i).en := io.req(i).valid 197 wpu.io.predVec(i).vaddr := io.req(i).bits.vaddr 198 s0_pred_way_en(i) := wpu.io.predVec(i).way_en 199 // io 200 io.req(i).ready := true.B 201 if (iwpuParam.enWPU) { 202 io.resp(i).valid := io.req(i).valid 203 } else { 204 io.resp(i).valid := false.B 205 } 206 io.resp(i).bits.s0_pred_way_en := s0_pred_way_en(i) 207 assert(PopCount(io.resp(i).bits.s0_pred_way_en) <= 1.U, "tag should not match with more than 1 way") 208 209 /** update in s1 */ 210 s1_pred_way_en(i) := io.lookup_upd(i).bits.s1_pred_way_en 211 s1_real_way_en(i) := io.lookup_upd(i).bits.s1_real_way_en 212 s1_pred_fail(i) := io.lookup_upd(i).valid && s1_pred_way_en(i) =/= s1_real_way_en(i) 213 // look up res 214 wpu.io.updLookup(i).en := io.lookup_upd(i).valid 215 wpu.io.updLookup(i).vaddr := io.lookup_upd(i).bits.vaddr 216 wpu.io.updLookup(i).way_en := io.lookup_upd(i).bits.s1_real_way_en 217 wpu.io.updLookup(i).pred_way_en := io.lookup_upd(i).bits.s1_pred_way_en 218 // which will update in look up pred fail 219 wpu.io.updReplaycarry := DontCare 220 // replace / tag write 221 wpu.io.updTagwrite := DontCare 222 } 223 wpu.io.updTagwrite.head.en := io.tagwrite_upd.valid 224 wpu.io.updTagwrite.head.vaddr := io.tagwrite_upd.bits.vaddr 225 wpu.io.updTagwrite.head.way_en := io.tagwrite_upd.bits.s1_real_way_en 226 227 XSPerfAccumulate("wpu_pred_total", PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid})) 228 XSPerfAccumulate("wpu_pred_succ", PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid && !s1_pred_fail(i)})) 229 XSPerfAccumulate("wpu_pred_fail", PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid && s1_pred_fail(i)})) 230 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})) 231 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})) 232} 233 234/** IdealWPU: 235 * req in s1 and resp in s1 236 */ 237class IdealWPU(implicit p:Parameters) extends WPUModule with HasDCacheParameters { 238 val io = IO(new Bundle{ 239 val req = Output(new Bundle { 240 val valid = Bool() 241 val s1_real_way_en = UInt(nWays.W) 242 }) 243 val resp = Output(new Bundle{ 244 val valid = Bool() 245 val s1_pred_way_en = UInt(nWays.W) 246 }) 247 }) 248 249 val s1_pred_way_en = io.req.s1_real_way_en 250 251 if(dwpuParam.enWPU){ 252 io.resp.valid := io.req.valid 253 }else{ 254 io.resp.valid := false.B 255 } 256 io.resp.s1_pred_way_en := s1_pred_way_en 257}