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