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