1*11d0c81dSLingrui98/*************************************************************************************** 2*11d0c81dSLingrui98* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3*11d0c81dSLingrui98* Copyright (c) 2020-2021 Peng Cheng Laboratory 4*11d0c81dSLingrui98* 5*11d0c81dSLingrui98* XiangShan is licensed under Mulan PSL v2. 6*11d0c81dSLingrui98* You can use this software according to the terms and conditions of the Mulan PSL v2. 7*11d0c81dSLingrui98* You may obtain a copy of Mulan PSL v2 at: 8*11d0c81dSLingrui98* http://license.coscl.org.cn/MulanPSL2 9*11d0c81dSLingrui98* 10*11d0c81dSLingrui98* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11*11d0c81dSLingrui98* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12*11d0c81dSLingrui98* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13*11d0c81dSLingrui98* 14*11d0c81dSLingrui98* See the Mulan PSL v2 for more details. 15*11d0c81dSLingrui98***************************************************************************************/ 16*11d0c81dSLingrui98 17*11d0c81dSLingrui98package xiangshan.frontend 18*11d0c81dSLingrui98 19*11d0c81dSLingrui98import chipsalliance.rocketchip.config.Parameters 20*11d0c81dSLingrui98import chisel3._ 21*11d0c81dSLingrui98import chisel3.util._ 22*11d0c81dSLingrui98import utils._ 23*11d0c81dSLingrui98import xiangshan._ 24*11d0c81dSLingrui98import chisel3.experimental.chiselName 25*11d0c81dSLingrui98import scala.{Tuple2 => &} 26*11d0c81dSLingrui98 27*11d0c81dSLingrui98trait FauFTBParams extends HasXSParameter with HasBPUConst { 28*11d0c81dSLingrui98 val numWays = 32 29*11d0c81dSLingrui98 val tagSize = 16 30*11d0c81dSLingrui98 31*11d0c81dSLingrui98 val TAR_STAT_SZ = 2 32*11d0c81dSLingrui98 def TAR_FIT = 0.U(TAR_STAT_SZ.W) 33*11d0c81dSLingrui98 def TAR_OVF = 1.U(TAR_STAT_SZ.W) 34*11d0c81dSLingrui98 def TAR_UDF = 2.U(TAR_STAT_SZ.W) 35*11d0c81dSLingrui98 36*11d0c81dSLingrui98 def BR_OFFSET_LEN = 12 37*11d0c81dSLingrui98 def JMP_OFFSET_LEN = 20 38*11d0c81dSLingrui98 39*11d0c81dSLingrui98 def getTag(pc: UInt) = pc(tagSize+instOffsetBits-1, instOffsetBits) 40*11d0c81dSLingrui98} 41*11d0c81dSLingrui98 42*11d0c81dSLingrui98class FauFTBEntry(implicit p: Parameters) extends FTBEntry()(p) {} 43*11d0c81dSLingrui98 44*11d0c81dSLingrui98class FauFTBWay(implicit p: Parameters) extends XSModule with FauFTBParams { 45*11d0c81dSLingrui98 val io = IO(new Bundle{ 46*11d0c81dSLingrui98 val req_tag = Input(UInt(tagSize.W)) 47*11d0c81dSLingrui98 val resp = Output(new FauFTBEntry) 48*11d0c81dSLingrui98 val resp_hit = Output(Bool()) 49*11d0c81dSLingrui98 val update_req_tag = Input(UInt(tagSize.W)) 50*11d0c81dSLingrui98 val update_hit = Output(Bool()) 51*11d0c81dSLingrui98 val write_valid = Input(Bool()) 52*11d0c81dSLingrui98 val write_entry = Input(new FauFTBEntry) 53*11d0c81dSLingrui98 val write_tag = Input(UInt(tagSize.W)) 54*11d0c81dSLingrui98 val tag_read = Output(UInt(tagSize.W)) 55*11d0c81dSLingrui98 }) 56*11d0c81dSLingrui98 57*11d0c81dSLingrui98 val data = Reg(new FauFTBEntry) 58*11d0c81dSLingrui98 val tag = Reg(UInt(tagSize.W)) 59*11d0c81dSLingrui98 val valid = RegInit(false.B) 60*11d0c81dSLingrui98 61*11d0c81dSLingrui98 io.resp := data 62*11d0c81dSLingrui98 io.resp_hit := tag === io.req_tag && valid 63*11d0c81dSLingrui98 // write bypass to avoid multiple hit 64*11d0c81dSLingrui98 io.update_hit := ((tag === io.update_req_tag) && valid) || 65*11d0c81dSLingrui98 ((io.write_tag === io.update_req_tag) && io.write_valid) 66*11d0c81dSLingrui98 io.tag_read := tag 67*11d0c81dSLingrui98 68*11d0c81dSLingrui98 when (io.write_valid) { 69*11d0c81dSLingrui98 when (!valid) { 70*11d0c81dSLingrui98 valid := true.B 71*11d0c81dSLingrui98 } 72*11d0c81dSLingrui98 tag := io.write_tag 73*11d0c81dSLingrui98 data := io.write_entry 74*11d0c81dSLingrui98 } 75*11d0c81dSLingrui98} 76*11d0c81dSLingrui98 77*11d0c81dSLingrui98 78*11d0c81dSLingrui98class FauFTB(implicit p: Parameters) extends BasePredictor with FauFTBParams { 79*11d0c81dSLingrui98 80*11d0c81dSLingrui98 class FauFTBMeta(implicit p: Parameters) extends XSBundle with FauFTBParams { 81*11d0c81dSLingrui98 val pred_way = UInt(log2Ceil(numWays).W) 82*11d0c81dSLingrui98 val hit = Bool() 83*11d0c81dSLingrui98 } 84*11d0c81dSLingrui98 val resp_meta = Wire(new FauFTBMeta) 85*11d0c81dSLingrui98 override val meta_size = resp_meta.getWidth 86*11d0c81dSLingrui98 87*11d0c81dSLingrui98 88*11d0c81dSLingrui98 89*11d0c81dSLingrui98 val ways = Seq.tabulate(numWays)(w => Module(new FauFTBWay)) 90*11d0c81dSLingrui98 // numWays * numBr 91*11d0c81dSLingrui98 val ctrs = Seq.tabulate(numWays)(w => Seq.tabulate(numBr)(b => RegInit(2.U(2.W)))) 92*11d0c81dSLingrui98 val replacer = ReplacementPolicy.fromString("plru", numWays) 93*11d0c81dSLingrui98 val replacer_touch_ways = Wire(Vec(2, Valid(UInt(log2Ceil(numWays).W)))) 94*11d0c81dSLingrui98 95*11d0c81dSLingrui98 96*11d0c81dSLingrui98 // pred req 97*11d0c81dSLingrui98 ways.foreach(_.io.req_tag := getTag(s1_pc)) 98*11d0c81dSLingrui98 99*11d0c81dSLingrui98 // pred resp 100*11d0c81dSLingrui98 val s1_hit_oh = VecInit(ways.map(_.io.resp_hit)).asUInt 101*11d0c81dSLingrui98 val s1_hit = s1_hit_oh.orR 102*11d0c81dSLingrui98 val s1_hit_way = OHToUInt(s1_hit_oh) 103*11d0c81dSLingrui98 val s1_possible_full_preds = Wire(Vec(numWays, new FullBranchPrediction)) 104*11d0c81dSLingrui98 105*11d0c81dSLingrui98 val s1_all_entries = VecInit(ways.map(_.io.resp)) 106*11d0c81dSLingrui98 for (c & fp & e <- ctrs zip s1_possible_full_preds zip s1_all_entries) { 107*11d0c81dSLingrui98 fp.hit := DontCare 108*11d0c81dSLingrui98 fp.fromFtbEntry(e, s1_pc) 109*11d0c81dSLingrui98 for (i <- 0 until numBr) { 110*11d0c81dSLingrui98 fp.br_taken_mask(i) := c(i)(1) || e.always_taken(i) 111*11d0c81dSLingrui98 } 112*11d0c81dSLingrui98 } 113*11d0c81dSLingrui98 val s1_hit_full_pred = Mux1H(s1_hit_oh, s1_possible_full_preds) 114*11d0c81dSLingrui98 XSError(PopCount(s1_hit_oh) > 1.U, "fauftb has multiple hits!\n") 115*11d0c81dSLingrui98 val fauftb_enable = RegNext(io.ctrl.ubtb_enable) 116*11d0c81dSLingrui98 io.out.s1.full_pred := s1_hit_full_pred 117*11d0c81dSLingrui98 io.out.s1.full_pred.hit := s1_hit && fauftb_enable 118*11d0c81dSLingrui98 io.out.s1.is_minimal := false.B 119*11d0c81dSLingrui98 120*11d0c81dSLingrui98 // assign metas 121*11d0c81dSLingrui98 io.out.last_stage_meta := resp_meta.asUInt 122*11d0c81dSLingrui98 resp_meta.hit := RegEnable(RegEnable(s1_hit, io.s1_fire), io.s2_fire) 123*11d0c81dSLingrui98 resp_meta.pred_way := RegEnable(RegEnable(s1_hit_way, io.s1_fire), io.s2_fire) 124*11d0c81dSLingrui98 125*11d0c81dSLingrui98 // pred update replacer state 126*11d0c81dSLingrui98 val s1_fire = io.s1_fire 127*11d0c81dSLingrui98 replacer_touch_ways(0).valid := RegNext(s1_fire && s1_hit) 128*11d0c81dSLingrui98 replacer_touch_ways(0).bits := RegEnable(s1_hit_way, s1_fire && s1_hit) 129*11d0c81dSLingrui98 130*11d0c81dSLingrui98 /********************** update ***********************/ 131*11d0c81dSLingrui98 // s0: update_valid, read and tag comparison 132*11d0c81dSLingrui98 // s1: alloc_way and write 133*11d0c81dSLingrui98 134*11d0c81dSLingrui98 // s0 135*11d0c81dSLingrui98 val u = io.update 136*11d0c81dSLingrui98 val u_meta = u.bits.meta.asTypeOf(new FauFTBMeta) 137*11d0c81dSLingrui98 val u_s0_tag = getTag(u.bits.pc) 138*11d0c81dSLingrui98 ways.foreach(_.io.update_req_tag := u_s0_tag) 139*11d0c81dSLingrui98 val u_s0_hit_oh = VecInit(ways.map(_.io.update_hit)).asUInt 140*11d0c81dSLingrui98 val u_s0_hit = u_s0_hit_oh.orR 141*11d0c81dSLingrui98 val u_s0_br_update_valids = 142*11d0c81dSLingrui98 VecInit((0 until numBr).map(w => 143*11d0c81dSLingrui98 u.bits.ftb_entry.brValids(w) && u.valid && !u.bits.ftb_entry.always_taken(w) && 144*11d0c81dSLingrui98 !(PriorityEncoder(u.bits.br_taken_mask) < w.U))) 145*11d0c81dSLingrui98 146*11d0c81dSLingrui98 // s1 147*11d0c81dSLingrui98 val u_s1_valid = RegNext(u.valid) 148*11d0c81dSLingrui98 val u_s1_tag = RegEnable(u_s0_tag, u.valid) 149*11d0c81dSLingrui98 val u_s1_hit_oh = RegEnable(u_s0_hit_oh, u.valid) 150*11d0c81dSLingrui98 val u_s1_hit = RegEnable(u_s0_hit, u.valid) 151*11d0c81dSLingrui98 val u_s1_alloc_way = replacer.way 152*11d0c81dSLingrui98 val u_s1_write_way_oh = Mux(u_s1_hit, u_s1_hit_oh, UIntToOH(u_s1_alloc_way)) 153*11d0c81dSLingrui98 val u_s1_ftb_entry = RegEnable(u.bits.ftb_entry, u.valid) 154*11d0c81dSLingrui98 val u_s1_ways_write_valid = VecInit((0 until numWays).map(w => u_s1_write_way_oh(w).asBool && u_s1_valid)) 155*11d0c81dSLingrui98 for (w <- 0 until numWays) { 156*11d0c81dSLingrui98 ways(w).io.write_valid := u_s1_ways_write_valid(w) 157*11d0c81dSLingrui98 ways(w).io.write_tag := u_s1_tag 158*11d0c81dSLingrui98 ways(w).io.write_entry := u_s1_ftb_entry 159*11d0c81dSLingrui98 } 160*11d0c81dSLingrui98 161*11d0c81dSLingrui98 // update saturating counters 162*11d0c81dSLingrui98 val u_s1_br_update_valids = RegEnable(u_s0_br_update_valids, u.valid) 163*11d0c81dSLingrui98 val u_s1_br_takens = RegEnable(u.bits.br_taken_mask, u.valid) 164*11d0c81dSLingrui98 for (w <- 0 until numWays) { 165*11d0c81dSLingrui98 when (u_s1_ways_write_valid(w)) { 166*11d0c81dSLingrui98 for (br <- 0 until numBr) { 167*11d0c81dSLingrui98 when (u_s1_br_update_valids(br)) { 168*11d0c81dSLingrui98 ctrs(w)(br) := satUpdate(ctrs(w)(br), 2, u_s1_br_takens(br)) 169*11d0c81dSLingrui98 } 170*11d0c81dSLingrui98 } 171*11d0c81dSLingrui98 } 172*11d0c81dSLingrui98 } 173*11d0c81dSLingrui98 174*11d0c81dSLingrui98 // commit update replacer state 175*11d0c81dSLingrui98 replacer_touch_ways(1).valid := u_s1_valid 176*11d0c81dSLingrui98 replacer_touch_ways(1).bits := OHToUInt(u_s1_write_way_oh) 177*11d0c81dSLingrui98 178*11d0c81dSLingrui98 /******** update replacer *********/ 179*11d0c81dSLingrui98 replacer.access(replacer_touch_ways) 180*11d0c81dSLingrui98 181*11d0c81dSLingrui98 182*11d0c81dSLingrui98 /********************** perf counters **********************/ 183*11d0c81dSLingrui98 val s0_fire_next_cycle = RegNext(io.s0_fire) 184*11d0c81dSLingrui98 val u_pred_hit_way_map = (0 until numWays).map(w => s0_fire_next_cycle && s1_hit && s1_hit_way === w.U) 185*11d0c81dSLingrui98 val u_commit_hit_way_map = (0 until numWays).map(w => u.valid && u_meta.hit && u_meta.pred_way === w.U) 186*11d0c81dSLingrui98 XSPerfAccumulate("uftb_read_hits", s0_fire_next_cycle && s1_hit) 187*11d0c81dSLingrui98 XSPerfAccumulate("uftb_read_misses", s0_fire_next_cycle && !s1_hit) 188*11d0c81dSLingrui98 XSPerfAccumulate("uftb_commit_hits", u.valid && u_meta.hit) 189*11d0c81dSLingrui98 XSPerfAccumulate("uftb_commit_misses", u.valid && !u_meta.hit) 190*11d0c81dSLingrui98 XSPerfAccumulate("uftb_commit_read_hit_pred_miss", u.valid && !u_meta.hit && u_s0_hit_oh.orR) 191*11d0c81dSLingrui98 for (w <- 0 until numWays) { 192*11d0c81dSLingrui98 XSPerfAccumulate(f"uftb_pred_hit_way_${w}", u_pred_hit_way_map(w)) 193*11d0c81dSLingrui98 XSPerfAccumulate(f"uftb_commit_hit_way_${w}", u_commit_hit_way_map(w)) 194*11d0c81dSLingrui98 XSPerfAccumulate(f"uftb_replace_way_${w}", !u_s1_hit && u_s1_alloc_way === w.U) 195*11d0c81dSLingrui98 } 196*11d0c81dSLingrui98 197*11d0c81dSLingrui98 override val perfEvents = Seq( 198*11d0c81dSLingrui98 ("fauftb_commit_hit ", u.valid && u_meta.hit), 199*11d0c81dSLingrui98 ("fauftb_commit_miss ", u.valid && !u_meta.hit), 200*11d0c81dSLingrui98 ) 201*11d0c81dSLingrui98 generatePerfEvent() 202*11d0c81dSLingrui98 203*11d0c81dSLingrui98}