111d0c81dSLingrui98/*************************************************************************************** 211d0c81dSLingrui98* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 311d0c81dSLingrui98* Copyright (c) 2020-2021 Peng Cheng Laboratory 411d0c81dSLingrui98* 511d0c81dSLingrui98* XiangShan is licensed under Mulan PSL v2. 611d0c81dSLingrui98* You can use this software according to the terms and conditions of the Mulan PSL v2. 711d0c81dSLingrui98* You may obtain a copy of Mulan PSL v2 at: 811d0c81dSLingrui98* http://license.coscl.org.cn/MulanPSL2 911d0c81dSLingrui98* 1011d0c81dSLingrui98* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 1111d0c81dSLingrui98* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 1211d0c81dSLingrui98* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 1311d0c81dSLingrui98* 1411d0c81dSLingrui98* See the Mulan PSL v2 for more details. 1511d0c81dSLingrui98***************************************************************************************/ 1611d0c81dSLingrui98 1711d0c81dSLingrui98package xiangshan.frontend 1811d0c81dSLingrui98 1911d0c81dSLingrui98import chisel3._ 2011d0c81dSLingrui98import chisel3.util._ 21cf7d6b7aSMuziimport org.chipsalliance.cde.config.Parameters 2211d0c81dSLingrui98import scala.{Tuple2 => &} 23cf7d6b7aSMuziimport utility._ 24cf7d6b7aSMuziimport xiangshan._ 2511d0c81dSLingrui98 2611d0c81dSLingrui98trait FauFTBParams extends HasXSParameter with HasBPUConst { 2711d0c81dSLingrui98 val numWays = 32 2811d0c81dSLingrui98 val tagSize = 16 2911d0c81dSLingrui98 3011d0c81dSLingrui98 val TAR_STAT_SZ = 2 3111d0c81dSLingrui98 def TAR_FIT = 0.U(TAR_STAT_SZ.W) 3211d0c81dSLingrui98 def TAR_OVF = 1.U(TAR_STAT_SZ.W) 3311d0c81dSLingrui98 def TAR_UDF = 2.U(TAR_STAT_SZ.W) 3411d0c81dSLingrui98 3511d0c81dSLingrui98 def BR_OFFSET_LEN = 12 3611d0c81dSLingrui98 def JMP_OFFSET_LEN = 20 3711d0c81dSLingrui98 3811d0c81dSLingrui98 def getTag(pc: UInt) = pc(tagSize + instOffsetBits - 1, instOffsetBits) 3911d0c81dSLingrui98} 4011d0c81dSLingrui98 4111d0c81dSLingrui98class FauFTBEntry(implicit p: Parameters) extends FTBEntry()(p) {} 4211d0c81dSLingrui98 4311d0c81dSLingrui98class FauFTBWay(implicit p: Parameters) extends XSModule with FauFTBParams { 4411d0c81dSLingrui98 val io = IO(new Bundle { 4511d0c81dSLingrui98 val req_tag = Input(UInt(tagSize.W)) 4611d0c81dSLingrui98 val resp = Output(new FauFTBEntry) 4711d0c81dSLingrui98 val resp_hit = Output(Bool()) 4811d0c81dSLingrui98 val update_req_tag = Input(UInt(tagSize.W)) 4911d0c81dSLingrui98 val update_hit = Output(Bool()) 5011d0c81dSLingrui98 val write_valid = Input(Bool()) 5111d0c81dSLingrui98 val write_entry = Input(new FauFTBEntry) 5211d0c81dSLingrui98 val write_tag = Input(UInt(tagSize.W)) 5311d0c81dSLingrui98 val tag_read = Output(UInt(tagSize.W)) 5411d0c81dSLingrui98 }) 5511d0c81dSLingrui98 5611d0c81dSLingrui98 val data = Reg(new FauFTBEntry) 5711d0c81dSLingrui98 val tag = Reg(UInt(tagSize.W)) 5811d0c81dSLingrui98 val valid = RegInit(false.B) 5911d0c81dSLingrui98 6011d0c81dSLingrui98 io.resp := data 6111d0c81dSLingrui98 io.resp_hit := tag === io.req_tag && valid 6211d0c81dSLingrui98 // write bypass to avoid multiple hit 6311d0c81dSLingrui98 io.update_hit := ((tag === io.update_req_tag) && valid) || 6411d0c81dSLingrui98 ((io.write_tag === io.update_req_tag) && io.write_valid) 6511d0c81dSLingrui98 io.tag_read := tag 6611d0c81dSLingrui98 6711d0c81dSLingrui98 when(io.write_valid) { 6811d0c81dSLingrui98 when(!valid) { 6911d0c81dSLingrui98 valid := true.B 7011d0c81dSLingrui98 } 7111d0c81dSLingrui98 tag := io.write_tag 7211d0c81dSLingrui98 data := io.write_entry 7311d0c81dSLingrui98 } 7411d0c81dSLingrui98} 7511d0c81dSLingrui98 7611d0c81dSLingrui98class FauFTB(implicit p: Parameters) extends BasePredictor with FauFTBParams { 7711d0c81dSLingrui98 7811d0c81dSLingrui98 class FauFTBMeta(implicit p: Parameters) extends XSBundle with FauFTBParams { 79deb3a97eSGao-Zeyu val pred_way = if (!env.FPGAPlatform) Some(UInt(log2Ceil(numWays).W)) else None 8011d0c81dSLingrui98 val hit = Bool() 8111d0c81dSLingrui98 } 8211d0c81dSLingrui98 val resp_meta = Wire(new FauFTBMeta) 8311d0c81dSLingrui98 override val meta_size = resp_meta.getWidth 84b60e4b0bSLingrui98 override val is_fast_pred = true 8511d0c81dSLingrui98 8611d0c81dSLingrui98 val ways = Seq.tabulate(numWays)(w => Module(new FauFTBWay)) 8711d0c81dSLingrui98 // numWays * numBr 8811d0c81dSLingrui98 val ctrs = Seq.tabulate(numWays)(w => Seq.tabulate(numBr)(b => RegInit(2.U(2.W)))) 8911d0c81dSLingrui98 val replacer = ReplacementPolicy.fromString("plru", numWays) 9011d0c81dSLingrui98 val replacer_touch_ways = Wire(Vec(2, Valid(UInt(log2Ceil(numWays).W)))) 9111d0c81dSLingrui98 9211d0c81dSLingrui98 // pred req 93adc0b8dfSGuokai Chen ways.foreach(_.io.req_tag := getTag(s1_pc_dup(0))) 9411d0c81dSLingrui98 9511d0c81dSLingrui98 // pred resp 9611d0c81dSLingrui98 val s1_hit_oh = VecInit(ways.map(_.io.resp_hit)).asUInt 9711d0c81dSLingrui98 val s1_hit = s1_hit_oh.orR 9811d0c81dSLingrui98 val s1_hit_way = OHToUInt(s1_hit_oh) 99c6a44c35Smy-mayfly val s1_possible_full_preds = Wire(Vec(numWays, new FullBranchPrediction(isNotS3 = true))) 10011d0c81dSLingrui98 10111d0c81dSLingrui98 val s1_all_entries = VecInit(ways.map(_.io.resp)) 10211d0c81dSLingrui98 for (c & fp & e <- ctrs zip s1_possible_full_preds zip s1_all_entries) { 10311d0c81dSLingrui98 fp.hit := DontCare 104fd3aa057SYuandongliang fp.multiHit := false.B 105adc0b8dfSGuokai Chen fp.fromFtbEntry(e, s1_pc_dup(0)) 10611d0c81dSLingrui98 for (i <- 0 until numBr) { 107dcf4211fSYuandongliang fp.br_taken_mask(i) := c(i)(1) || e.strong_bias(i) 10811d0c81dSLingrui98 } 10911d0c81dSLingrui98 } 11011d0c81dSLingrui98 val s1_hit_full_pred = Mux1H(s1_hit_oh, s1_possible_full_preds) 111fd3aa057SYuandongliang val s1_hit_fauftbentry = Mux1H(s1_hit_oh, s1_all_entries) 11211d0c81dSLingrui98 XSError(PopCount(s1_hit_oh) > 1.U, "fauftb has multiple hits!\n") 11311d0c81dSLingrui98 val fauftb_enable = RegNext(io.ctrl.ubtb_enable) 114adc0b8dfSGuokai Chen io.out.s1.full_pred.map(_ := s1_hit_full_pred) 115adc0b8dfSGuokai Chen io.out.s1.full_pred.map(_.hit := s1_hit && fauftb_enable) 116fd3aa057SYuandongliang io.fauftb_entry_out := s1_hit_fauftbentry 117fd3aa057SYuandongliang io.fauftb_entry_hit_out := s1_hit && fauftb_enable 118fd3aa057SYuandongliang 119cabb9f41SYuandongliang // Illegal check for FTB entry reading 120cabb9f41SYuandongliang val s1_pc_startLower = Cat(0.U(1.W), s1_pc_dup(0)(instOffsetBits + log2Ceil(PredictWidth) - 1, instOffsetBits)) 121cabb9f41SYuandongliang val uftb_entry_endLowerwithCarry = Cat(s1_hit_fauftbentry.carry, s1_hit_fauftbentry.pftAddr) 122cf7d6b7aSMuzi val fallThroughErr = s1_pc_startLower + PredictWidth.U >= uftb_entry_endLowerwithCarry 123cabb9f41SYuandongliang when(io.s1_fire(0) && s1_hit) { 124cabb9f41SYuandongliang assert(fallThroughErr, s"FauFTB read entry fallThrough address error!") 125cabb9f41SYuandongliang } 126cabb9f41SYuandongliang 12711d0c81dSLingrui98 // assign metas 12811d0c81dSLingrui98 io.out.last_stage_meta := resp_meta.asUInt 129adc0b8dfSGuokai Chen resp_meta.hit := RegEnable(RegEnable(s1_hit, io.s1_fire(0)), io.s2_fire(0)) 130cf7d6b7aSMuzi if (resp_meta.pred_way.isDefined) { 131cf7d6b7aSMuzi resp_meta.pred_way.get := RegEnable(RegEnable(s1_hit_way, io.s1_fire(0)), io.s2_fire(0)) 132cf7d6b7aSMuzi } 13311d0c81dSLingrui98 13411d0c81dSLingrui98 // pred update replacer state 135adc0b8dfSGuokai Chen val s1_fire = io.s1_fire(0) 136adc0b8dfSGuokai Chen replacer_touch_ways(0).valid := RegNext(s1_fire(0) && s1_hit) 137adc0b8dfSGuokai Chen replacer_touch_ways(0).bits := RegEnable(s1_hit_way, s1_fire(0) && s1_hit) 13811d0c81dSLingrui98 13911d0c81dSLingrui98 /********************** update ***********************/ 14011d0c81dSLingrui98 // s0: update_valid, read and tag comparison 14111d0c81dSLingrui98 // s1: alloc_way and write 14211d0c81dSLingrui98 14311d0c81dSLingrui98 // s0 144*03426fe2Spengxiao val u_valid = RegNext(io.update.valid, init = false.B) 145*03426fe2Spengxiao val u_bits = RegEnable(io.update.bits, io.update.valid) 146*03426fe2Spengxiao 147*03426fe2Spengxiao // 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*03426fe2Spengxiao // so io.update.bits.pc is used directly here 149*03426fe2Spengxiao val u_pc = io.update.bits.pc 150*03426fe2Spengxiao 151*03426fe2Spengxiao val u_meta = u_bits.meta.asTypeOf(new FauFTBMeta) 152*03426fe2Spengxiao val u_s0_tag = getTag(u_pc) 15311d0c81dSLingrui98 ways.foreach(_.io.update_req_tag := u_s0_tag) 15411d0c81dSLingrui98 val u_s0_hit_oh = VecInit(ways.map(_.io.update_hit)).asUInt 15511d0c81dSLingrui98 val u_s0_hit = u_s0_hit_oh.orR 15611d0c81dSLingrui98 val u_s0_br_update_valids = 15711d0c81dSLingrui98 VecInit((0 until numBr).map(w => 158*03426fe2Spengxiao u_bits.ftb_entry.brValids(w) && u_valid && !u_bits.ftb_entry.strong_bias(w) && 159*03426fe2Spengxiao !(PriorityEncoder(u_bits.br_taken_mask) < w.U) 160cf7d6b7aSMuzi )) 16111d0c81dSLingrui98 16211d0c81dSLingrui98 // s1 163*03426fe2Spengxiao val u_s1_valid = RegNext(u_valid) 164*03426fe2Spengxiao val u_s1_tag = RegEnable(u_s0_tag, u_valid) 165*03426fe2Spengxiao val u_s1_hit_oh = RegEnable(u_s0_hit_oh, u_valid) 166*03426fe2Spengxiao val u_s1_hit = RegEnable(u_s0_hit, u_valid) 16711d0c81dSLingrui98 val u_s1_alloc_way = replacer.way 16811d0c81dSLingrui98 val u_s1_write_way_oh = Mux(u_s1_hit, u_s1_hit_oh, UIntToOH(u_s1_alloc_way)) 169*03426fe2Spengxiao val u_s1_ftb_entry = RegEnable(u_bits.ftb_entry, u_valid) 17011d0c81dSLingrui98 val u_s1_ways_write_valid = VecInit((0 until numWays).map(w => u_s1_write_way_oh(w).asBool && u_s1_valid)) 17111d0c81dSLingrui98 for (w <- 0 until numWays) { 17211d0c81dSLingrui98 ways(w).io.write_valid := u_s1_ways_write_valid(w) 17311d0c81dSLingrui98 ways(w).io.write_tag := u_s1_tag 17411d0c81dSLingrui98 ways(w).io.write_entry := u_s1_ftb_entry 17511d0c81dSLingrui98 } 17611d0c81dSLingrui98 177fd3aa057SYuandongliang // Illegal check for FTB entry writing 178*03426fe2Spengxiao val uftb_write_pc = RegEnable(u_pc, u_valid) 179fd3aa057SYuandongliang val uftb_write_fallThrough = u_s1_ftb_entry.getFallThrough(uftb_write_pc) 180fd3aa057SYuandongliang when(u_s1_valid && u_s1_hit) { 181cf7d6b7aSMuzi assert( 182cf7d6b7aSMuzi uftb_write_pc + (FetchWidth * 4).U >= uftb_write_fallThrough, 183cf7d6b7aSMuzi s"FauFTB write entry fallThrough address error!" 184cf7d6b7aSMuzi ) 185fd3aa057SYuandongliang } 186fd3aa057SYuandongliang 18711d0c81dSLingrui98 // update saturating counters 188*03426fe2Spengxiao val u_s1_br_update_valids = RegEnable(u_s0_br_update_valids, u_valid) 189*03426fe2Spengxiao val u_s1_br_takens = RegEnable(u_bits.br_taken_mask, u_valid) 19011d0c81dSLingrui98 for (w <- 0 until numWays) { 19111d0c81dSLingrui98 when(u_s1_ways_write_valid(w)) { 19211d0c81dSLingrui98 for (br <- 0 until numBr) { 19311d0c81dSLingrui98 when(u_s1_br_update_valids(br)) { 19411d0c81dSLingrui98 ctrs(w)(br) := satUpdate(ctrs(w)(br), 2, u_s1_br_takens(br)) 19511d0c81dSLingrui98 } 19611d0c81dSLingrui98 } 19711d0c81dSLingrui98 } 19811d0c81dSLingrui98 } 19911d0c81dSLingrui98 20011d0c81dSLingrui98 // commit update replacer state 20111d0c81dSLingrui98 replacer_touch_ways(1).valid := u_s1_valid 20211d0c81dSLingrui98 replacer_touch_ways(1).bits := OHToUInt(u_s1_write_way_oh) 20311d0c81dSLingrui98 20411d0c81dSLingrui98 /******** update replacer *********/ 20511d0c81dSLingrui98 replacer.access(replacer_touch_ways) 20611d0c81dSLingrui98 20711d0c81dSLingrui98 /********************** perf counters **********************/ 208adc0b8dfSGuokai Chen val s0_fire_next_cycle = RegNext(io.s0_fire(0)) 20911d0c81dSLingrui98 val u_pred_hit_way_map = (0 until numWays).map(w => s0_fire_next_cycle && s1_hit && s1_hit_way === w.U) 21011d0c81dSLingrui98 XSPerfAccumulate("uftb_read_hits", s0_fire_next_cycle && s1_hit) 21111d0c81dSLingrui98 XSPerfAccumulate("uftb_read_misses", s0_fire_next_cycle && !s1_hit) 212*03426fe2Spengxiao XSPerfAccumulate("uftb_commit_hits", u_valid && u_meta.hit) 213*03426fe2Spengxiao XSPerfAccumulate("uftb_commit_misses", u_valid && !u_meta.hit) 214*03426fe2Spengxiao XSPerfAccumulate("uftb_commit_read_hit_pred_miss", u_valid && !u_meta.hit && u_s0_hit_oh.orR) 21511d0c81dSLingrui98 for (w <- 0 until numWays) { 21611d0c81dSLingrui98 XSPerfAccumulate(f"uftb_pred_hit_way_${w}", u_pred_hit_way_map(w)) 21711d0c81dSLingrui98 XSPerfAccumulate(f"uftb_replace_way_${w}", !u_s1_hit && u_s1_alloc_way === w.U) 21811d0c81dSLingrui98 } 21911d0c81dSLingrui98 220deb3a97eSGao-Zeyu if (u_meta.pred_way.isDefined) { 221*03426fe2Spengxiao val u_commit_hit_way_map = (0 until numWays).map(w => u_valid && u_meta.hit && u_meta.pred_way.get === w.U) 222deb3a97eSGao-Zeyu for (w <- 0 until numWays) { 223deb3a97eSGao-Zeyu XSPerfAccumulate(f"uftb_commit_hit_way_${w}", u_commit_hit_way_map(w)) 224deb3a97eSGao-Zeyu } 225deb3a97eSGao-Zeyu } 226deb3a97eSGao-Zeyu 22711d0c81dSLingrui98 override val perfEvents = Seq( 228*03426fe2Spengxiao ("fauftb_commit_hit ", u_valid && u_meta.hit), 229*03426fe2Spengxiao ("fauftb_commit_miss ", u_valid && !u_meta.hit) 23011d0c81dSLingrui98 ) 23111d0c81dSLingrui98 generatePerfEvent() 23211d0c81dSLingrui98 23311d0c81dSLingrui98} 234