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.frontend 18 19import chisel3._ 20import chisel3.util._ 21import org.chipsalliance.cde.config.Parameters 22import scala.{Tuple2 => &} 23import utility._ 24import xiangshan._ 25 26trait FauFTBParams extends HasXSParameter with HasBPUConst { 27 val numWays = 32 28 val tagSize = 16 29 30 val TAR_STAT_SZ = 2 31 def TAR_FIT = 0.U(TAR_STAT_SZ.W) 32 def TAR_OVF = 1.U(TAR_STAT_SZ.W) 33 def TAR_UDF = 2.U(TAR_STAT_SZ.W) 34 35 def BR_OFFSET_LEN = 12 36 def JMP_OFFSET_LEN = 20 37 38 def getTag(pc: UInt) = pc(tagSize + instOffsetBits - 1, instOffsetBits) 39} 40 41class FauFTBEntry(implicit p: Parameters) extends FTBEntry()(p) {} 42 43class FauFTBWay(implicit p: Parameters) extends XSModule with FauFTBParams { 44 val io = IO(new Bundle { 45 val req_tag = Input(UInt(tagSize.W)) 46 val resp = Output(new FauFTBEntry) 47 val resp_hit = Output(Bool()) 48 val update_req_tag = Input(UInt(tagSize.W)) 49 val update_hit = Output(Bool()) 50 val write_valid = Input(Bool()) 51 val write_entry = Input(new FauFTBEntry) 52 val write_tag = Input(UInt(tagSize.W)) 53 val tag_read = Output(UInt(tagSize.W)) 54 }) 55 56 val data = Reg(new FauFTBEntry) 57 val tag = Reg(UInt(tagSize.W)) 58 val valid = RegInit(false.B) 59 60 io.resp := data 61 io.resp_hit := tag === io.req_tag && valid 62 // write bypass to avoid multiple hit 63 io.update_hit := ((tag === io.update_req_tag) && valid) || 64 ((io.write_tag === io.update_req_tag) && io.write_valid) 65 io.tag_read := tag 66 67 when(io.write_valid) { 68 when(!valid) { 69 valid := true.B 70 } 71 tag := io.write_tag 72 data := io.write_entry 73 } 74} 75 76class FauFTB(implicit p: Parameters) extends BasePredictor with FauFTBParams { 77 78 class FauFTBMeta(implicit p: Parameters) extends XSBundle with FauFTBParams { 79 val pred_way = if (!env.FPGAPlatform) Some(UInt(log2Ceil(numWays).W)) else None 80 val hit = Bool() 81 } 82 val resp_meta = Wire(new FauFTBMeta) 83 override val meta_size = resp_meta.getWidth 84 override val is_fast_pred = true 85 86 val ways = Seq.tabulate(numWays)(w => Module(new FauFTBWay)) 87 // numWays * numBr 88 val ctrs = Seq.tabulate(numWays)(w => Seq.tabulate(numBr)(b => RegInit(2.U(2.W)))) 89 val replacer = ReplacementPolicy.fromString("plru", numWays) 90 val replacer_touch_ways = Wire(Vec(2, Valid(UInt(log2Ceil(numWays).W)))) 91 92 // pred req 93 ways.foreach(_.io.req_tag := getTag(s1_pc_dup(0))) 94 95 // pred resp 96 val s1_hit_oh = VecInit(ways.map(_.io.resp_hit)).asUInt 97 val s1_hit = s1_hit_oh.orR 98 val s1_hit_way = OHToUInt(s1_hit_oh) 99 val s1_possible_full_preds = Wire(Vec(numWays, new FullBranchPrediction(isNotS3 = true))) 100 101 val s1_all_entries = VecInit(ways.map(_.io.resp)) 102 for (c & fp & e <- ctrs zip s1_possible_full_preds zip s1_all_entries) { 103 fp.hit := DontCare 104 fp.multiHit := false.B 105 fp.fromFtbEntry(e, s1_pc_dup(0)) 106 for (i <- 0 until numBr) { 107 fp.br_taken_mask(i) := c(i)(1) || e.strong_bias(i) 108 } 109 } 110 val s1_hit_full_pred = Mux1H(s1_hit_oh, s1_possible_full_preds) 111 val s1_hit_fauftbentry = Mux1H(s1_hit_oh, s1_all_entries) 112 XSError(PopCount(s1_hit_oh) > 1.U, "fauftb has multiple hits!\n") 113 val fauftb_enable = RegNext(io.ctrl.ubtb_enable) 114 io.out.s1.full_pred.map(_ := s1_hit_full_pred) 115 io.out.s1.full_pred.map(_.hit := s1_hit && fauftb_enable) 116 io.fauftb_entry_out := s1_hit_fauftbentry 117 io.fauftb_entry_hit_out := s1_hit && fauftb_enable 118 119 // Illegal check for FTB entry reading 120 val s1_pc_startLower = Cat(0.U(1.W), s1_pc_dup(0)(instOffsetBits + log2Ceil(PredictWidth) - 1, instOffsetBits)) 121 val uftb_entry_endLowerwithCarry = Cat(s1_hit_fauftbentry.carry, s1_hit_fauftbentry.pftAddr) 122 val fallThroughErr = s1_pc_startLower + PredictWidth.U >= uftb_entry_endLowerwithCarry 123 when(io.s1_fire(0) && s1_hit) { 124 assert(fallThroughErr, s"FauFTB read entry fallThrough address error!") 125 } 126 127 // assign metas 128 io.out.last_stage_meta := resp_meta.asUInt 129 resp_meta.hit := RegEnable(RegEnable(s1_hit, io.s1_fire(0)), io.s2_fire(0)) 130 if (resp_meta.pred_way.isDefined) { 131 resp_meta.pred_way.get := RegEnable(RegEnable(s1_hit_way, io.s1_fire(0)), io.s2_fire(0)) 132 } 133 134 // pred update replacer state 135 val s1_fire = io.s1_fire(0) 136 replacer_touch_ways(0).valid := RegNext(s1_fire(0) && s1_hit) 137 replacer_touch_ways(0).bits := RegEnable(s1_hit_way, s1_fire(0) && s1_hit) 138 139 /********************** update ***********************/ 140 // s0: update_valid, read and tag comparison 141 // s1: alloc_way and write 142 143 // s0 144 val u_valid = RegNext(io.update.valid, init = false.B) 145 val u_bits = RegEnable(io.update.bits, io.update.valid) 146 147 // The pc register has been moved outside of predictor, pc field of update bundle and other update data are not in the same stage 148 // so io.update.bits.pc is used directly here 149 val u_pc = io.update.bits.pc 150 151 val u_meta = u_bits.meta.asTypeOf(new FauFTBMeta) 152 val u_s0_tag = getTag(u_pc) 153 ways.foreach(_.io.update_req_tag := u_s0_tag) 154 val u_s0_hit_oh = VecInit(ways.map(_.io.update_hit)).asUInt 155 val u_s0_hit = u_s0_hit_oh.orR 156 val u_s0_br_update_valids = 157 VecInit((0 until numBr).map(w => 158 u_bits.ftb_entry.brValids(w) && u_valid && !u_bits.ftb_entry.strong_bias(w) && 159 !(PriorityEncoder(u_bits.br_taken_mask) < w.U) 160 )) 161 162 // s1 163 val u_s1_valid = RegNext(u_valid) 164 val u_s1_tag = RegEnable(u_s0_tag, u_valid) 165 val u_s1_hit_oh = RegEnable(u_s0_hit_oh, u_valid) 166 val u_s1_hit = RegEnable(u_s0_hit, u_valid) 167 val u_s1_alloc_way = replacer.way 168 val u_s1_write_way_oh = Mux(u_s1_hit, u_s1_hit_oh, UIntToOH(u_s1_alloc_way)) 169 val u_s1_ftb_entry = RegEnable(u_bits.ftb_entry, u_valid) 170 val u_s1_ways_write_valid = VecInit((0 until numWays).map(w => u_s1_write_way_oh(w).asBool && u_s1_valid)) 171 for (w <- 0 until numWays) { 172 ways(w).io.write_valid := u_s1_ways_write_valid(w) 173 ways(w).io.write_tag := u_s1_tag 174 ways(w).io.write_entry := u_s1_ftb_entry 175 } 176 177 // Illegal check for FTB entry writing 178 val uftb_write_pc = RegEnable(u_pc, u_valid) 179 val uftb_write_fallThrough = u_s1_ftb_entry.getFallThrough(uftb_write_pc) 180 when(u_s1_valid && u_s1_hit) { 181 assert( 182 uftb_write_pc + (FetchWidth * 4).U >= uftb_write_fallThrough, 183 s"FauFTB write entry fallThrough address error!" 184 ) 185 } 186 187 // update saturating counters 188 val u_s1_br_update_valids = RegEnable(u_s0_br_update_valids, u_valid) 189 val u_s1_br_takens = RegEnable(u_bits.br_taken_mask, u_valid) 190 for (w <- 0 until numWays) { 191 when(u_s1_ways_write_valid(w)) { 192 for (br <- 0 until numBr) { 193 when(u_s1_br_update_valids(br)) { 194 ctrs(w)(br) := satUpdate(ctrs(w)(br), 2, u_s1_br_takens(br)) 195 } 196 } 197 } 198 } 199 200 // commit update replacer state 201 replacer_touch_ways(1).valid := u_s1_valid 202 replacer_touch_ways(1).bits := OHToUInt(u_s1_write_way_oh) 203 204 /******** update replacer *********/ 205 replacer.access(replacer_touch_ways) 206 207 /********************** perf counters **********************/ 208 val s0_fire_next_cycle = RegNext(io.s0_fire(0)) 209 val u_pred_hit_way_map = (0 until numWays).map(w => s0_fire_next_cycle && s1_hit && s1_hit_way === w.U) 210 XSPerfAccumulate("uftb_read_hits", s0_fire_next_cycle && s1_hit) 211 XSPerfAccumulate("uftb_read_misses", s0_fire_next_cycle && !s1_hit) 212 XSPerfAccumulate("uftb_commit_hits", u_valid && u_meta.hit) 213 XSPerfAccumulate("uftb_commit_misses", u_valid && !u_meta.hit) 214 XSPerfAccumulate("uftb_commit_read_hit_pred_miss", u_valid && !u_meta.hit && u_s0_hit_oh.orR) 215 for (w <- 0 until numWays) { 216 XSPerfAccumulate(f"uftb_pred_hit_way_${w}", u_pred_hit_way_map(w)) 217 XSPerfAccumulate(f"uftb_replace_way_${w}", !u_s1_hit && u_s1_alloc_way === w.U) 218 } 219 220 if (u_meta.pred_way.isDefined) { 221 val u_commit_hit_way_map = (0 until numWays).map(w => u_valid && u_meta.hit && u_meta.pred_way.get === w.U) 222 for (w <- 0 until numWays) { 223 XSPerfAccumulate(f"uftb_commit_hit_way_${w}", u_commit_hit_way_map(w)) 224 } 225 } 226 227 override val perfEvents = Seq( 228 ("fauftb_commit_hit ", u_valid && u_meta.hit), 229 ("fauftb_commit_miss ", u_valid && !u_meta.hit) 230 ) 231 generatePerfEvent() 232 233} 234