1/*************************************************************************************** 2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3* Copyright (c) 2020-2021 Peng Cheng Laboratory 4* 5* XiangShan is licensed under Mulan PSL v2. 6* You can use this software according to the terms and conditions of the Mulan PSL v2. 7* You may obtain a copy of Mulan PSL v2 at: 8* http://license.coscl.org.cn/MulanPSL2 9* 10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13* 14* See the Mulan PSL v2 for more details. 15***************************************************************************************/ 16 17package xiangshan.frontend 18 19import chipsalliance.rocketchip.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import utils._ 23import xiangshan._ 24import xiangshan.frontend.icache._ 25import xiangshan.backend.CtrlToFtqIO 26import xiangshan.backend.decode.ImmUnion 27import huancun.utils.ChiselDB 28 29class FtqDebugBundle extends Bundle { 30 val pc = UInt(39.W) 31 val target = UInt(39.W) 32 val isBr = Bool() 33 val isJmp = Bool() 34 val isCall = Bool() 35 val isRet = Bool() 36 val misPred = Bool() 37 val isTaken = Bool() 38 val predStage = UInt(2.W) 39} 40 41class FtqPtr(implicit p: Parameters) extends CircularQueuePtr[FtqPtr]( 42 p => p(XSCoreParamsKey).FtqSize 43){ 44} 45 46object FtqPtr { 47 def apply(f: Bool, v: UInt)(implicit p: Parameters): FtqPtr = { 48 val ptr = Wire(new FtqPtr) 49 ptr.flag := f 50 ptr.value := v 51 ptr 52 } 53 def inverse(ptr: FtqPtr)(implicit p: Parameters): FtqPtr = { 54 apply(!ptr.flag, ptr.value) 55 } 56} 57 58class FtqNRSRAM[T <: Data](gen: T, numRead: Int)(implicit p: Parameters) extends XSModule { 59 60 val io = IO(new Bundle() { 61 val raddr = Input(Vec(numRead, UInt(log2Up(FtqSize).W))) 62 val ren = Input(Vec(numRead, Bool())) 63 val rdata = Output(Vec(numRead, gen)) 64 val waddr = Input(UInt(log2Up(FtqSize).W)) 65 val wen = Input(Bool()) 66 val wdata = Input(gen) 67 }) 68 69 for(i <- 0 until numRead){ 70 val sram = Module(new SRAMTemplate(gen, FtqSize)) 71 sram.io.r.req.valid := io.ren(i) 72 sram.io.r.req.bits.setIdx := io.raddr(i) 73 io.rdata(i) := sram.io.r.resp.data(0) 74 sram.io.w.req.valid := io.wen 75 sram.io.w.req.bits.setIdx := io.waddr 76 sram.io.w.req.bits.data := VecInit(io.wdata) 77 } 78 79} 80 81class Ftq_RF_Components(implicit p: Parameters) extends XSBundle with BPUUtils { 82 val startAddr = UInt(VAddrBits.W) 83 val nextLineAddr = UInt(VAddrBits.W) 84 val isNextMask = Vec(PredictWidth, Bool()) 85 val fallThruError = Bool() 86 // val carry = Bool() 87 def getPc(offset: UInt) = { 88 def getHigher(pc: UInt) = pc(VAddrBits-1, log2Ceil(PredictWidth)+instOffsetBits+1) 89 def getOffset(pc: UInt) = pc(log2Ceil(PredictWidth)+instOffsetBits, instOffsetBits) 90 Cat(getHigher(Mux(isNextMask(offset) && startAddr(log2Ceil(PredictWidth)+instOffsetBits), nextLineAddr, startAddr)), 91 getOffset(startAddr)+offset, 0.U(instOffsetBits.W)) 92 } 93 def fromBranchPrediction(resp: BranchPredictionBundle) = { 94 def carryPos(addr: UInt) = addr(instOffsetBits+log2Ceil(PredictWidth)+1) 95 this.startAddr := resp.pc 96 this.nextLineAddr := resp.pc + (FetchWidth * 4 * 2).U // may be broken on other configs 97 this.isNextMask := VecInit((0 until PredictWidth).map(i => 98 (resp.pc(log2Ceil(PredictWidth), 1) +& i.U)(log2Ceil(PredictWidth)).asBool() 99 )) 100 this.fallThruError := resp.fallThruError 101 this 102 } 103 override def toPrintable: Printable = { 104 p"startAddr:${Hexadecimal(startAddr)}" 105 } 106} 107 108class Ftq_pd_Entry(implicit p: Parameters) extends XSBundle { 109 val brMask = Vec(PredictWidth, Bool()) 110 val jmpInfo = ValidUndirectioned(Vec(3, Bool())) 111 val jmpOffset = UInt(log2Ceil(PredictWidth).W) 112 val jalTarget = UInt(VAddrBits.W) 113 val rvcMask = Vec(PredictWidth, Bool()) 114 def hasJal = jmpInfo.valid && !jmpInfo.bits(0) 115 def hasJalr = jmpInfo.valid && jmpInfo.bits(0) 116 def hasCall = jmpInfo.valid && jmpInfo.bits(1) 117 def hasRet = jmpInfo.valid && jmpInfo.bits(2) 118 119 def fromPdWb(pdWb: PredecodeWritebackBundle) = { 120 val pds = pdWb.pd 121 this.brMask := VecInit(pds.map(pd => pd.isBr && pd.valid)) 122 this.jmpInfo.valid := VecInit(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)).asUInt.orR 123 this.jmpInfo.bits := ParallelPriorityMux(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid), 124 pds.map(pd => VecInit(pd.isJalr, pd.isCall, pd.isRet))) 125 this.jmpOffset := ParallelPriorityEncoder(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)) 126 this.rvcMask := VecInit(pds.map(pd => pd.isRVC)) 127 this.jalTarget := pdWb.jalTarget 128 } 129 130 def toPd(offset: UInt) = { 131 require(offset.getWidth == log2Ceil(PredictWidth)) 132 val pd = Wire(new PreDecodeInfo) 133 pd.valid := true.B 134 pd.isRVC := rvcMask(offset) 135 val isBr = brMask(offset) 136 val isJalr = offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(0) 137 pd.brType := Cat(offset === jmpOffset && jmpInfo.valid, isJalr || isBr) 138 pd.isCall := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(1) 139 pd.isRet := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(2) 140 pd 141 } 142} 143 144 145 146class Ftq_Redirect_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst { 147 val rasSp = UInt(log2Ceil(RasSize).W) 148 val rasEntry = new RASEntry 149 // val specCnt = Vec(numBr, UInt(10.W)) 150 // val ghist = new ShiftingGlobalHistory 151 val folded_hist = new AllFoldedHistories(foldedGHistInfos) 152 val afhob = new AllAheadFoldedHistoryOldestBits(foldedGHistInfos) 153 val lastBrNumOH = UInt((numBr+1).W) 154 155 val histPtr = new CGHPtr 156 157 def fromBranchPrediction(resp: BranchPredictionBundle) = { 158 assert(!resp.is_minimal) 159 this.rasSp := resp.rasSp 160 this.rasEntry := resp.rasTop 161 this.folded_hist := resp.folded_hist 162 this.afhob := resp.afhob 163 this.lastBrNumOH := resp.lastBrNumOH 164 this.histPtr := resp.histPtr 165 this 166 } 167} 168 169class Ftq_1R_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst { 170 val meta = UInt(MaxMetaLength.W) 171} 172 173class Ftq_Pred_Info(implicit p: Parameters) extends XSBundle { 174 val target = UInt(VAddrBits.W) 175 val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)) 176} 177 178 179class FtqRead[T <: Data](private val gen: T)(implicit p: Parameters) extends XSBundle { 180 val ptr = Output(new FtqPtr) 181 val offset = Output(UInt(log2Ceil(PredictWidth).W)) 182 val data = Input(gen) 183 def apply(ptr: FtqPtr, offset: UInt) = { 184 this.ptr := ptr 185 this.offset := offset 186 this.data 187 } 188} 189 190 191class FtqToBpuIO(implicit p: Parameters) extends XSBundle { 192 val redirect = Valid(new BranchPredictionRedirect) 193 val update = Valid(new BranchPredictionUpdate) 194 val enq_ptr = Output(new FtqPtr) 195} 196 197class FtqToIfuIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper { 198 val req = Decoupled(new FetchRequestBundle) 199 val redirect = Valid(new Redirect) 200 val flushFromBpu = new Bundle { 201 // when ifu pipeline is not stalled, 202 // a packet from bpu s3 can reach f1 at most 203 val s2 = Valid(new FtqPtr) 204 val s3 = Valid(new FtqPtr) 205 def shouldFlushBy(src: Valid[FtqPtr], idx_to_flush: FtqPtr) = { 206 src.valid && !isAfter(src.bits, idx_to_flush) 207 } 208 def shouldFlushByStage2(idx: FtqPtr) = shouldFlushBy(s2, idx) 209 def shouldFlushByStage3(idx: FtqPtr) = shouldFlushBy(s3, idx) 210 } 211} 212 213trait HasBackendRedirectInfo extends HasXSParameter { 214 def numRedirectPcRead = exuParameters.JmpCnt + exuParameters.AluCnt + 1 215 def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself() 216} 217 218class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo { 219 // write to backend pc mem 220 val pc_mem_wen = Output(Bool()) 221 val pc_mem_waddr = Output(UInt(log2Ceil(FtqSize).W)) 222 val pc_mem_wdata = Output(new Ftq_RF_Components) 223 val target = Output(UInt(VAddrBits.W)) 224 // predecode correct target 225 val pd_redirect_waddr = Valid(UInt(log2Ceil(FtqSize).W)) 226 val pd_redirect_target = Output(UInt(VAddrBits.W)) 227} 228 229 230class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter { 231 val io = IO(new Bundle { 232 val start_addr = Input(UInt(VAddrBits.W)) 233 val old_entry = Input(new FTBEntry) 234 val pd = Input(new Ftq_pd_Entry) 235 val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W))) 236 val target = Input(UInt(VAddrBits.W)) 237 val hit = Input(Bool()) 238 val mispredict_vec = Input(Vec(PredictWidth, Bool())) 239 240 val new_entry = Output(new FTBEntry) 241 val new_br_insert_pos = Output(Vec(numBr, Bool())) 242 val taken_mask = Output(Vec(numBr, Bool())) 243 val mispred_mask = Output(Vec(numBr+1, Bool())) 244 245 // for perf counters 246 val is_init_entry = Output(Bool()) 247 val is_old_entry = Output(Bool()) 248 val is_new_br = Output(Bool()) 249 val is_jalr_target_modified = Output(Bool()) 250 val is_always_taken_modified = Output(Bool()) 251 val is_br_full = Output(Bool()) 252 }) 253 254 // no mispredictions detected at predecode 255 val hit = io.hit 256 val pd = io.pd 257 258 val init_entry = WireInit(0.U.asTypeOf(new FTBEntry)) 259 260 261 val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid 262 val entry_has_jmp = pd.jmpInfo.valid 263 val new_jmp_is_jal = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid 264 val new_jmp_is_jalr = entry_has_jmp && pd.jmpInfo.bits(0) && io.cfiIndex.valid 265 val new_jmp_is_call = entry_has_jmp && pd.jmpInfo.bits(1) && io.cfiIndex.valid 266 val new_jmp_is_ret = entry_has_jmp && pd.jmpInfo.bits(2) && io.cfiIndex.valid 267 val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask.last 268 // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last 269 270 val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal 271 val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr 272 273 def carryPos = log2Ceil(PredictWidth)+instOffsetBits 274 def getLower(pc: UInt) = pc(carryPos-1, instOffsetBits) 275 // if not hit, establish a new entry 276 init_entry.valid := true.B 277 // tag is left for ftb to assign 278 279 // case br 280 val init_br_slot = init_entry.getSlotForBr(0) 281 when (cfi_is_br) { 282 init_br_slot.valid := true.B 283 init_br_slot.offset := io.cfiIndex.bits 284 init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1) 285 init_entry.always_taken(0) := true.B // set to always taken on init 286 } 287 288 // case jmp 289 when (entry_has_jmp) { 290 init_entry.tailSlot.offset := pd.jmpOffset 291 init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr 292 init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare=false) 293 } 294 295 val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U) 296 init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr)) 297 init_entry.carry := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos-instOffsetBits), true.B) 298 init_entry.isJalr := new_jmp_is_jalr 299 init_entry.isCall := new_jmp_is_call 300 init_entry.isRet := new_jmp_is_ret 301 // that means fall thru points to the middle of an inst 302 init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask(pd.jmpOffset) 303 304 // if hit, check whether a new cfi(only br is possible) is detected 305 val oe = io.old_entry 306 val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits) 307 val br_recorded = br_recorded_vec.asUInt.orR 308 val is_new_br = cfi_is_br && !br_recorded 309 val new_br_offset = io.cfiIndex.bits 310 // vec(i) means new br will be inserted BEFORE old br(i) 311 val allBrSlotsVec = oe.allSlotsForBr 312 val new_br_insert_onehot = VecInit((0 until numBr).map{ 313 i => i match { 314 case 0 => 315 !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset 316 case idx => 317 allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset && 318 (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset) 319 } 320 }) 321 322 val old_entry_modified = WireInit(io.old_entry) 323 for (i <- 0 until numBr) { 324 val slot = old_entry_modified.allSlotsForBr(i) 325 when (new_br_insert_onehot(i)) { 326 slot.valid := true.B 327 slot.offset := new_br_offset 328 slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr-1) 329 old_entry_modified.always_taken(i) := true.B 330 }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) { 331 old_entry_modified.always_taken(i) := false.B 332 // all other fields remain unchanged 333 }.otherwise { 334 // case i == 0, remain unchanged 335 if (i != 0) { 336 val noNeedToMoveFromFormerSlot = (i == numBr-1).B && !oe.brSlots.last.valid 337 when (!noNeedToMoveFromFormerSlot) { 338 slot.fromAnotherSlot(oe.allSlotsForBr(i-1)) 339 old_entry_modified.always_taken(i) := oe.always_taken(i) 340 } 341 } 342 } 343 } 344 345 // two circumstances: 346 // 1. oe: | br | j |, new br should be in front of j, thus addr of j should be new pft 347 // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either 348 // the previous last br or the new br 349 val may_have_to_replace = oe.noEmptySlotForNewBr 350 val pft_need_to_change = is_new_br && may_have_to_replace 351 // it should either be the given last br or the new br 352 when (pft_need_to_change) { 353 val new_pft_offset = 354 Mux(!new_br_insert_onehot.asUInt.orR, 355 new_br_offset, oe.allSlotsForBr.last.offset) 356 357 // set jmp to invalid 358 old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset 359 old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool 360 old_entry_modified.last_may_be_rvi_call := false.B 361 old_entry_modified.isCall := false.B 362 old_entry_modified.isRet := false.B 363 old_entry_modified.isJalr := false.B 364 } 365 366 val old_entry_jmp_target_modified = WireInit(oe) 367 val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits 368 val old_tail_is_jmp = !oe.tailSlot.sharing 369 val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target 370 when (jalr_target_modified) { 371 old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target) 372 old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool())) 373 } 374 375 val old_entry_always_taken = WireInit(oe) 376 val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not 377 for (i <- 0 until numBr) { 378 old_entry_always_taken.always_taken(i) := 379 oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i) 380 always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i) 381 } 382 val always_taken_modified = always_taken_modified_vec.reduce(_||_) 383 384 385 386 val derived_from_old_entry = 387 Mux(is_new_br, old_entry_modified, 388 Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken)) 389 390 391 io.new_entry := Mux(!hit, init_entry, derived_from_old_entry) 392 393 io.new_br_insert_pos := new_br_insert_onehot 394 io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{ 395 case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v 396 }) 397 for (i <- 0 until numBr) { 398 io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i)) 399 } 400 io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset) 401 402 // for perf counters 403 io.is_init_entry := !hit 404 io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified 405 io.is_new_br := hit && is_new_br 406 io.is_jalr_target_modified := hit && jalr_target_modified 407 io.is_always_taken_modified := hit && always_taken_modified 408 io.is_br_full := hit && is_new_br && may_have_to_replace 409} 410 411class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper 412 with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents 413 with HasICacheParameters{ 414 val io = IO(new Bundle { 415 val fromBpu = Flipped(new BpuToFtqIO) 416 val fromIfu = Flipped(new IfuToFtqIO) 417 val fromBackend = Flipped(new CtrlToFtqIO) 418 419 val toBpu = new FtqToBpuIO 420 val toIfu = new FtqToIfuIO 421 val toBackend = new FtqToCtrlIO 422 423 val toPrefetch = new FtqPrefechBundle 424 425 val bpuInfo = new Bundle { 426 val bpRight = Output(UInt(XLEN.W)) 427 val bpWrong = Output(UInt(XLEN.W)) 428 } 429 }) 430 io.bpuInfo := DontCare 431 432 val backendRedirect = Wire(Valid(new Redirect)) 433 val backendRedirectReg = RegNext(backendRedirect) 434 435 val stage2Flush = backendRedirect.valid 436 val backendFlush = stage2Flush || RegNext(stage2Flush) 437 val ifuFlush = Wire(Bool()) 438 439 val flush = stage2Flush || RegNext(stage2Flush) 440 441 val allowBpuIn, allowToIfu = WireInit(false.B) 442 val flushToIfu = !allowToIfu 443 allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 444 allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 445 446 val bpuPtr, ifuPtr, ifuWbPtr, commPtr = RegInit(FtqPtr(false.B, 0.U)) 447 val ifuPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 448 val validEntries = distanceBetween(bpuPtr, commPtr) 449 450 // ********************************************************************** 451 // **************************** enq from bpu **************************** 452 // ********************************************************************** 453 val new_entry_ready = validEntries < FtqSize.U 454 io.fromBpu.resp.ready := new_entry_ready 455 456 val bpu_s2_resp = io.fromBpu.resp.bits.s2 457 val bpu_s3_resp = io.fromBpu.resp.bits.s3 458 val bpu_s2_redirect = bpu_s2_resp.valid && bpu_s2_resp.hasRedirect 459 val bpu_s3_redirect = bpu_s3_resp.valid && bpu_s3_resp.hasRedirect 460 461 io.toBpu.enq_ptr := bpuPtr 462 val enq_fire = io.fromBpu.resp.fire() && allowBpuIn // from bpu s1 463 val bpu_in_fire = (io.fromBpu.resp.fire() || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn 464 465 val bpu_in_resp = io.fromBpu.resp.bits.selectedResp 466 val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdx 467 val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx) 468 val bpu_in_resp_idx = bpu_in_resp_ptr.value 469 470 // read ports: ifuReq1 + ifuReq2 + commitUpdate 471 val ftq_pc_mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, 3, 1)) 472 // resp from uBTB 473 ftq_pc_mem.io.wen(0) := bpu_in_fire 474 ftq_pc_mem.io.waddr(0) := bpu_in_resp_idx 475 ftq_pc_mem.io.wdata(0).fromBranchPrediction(bpu_in_resp) 476 477 // ifuRedirect + backendRedirect + commit 478 val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+1+1)) 479 // these info is intended to enq at the last stage of bpu 480 ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid 481 ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 482 ftq_redirect_sram.io.wdata.fromBranchPrediction(io.fromBpu.resp.bits.lastStage) 483 println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3") 484 println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3") 485 486 val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1)) 487 // these info is intended to enq at the last stage of bpu 488 ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid 489 ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 490 ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.meta 491 // ifuRedirect + backendRedirect + commit 492 val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+1+1, 1)) 493 ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid 494 ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value 495 ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.lastStage.ftb_entry 496 497 498 // multi-write 499 val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough 500 val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))) 501 val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool()))) 502 val pred_stage = Reg(Vec(FtqSize, UInt(2.W))) 503 504 val c_invalid :: c_valid :: c_commited :: Nil = Enum(3) 505 val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) { 506 VecInit(Seq.fill(PredictWidth)(c_invalid)) 507 })) 508 509 val f_to_send :: f_sent :: Nil = Enum(2) 510 val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent))) 511 512 val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3) 513 val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit))) 514 515 // modify registers one cycle later to cut critical path 516 val last_cycle_bpu_in = RegNext(bpu_in_fire) 517 val last_cycle_bpu_in_idx = RegNext(bpu_in_resp_idx) 518 val last_cycle_update_target = RegNext(bpu_in_resp.getTarget) 519 val last_cycle_cfiIndex = RegNext(bpu_in_resp.cfiIndex) 520 val last_cycle_bpu_in_stage = RegNext(bpu_in_stage) 521 when (last_cycle_bpu_in) { 522 entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send 523 commitStateQueue(last_cycle_bpu_in_idx) := VecInit(Seq.fill(PredictWidth)(c_invalid)) 524 cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex 525 mispredict_vec(last_cycle_bpu_in_idx) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B))) 526 update_target(last_cycle_bpu_in_idx) := last_cycle_update_target 527 pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage 528 } 529 530 531 bpuPtr := bpuPtr + enq_fire 532 when (io.toIfu.req.fire && allowToIfu) { 533 ifuPtr := ifuPtrPlus1 534 ifuPtrPlus1 := ifuPtrPlus1 + 1.U 535 } 536 537 // only use ftb result to assign hit status 538 when (bpu_s2_resp.valid) { 539 entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred.hit, h_hit, h_not_hit) 540 } 541 542 543 io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect 544 io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx 545 when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect) { 546 bpuPtr := bpu_s2_resp.ftq_idx + 1.U 547 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 548 when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) { 549 ifuPtr := bpu_s2_resp.ftq_idx 550 ifuPtrPlus1 := bpu_s2_resp.ftq_idx + 1.U 551 } 552 } 553 554 io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect 555 io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx 556 when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect) { 557 bpuPtr := bpu_s3_resp.ftq_idx + 1.U 558 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 559 when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) { 560 ifuPtr := bpu_s3_resp.ftq_idx 561 ifuPtrPlus1 := bpu_s3_resp.ftq_idx + 1.U 562 } 563 } 564 565 XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n") 566 567 // **************************************************************** 568 // **************************** to ifu **************************** 569 // **************************************************************** 570 val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata(0), bpu_in_fire) 571 val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr) 572 val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire) 573 574 // read pc and target 575 ftq_pc_mem.io.raddr.init.init.last := ifuPtr.value 576 ftq_pc_mem.io.raddr.init.last := ifuPtrPlus1.value 577 578 io.toIfu.req.bits.ftqIdx := ifuPtr 579 580 581 val toIfuPcBundle = Wire(new Ftq_RF_Components) 582 val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send) 583 val entry_next_addr = WireInit(update_target(ifuPtr.value)) 584 val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value)) 585 586 587 when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) { 588 toIfuPcBundle := bpu_in_bypass_buf 589 entry_is_to_send := true.B 590 entry_next_addr := last_cycle_update_target 591 entry_ftq_offset := last_cycle_cfiIndex 592 }.elsewhen (last_cycle_to_ifu_fire) { 593 toIfuPcBundle := ftq_pc_mem.io.rdata.init.last 594 entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) || 595 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles 596 }.otherwise { 597 toIfuPcBundle := ftq_pc_mem.io.rdata.init.init.last 598 entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) 599 } 600 601 io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 602 io.toIfu.req.bits.nextStartAddr := entry_next_addr 603 io.toIfu.req.bits.ftqOffset := entry_ftq_offset 604 io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle) 605 606 // when fall through is smaller in value than start address, there must be a false hit 607 when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) { 608 when (io.toIfu.req.fire && 609 !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && 610 !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr) 611 ) { 612 entry_hit_status(ifuPtr.value) := h_false_hit 613 // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 614 } 615 XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 616 } 617 618 XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit && 619 io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)) 620 621 val ifu_req_should_be_flushed = 622 io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) || 623 io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx) 624 625 when (io.toIfu.req.fire && !ifu_req_should_be_flushed) { 626 entry_fetch_status(ifuPtr.value) := f_sent 627 } 628 629 // ********************************************************************* 630 // **************************** wb from ifu **************************** 631 // ********************************************************************* 632 val pdWb = io.fromIfu.pdWb 633 val pds = pdWb.bits.pd 634 val ifu_wb_valid = pdWb.valid 635 val ifu_wb_idx = pdWb.bits.ftqIdx.value 636 // read ports: commit update 637 val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1)) 638 ftq_pd_mem.io.wen(0) := ifu_wb_valid 639 ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value 640 ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits) 641 642 val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid 643 val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid 644 val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B) 645 val pd_reg = RegEnable(pds, pdWb.valid) 646 val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid) 647 val wb_idx_reg = RegEnable(ifu_wb_idx, pdWb.valid) 648 649 when (ifu_wb_valid) { 650 val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{ 651 case (v, inRange) => v && inRange 652 }) 653 (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{ 654 case (qe, v) => when (v) { qe := c_valid } 655 } 656 } 657 658 ifuWbPtr := ifuWbPtr + ifu_wb_valid 659 660 ftb_entry_mem.io.raddr.head := ifu_wb_idx 661 val has_false_hit = WireInit(false.B) 662 when (RegNext(hit_pd_valid)) { 663 // check for false hit 664 val pred_ftb_entry = ftb_entry_mem.io.rdata.head 665 val brSlots = pred_ftb_entry.brSlots 666 val tailSlot = pred_ftb_entry.tailSlot 667 // we check cfis that bpu predicted 668 669 // bpu predicted branches but denied by predecode 670 val br_false_hit = 671 brSlots.map{ 672 s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr) 673 }.reduce(_||_) || 674 (tailSlot.valid && pred_ftb_entry.tailSlot.sharing && 675 !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr)) 676 677 val jmpOffset = tailSlot.offset 678 val jmp_pd = pd_reg(jmpOffset) 679 val jal_false_hit = pred_ftb_entry.jmpValid && 680 ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) || 681 (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) || 682 (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) || 683 (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)) 684 ) 685 686 has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg 687 XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0)) 688 689 // assert(!has_false_hit) 690 } 691 692 when (has_false_hit) { 693 entry_hit_status(wb_idx_reg) := h_false_hit 694 } 695 696 697 // ********************************************************************** 698 // ***************************** to backend ***************************** 699 // ********************************************************************** 700 // to backend pc mem / target 701 io.toBackend.pc_mem_wen := RegNext(last_cycle_bpu_in) 702 io.toBackend.pc_mem_waddr := RegNext(last_cycle_bpu_in_idx) 703 io.toBackend.pc_mem_wdata := RegNext(bpu_in_bypass_buf) 704 io.toBackend.target := RegNext(last_cycle_update_target) 705 706 // ******************************************************************************* 707 // **************************** redirect from backend **************************** 708 // ******************************************************************************* 709 710 // redirect read cfiInfo, couples to redirectGen s2 711 ftq_redirect_sram.io.ren.init.last := backendRedirect.valid 712 ftq_redirect_sram.io.raddr.init.last := backendRedirect.bits.ftqIdx.value 713 714 ftb_entry_mem.io.raddr.init.last := backendRedirect.bits.ftqIdx.value 715 716 val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last 717 val fromBackendRedirect = WireInit(backendRedirectReg) 718 val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate 719 backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo) 720 721 val r_ftb_entry = ftb_entry_mem.io.rdata.init.last 722 val r_ftqOffset = fromBackendRedirect.bits.ftqOffset 723 724 when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) { 725 backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +& 726 (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) && 727 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 728 729 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) || 730 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 731 }.otherwise { 732 backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt 733 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt 734 } 735 736 737 // *************************************************************************** 738 // **************************** redirect from ifu **************************** 739 // *************************************************************************** 740 val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect))) 741 fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush 742 fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx 743 fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits 744 fromIfuRedirect.bits.level := RedirectLevel.flushAfter 745 746 val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate 747 ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits) 748 ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits) 749 ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid 750 ifuRedirectCfiUpdate.target := pdWb.bits.target 751 ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid 752 ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid 753 754 val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect))) 755 val ifuRedirectToBpu = WireInit(ifuRedirectReg) 756 ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid 757 758 ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid 759 ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 760 761 ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 762 763 val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate 764 toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head) 765 when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) { 766 toBpuCfi.target := toBpuCfi.rasEntry.retAddr 767 } 768 769 // ********************************************************************* 770 // **************************** wb from exu **************************** 771 // ********************************************************************* 772 773 backendRedirect := io.fromBackend.redirect 774 775 def extractRedirectInfo(wb: Valid[Redirect]) = { 776 val ftqIdx = wb.bits.ftqIdx.value 777 val ftqOffset = wb.bits.ftqOffset 778 val taken = wb.bits.cfiUpdate.taken 779 val mispred = wb.bits.cfiUpdate.isMisPred 780 (wb.valid, ftqIdx, ftqOffset, taken, mispred) 781 } 782 783 // fix mispredict entry 784 val lastIsMispredict = RegNext( 785 backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B 786 ) 787 788 def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = { 789 val (r_valid, r_idx, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect) 790 val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits 791 val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits 792 when (cfiIndex_bits_wen || cfiIndex_valid_wen) { 793 cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken 794 } 795 when (cfiIndex_bits_wen) { 796 cfiIndex_vec(r_idx).bits := r_offset 797 } 798 update_target(r_idx) := redirect.bits.cfiUpdate.target 799 if (isBackend) { 800 mispredict_vec(r_idx)(r_offset) := r_mispred 801 } 802 } 803 804 // write to backend target vec 805 io.toBackend.pd_redirect_waddr.valid := RegNext(fromIfuRedirect.valid) 806 io.toBackend.pd_redirect_waddr.bits := RegNext(fromIfuRedirect.bits.ftqIdx.value) 807 io.toBackend.pd_redirect_target := RegNext(fromIfuRedirect.bits.cfiUpdate.target) 808 809 when(backendRedirectReg.valid && lastIsMispredict) { 810 updateCfiInfo(backendRedirectReg) 811 }.elsewhen (ifuRedirectToBpu.valid) { 812 updateCfiInfo(ifuRedirectToBpu, isBackend=false) 813 } 814 815 // *********************************************************************************** 816 // **************************** flush ptr and state queue **************************** 817 // *********************************************************************************** 818 819 val redirectVec = VecInit(backendRedirect, fromIfuRedirect) 820 821 // when redirect, we should reset ptrs and status queues 822 when(redirectVec.map(r => r.valid).reduce(_||_)){ 823 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 824 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 825 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 826 val next = idx + 1.U 827 bpuPtr := next 828 ifuPtr := next 829 ifuWbPtr := next 830 ifuPtrPlus1 := idx + 2.U 831 when (notIfu) { 832 commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) => 833 when(i.U > offset || i.U === offset && flushItSelf){ 834 s := c_invalid 835 } 836 }) 837 } 838 } 839 840 // only the valid bit is actually needed 841 io.toIfu.redirect.bits := backendRedirect.bits 842 io.toIfu.redirect.valid := stage2Flush 843 844 // commit 845 for (c <- io.fromBackend.rob_commits) { 846 when(c.valid) { 847 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited 848 // TODO: remove this 849 // For instruction fusions, we also update the next instruction 850 when (c.bits.commitType === 4.U) { 851 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited 852 }.elsewhen(c.bits.commitType === 5.U) { 853 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited 854 }.elsewhen(c.bits.commitType === 6.U) { 855 val index = (c.bits.ftqIdx + 1.U).value 856 commitStateQueue(index)(0) := c_commited 857 }.elsewhen(c.bits.commitType === 7.U) { 858 val index = (c.bits.ftqIdx + 1.U).value 859 commitStateQueue(index)(1) := c_commited 860 } 861 } 862 } 863 864 // **************************************************************** 865 // **************************** to bpu **************************** 866 // **************************************************************** 867 868 io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 869 870 val may_have_stall_from_bpu = Wire(Bool()) 871 val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states 872 may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U 873 val canCommit = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 874 Cat(commitStateQueue(commPtr.value).map(s => { 875 s === c_invalid || s === c_commited 876 })).andR() 877 878 // commit reads 879 ftq_pc_mem.io.raddr.last := commPtr.value 880 val commit_pc_bundle = ftq_pc_mem.io.rdata.last 881 ftq_pd_mem.io.raddr.last := commPtr.value 882 val commit_pd = ftq_pd_mem.io.rdata.last 883 ftq_redirect_sram.io.ren.last := canCommit 884 ftq_redirect_sram.io.raddr.last := commPtr.value 885 val commit_spec_meta = ftq_redirect_sram.io.rdata.last 886 ftq_meta_1r_sram.io.ren(0) := canCommit 887 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 888 val commit_meta = ftq_meta_1r_sram.io.rdata(0) 889 ftb_entry_mem.io.raddr.last := commPtr.value 890 val commit_ftb_entry = ftb_entry_mem.io.rdata.last 891 892 // need one cycle to read mem and srams 893 val do_commit_ptr = RegNext(commPtr) 894 val do_commit = RegNext(canCommit, init=false.B) 895 when (canCommit) { commPtr := commPtr + 1.U } 896 val commit_state = RegNext(commitStateQueue(commPtr.value)) 897 val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value)) 898 when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) { 899 can_commit_cfi.valid := false.B 900 } 901 val commit_cfi = RegNext(can_commit_cfi) 902 903 val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map { 904 case (mis, state) => mis && state === c_commited 905 }) 906 val can_commit_hit = entry_hit_status(commPtr.value) 907 val commit_hit = RegNext(can_commit_hit) 908 val commit_target = RegNext(update_target(commPtr.value)) 909 val commit_stage = RegNext(pred_stage(commPtr.value)) 910 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 911 912 val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit 913 switch (bpu_ftb_update_stall) { 914 is (0.U) { 915 when (can_commit_cfi.valid && !to_bpu_hit && canCommit) { 916 bpu_ftb_update_stall := 2.U // 2-cycle stall 917 } 918 } 919 is (2.U) { 920 bpu_ftb_update_stall := 1.U 921 } 922 is (1.U) { 923 bpu_ftb_update_stall := 0.U 924 } 925 is (3.U) { 926 XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2") 927 } 928 } 929 930 io.toBpu.update := DontCare 931 io.toBpu.update.valid := commit_valid && do_commit 932 val update = io.toBpu.update.bits 933 update.false_hit := commit_hit === h_false_hit 934 update.pc := commit_pc_bundle.startAddr 935 update.meta := commit_meta.meta 936 update.full_target := commit_target 937 update.from_stage := commit_stage 938 update.fromFtqRedirectSram(commit_spec_meta) 939 940 val commit_real_hit = commit_hit === h_hit 941 val update_ftb_entry = update.ftb_entry 942 943 val ftbEntryGen = Module(new FTBEntryGen).io 944 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 945 ftbEntryGen.old_entry := commit_ftb_entry 946 ftbEntryGen.pd := commit_pd 947 ftbEntryGen.cfiIndex := commit_cfi 948 ftbEntryGen.target := commit_target 949 ftbEntryGen.hit := commit_real_hit 950 ftbEntryGen.mispredict_vec := commit_mispredict 951 952 update_ftb_entry := ftbEntryGen.new_entry 953 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 954 update.mispred_mask := ftbEntryGen.mispred_mask 955 update.old_entry := ftbEntryGen.is_old_entry 956 update.pred_hit := commit_hit === h_hit || commit_hit === h_false_hit 957 958 update.is_minimal := false.B 959 update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc) 960 update.full_pred.br_taken_mask := ftbEntryGen.taken_mask 961 update.full_pred.jalr_target := commit_target 962 update.full_pred.hit := true.B 963 when (update.full_pred.is_jalr) { 964 update.full_pred.targets.last := commit_target 965 } 966 967 // **************************************************************** 968 // *********************** to prefetch **************************** 969 // **************************************************************** 970 971 if(cacheParams.hasPrefetch){ 972 val prefetchPtr = RegInit(FtqPtr(false.B, 0.U)) 973 prefetchPtr := prefetchPtr + io.toPrefetch.req.fire() 974 975 when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s2_resp.ftq_idx)) { 976 prefetchPtr := bpu_s2_resp.ftq_idx 977 } 978 979 when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s3_resp.ftq_idx)) { 980 prefetchPtr := bpu_s3_resp.ftq_idx 981 // XSError(true.B, "\ns3_redirect mechanism not implemented!\n") 982 } 983 984 985 val prefetch_is_to_send = WireInit(entry_fetch_status(prefetchPtr.value) === f_to_send) 986 val prefetch_addr = WireInit(update_target(prefetchPtr.value)) 987 988 when (last_cycle_bpu_in && bpu_in_bypass_ptr === prefetchPtr) { 989 prefetch_is_to_send := true.B 990 prefetch_addr := last_cycle_update_target 991 } 992 io.toPrefetch.req.valid := prefetchPtr =/= bpuPtr && prefetch_is_to_send 993 io.toPrefetch.req.bits.target := prefetch_addr 994 995 when(redirectVec.map(r => r.valid).reduce(_||_)){ 996 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 997 val next = r.ftqIdx + 1.U 998 prefetchPtr := next 999 } 1000 1001 XSError(isBefore(bpuPtr, prefetchPtr) && !isFull(bpuPtr, prefetchPtr), "\nprefetchPtr is before bpuPtr!\n") 1002 XSError(isBefore(prefetchPtr, ifuPtr) && !isFull(ifuPtr, prefetchPtr), "\nifuPtr is before prefetchPtr!\n") 1003 } 1004 else { 1005 io.toPrefetch.req <> DontCare 1006 } 1007 1008 // ****************************************************************************** 1009 // **************************** commit perf counters **************************** 1010 // ****************************************************************************** 1011 1012 val commit_inst_mask = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt 1013 val commit_mispred_mask = commit_mispredict.asUInt 1014 val commit_not_mispred_mask = ~commit_mispred_mask 1015 1016 val commit_br_mask = commit_pd.brMask.asUInt 1017 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 1018 val commit_cfi_mask = (commit_br_mask | commit_jmp_mask) 1019 1020 val mbpInstrs = commit_inst_mask & commit_cfi_mask 1021 1022 val mbpRights = mbpInstrs & commit_not_mispred_mask 1023 val mbpWrongs = mbpInstrs & commit_mispred_mask 1024 1025 io.bpuInfo.bpRight := PopCount(mbpRights) 1026 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 1027 1028 val ftqBranchTraceDB = ChiselDB.createTable("FTQTable" + p(XSCoreParamsKey).HartId.toString, new FtqDebugBundle) 1029 // Cfi Info 1030 for (i <- 0 until PredictWidth) { 1031 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 1032 val v = commit_state(i) === c_commited 1033 val isBr = commit_pd.brMask(i) 1034 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 1035 val isCfi = isBr || isJmp 1036 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 1037 val misPred = commit_mispredict(i) 1038 // val ghist = commit_spec_meta.ghist.predHist 1039 val histPtr = commit_spec_meta.histPtr 1040 val predCycle = commit_meta.meta(63, 0) 1041 val target = commit_target 1042 1043 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}))) 1044 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_) 1045 val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)) 1046 XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 1047 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " + 1048 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 1049 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n") 1050 1051 val logbundle = Wire(new FtqDebugBundle) 1052 logbundle.pc := pc 1053 logbundle.target := target 1054 logbundle.isBr := isBr 1055 logbundle.isJmp := isJmp 1056 logbundle.isCall := isJmp && commit_pd.hasCall 1057 logbundle.isRet := isJmp && commit_pd.hasRet 1058 logbundle.misPred := misPred 1059 logbundle.isTaken := isTaken 1060 logbundle.predStage := commit_stage 1061 1062 ftqBranchTraceDB.log( 1063 data = logbundle /* hardware of type T */, 1064 en = v && do_commit && isCfi, 1065 site = "FTQ" + p(XSCoreParamsKey).HartId.toString, 1066 clock = clock, 1067 reset = reset 1068 ) 1069 } 1070 1071 val enq = io.fromBpu.resp 1072 val perf_redirect = backendRedirect 1073 1074 XSPerfAccumulate("entry", validEntries) 1075 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 1076 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 1077 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 1078 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 1079 1080 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 1081 1082 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 1083 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 1084 XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr) 1085 1086 val from_bpu = io.fromBpu.resp.bits 1087 def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = { 1088 assert(!resp.is_minimal) 1089 val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits 1090 val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U) 1091 val entry_len_map = (1 to PredictWidth+1).map(i => 1092 f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid) 1093 ).foldLeft(Map[String, UInt]())(_+_) 1094 entry_len_map 1095 } 1096 val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2") 1097 val s3_entry_len_map = in_entry_len_map_gen(from_bpu.s3)("s3") 1098 1099 val to_ifu = io.toIfu.req.bits 1100 1101 1102 1103 val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U) 1104 val commit_num_inst_map = (1 to PredictWidth).map(i => 1105 f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit) 1106 ).foldLeft(Map[String, UInt]())(_+_) 1107 1108 1109 1110 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 1111 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 1112 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 1113 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 1114 1115 1116 val mbpBRights = mbpRights & commit_br_mask 1117 val mbpJRights = mbpRights & commit_jal_mask 1118 val mbpIRights = mbpRights & commit_jalr_mask 1119 val mbpCRights = mbpRights & commit_call_mask 1120 val mbpRRights = mbpRights & commit_ret_mask 1121 1122 val mbpBWrongs = mbpWrongs & commit_br_mask 1123 val mbpJWrongs = mbpWrongs & commit_jal_mask 1124 val mbpIWrongs = mbpWrongs & commit_jalr_mask 1125 val mbpCWrongs = mbpWrongs & commit_call_mask 1126 val mbpRWrongs = mbpWrongs & commit_ret_mask 1127 1128 val commit_pred_stage = RegNext(pred_stage(commPtr.value)) 1129 1130 def pred_stage_map(src: UInt, name: String) = { 1131 (0 until numBpStages).map(i => 1132 f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i))) 1133 ).foldLeft(Map[String, UInt]())(_+_) 1134 } 1135 1136 val mispred_stage_map = pred_stage_map(mbpWrongs, "mispredict") 1137 val br_mispred_stage_map = pred_stage_map(mbpBWrongs, "br_mispredict") 1138 val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict") 1139 val correct_stage_map = pred_stage_map(mbpRights, "correct") 1140 val br_correct_stage_map = pred_stage_map(mbpBRights, "br_correct") 1141 val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct") 1142 1143 val update_valid = io.toBpu.update.valid 1144 def u(cond: Bool) = update_valid && cond 1145 val ftb_false_hit = u(update.false_hit) 1146 // assert(!ftb_false_hit) 1147 val ftb_hit = u(commit_hit === h_hit) 1148 1149 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1150 val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid 1151 val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0) 1152 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid 1153 1154 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1155 1156 val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified) 1157 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1158 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1159 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1160 val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified 1161 1162 val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits 1163 val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U) 1164 val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i => 1165 f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry) 1166 ).foldLeft(Map[String, UInt]())(_+_) 1167 val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i => 1168 f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry) 1169 ).foldLeft(Map[String, UInt]())(_+_) 1170 1171 val ftq_occupancy_map = (0 to FtqSize).map(i => 1172 f"ftq_has_entry_$i" ->( validEntries === i.U) 1173 ).foldLeft(Map[String, UInt]())(_+_) 1174 1175 val perfCountsMap = Map( 1176 "BpInstr" -> PopCount(mbpInstrs), 1177 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1178 "BpRight" -> PopCount(mbpRights), 1179 "BpWrong" -> PopCount(mbpWrongs), 1180 "BpBRight" -> PopCount(mbpBRights), 1181 "BpBWrong" -> PopCount(mbpBWrongs), 1182 "BpJRight" -> PopCount(mbpJRights), 1183 "BpJWrong" -> PopCount(mbpJWrongs), 1184 "BpIRight" -> PopCount(mbpIRights), 1185 "BpIWrong" -> PopCount(mbpIWrongs), 1186 "BpCRight" -> PopCount(mbpCRights), 1187 "BpCWrong" -> PopCount(mbpCWrongs), 1188 "BpRRight" -> PopCount(mbpRRights), 1189 "BpRWrong" -> PopCount(mbpRWrongs), 1190 1191 "ftb_false_hit" -> PopCount(ftb_false_hit), 1192 "ftb_hit" -> PopCount(ftb_hit), 1193 "ftb_new_entry" -> PopCount(ftb_new_entry), 1194 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1195 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1196 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1197 "ftb_old_entry" -> PopCount(ftb_old_entry), 1198 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1199 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1200 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1201 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1202 "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken) 1203 ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ s2_entry_len_map ++ 1204 s3_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map ++ 1205 mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++ 1206 correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map 1207 1208 for((key, value) <- perfCountsMap) { 1209 XSPerfAccumulate(key, value) 1210 } 1211 1212 // --------------------------- Debug -------------------------------- 1213 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1214 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1215 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1216 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1217 XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1218 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n") 1219 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1220 1221 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1222 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1223 // case (((valid, pd), ans), taken) => 1224 // Mux(valid && pd.isBr, 1225 // isWrong ^ Mux(ans.hit.asBool, 1226 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1227 // !taken), 1228 // !taken), 1229 // false.B) 1230 // } 1231 // } 1232 1233 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1234 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1235 // case (((valid, pd), ans), taken) => 1236 // Mux(valid && pd.isBr, 1237 // isWrong ^ Mux(ans.hit.asBool, 1238 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1239 // !taken), 1240 // !taken), 1241 // false.B) 1242 // } 1243 // } 1244 1245 // def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1246 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1247 // case (((valid, pd), ans), taken) => 1248 // Mux(valid && pd.isBr, 1249 // isWrong ^ (ans.taken.asBool === taken), 1250 // false.B) 1251 // } 1252 // } 1253 1254 // def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1255 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1256 // case (((valid, pd), ans), taken) => 1257 // Mux(valid && (pd.isBr) && ans.hit.asBool, 1258 // isWrong ^ (!taken), 1259 // false.B) 1260 // } 1261 // } 1262 1263 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1264 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1265 // case (((valid, pd), ans), taken) => 1266 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1267 // isWrong ^ (ans.target === commitEntry.target), 1268 // false.B) 1269 // } 1270 // } 1271 1272 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1273 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1274 // // btb and ubtb pred jal and jalr as well 1275 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1276 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1277 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1278 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1279 1280 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1281 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1282 1283 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1284 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1285 1286 val perfEvents = Seq( 1287 ("bpu_s2_redirect ", bpu_s2_redirect ), 1288 ("bpu_s3_redirect ", bpu_s3_redirect ), 1289 ("bpu_to_ftq_stall ", enq.valid && ~enq.ready ), 1290 ("mispredictRedirect ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level), 1291 ("replayRedirect ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level) ), 1292 ("predecodeRedirect ", fromIfuRedirect.valid ), 1293 ("to_ifu_bubble ", io.toIfu.req.ready && !io.toIfu.req.valid ), 1294 ("from_bpu_real_bubble ", !enq.valid && enq.ready && allowBpuIn ), 1295 ("BpInstr ", PopCount(mbpInstrs) ), 1296 ("BpBInstr ", PopCount(mbpBRights | mbpBWrongs) ), 1297 ("BpRight ", PopCount(mbpRights) ), 1298 ("BpWrong ", PopCount(mbpWrongs) ), 1299 ("BpBRight ", PopCount(mbpBRights) ), 1300 ("BpBWrong ", PopCount(mbpBWrongs) ), 1301 ("BpJRight ", PopCount(mbpJRights) ), 1302 ("BpJWrong ", PopCount(mbpJWrongs) ), 1303 ("BpIRight ", PopCount(mbpIRights) ), 1304 ("BpIWrong ", PopCount(mbpIWrongs) ), 1305 ("BpCRight ", PopCount(mbpCRights) ), 1306 ("BpCWrong ", PopCount(mbpCWrongs) ), 1307 ("BpRRight ", PopCount(mbpRRights) ), 1308 ("BpRWrong ", PopCount(mbpRWrongs) ), 1309 ("ftb_false_hit ", PopCount(ftb_false_hit) ), 1310 ("ftb_hit ", PopCount(ftb_hit) ), 1311 ) 1312 generatePerfEvent() 1313} 1314