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._ 22import utils._ 23import utility._ 24import xiangshan._ 25import xiangshan.frontend.icache._ 26import xiangshan.backend.CtrlToFtqIO 27import xiangshan.backend.decode.ImmUnion 28import utility.ChiselDB 29 30class FtqDebugBundle extends Bundle { 31 val pc = UInt(39.W) 32 val target = UInt(39.W) 33 val isBr = Bool() 34 val isJmp = Bool() 35 val isCall = Bool() 36 val isRet = Bool() 37 val misPred = Bool() 38 val isTaken = Bool() 39 val predStage = UInt(2.W) 40} 41 42class FtqPtr(entries: Int) extends CircularQueuePtr[FtqPtr]( 43 entries 44){ 45 def this()(implicit p: Parameters) = this(p(XSCoreParamsKey).FtqSize) 46} 47 48object FtqPtr { 49 def apply(f: Bool, v: UInt)(implicit p: Parameters): FtqPtr = { 50 val ptr = Wire(new FtqPtr) 51 ptr.flag := f 52 ptr.value := v 53 ptr 54 } 55 def inverse(ptr: FtqPtr)(implicit p: Parameters): FtqPtr = { 56 apply(!ptr.flag, ptr.value) 57 } 58} 59 60class FtqNRSRAM[T <: Data](gen: T, numRead: Int)(implicit p: Parameters) extends XSModule { 61 62 val io = IO(new Bundle() { 63 val raddr = Input(Vec(numRead, UInt(log2Up(FtqSize).W))) 64 val ren = Input(Vec(numRead, Bool())) 65 val rdata = Output(Vec(numRead, gen)) 66 val waddr = Input(UInt(log2Up(FtqSize).W)) 67 val wen = Input(Bool()) 68 val wdata = Input(gen) 69 }) 70 71 for(i <- 0 until numRead){ 72 val sram = Module(new SRAMTemplate(gen, FtqSize)) 73 sram.io.r.req.valid := io.ren(i) 74 sram.io.r.req.bits.setIdx := io.raddr(i) 75 io.rdata(i) := sram.io.r.resp.data(0) 76 sram.io.w.req.valid := io.wen 77 sram.io.w.req.bits.setIdx := io.waddr 78 sram.io.w.req.bits.data := VecInit(io.wdata) 79 } 80 81} 82 83class Ftq_RF_Components(implicit p: Parameters) extends XSBundle with BPUUtils { 84 val startAddr = UInt(VAddrBits.W) 85 val nextLineAddr = UInt(VAddrBits.W) 86 val isNextMask = Vec(PredictWidth, Bool()) 87 val fallThruError = Bool() 88 // val carry = Bool() 89 def getPc(offset: UInt) = { 90 def getHigher(pc: UInt) = pc(VAddrBits-1, log2Ceil(PredictWidth)+instOffsetBits+1) 91 def getOffset(pc: UInt) = pc(log2Ceil(PredictWidth)+instOffsetBits, instOffsetBits) 92 Cat(getHigher(Mux(isNextMask(offset) && startAddr(log2Ceil(PredictWidth)+instOffsetBits), nextLineAddr, startAddr)), 93 getOffset(startAddr)+offset, 0.U(instOffsetBits.W)) 94 } 95 def fromBranchPrediction(resp: BranchPredictionBundle) = { 96 def carryPos(addr: UInt) = addr(instOffsetBits+log2Ceil(PredictWidth)+1) 97 this.startAddr := resp.pc(3) 98 this.nextLineAddr := resp.pc(3) + (FetchWidth * 4 * 2).U // may be broken on other configs 99 this.isNextMask := VecInit((0 until PredictWidth).map(i => 100 (resp.pc(3)(log2Ceil(PredictWidth), 1) +& i.U)(log2Ceil(PredictWidth)).asBool 101 )) 102 this.fallThruError := resp.fallThruError(3) 103 this 104 } 105 override def toPrintable: Printable = { 106 p"startAddr:${Hexadecimal(startAddr)}" 107 } 108} 109 110class Ftq_pd_Entry(implicit p: Parameters) extends XSBundle { 111 val brMask = Vec(PredictWidth, Bool()) 112 val jmpInfo = ValidUndirectioned(Vec(3, Bool())) 113 val jmpOffset = UInt(log2Ceil(PredictWidth).W) 114 val jalTarget = UInt(VAddrBits.W) 115 val rvcMask = Vec(PredictWidth, Bool()) 116 def hasJal = jmpInfo.valid && !jmpInfo.bits(0) 117 def hasJalr = jmpInfo.valid && jmpInfo.bits(0) 118 def hasCall = jmpInfo.valid && jmpInfo.bits(1) 119 def hasRet = jmpInfo.valid && jmpInfo.bits(2) 120 121 def fromPdWb(pdWb: PredecodeWritebackBundle) = { 122 val pds = pdWb.pd 123 this.brMask := VecInit(pds.map(pd => pd.isBr && pd.valid)) 124 this.jmpInfo.valid := VecInit(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)).asUInt.orR 125 this.jmpInfo.bits := ParallelPriorityMux(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid), 126 pds.map(pd => VecInit(pd.isJalr, pd.isCall, pd.isRet))) 127 this.jmpOffset := ParallelPriorityEncoder(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)) 128 this.rvcMask := VecInit(pds.map(pd => pd.isRVC)) 129 this.jalTarget := pdWb.jalTarget 130 } 131 132 def toPd(offset: UInt) = { 133 require(offset.getWidth == log2Ceil(PredictWidth)) 134 val pd = Wire(new PreDecodeInfo) 135 pd.valid := true.B 136 pd.isRVC := rvcMask(offset) 137 val isBr = brMask(offset) 138 val isJalr = offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(0) 139 pd.brType := Cat(offset === jmpOffset && jmpInfo.valid, isJalr || isBr) 140 pd.isCall := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(1) 141 pd.isRet := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(2) 142 pd 143 } 144} 145 146class PrefetchPtrDB(implicit p: Parameters) extends Bundle { 147 val fromFtqPtr = UInt(log2Up(p(XSCoreParamsKey).FtqSize).W) 148 val fromIfuPtr = UInt(log2Up(p(XSCoreParamsKey).FtqSize).W) 149} 150 151class Ftq_Redirect_SRAMEntry(implicit p: Parameters) extends SpeculativeInfo { 152 val sc_disagree = if (!env.FPGAPlatform) Some(Vec(numBr, Bool())) else None 153} 154 155class Ftq_1R_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst { 156 val meta = UInt(MaxMetaLength.W) 157} 158 159class Ftq_Pred_Info(implicit p: Parameters) extends XSBundle { 160 val target = UInt(VAddrBits.W) 161 val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)) 162} 163 164 165class FtqRead[T <: Data](private val gen: T)(implicit p: Parameters) extends XSBundle { 166 val ptr = Output(new FtqPtr) 167 val offset = Output(UInt(log2Ceil(PredictWidth).W)) 168 val data = Input(gen) 169 def apply(ptr: FtqPtr, offset: UInt) = { 170 this.ptr := ptr 171 this.offset := offset 172 this.data 173 } 174} 175 176 177class FtqToBpuIO(implicit p: Parameters) extends XSBundle { 178 val redirect = Valid(new BranchPredictionRedirect) 179 val update = Valid(new BranchPredictionUpdate) 180 val enq_ptr = Output(new FtqPtr) 181} 182 183class FtqToIfuIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper { 184 val req = Decoupled(new FetchRequestBundle) 185 val redirect = Valid(new BranchPredictionRedirect) 186 val topdown_redirect = Valid(new BranchPredictionRedirect) 187 val flushFromBpu = new Bundle { 188 // when ifu pipeline is not stalled, 189 // a packet from bpu s3 can reach f1 at most 190 val s2 = Valid(new FtqPtr) 191 val s3 = Valid(new FtqPtr) 192 def shouldFlushBy(src: Valid[FtqPtr], idx_to_flush: FtqPtr) = { 193 src.valid && !isAfter(src.bits, idx_to_flush) 194 } 195 def shouldFlushByStage2(idx: FtqPtr) = shouldFlushBy(s2, idx) 196 def shouldFlushByStage3(idx: FtqPtr) = shouldFlushBy(s3, idx) 197 } 198} 199 200class FtqToICacheIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper { 201 //NOTE: req.bits must be prepare in T cycle 202 // while req.valid is set true in T + 1 cycle 203 val req = Decoupled(new FtqToICacheRequestBundle) 204} 205 206trait HasBackendRedirectInfo extends HasXSParameter { 207 def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself() 208} 209 210class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo { 211 // write to backend pc mem 212 val pc_mem_wen = Output(Bool()) 213 val pc_mem_waddr = Output(UInt(log2Ceil(FtqSize).W)) 214 val pc_mem_wdata = Output(new Ftq_RF_Components) 215 // newest target 216 val newest_entry_target = Output(UInt(VAddrBits.W)) 217 val newest_entry_ptr = Output(new FtqPtr) 218} 219 220 221class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter { 222 val io = IO(new Bundle { 223 val start_addr = Input(UInt(VAddrBits.W)) 224 val old_entry = Input(new FTBEntry) 225 val pd = Input(new Ftq_pd_Entry) 226 val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W))) 227 val target = Input(UInt(VAddrBits.W)) 228 val hit = Input(Bool()) 229 val mispredict_vec = Input(Vec(PredictWidth, Bool())) 230 231 val new_entry = Output(new FTBEntry) 232 val new_br_insert_pos = Output(Vec(numBr, Bool())) 233 val taken_mask = Output(Vec(numBr, Bool())) 234 val jmp_taken = Output(Bool()) 235 val mispred_mask = Output(Vec(numBr+1, Bool())) 236 237 // for perf counters 238 val is_init_entry = Output(Bool()) 239 val is_old_entry = Output(Bool()) 240 val is_new_br = Output(Bool()) 241 val is_jalr_target_modified = Output(Bool()) 242 val is_always_taken_modified = Output(Bool()) 243 val is_br_full = Output(Bool()) 244 }) 245 246 // no mispredictions detected at predecode 247 val hit = io.hit 248 val pd = io.pd 249 250 val init_entry = WireInit(0.U.asTypeOf(new FTBEntry)) 251 252 253 val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid 254 val entry_has_jmp = pd.jmpInfo.valid 255 val new_jmp_is_jal = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid 256 val new_jmp_is_jalr = entry_has_jmp && pd.jmpInfo.bits(0) && io.cfiIndex.valid 257 val new_jmp_is_call = entry_has_jmp && pd.jmpInfo.bits(1) && io.cfiIndex.valid 258 val new_jmp_is_ret = entry_has_jmp && pd.jmpInfo.bits(2) && io.cfiIndex.valid 259 val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask.last 260 // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last 261 262 val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal 263 val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr 264 265 def carryPos = log2Ceil(PredictWidth)+instOffsetBits 266 def getLower(pc: UInt) = pc(carryPos-1, instOffsetBits) 267 // if not hit, establish a new entry 268 init_entry.valid := true.B 269 // tag is left for ftb to assign 270 271 // case br 272 val init_br_slot = init_entry.getSlotForBr(0) 273 when (cfi_is_br) { 274 init_br_slot.valid := true.B 275 init_br_slot.offset := io.cfiIndex.bits 276 init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1) 277 init_entry.always_taken(0) := true.B // set to always taken on init 278 } 279 280 // case jmp 281 when (entry_has_jmp) { 282 init_entry.tailSlot.offset := pd.jmpOffset 283 init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr 284 init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare=false) 285 } 286 287 val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U) 288 init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr)) 289 init_entry.carry := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos-instOffsetBits), true.B) 290 init_entry.isJalr := new_jmp_is_jalr 291 init_entry.isCall := new_jmp_is_call 292 init_entry.isRet := new_jmp_is_ret 293 // that means fall thru points to the middle of an inst 294 init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask(pd.jmpOffset) 295 296 // if hit, check whether a new cfi(only br is possible) is detected 297 val oe = io.old_entry 298 val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits) 299 val br_recorded = br_recorded_vec.asUInt.orR 300 val is_new_br = cfi_is_br && !br_recorded 301 val new_br_offset = io.cfiIndex.bits 302 // vec(i) means new br will be inserted BEFORE old br(i) 303 val allBrSlotsVec = oe.allSlotsForBr 304 val new_br_insert_onehot = VecInit((0 until numBr).map{ 305 i => i match { 306 case 0 => 307 !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset 308 case idx => 309 allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset && 310 (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset) 311 } 312 }) 313 314 val old_entry_modified = WireInit(io.old_entry) 315 for (i <- 0 until numBr) { 316 val slot = old_entry_modified.allSlotsForBr(i) 317 when (new_br_insert_onehot(i)) { 318 slot.valid := true.B 319 slot.offset := new_br_offset 320 slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr-1) 321 old_entry_modified.always_taken(i) := true.B 322 }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) { 323 old_entry_modified.always_taken(i) := false.B 324 // all other fields remain unchanged 325 }.otherwise { 326 // case i == 0, remain unchanged 327 if (i != 0) { 328 val noNeedToMoveFromFormerSlot = (i == numBr-1).B && !oe.brSlots.last.valid 329 when (!noNeedToMoveFromFormerSlot) { 330 slot.fromAnotherSlot(oe.allSlotsForBr(i-1)) 331 old_entry_modified.always_taken(i) := oe.always_taken(i) 332 } 333 } 334 } 335 } 336 337 // two circumstances: 338 // 1. oe: | br | j |, new br should be in front of j, thus addr of j should be new pft 339 // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either 340 // the previous last br or the new br 341 val may_have_to_replace = oe.noEmptySlotForNewBr 342 val pft_need_to_change = is_new_br && may_have_to_replace 343 // it should either be the given last br or the new br 344 when (pft_need_to_change) { 345 val new_pft_offset = 346 Mux(!new_br_insert_onehot.asUInt.orR, 347 new_br_offset, oe.allSlotsForBr.last.offset) 348 349 // set jmp to invalid 350 old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset 351 old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool 352 old_entry_modified.last_may_be_rvi_call := false.B 353 old_entry_modified.isCall := false.B 354 old_entry_modified.isRet := false.B 355 old_entry_modified.isJalr := false.B 356 } 357 358 val old_entry_jmp_target_modified = WireInit(oe) 359 val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits 360 val old_tail_is_jmp = !oe.tailSlot.sharing 361 val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target 362 when (jalr_target_modified) { 363 old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target) 364 old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool())) 365 } 366 367 val old_entry_always_taken = WireInit(oe) 368 val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not 369 for (i <- 0 until numBr) { 370 old_entry_always_taken.always_taken(i) := 371 oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i) 372 always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i) 373 } 374 val always_taken_modified = always_taken_modified_vec.reduce(_||_) 375 376 377 378 val derived_from_old_entry = 379 Mux(is_new_br, old_entry_modified, 380 Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken)) 381 382 383 io.new_entry := Mux(!hit, init_entry, derived_from_old_entry) 384 385 io.new_br_insert_pos := new_br_insert_onehot 386 io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{ 387 case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v 388 }) 389 io.jmp_taken := io.new_entry.jmpValid && io.new_entry.tailSlot.offset === io.cfiIndex.bits 390 for (i <- 0 until numBr) { 391 io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i)) 392 } 393 io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset) 394 395 // for perf counters 396 io.is_init_entry := !hit 397 io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified 398 io.is_new_br := hit && is_new_br 399 io.is_jalr_target_modified := hit && jalr_target_modified 400 io.is_always_taken_modified := hit && always_taken_modified 401 io.is_br_full := hit && is_new_br && may_have_to_replace 402} 403 404class FtqPcMemWrapper(numOtherReads: Int)(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo { 405 val io = IO(new Bundle { 406 val ifuPtr_w = Input(new FtqPtr) 407 val ifuPtrPlus1_w = Input(new FtqPtr) 408 val ifuPtrPlus2_w = Input(new FtqPtr) 409 val commPtr_w = Input(new FtqPtr) 410 val commPtrPlus1_w = Input(new FtqPtr) 411 val ifuPtr_rdata = Output(new Ftq_RF_Components) 412 val ifuPtrPlus1_rdata = Output(new Ftq_RF_Components) 413 val ifuPtrPlus2_rdata = Output(new Ftq_RF_Components) 414 val commPtr_rdata = Output(new Ftq_RF_Components) 415 val commPtrPlus1_rdata = Output(new Ftq_RF_Components) 416 417 val other_raddrs = Input(Vec(numOtherReads, UInt(log2Ceil(FtqSize).W))) 418 val other_rdatas = Output(Vec(numOtherReads, new Ftq_RF_Components)) 419 420 val wen = Input(Bool()) 421 val waddr = Input(UInt(log2Ceil(FtqSize).W)) 422 val wdata = Input(new Ftq_RF_Components) 423 }) 424 425 val num_pc_read = numOtherReads + 5 426 val mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, 427 num_pc_read, 1, "FtqPC")) 428 mem.io.wen(0) := io.wen 429 mem.io.waddr(0) := io.waddr 430 mem.io.wdata(0) := io.wdata 431 432 // read one cycle ahead for ftq local reads 433 val raddr_vec = VecInit(io.other_raddrs ++ 434 Seq(io.ifuPtr_w.value, io.ifuPtrPlus1_w.value, io.ifuPtrPlus2_w.value, io.commPtrPlus1_w.value, io.commPtr_w.value)) 435 436 mem.io.raddr := raddr_vec 437 438 io.other_rdatas := mem.io.rdata.dropRight(5) 439 io.ifuPtr_rdata := mem.io.rdata.dropRight(4).last 440 io.ifuPtrPlus1_rdata := mem.io.rdata.dropRight(3).last 441 io.ifuPtrPlus2_rdata := mem.io.rdata.dropRight(2).last 442 io.commPtrPlus1_rdata := mem.io.rdata.dropRight(1).last 443 io.commPtr_rdata := mem.io.rdata.last 444} 445 446class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper 447 with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents 448 with HasICacheParameters{ 449 val io = IO(new Bundle { 450 val fromBpu = Flipped(new BpuToFtqIO) 451 val fromIfu = Flipped(new IfuToFtqIO) 452 val fromBackend = Flipped(new CtrlToFtqIO) 453 454 val toBpu = new FtqToBpuIO 455 val toIfu = new FtqToIfuIO 456 val toICache = new FtqToICacheIO 457 val toBackend = new FtqToCtrlIO 458 459 val toPrefetch = new FtqPrefechBundle 460 461 val bpuInfo = new Bundle { 462 val bpRight = Output(UInt(XLEN.W)) 463 val bpWrong = Output(UInt(XLEN.W)) 464 } 465 466 val mmioCommitRead = Flipped(new mmioCommitRead) 467 468 // for perf 469 val ControlBTBMissBubble = Output(Bool()) 470 val TAGEMissBubble = Output(Bool()) 471 val SCMissBubble = Output(Bool()) 472 val ITTAGEMissBubble = Output(Bool()) 473 val RASMissBubble = Output(Bool()) 474 }) 475 io.bpuInfo := DontCare 476 477 val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle)) 478 // only driven by clock, not valid-ready 479 topdown_stage := io.fromBpu.resp.bits.topdown_info 480 io.toIfu.req.bits.topdown_info := topdown_stage 481 482 val ifuRedirected = RegInit(VecInit(Seq.fill(FtqSize)(false.B))) 483 484 485 // io.fromBackend.ftqIdxAhead: jmp + alu(aluCnt) + ldReplay + exception 486 val aluAheadStart = 1 487 val ftqIdxAhead = VecInit(Seq.tabulate(FtqRedirectAheadNum)(i => io.fromBackend.ftqIdxAhead(i + aluAheadStart))) // only alu 488 val ftqIdxSelOH = io.fromBackend.ftqIdxSelOH.bits(FtqRedirectAheadNum, 1) 489 490 val aheadValid = ftqIdxAhead.map(_.valid).reduce(_|_) && !io.fromBackend.redirect.valid 491 val realAhdValid = io.fromBackend.redirect.valid && (ftqIdxSelOH > 0.U) && RegNext(aheadValid) 492 val backendRedirect = Wire(Valid(new BranchPredictionRedirect)) 493 val backendRedirectReg = RegNext(backendRedirect) 494 backendRedirectReg.valid := Mux(realAhdValid, 0.B, backendRedirect.valid) 495 val fromBackendRedirect = Wire(Valid(new BranchPredictionRedirect)) 496 fromBackendRedirect := Mux(realAhdValid, backendRedirect, backendRedirectReg) 497 498 val stage2Flush = backendRedirect.valid 499 val backendFlush = stage2Flush || RegNext(stage2Flush) 500 val ifuFlush = Wire(Bool()) 501 502 val flush = stage2Flush || RegNext(stage2Flush) 503 504 val allowBpuIn, allowToIfu = WireInit(false.B) 505 val flushToIfu = !allowToIfu 506 allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 507 allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 508 509 def copyNum = 5 510 val bpuPtr, ifuPtr, ifuWbPtr, commPtr, robCommPtr = RegInit(FtqPtr(false.B, 0.U)) 511 val ifuPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 512 val ifuPtrPlus2 = RegInit(FtqPtr(false.B, 2.U)) 513 val commPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 514 val copied_ifu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U))) 515 val copied_bpu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U))) 516 require(FtqSize >= 4) 517 val ifuPtr_write = WireInit(ifuPtr) 518 val ifuPtrPlus1_write = WireInit(ifuPtrPlus1) 519 val ifuPtrPlus2_write = WireInit(ifuPtrPlus2) 520 val ifuWbPtr_write = WireInit(ifuWbPtr) 521 val commPtr_write = WireInit(commPtr) 522 val commPtrPlus1_write = WireInit(commPtrPlus1) 523 val robCommPtr_write = WireInit(robCommPtr) 524 ifuPtr := ifuPtr_write 525 ifuPtrPlus1 := ifuPtrPlus1_write 526 ifuPtrPlus2 := ifuPtrPlus2_write 527 ifuWbPtr := ifuWbPtr_write 528 commPtr := commPtr_write 529 commPtrPlus1 := commPtrPlus1_write 530 copied_ifu_ptr.map{ptr => 531 ptr := ifuPtr_write 532 dontTouch(ptr) 533 } 534 robCommPtr := robCommPtr_write 535 val validEntries = distanceBetween(bpuPtr, commPtr) 536 val canCommit = Wire(Bool()) 537 538 // ********************************************************************** 539 // **************************** enq from bpu **************************** 540 // ********************************************************************** 541 val new_entry_ready = validEntries < FtqSize.U || canCommit 542 io.fromBpu.resp.ready := new_entry_ready 543 544 val bpu_s2_resp = io.fromBpu.resp.bits.s2 545 val bpu_s3_resp = io.fromBpu.resp.bits.s3 546 val bpu_s2_redirect = bpu_s2_resp.valid(3) && bpu_s2_resp.hasRedirect(3) 547 val bpu_s3_redirect = bpu_s3_resp.valid(3) && bpu_s3_resp.hasRedirect(3) 548 549 io.toBpu.enq_ptr := bpuPtr 550 val enq_fire = io.fromBpu.resp.fire && allowBpuIn // from bpu s1 551 val bpu_in_fire = (io.fromBpu.resp.fire || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn 552 553 val bpu_in_resp = io.fromBpu.resp.bits.selectedResp 554 val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdxForFtq 555 val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx) 556 val bpu_in_resp_idx = bpu_in_resp_ptr.value 557 558 // read ports: prefetchReq ++ ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate 559 val ftq_pc_mem = Module(new FtqPcMemWrapper(1)) 560 // resp from uBTB 561 ftq_pc_mem.io.wen := bpu_in_fire 562 ftq_pc_mem.io.waddr := bpu_in_resp_idx 563 ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp) 564 565 // ifuRedirect + backendRedirect + commit 566 val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+FtqRedirectAheadNum+1)) 567 // these info is intended to enq at the last stage of bpu 568 ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3) 569 ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 570 ftq_redirect_sram.io.wdata := io.fromBpu.resp.bits.last_stage_spec_info 571 println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3") 572 println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3") 573 574 val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1)) 575 // these info is intended to enq at the last stage of bpu 576 ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3) 577 ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 578 ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.last_stage_meta 579 // ifuRedirect + backendRedirect + commit 580 val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+FtqRedirectAheadNum+1, 1)) 581 ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid(3) 582 ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value 583 ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_ftb_entry 584 585 586 // multi-write 587 val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this 588 val newest_entry_target = Reg(UInt(VAddrBits.W)) 589 val newest_entry_ptr = Reg(new FtqPtr) 590 val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))) 591 val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool()))) 592 val pred_stage = Reg(Vec(FtqSize, UInt(2.W))) 593 val pred_s1_cycle = if (!env.FPGAPlatform) Some(Reg(Vec(FtqSize, UInt(64.W)))) else None 594 595 val c_invalid :: c_valid :: c_commited :: Nil = Enum(3) 596 val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) { 597 VecInit(Seq.fill(PredictWidth)(c_invalid)) 598 })) 599 600 val f_to_send :: f_sent :: Nil = Enum(2) 601 val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent))) 602 603 val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3) 604 val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit))) 605 606 // modify registers one cycle later to cut critical path 607 val last_cycle_bpu_in = RegNext(bpu_in_fire) 608 val last_cycle_bpu_in_ptr = RegNext(bpu_in_resp_ptr) 609 val last_cycle_bpu_in_idx = last_cycle_bpu_in_ptr.value 610 val last_cycle_bpu_target = RegNext(bpu_in_resp.getTarget(3)) 611 val last_cycle_cfiIndex = RegNext(bpu_in_resp.cfiIndex(3)) 612 val last_cycle_bpu_in_stage = RegNext(bpu_in_stage) 613 614 def extra_copyNum_for_commitStateQueue = 2 615 val copied_last_cycle_bpu_in = VecInit(Seq.fill(copyNum+extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_fire))) 616 val copied_last_cycle_bpu_in_ptr_for_ftq = VecInit(Seq.fill(extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_resp_ptr))) 617 618 when (last_cycle_bpu_in) { 619 entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send 620 cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex 621 pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage 622 623 update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this 624 newest_entry_target := last_cycle_bpu_target 625 newest_entry_ptr := last_cycle_bpu_in_ptr 626 } 627 628 // reduce fanout by delay write for a cycle 629 when (RegNext(last_cycle_bpu_in)) { 630 mispredict_vec(RegNext(last_cycle_bpu_in_idx)) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B))) 631 } 632 633 // record s1 pred cycles 634 pred_s1_cycle.map(vec => { 635 when (bpu_in_fire && (bpu_in_stage === BP_S1)) { 636 vec(bpu_in_resp_ptr.value) := bpu_in_resp.full_pred(0).predCycle.getOrElse(0.U) 637 } 638 }) 639 640 // reduce fanout using copied last_cycle_bpu_in and copied last_cycle_bpu_in_ptr 641 val copied_last_cycle_bpu_in_for_ftq = copied_last_cycle_bpu_in.takeRight(extra_copyNum_for_commitStateQueue) 642 copied_last_cycle_bpu_in_for_ftq.zip(copied_last_cycle_bpu_in_ptr_for_ftq).zipWithIndex.map { 643 case ((in, ptr), i) => 644 when (in) { 645 val perSetEntries = FtqSize / extra_copyNum_for_commitStateQueue // 32 646 require(FtqSize % extra_copyNum_for_commitStateQueue == 0) 647 for (j <- 0 until perSetEntries) { 648 when (ptr.value === (i*perSetEntries+j).U) { 649 commitStateQueue(i*perSetEntries+j) := VecInit(Seq.fill(PredictWidth)(c_invalid)) 650 } 651 } 652 } 653 } 654 655 // num cycle is fixed 656 io.toBackend.newest_entry_ptr := RegNext(newest_entry_ptr) 657 io.toBackend.newest_entry_target := RegNext(newest_entry_target) 658 659 660 bpuPtr := bpuPtr + enq_fire 661 copied_bpu_ptr.map(_ := bpuPtr + enq_fire) 662 when (io.toIfu.req.fire && allowToIfu) { 663 ifuPtr_write := ifuPtrPlus1 664 ifuPtrPlus1_write := ifuPtrPlus2 665 ifuPtrPlus2_write := ifuPtrPlus2 + 1.U 666 } 667 668 // only use ftb result to assign hit status 669 when (bpu_s2_resp.valid(3)) { 670 entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred(3).hit, h_hit, h_not_hit) 671 } 672 673 674 io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect 675 io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx 676 when (bpu_s2_redirect) { 677 bpuPtr := bpu_s2_resp.ftq_idx + 1.U 678 copied_bpu_ptr.map(_ := bpu_s2_resp.ftq_idx + 1.U) 679 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 680 when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) { 681 ifuPtr_write := bpu_s2_resp.ftq_idx 682 ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U 683 ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U 684 } 685 } 686 687 io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect 688 io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx 689 when (bpu_s3_redirect) { 690 bpuPtr := bpu_s3_resp.ftq_idx + 1.U 691 copied_bpu_ptr.map(_ := bpu_s3_resp.ftq_idx + 1.U) 692 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 693 when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) { 694 ifuPtr_write := bpu_s3_resp.ftq_idx 695 ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U 696 ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U 697 } 698 } 699 700 XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n") 701 XSError(isBefore(ifuWbPtr, commPtr) && !isFull(ifuWbPtr, commPtr), "\ncommPtr is before ifuWbPtr!\n") 702 703 (0 until copyNum).map{i => 704 XSError(copied_bpu_ptr(i) =/= bpuPtr, "\ncopiedBpuPtr is different from bpuPtr!\n") 705 } 706 707 // **************************************************************** 708 // **************************** to ifu **************************** 709 // **************************************************************** 710 // 0 for ifu, and 1-4 for ICache 711 val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire) 712 val copied_bpu_in_bypass_buf = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire))) 713 val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf 714 val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr) 715 val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire) 716 717 val copied_bpu_in_bypass_ptr = VecInit(Seq.fill(copyNum)(RegNext(bpu_in_resp_ptr))) 718 val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire))) 719 720 // read pc and target 721 ftq_pc_mem.io.ifuPtr_w := ifuPtr_write 722 ftq_pc_mem.io.ifuPtrPlus1_w := ifuPtrPlus1_write 723 ftq_pc_mem.io.ifuPtrPlus2_w := ifuPtrPlus2_write 724 ftq_pc_mem.io.commPtr_w := commPtr_write 725 ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write 726 727 728 io.toIfu.req.bits.ftqIdx := ifuPtr 729 730 val toICachePcBundle = Wire(Vec(copyNum,new Ftq_RF_Components)) 731 val toICacheEntryToSend = Wire(Vec(copyNum,Bool())) 732 val toIfuPcBundle = Wire(new Ftq_RF_Components) 733 val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send) 734 val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value)) 735 val entry_next_addr = Wire(UInt(VAddrBits.W)) 736 737 val pc_mem_ifu_ptr_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata))) 738 val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata))) 739 val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this 740 741 val copied_ifu_plus1_to_send = VecInit(Seq.fill(copyNum)(RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) || RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)))) 742 val copied_ifu_ptr_to_send = VecInit(Seq.fill(copyNum)(RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) || RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr))) 743 744 for(i <- 0 until copyNum){ 745 when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)){ 746 toICachePcBundle(i) := copied_bpu_in_bypass_buf(i) 747 toICacheEntryToSend(i) := true.B 748 }.elsewhen(copied_last_cycle_to_ifu_fire(i)){ 749 toICachePcBundle(i) := pc_mem_ifu_plus1_rdata(i) 750 toICacheEntryToSend(i) := copied_ifu_plus1_to_send(i) 751 }.otherwise{ 752 toICachePcBundle(i) := pc_mem_ifu_ptr_rdata(i) 753 toICacheEntryToSend(i) := copied_ifu_ptr_to_send(i) 754 } 755 } 756 757 // TODO: reconsider target address bypass logic 758 when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) { 759 toIfuPcBundle := bpu_in_bypass_buf_for_ifu 760 entry_is_to_send := true.B 761 entry_next_addr := last_cycle_bpu_target 762 entry_ftq_offset := last_cycle_cfiIndex 763 diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this 764 }.elsewhen (last_cycle_to_ifu_fire) { 765 toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata) 766 entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) || 767 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles 768 entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1), 769 bpu_in_bypass_buf_for_ifu.startAddr, 770 Mux(ifuPtr === newest_entry_ptr, 771 newest_entry_target, 772 RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))) // ifuPtr+2 773 }.otherwise { 774 toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata) 775 entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) || 776 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles 777 entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1), 778 bpu_in_bypass_buf_for_ifu.startAddr, 779 Mux(ifuPtr === newest_entry_ptr, 780 newest_entry_target, 781 RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))) // ifuPtr+1 782 } 783 784 io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 785 io.toIfu.req.bits.nextStartAddr := entry_next_addr 786 io.toIfu.req.bits.ftqOffset := entry_ftq_offset 787 io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle) 788 789 io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 790 io.toICache.req.bits.readValid.zipWithIndex.map{case(copy, i) => copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)} 791 io.toICache.req.bits.pcMemRead.zipWithIndex.map{case(copy,i) => copy.fromFtqPcBundle(toICachePcBundle(i))} 792 // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr 793 // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) => 794 // bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr 795 // bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr 796 // } 797 798 // TODO: remove this 799 XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr, 800 p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n") 801 802 // when fall through is smaller in value than start address, there must be a false hit 803 when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) { 804 when (io.toIfu.req.fire && 805 !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && 806 !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr) 807 ) { 808 entry_hit_status(ifuPtr.value) := h_false_hit 809 // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 810 } 811 XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 812 } 813 814 XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit && 815 io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)) 816 817 val ifu_req_should_be_flushed = 818 io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) || 819 io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx) 820 821 when (io.toIfu.req.fire && !ifu_req_should_be_flushed) { 822 entry_fetch_status(ifuPtr.value) := f_sent 823 } 824 825 // ********************************************************************* 826 // **************************** wb from ifu **************************** 827 // ********************************************************************* 828 val pdWb = io.fromIfu.pdWb 829 val pds = pdWb.bits.pd 830 val ifu_wb_valid = pdWb.valid 831 val ifu_wb_idx = pdWb.bits.ftqIdx.value 832 // read ports: commit update 833 val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1)) 834 ftq_pd_mem.io.wen(0) := ifu_wb_valid 835 ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value 836 ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits) 837 838 val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid 839 val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid 840 val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B) 841 val pd_reg = RegEnable(pds, pdWb.valid) 842 val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid) 843 val wb_idx_reg = RegEnable(ifu_wb_idx, pdWb.valid) 844 845 when (ifu_wb_valid) { 846 val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{ 847 case (v, inRange) => v && inRange 848 }) 849 (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{ 850 case (qe, v) => when (v) { qe := c_valid } 851 } 852 } 853 854 when (ifu_wb_valid) { 855 ifuWbPtr_write := ifuWbPtr + 1.U 856 } 857 858 XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU") 859 860 ftb_entry_mem.io.raddr.head := ifu_wb_idx 861 val has_false_hit = WireInit(false.B) 862 when (RegNext(hit_pd_valid)) { 863 // check for false hit 864 val pred_ftb_entry = ftb_entry_mem.io.rdata.head 865 val brSlots = pred_ftb_entry.brSlots 866 val tailSlot = pred_ftb_entry.tailSlot 867 // we check cfis that bpu predicted 868 869 // bpu predicted branches but denied by predecode 870 val br_false_hit = 871 brSlots.map{ 872 s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr) 873 }.reduce(_||_) || 874 (tailSlot.valid && pred_ftb_entry.tailSlot.sharing && 875 !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr)) 876 877 val jmpOffset = tailSlot.offset 878 val jmp_pd = pd_reg(jmpOffset) 879 val jal_false_hit = pred_ftb_entry.jmpValid && 880 ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) || 881 (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) || 882 (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) || 883 (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)) 884 ) 885 886 has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg 887 XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0)) 888 889 // assert(!has_false_hit) 890 } 891 892 when (has_false_hit) { 893 entry_hit_status(wb_idx_reg) := h_false_hit 894 } 895 896 897 // ********************************************************************** 898 // ***************************** to backend ***************************** 899 // ********************************************************************** 900 // to backend pc mem / target 901 io.toBackend.pc_mem_wen := RegNext(last_cycle_bpu_in) 902 io.toBackend.pc_mem_waddr := RegNext(last_cycle_bpu_in_idx) 903 io.toBackend.pc_mem_wdata := RegNext(bpu_in_bypass_buf_for_ifu) 904 905 // ******************************************************************************* 906 // **************************** redirect from backend **************************** 907 // ******************************************************************************* 908 909 // redirect read cfiInfo, couples to redirectGen s2 910 val redirectReadStart = 1 // 0 for ifuRedirect 911 val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry)) 912 val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry)) 913 for (i <- redirectReadStart until FtqRedirectAheadNum) { 914 ftq_redirect_sram.io.ren(i + redirectReadStart) := ftqIdxAhead(i).valid 915 ftq_redirect_sram.io.raddr(i + redirectReadStart) := ftqIdxAhead(i).bits.value 916 ftb_entry_mem.io.raddr(i + redirectReadStart) := ftqIdxAhead(i).bits.value 917 } 918 ftq_redirect_sram.io.ren(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid) 919 ftq_redirect_sram.io.raddr(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value) 920 ftb_entry_mem.io.raddr(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value) 921 922 for (i <- 0 until FtqRedirectAheadNum) { 923 ftq_redirect_rdata(i) := ftq_redirect_sram.io.rdata(i + redirectReadStart) 924 ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + redirectReadStart) 925 } 926 val stage3CfiInfo = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_sram.io.rdata(redirectReadStart)) 927 val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate 928 backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo) 929 930 931 val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(redirectReadStart)) 932 val r_ftqOffset = fromBackendRedirect.bits.ftqOffset 933 934 backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset) 935 backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset 936 // FIXME: not portable 937 val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B))) 938 backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(r_ftb_entry.brSlots(0).offset === r_ftqOffset, 939 sc_disagree(0), sc_disagree(1)) 940 941 when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) { 942 backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +& 943 (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) && 944 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 945 946 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) || 947 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 948 }.otherwise { 949 backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt 950 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt 951 } 952 953 954 // *************************************************************************** 955 // **************************** redirect from ifu **************************** 956 // *************************************************************************** 957 val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect))) 958 fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush 959 fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx 960 fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits 961 fromIfuRedirect.bits.level := RedirectLevel.flushAfter 962 fromIfuRedirect.bits.BTBMissBubble := true.B 963 fromIfuRedirect.bits.debugIsMemVio := false.B 964 fromIfuRedirect.bits.debugIsCtrl := false.B 965 966 val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate 967 ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits) 968 ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits) 969 ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid 970 ifuRedirectCfiUpdate.target := pdWb.bits.target 971 ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid 972 ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid 973 974 val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new BranchPredictionRedirect))) 975 val ifuRedirectToBpu = WireInit(ifuRedirectReg) 976 ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid 977 978 ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid 979 ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 980 981 ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 982 983 val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate 984 toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head) 985 when (ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) { 986 toBpuCfi.target := toBpuCfi.topAddr 987 } 988 989 when (ifuRedirectReg.valid) { 990 ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B 991 } .elsewhen(RegNext(pdWb.valid)) { 992 // if pdWb and no redirect, set to false 993 ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B 994 } 995 996 // ********************************************************************* 997 // **************************** wb from exu **************************** 998 // ********************************************************************* 999 1000 backendRedirect.valid := io.fromBackend.redirect.valid 1001 backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits) 1002 backendRedirect.bits.BTBMissBubble := false.B 1003 1004 1005 def extractRedirectInfo(wb: Valid[Redirect]) = { 1006 val ftqPtr = wb.bits.ftqIdx 1007 val ftqOffset = wb.bits.ftqOffset 1008 val taken = wb.bits.cfiUpdate.taken 1009 val mispred = wb.bits.cfiUpdate.isMisPred 1010 (wb.valid, ftqPtr, ftqOffset, taken, mispred) 1011 } 1012 1013 // fix mispredict entry 1014 val lastIsMispredict = RegNext( 1015 backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B 1016 ) 1017 1018 def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = { 1019 val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect) 1020 val r_idx = r_ptr.value 1021 val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits 1022 val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits 1023 when (cfiIndex_bits_wen || cfiIndex_valid_wen) { 1024 cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken 1025 } .elsewhen (r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) { 1026 cfiIndex_vec(r_idx).valid :=false.B 1027 } 1028 when (cfiIndex_bits_wen) { 1029 cfiIndex_vec(r_idx).bits := r_offset 1030 } 1031 newest_entry_target := redirect.bits.cfiUpdate.target 1032 newest_entry_ptr := r_ptr 1033 update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this 1034 if (isBackend) { 1035 mispredict_vec(r_idx)(r_offset) := r_mispred 1036 } 1037 } 1038 1039 when(fromBackendRedirect.valid) { 1040 updateCfiInfo(fromBackendRedirect) 1041 }.elsewhen (ifuRedirectToBpu.valid) { 1042 updateCfiInfo(ifuRedirectToBpu, isBackend=false) 1043 } 1044 1045 when (fromBackendRedirect.valid) { 1046 when (fromBackendRedirect.bits.ControlRedirectBubble) { 1047 when (fromBackendRedirect.bits.ControlBTBMissBubble) { 1048 topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1049 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1050 } .elsewhen (fromBackendRedirect.bits.TAGEMissBubble) { 1051 topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 1052 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 1053 } .elsewhen (fromBackendRedirect.bits.SCMissBubble) { 1054 topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B 1055 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B 1056 } .elsewhen (fromBackendRedirect.bits.ITTAGEMissBubble) { 1057 topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 1058 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 1059 } .elsewhen (fromBackendRedirect.bits.RASMissBubble) { 1060 topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B 1061 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B 1062 } 1063 1064 1065 } .elsewhen (backendRedirect.bits.MemVioRedirectBubble) { 1066 topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 1067 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 1068 } .otherwise { 1069 topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 1070 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 1071 } 1072 } .elsewhen (ifuRedirectReg.valid) { 1073 topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1074 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1075 } 1076 1077 io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble 1078 io.TAGEMissBubble := fromBackendRedirect.bits.TAGEMissBubble 1079 io.SCMissBubble := fromBackendRedirect.bits.SCMissBubble 1080 io.ITTAGEMissBubble := fromBackendRedirect.bits.ITTAGEMissBubble 1081 io.RASMissBubble := fromBackendRedirect.bits.RASMissBubble 1082 1083 // *********************************************************************************** 1084 // **************************** flush ptr and state queue **************************** 1085 // *********************************************************************************** 1086 1087 val redirectVec = VecInit(backendRedirect, fromIfuRedirect) 1088 1089 // when redirect, we should reset ptrs and status queues 1090 when(redirectVec.map(r => r.valid).reduce(_||_)){ 1091 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1092 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 1093 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 1094 val next = idx + 1.U 1095 bpuPtr := next 1096 copied_bpu_ptr.map(_ := next) 1097 ifuPtr_write := next 1098 ifuWbPtr_write := next 1099 ifuPtrPlus1_write := idx + 2.U 1100 ifuPtrPlus2_write := idx + 3.U 1101 1102 } 1103 when(RegNext(redirectVec.map(r => r.valid).reduce(_||_))){ 1104 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1105 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 1106 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 1107 when (RegNext(notIfu)) { 1108 commitStateQueue(RegNext(idx.value)).zipWithIndex.foreach({ case (s, i) => 1109 when(i.U > RegNext(offset) || i.U === RegNext(offset) && RegNext(flushItSelf)){ 1110 s := c_invalid 1111 } 1112 }) 1113 } 1114 } 1115 1116 1117 // only the valid bit is actually needed 1118 io.toIfu.redirect.bits := backendRedirect.bits 1119 io.toIfu.redirect.valid := stage2Flush 1120 io.toIfu.topdown_redirect := fromBackendRedirect 1121 1122 // commit 1123 for (c <- io.fromBackend.rob_commits) { 1124 when(c.valid) { 1125 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited 1126 // TODO: remove this 1127 // For instruction fusions, we also update the next instruction 1128 when (c.bits.commitType === 4.U) { 1129 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited 1130 }.elsewhen(c.bits.commitType === 5.U) { 1131 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited 1132 }.elsewhen(c.bits.commitType === 6.U) { 1133 val index = (c.bits.ftqIdx + 1.U).value 1134 commitStateQueue(index)(0) := c_commited 1135 }.elsewhen(c.bits.commitType === 7.U) { 1136 val index = (c.bits.ftqIdx + 1.U).value 1137 commitStateQueue(index)(1) := c_commited 1138 } 1139 } 1140 } 1141 1142 robCommPtr_write := Mux(io.fromBackend.rob_commits.map(_.valid).reduce(_ | _), ParallelPriorityMux(io.fromBackend.rob_commits.map(_.valid).reverse, io.fromBackend.rob_commits.map(_.bits.ftqIdx).reverse), robCommPtr) 1143 1144 // **************************************************************** 1145 // **************************** to bpu **************************** 1146 // **************************************************************** 1147 1148 io.toBpu.redirect := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 1149 val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_=>0.U(64.W))) 1150 val redirect_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U 1151 XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1) 1152 XSPerfHistogram("ifu_redirect_latency", redirect_latency, !fromBackendRedirect.valid && ifuRedirectToBpu.valid, 0, 60, 1) 1153 1154 XSError(io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr), "Ftq received a redirect after its commit, check backend or replay") 1155 1156 val may_have_stall_from_bpu = Wire(Bool()) 1157 val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states 1158 may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U 1159 val notInvalidSeq = commitStateQueue(commPtr.value).map(s => s =/= c_invalid).reverse 1160 // Todo: @huxuan check it 1161 // canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1162 // Cat(commitStateQueue(commPtr.value).map(s => { 1163 // s === c_invalid || s === c_commited 1164 // })).andR 1165 canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1166 (isAfter(robCommPtr, commPtr) || PriorityMuxDefault(notInvalidSeq.zip(commitStateQueue(commPtr.value).reverse), c_invalid) === c_commited) 1167 1168 val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr 1169 val mmioLastCommit = isBefore(commPtr, mmioReadPtr) && (isAfter(ifuPtr,mmioReadPtr) || mmioReadPtr === ifuPtr) && 1170 Cat(commitStateQueue(mmioReadPtr.value).map(s => { s === c_invalid || s === c_commited})).andR 1171 io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit) 1172 1173 // commit reads 1174 val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata) 1175 val commit_target = 1176 Mux(RegNext(commPtr === newest_entry_ptr), 1177 RegNext(newest_entry_target), 1178 RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr)) 1179 ftq_pd_mem.io.raddr.last := commPtr.value 1180 val commit_pd = ftq_pd_mem.io.rdata.last 1181 ftq_redirect_sram.io.ren.last := canCommit 1182 ftq_redirect_sram.io.raddr.last := commPtr.value 1183 val commit_spec_meta = ftq_redirect_sram.io.rdata.last 1184 ftq_meta_1r_sram.io.ren(0) := canCommit 1185 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 1186 val commit_meta = ftq_meta_1r_sram.io.rdata(0) 1187 ftb_entry_mem.io.raddr.last := commPtr.value 1188 val commit_ftb_entry = ftb_entry_mem.io.rdata.last 1189 1190 // need one cycle to read mem and srams 1191 val do_commit_ptr = RegNext(commPtr) 1192 val do_commit = RegNext(canCommit, init=false.B) 1193 when (canCommit) { 1194 commPtr_write := commPtrPlus1 1195 commPtrPlus1_write := commPtrPlus1 + 1.U 1196 } 1197 val commit_state = RegNext(commitStateQueue(commPtr.value)) 1198 val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value)) 1199 val do_commit_cfi = WireInit(cfiIndex_vec(do_commit_ptr.value)) 1200 // 1201 //when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) { 1202 // can_commit_cfi.valid := false.B 1203 //} 1204 val commit_cfi = RegNext(can_commit_cfi) 1205 val debug_cfi = commitStateQueue(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_commited && do_commit_cfi.valid 1206 1207 val commit_mispredict : Vec[Bool] = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map { 1208 case (mis, state) => mis && state === c_commited 1209 }) 1210 val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_commited)) // [PredictWidth] 1211 val can_commit_hit = entry_hit_status(commPtr.value) 1212 val commit_hit = RegNext(can_commit_hit) 1213 val diff_commit_target = RegNext(update_target(commPtr.value)) // TODO: remove this 1214 val commit_stage = RegNext(pred_stage(commPtr.value)) 1215 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 1216 1217 val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit 1218 switch (bpu_ftb_update_stall) { 1219 is (0.U) { 1220 when (can_commit_cfi.valid && !to_bpu_hit && canCommit) { 1221 bpu_ftb_update_stall := 2.U // 2-cycle stall 1222 } 1223 } 1224 is (2.U) { 1225 bpu_ftb_update_stall := 1.U 1226 } 1227 is (1.U) { 1228 bpu_ftb_update_stall := 0.U 1229 } 1230 is (3.U) { 1231 XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2") 1232 } 1233 } 1234 1235 // TODO: remove this 1236 XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n") 1237 1238 // update latency stats 1239 val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U 1240 XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2) 1241 1242 io.toBpu.update := DontCare 1243 io.toBpu.update.valid := commit_valid && do_commit 1244 val update = io.toBpu.update.bits 1245 update.false_hit := commit_hit === h_false_hit 1246 update.pc := commit_pc_bundle.startAddr 1247 update.meta := commit_meta.meta 1248 update.cfi_idx := commit_cfi 1249 update.full_target := commit_target 1250 update.from_stage := commit_stage 1251 update.spec_info := commit_spec_meta 1252 XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n") 1253 1254 val commit_real_hit = commit_hit === h_hit 1255 val update_ftb_entry = update.ftb_entry 1256 1257 val ftbEntryGen = Module(new FTBEntryGen).io 1258 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 1259 ftbEntryGen.old_entry := commit_ftb_entry 1260 ftbEntryGen.pd := commit_pd 1261 ftbEntryGen.cfiIndex := commit_cfi 1262 ftbEntryGen.target := commit_target 1263 ftbEntryGen.hit := commit_real_hit 1264 ftbEntryGen.mispredict_vec := commit_mispredict 1265 1266 update_ftb_entry := ftbEntryGen.new_entry 1267 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 1268 update.mispred_mask := ftbEntryGen.mispred_mask 1269 update.old_entry := ftbEntryGen.is_old_entry 1270 update.pred_hit := commit_hit === h_hit || commit_hit === h_false_hit 1271 update.br_taken_mask := ftbEntryGen.taken_mask 1272 update.br_committed := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map { 1273 case (valid, offset) => valid && commit_instCommited(offset) 1274 } 1275 update.jmp_taken := ftbEntryGen.jmp_taken 1276 1277 // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc) 1278 // update.full_pred.jalr_target := commit_target 1279 // update.full_pred.hit := true.B 1280 // when (update.full_pred.is_jalr) { 1281 // update.full_pred.targets.last := commit_target 1282 // } 1283 1284 // **************************************************************** 1285 // *********************** to prefetch **************************** 1286 // **************************************************************** 1287 /** 1288 ****************************************************************************** 1289 * prefetchPtr control 1290 * - 1. prefetchPtr plus 1 when toPrefetch fire and keep distance from bpuPtr more than 2 1291 * - 2. limit range of prefetchPtr is in [ifuPtr + minRange, ifuPtr + maxRange] 1292 * - 3. flush prefetchPtr when receive redirect from ifu or backend 1293 ****************************************************************************** 1294 */ 1295 val prefetchPtr = RegInit(FtqPtr(false.B, 0.U)) 1296 val nextPrefetchPtr = WireInit(prefetchPtr) 1297 1298 prefetchPtr := nextPrefetchPtr 1299 1300 // TODO: consider req which cross cacheline 1301 when(io.toPrefetch.req.fire) { 1302 when(prefetchPtr < bpuPtr - 2.U) { 1303 nextPrefetchPtr := prefetchPtr + 1.U 1304 } 1305 } 1306 1307 when(prefetchPtr < ifuPtr + minRangeFromIFUptr.U) { 1308 nextPrefetchPtr := ifuPtr + minRangeFromIFUptr.U 1309 }.elsewhen(prefetchPtr > ifuPtr + maxRangeFromIFUptr.U) { 1310 nextPrefetchPtr := ifuPtr + maxRangeFromIFUptr.U 1311 } 1312 1313 when(redirectVec.map(r => r.valid).reduce(_||_)){ 1314 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1315 val next = r.ftqIdx + minRangeFromIFUptr.U 1316 nextPrefetchPtr := next 1317 } 1318 1319 // data from ftq_pc_mem has 1 cycle delay 1320 io.toPrefetch.req.valid := RegNext(entry_fetch_status(nextPrefetchPtr.value) === f_to_send) 1321 ftq_pc_mem.io.other_raddrs(0) := nextPrefetchPtr.value 1322 io.toPrefetch.req.bits.target := RegNext(ftq_pc_mem.io.other_rdatas(0).startAddr) 1323 1324 // record position relationship between ifuPtr, pfPtr and bpuPtr 1325 val isWritePrefetchPtrTable = WireInit(Constantin.createRecord("isWritePrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString)) 1326 val prefetchPtrTable = ChiselDB.createTable("PrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString, new PrefetchPtrDB) 1327 val prefetchPtrDumpData = Wire(new PrefetchPtrDB) 1328 prefetchPtrDumpData.fromFtqPtr := distanceBetween(bpuPtr, prefetchPtr) 1329 prefetchPtrDumpData.fromIfuPtr := distanceBetween(prefetchPtr, ifuPtr) 1330 1331 prefetchPtrTable.log( 1332 data = prefetchPtrDumpData, 1333 en = isWritePrefetchPtrTable.orR && io.toPrefetch.req.fire, 1334 site = "FTQ" + p(XSCoreParamsKey).HartId.toString, 1335 clock = clock, 1336 reset = reset 1337 ) 1338 1339 1340 // ****************************************************************************** 1341 // **************************** commit perf counters **************************** 1342 // ****************************************************************************** 1343 1344 val commit_inst_mask = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt 1345 val commit_mispred_mask = commit_mispredict.asUInt 1346 val commit_not_mispred_mask = ~commit_mispred_mask 1347 1348 val commit_br_mask = commit_pd.brMask.asUInt 1349 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 1350 val commit_cfi_mask = (commit_br_mask | commit_jmp_mask) 1351 1352 val mbpInstrs = commit_inst_mask & commit_cfi_mask 1353 1354 val mbpRights = mbpInstrs & commit_not_mispred_mask 1355 val mbpWrongs = mbpInstrs & commit_mispred_mask 1356 1357 io.bpuInfo.bpRight := PopCount(mbpRights) 1358 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 1359 1360 val isWriteFTQTable = WireInit(Constantin.createRecord("isWriteFTQTable" + p(XSCoreParamsKey).HartId.toString)) 1361 val ftqBranchTraceDB = ChiselDB.createTable("FTQTable" + p(XSCoreParamsKey).HartId.toString, new FtqDebugBundle) 1362 // Cfi Info 1363 for (i <- 0 until PredictWidth) { 1364 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 1365 val v = commit_state(i) === c_commited 1366 val isBr = commit_pd.brMask(i) 1367 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 1368 val isCfi = isBr || isJmp 1369 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 1370 val misPred = commit_mispredict(i) 1371 // val ghist = commit_spec_meta.ghist.predHist 1372 val histPtr = commit_spec_meta.histPtr 1373 val predCycle = commit_meta.meta(63, 0) 1374 val target = commit_target 1375 1376 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}))) 1377 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_) 1378 val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)) 1379 XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 1380 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " + 1381 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 1382 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n") 1383 1384 val logbundle = Wire(new FtqDebugBundle) 1385 logbundle.pc := pc 1386 logbundle.target := target 1387 logbundle.isBr := isBr 1388 logbundle.isJmp := isJmp 1389 logbundle.isCall := isJmp && commit_pd.hasCall 1390 logbundle.isRet := isJmp && commit_pd.hasRet 1391 logbundle.misPred := misPred 1392 logbundle.isTaken := isTaken 1393 logbundle.predStage := commit_stage 1394 1395 ftqBranchTraceDB.log( 1396 data = logbundle /* hardware of type T */, 1397 en = isWriteFTQTable.orR && v && do_commit && isCfi, 1398 site = "FTQ" + p(XSCoreParamsKey).HartId.toString, 1399 clock = clock, 1400 reset = reset 1401 ) 1402 } 1403 1404 val enq = io.fromBpu.resp 1405 val perf_redirect = backendRedirect 1406 1407 XSPerfAccumulate("entry", validEntries) 1408 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 1409 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 1410 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 1411 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 1412 1413 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 1414 1415 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 1416 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 1417 XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr) 1418 XSPerfAccumulate("bpu_to_ifu_bubble_when_ftq_full", (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready) 1419 1420 XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_|_)) 1421 XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid) 1422 XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid) 1423 1424 val from_bpu = io.fromBpu.resp.bits 1425 val to_ifu = io.toIfu.req.bits 1426 1427 1428 XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth+1, 1) 1429 1430 1431 1432 1433 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 1434 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 1435 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 1436 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 1437 1438 1439 val mbpBRights = mbpRights & commit_br_mask 1440 val mbpJRights = mbpRights & commit_jal_mask 1441 val mbpIRights = mbpRights & commit_jalr_mask 1442 val mbpCRights = mbpRights & commit_call_mask 1443 val mbpRRights = mbpRights & commit_ret_mask 1444 1445 val mbpBWrongs = mbpWrongs & commit_br_mask 1446 val mbpJWrongs = mbpWrongs & commit_jal_mask 1447 val mbpIWrongs = mbpWrongs & commit_jalr_mask 1448 val mbpCWrongs = mbpWrongs & commit_call_mask 1449 val mbpRWrongs = mbpWrongs & commit_ret_mask 1450 1451 val commit_pred_stage = RegNext(pred_stage(commPtr.value)) 1452 1453 def pred_stage_map(src: UInt, name: String) = { 1454 (0 until numBpStages).map(i => 1455 f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i))) 1456 ).foldLeft(Map[String, UInt]())(_+_) 1457 } 1458 1459 val mispred_stage_map = pred_stage_map(mbpWrongs, "mispredict") 1460 val br_mispred_stage_map = pred_stage_map(mbpBWrongs, "br_mispredict") 1461 val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict") 1462 val correct_stage_map = pred_stage_map(mbpRights, "correct") 1463 val br_correct_stage_map = pred_stage_map(mbpBRights, "br_correct") 1464 val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct") 1465 1466 val update_valid = io.toBpu.update.valid 1467 def u(cond: Bool) = update_valid && cond 1468 val ftb_false_hit = u(update.false_hit) 1469 // assert(!ftb_false_hit) 1470 val ftb_hit = u(commit_hit === h_hit) 1471 1472 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1473 val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid 1474 val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0) 1475 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid 1476 1477 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1478 1479 val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified) 1480 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1481 val ftb_modified_entry_ifu_redirected = u(ifuRedirected(do_commit_ptr.value)) 1482 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1483 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1484 val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified 1485 1486 def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits 1487 val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry) 1488 XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth+1, 1) 1489 XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth+1, 1) 1490 val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry) 1491 XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth+1, 1) 1492 1493 XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize+1, 1) 1494 1495 val perfCountsMap = Map( 1496 "BpInstr" -> PopCount(mbpInstrs), 1497 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1498 "BpRight" -> PopCount(mbpRights), 1499 "BpWrong" -> PopCount(mbpWrongs), 1500 "BpBRight" -> PopCount(mbpBRights), 1501 "BpBWrong" -> PopCount(mbpBWrongs), 1502 "BpJRight" -> PopCount(mbpJRights), 1503 "BpJWrong" -> PopCount(mbpJWrongs), 1504 "BpIRight" -> PopCount(mbpIRights), 1505 "BpIWrong" -> PopCount(mbpIWrongs), 1506 "BpCRight" -> PopCount(mbpCRights), 1507 "BpCWrong" -> PopCount(mbpCWrongs), 1508 "BpRRight" -> PopCount(mbpRRights), 1509 "BpRWrong" -> PopCount(mbpRWrongs), 1510 1511 "ftb_false_hit" -> PopCount(ftb_false_hit), 1512 "ftb_hit" -> PopCount(ftb_hit), 1513 "ftb_new_entry" -> PopCount(ftb_new_entry), 1514 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1515 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1516 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1517 "ftb_old_entry" -> PopCount(ftb_old_entry), 1518 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1519 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1520 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1521 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1522 "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken) 1523 ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++ 1524 correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map 1525 1526 for((key, value) <- perfCountsMap) { 1527 XSPerfAccumulate(key, value) 1528 } 1529 1530 // --------------------------- Debug -------------------------------- 1531 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1532 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1533 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1534 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1535 XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1536 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n") 1537 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1538 1539 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1540 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1541 // case (((valid, pd), ans), taken) => 1542 // Mux(valid && pd.isBr, 1543 // isWrong ^ Mux(ans.hit.asBool, 1544 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1545 // !taken), 1546 // !taken), 1547 // false.B) 1548 // } 1549 // } 1550 1551 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1552 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1553 // case (((valid, pd), ans), taken) => 1554 // Mux(valid && pd.isBr, 1555 // isWrong ^ Mux(ans.hit.asBool, 1556 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1557 // !taken), 1558 // !taken), 1559 // false.B) 1560 // } 1561 // } 1562 1563 // def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1564 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1565 // case (((valid, pd), ans), taken) => 1566 // Mux(valid && pd.isBr, 1567 // isWrong ^ (ans.taken.asBool === taken), 1568 // false.B) 1569 // } 1570 // } 1571 1572 // def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1573 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1574 // case (((valid, pd), ans), taken) => 1575 // Mux(valid && (pd.isBr) && ans.hit.asBool, 1576 // isWrong ^ (!taken), 1577 // false.B) 1578 // } 1579 // } 1580 1581 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1582 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1583 // case (((valid, pd), ans), taken) => 1584 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1585 // isWrong ^ (ans.target === commitEntry.target), 1586 // false.B) 1587 // } 1588 // } 1589 1590 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1591 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1592 // // btb and ubtb pred jal and jalr as well 1593 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1594 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1595 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1596 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1597 1598 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1599 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1600 1601 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1602 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1603 1604 val perfEvents = Seq( 1605 ("bpu_s2_redirect ", bpu_s2_redirect ), 1606 ("bpu_s3_redirect ", bpu_s3_redirect ), 1607 ("bpu_to_ftq_stall ", enq.valid && ~enq.ready ), 1608 ("mispredictRedirect ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level), 1609 ("replayRedirect ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level) ), 1610 ("predecodeRedirect ", fromIfuRedirect.valid ), 1611 ("to_ifu_bubble ", io.toIfu.req.ready && !io.toIfu.req.valid ), 1612 ("from_bpu_real_bubble ", !enq.valid && enq.ready && allowBpuIn ), 1613 ("BpInstr ", PopCount(mbpInstrs) ), 1614 ("BpBInstr ", PopCount(mbpBRights | mbpBWrongs) ), 1615 ("BpRight ", PopCount(mbpRights) ), 1616 ("BpWrong ", PopCount(mbpWrongs) ), 1617 ("BpBRight ", PopCount(mbpBRights) ), 1618 ("BpBWrong ", PopCount(mbpBWrongs) ), 1619 ("BpJRight ", PopCount(mbpJRights) ), 1620 ("BpJWrong ", PopCount(mbpJWrongs) ), 1621 ("BpIRight ", PopCount(mbpIRights) ), 1622 ("BpIWrong ", PopCount(mbpIWrongs) ), 1623 ("BpCRight ", PopCount(mbpCRights) ), 1624 ("BpCWrong ", PopCount(mbpCWrongs) ), 1625 ("BpRRight ", PopCount(mbpRRights) ), 1626 ("BpRWrong ", PopCount(mbpRWrongs) ), 1627 ("ftb_false_hit ", PopCount(ftb_false_hit) ), 1628 ("ftb_hit ", PopCount(ftb_hit) ), 1629 ) 1630 generatePerfEvent() 1631} 1632