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: bju(BjuCnt) + ldReplay + exception 486 val ftqIdxAhead = VecInit(Seq.tabulate(FtqRedirectAheadNum)(i => io.fromBackend.ftqIdxAhead(i))) // only bju 487 val ftqIdxSelOH = io.fromBackend.ftqIdxSelOH.bits(FtqRedirectAheadNum - 1, 0) 488 489 val aheadValid = ftqIdxAhead.map(_.valid).reduce(_|_) && !io.fromBackend.redirect.valid 490 val realAhdValid = io.fromBackend.redirect.valid && (ftqIdxSelOH > 0.U) && RegNext(aheadValid) 491 val backendRedirect = Wire(Valid(new BranchPredictionRedirect)) 492 val backendRedirectReg = RegNext(backendRedirect) 493 backendRedirectReg.valid := Mux(realAhdValid, 0.B, backendRedirect.valid) 494 val fromBackendRedirect = Wire(Valid(new BranchPredictionRedirect)) 495 fromBackendRedirect := Mux(realAhdValid, backendRedirect, backendRedirectReg) 496 497 val stage2Flush = backendRedirect.valid 498 val backendFlush = stage2Flush || RegNext(stage2Flush) 499 val ifuFlush = Wire(Bool()) 500 501 val flush = stage2Flush || RegNext(stage2Flush) 502 503 val allowBpuIn, allowToIfu = WireInit(false.B) 504 val flushToIfu = !allowToIfu 505 allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 506 allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 507 508 def copyNum = 5 509 val bpuPtr, ifuPtr, ifuWbPtr, commPtr, robCommPtr = RegInit(FtqPtr(false.B, 0.U)) 510 val ifuPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 511 val ifuPtrPlus2 = RegInit(FtqPtr(false.B, 2.U)) 512 val commPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 513 val copied_ifu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U))) 514 val copied_bpu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U))) 515 require(FtqSize >= 4) 516 val ifuPtr_write = WireInit(ifuPtr) 517 val ifuPtrPlus1_write = WireInit(ifuPtrPlus1) 518 val ifuPtrPlus2_write = WireInit(ifuPtrPlus2) 519 val ifuWbPtr_write = WireInit(ifuWbPtr) 520 val commPtr_write = WireInit(commPtr) 521 val commPtrPlus1_write = WireInit(commPtrPlus1) 522 val robCommPtr_write = WireInit(robCommPtr) 523 ifuPtr := ifuPtr_write 524 ifuPtrPlus1 := ifuPtrPlus1_write 525 ifuPtrPlus2 := ifuPtrPlus2_write 526 ifuWbPtr := ifuWbPtr_write 527 commPtr := commPtr_write 528 commPtrPlus1 := commPtrPlus1_write 529 copied_ifu_ptr.map{ptr => 530 ptr := ifuPtr_write 531 dontTouch(ptr) 532 } 533 robCommPtr := robCommPtr_write 534 val validEntries = distanceBetween(bpuPtr, commPtr) 535 val canCommit = Wire(Bool()) 536 537 // ********************************************************************** 538 // **************************** enq from bpu **************************** 539 // ********************************************************************** 540 val new_entry_ready = validEntries < FtqSize.U || canCommit 541 io.fromBpu.resp.ready := new_entry_ready 542 543 val bpu_s2_resp = io.fromBpu.resp.bits.s2 544 val bpu_s3_resp = io.fromBpu.resp.bits.s3 545 val bpu_s2_redirect = bpu_s2_resp.valid(3) && bpu_s2_resp.hasRedirect(3) 546 val bpu_s3_redirect = bpu_s3_resp.valid(3) && bpu_s3_resp.hasRedirect(3) 547 548 io.toBpu.enq_ptr := bpuPtr 549 val enq_fire = io.fromBpu.resp.fire && allowBpuIn // from bpu s1 550 val bpu_in_fire = (io.fromBpu.resp.fire || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn 551 552 val bpu_in_resp = io.fromBpu.resp.bits.selectedResp 553 val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdxForFtq 554 val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx) 555 val bpu_in_resp_idx = bpu_in_resp_ptr.value 556 557 // read ports: prefetchReq ++ ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate 558 val ftq_pc_mem = Module(new FtqPcMemWrapper(1)) 559 // resp from uBTB 560 ftq_pc_mem.io.wen := bpu_in_fire 561 ftq_pc_mem.io.waddr := bpu_in_resp_idx 562 ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp) 563 564 // ifuRedirect + backendRedirect + commit 565 val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+FtqRedirectAheadNum+1)) 566 // these info is intended to enq at the last stage of bpu 567 ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3) 568 ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 569 ftq_redirect_sram.io.wdata := io.fromBpu.resp.bits.last_stage_spec_info 570 println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3") 571 println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3") 572 573 val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1)) 574 // these info is intended to enq at the last stage of bpu 575 ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3) 576 ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 577 ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.last_stage_meta 578 // ifuRedirect + backendRedirect + commit 579 val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+FtqRedirectAheadNum+1, 1)) 580 ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid(3) 581 ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value 582 ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_ftb_entry 583 584 585 // multi-write 586 val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this 587 val newest_entry_target = Reg(UInt(VAddrBits.W)) 588 val newest_entry_ptr = Reg(new FtqPtr) 589 val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))) 590 val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool()))) 591 val pred_stage = Reg(Vec(FtqSize, UInt(2.W))) 592 val pred_s1_cycle = if (!env.FPGAPlatform) Some(Reg(Vec(FtqSize, UInt(64.W)))) else None 593 594 val c_invalid :: c_valid :: c_commited :: Nil = Enum(3) 595 val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) { 596 VecInit(Seq.fill(PredictWidth)(c_invalid)) 597 })) 598 599 val f_to_send :: f_sent :: Nil = Enum(2) 600 val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent))) 601 602 val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3) 603 val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit))) 604 605 // modify registers one cycle later to cut critical path 606 val last_cycle_bpu_in = RegNext(bpu_in_fire) 607 val last_cycle_bpu_in_ptr = RegNext(bpu_in_resp_ptr) 608 val last_cycle_bpu_in_idx = last_cycle_bpu_in_ptr.value 609 val last_cycle_bpu_target = RegNext(bpu_in_resp.getTarget(3)) 610 val last_cycle_cfiIndex = RegNext(bpu_in_resp.cfiIndex(3)) 611 val last_cycle_bpu_in_stage = RegNext(bpu_in_stage) 612 613 def extra_copyNum_for_commitStateQueue = 2 614 val copied_last_cycle_bpu_in = VecInit(Seq.fill(copyNum+extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_fire))) 615 val copied_last_cycle_bpu_in_ptr_for_ftq = VecInit(Seq.fill(extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_resp_ptr))) 616 617 when (last_cycle_bpu_in) { 618 entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send 619 cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex 620 pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage 621 622 update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this 623 newest_entry_target := last_cycle_bpu_target 624 newest_entry_ptr := last_cycle_bpu_in_ptr 625 } 626 627 // reduce fanout by delay write for a cycle 628 when (RegNext(last_cycle_bpu_in)) { 629 mispredict_vec(RegNext(last_cycle_bpu_in_idx)) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B))) 630 } 631 632 // record s1 pred cycles 633 pred_s1_cycle.map(vec => { 634 when (bpu_in_fire && (bpu_in_stage === BP_S1)) { 635 vec(bpu_in_resp_ptr.value) := bpu_in_resp.full_pred(0).predCycle.getOrElse(0.U) 636 } 637 }) 638 639 // reduce fanout using copied last_cycle_bpu_in and copied last_cycle_bpu_in_ptr 640 val copied_last_cycle_bpu_in_for_ftq = copied_last_cycle_bpu_in.takeRight(extra_copyNum_for_commitStateQueue) 641 copied_last_cycle_bpu_in_for_ftq.zip(copied_last_cycle_bpu_in_ptr_for_ftq).zipWithIndex.map { 642 case ((in, ptr), i) => 643 when (in) { 644 val perSetEntries = FtqSize / extra_copyNum_for_commitStateQueue // 32 645 require(FtqSize % extra_copyNum_for_commitStateQueue == 0) 646 for (j <- 0 until perSetEntries) { 647 when (ptr.value === (i*perSetEntries+j).U) { 648 commitStateQueue(i*perSetEntries+j) := VecInit(Seq.fill(PredictWidth)(c_invalid)) 649 } 650 } 651 } 652 } 653 654 // num cycle is fixed 655 io.toBackend.newest_entry_ptr := RegNext(newest_entry_ptr) 656 io.toBackend.newest_entry_target := RegNext(newest_entry_target) 657 658 659 bpuPtr := bpuPtr + enq_fire 660 copied_bpu_ptr.map(_ := bpuPtr + enq_fire) 661 when (io.toIfu.req.fire && allowToIfu) { 662 ifuPtr_write := ifuPtrPlus1 663 ifuPtrPlus1_write := ifuPtrPlus2 664 ifuPtrPlus2_write := ifuPtrPlus2 + 1.U 665 } 666 667 // only use ftb result to assign hit status 668 when (bpu_s2_resp.valid(3)) { 669 entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred(3).hit, h_hit, h_not_hit) 670 } 671 672 673 io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect 674 io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx 675 when (bpu_s2_redirect) { 676 bpuPtr := bpu_s2_resp.ftq_idx + 1.U 677 copied_bpu_ptr.map(_ := bpu_s2_resp.ftq_idx + 1.U) 678 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 679 when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) { 680 ifuPtr_write := bpu_s2_resp.ftq_idx 681 ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U 682 ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U 683 } 684 } 685 686 io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect 687 io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx 688 when (bpu_s3_redirect) { 689 bpuPtr := bpu_s3_resp.ftq_idx + 1.U 690 copied_bpu_ptr.map(_ := bpu_s3_resp.ftq_idx + 1.U) 691 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 692 when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) { 693 ifuPtr_write := bpu_s3_resp.ftq_idx 694 ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U 695 ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U 696 } 697 } 698 699 XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n") 700 XSError(isBefore(ifuWbPtr, commPtr) && !isFull(ifuWbPtr, commPtr), "\ncommPtr is before ifuWbPtr!\n") 701 702 (0 until copyNum).map{i => 703 XSError(copied_bpu_ptr(i) =/= bpuPtr, "\ncopiedBpuPtr is different from bpuPtr!\n") 704 } 705 706 // **************************************************************** 707 // **************************** to ifu **************************** 708 // **************************************************************** 709 // 0 for ifu, and 1-4 for ICache 710 val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire) 711 val copied_bpu_in_bypass_buf = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire))) 712 val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf 713 val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr) 714 val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire) 715 716 val copied_bpu_in_bypass_ptr = VecInit(Seq.fill(copyNum)(RegNext(bpu_in_resp_ptr))) 717 val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire))) 718 719 // read pc and target 720 ftq_pc_mem.io.ifuPtr_w := ifuPtr_write 721 ftq_pc_mem.io.ifuPtrPlus1_w := ifuPtrPlus1_write 722 ftq_pc_mem.io.ifuPtrPlus2_w := ifuPtrPlus2_write 723 ftq_pc_mem.io.commPtr_w := commPtr_write 724 ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write 725 726 727 io.toIfu.req.bits.ftqIdx := ifuPtr 728 729 val toICachePcBundle = Wire(Vec(copyNum,new Ftq_RF_Components)) 730 val toICacheEntryToSend = Wire(Vec(copyNum,Bool())) 731 val toIfuPcBundle = Wire(new Ftq_RF_Components) 732 val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send) 733 val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value)) 734 val entry_next_addr = Wire(UInt(VAddrBits.W)) 735 736 val pc_mem_ifu_ptr_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata))) 737 val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata))) 738 val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this 739 740 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)))) 741 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))) 742 743 for(i <- 0 until copyNum){ 744 when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)){ 745 toICachePcBundle(i) := copied_bpu_in_bypass_buf(i) 746 toICacheEntryToSend(i) := true.B 747 }.elsewhen(copied_last_cycle_to_ifu_fire(i)){ 748 toICachePcBundle(i) := pc_mem_ifu_plus1_rdata(i) 749 toICacheEntryToSend(i) := copied_ifu_plus1_to_send(i) 750 }.otherwise{ 751 toICachePcBundle(i) := pc_mem_ifu_ptr_rdata(i) 752 toICacheEntryToSend(i) := copied_ifu_ptr_to_send(i) 753 } 754 } 755 756 // TODO: reconsider target address bypass logic 757 when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) { 758 toIfuPcBundle := bpu_in_bypass_buf_for_ifu 759 entry_is_to_send := true.B 760 entry_next_addr := last_cycle_bpu_target 761 entry_ftq_offset := last_cycle_cfiIndex 762 diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this 763 }.elsewhen (last_cycle_to_ifu_fire) { 764 toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata) 765 entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) || 766 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles 767 entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1), 768 bpu_in_bypass_buf_for_ifu.startAddr, 769 Mux(ifuPtr === newest_entry_ptr, 770 newest_entry_target, 771 RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))) // ifuPtr+2 772 }.otherwise { 773 toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata) 774 entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) || 775 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles 776 entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1), 777 bpu_in_bypass_buf_for_ifu.startAddr, 778 Mux(ifuPtr === newest_entry_ptr, 779 newest_entry_target, 780 RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))) // ifuPtr+1 781 } 782 783 io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 784 io.toIfu.req.bits.nextStartAddr := entry_next_addr 785 io.toIfu.req.bits.ftqOffset := entry_ftq_offset 786 io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle) 787 788 io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 789 io.toICache.req.bits.readValid.zipWithIndex.map{case(copy, i) => copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)} 790 io.toICache.req.bits.pcMemRead.zipWithIndex.map{case(copy,i) => copy.fromFtqPcBundle(toICachePcBundle(i))} 791 // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr 792 // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) => 793 // bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr 794 // bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr 795 // } 796 797 // TODO: remove this 798 XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr, 799 p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n") 800 801 // when fall through is smaller in value than start address, there must be a false hit 802 when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) { 803 when (io.toIfu.req.fire && 804 !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && 805 !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr) 806 ) { 807 entry_hit_status(ifuPtr.value) := h_false_hit 808 // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 809 } 810 XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 811 } 812 813 XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit && 814 io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)) 815 816 val ifu_req_should_be_flushed = 817 io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) || 818 io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx) 819 820 when (io.toIfu.req.fire && !ifu_req_should_be_flushed) { 821 entry_fetch_status(ifuPtr.value) := f_sent 822 } 823 824 // ********************************************************************* 825 // **************************** wb from ifu **************************** 826 // ********************************************************************* 827 val pdWb = io.fromIfu.pdWb 828 val pds = pdWb.bits.pd 829 val ifu_wb_valid = pdWb.valid 830 val ifu_wb_idx = pdWb.bits.ftqIdx.value 831 // read ports: commit update 832 val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1)) 833 ftq_pd_mem.io.wen(0) := ifu_wb_valid 834 ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value 835 ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits) 836 837 val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid 838 val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid 839 val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B) 840 val pd_reg = RegEnable(pds, pdWb.valid) 841 val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid) 842 val wb_idx_reg = RegEnable(ifu_wb_idx, pdWb.valid) 843 844 when (ifu_wb_valid) { 845 val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{ 846 case (v, inRange) => v && inRange 847 }) 848 (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{ 849 case (qe, v) => when (v) { qe := c_valid } 850 } 851 } 852 853 when (ifu_wb_valid) { 854 ifuWbPtr_write := ifuWbPtr + 1.U 855 } 856 857 XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU") 858 859 ftb_entry_mem.io.raddr.head := ifu_wb_idx 860 val has_false_hit = WireInit(false.B) 861 when (RegNext(hit_pd_valid)) { 862 // check for false hit 863 val pred_ftb_entry = ftb_entry_mem.io.rdata.head 864 val brSlots = pred_ftb_entry.brSlots 865 val tailSlot = pred_ftb_entry.tailSlot 866 // we check cfis that bpu predicted 867 868 // bpu predicted branches but denied by predecode 869 val br_false_hit = 870 brSlots.map{ 871 s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr) 872 }.reduce(_||_) || 873 (tailSlot.valid && pred_ftb_entry.tailSlot.sharing && 874 !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr)) 875 876 val jmpOffset = tailSlot.offset 877 val jmp_pd = pd_reg(jmpOffset) 878 val jal_false_hit = pred_ftb_entry.jmpValid && 879 ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) || 880 (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) || 881 (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) || 882 (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)) 883 ) 884 885 has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg 886 XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0)) 887 888 // assert(!has_false_hit) 889 } 890 891 when (has_false_hit) { 892 entry_hit_status(wb_idx_reg) := h_false_hit 893 } 894 895 896 // ********************************************************************** 897 // ***************************** to backend ***************************** 898 // ********************************************************************** 899 // to backend pc mem / target 900 io.toBackend.pc_mem_wen := RegNext(last_cycle_bpu_in) 901 io.toBackend.pc_mem_waddr := RegNext(last_cycle_bpu_in_idx) 902 io.toBackend.pc_mem_wdata := RegNext(bpu_in_bypass_buf_for_ifu) 903 904 // ******************************************************************************* 905 // **************************** redirect from backend **************************** 906 // ******************************************************************************* 907 908 // redirect read cfiInfo, couples to redirectGen s2 909 val redirectReadStart = 1 // 0 for ifuRedirect 910 val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry)) 911 val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry)) 912 for (i <- redirectReadStart until FtqRedirectAheadNum) { 913 ftq_redirect_sram.io.ren(i + redirectReadStart) := ftqIdxAhead(i).valid 914 ftq_redirect_sram.io.raddr(i + redirectReadStart) := ftqIdxAhead(i).bits.value 915 ftb_entry_mem.io.raddr(i + redirectReadStart) := ftqIdxAhead(i).bits.value 916 } 917 ftq_redirect_sram.io.ren(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid) 918 ftq_redirect_sram.io.raddr(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value) 919 ftb_entry_mem.io.raddr(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value) 920 921 for (i <- 0 until FtqRedirectAheadNum) { 922 ftq_redirect_rdata(i) := ftq_redirect_sram.io.rdata(i + redirectReadStart) 923 ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + redirectReadStart) 924 } 925 val stage3CfiInfo = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_sram.io.rdata(redirectReadStart)) 926 val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate 927 backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo) 928 929 930 val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(redirectReadStart)) 931 val r_ftqOffset = fromBackendRedirect.bits.ftqOffset 932 933 backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset) 934 backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset 935 // FIXME: not portable 936 val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B))) 937 backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(r_ftb_entry.brSlots(0).offset === r_ftqOffset, 938 sc_disagree(0), sc_disagree(1)) 939 940 when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) { 941 backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +& 942 (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) && 943 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 944 945 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) || 946 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 947 }.otherwise { 948 backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt 949 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt 950 } 951 952 953 // *************************************************************************** 954 // **************************** redirect from ifu **************************** 955 // *************************************************************************** 956 val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect))) 957 fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush 958 fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx 959 fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits 960 fromIfuRedirect.bits.level := RedirectLevel.flushAfter 961 fromIfuRedirect.bits.BTBMissBubble := true.B 962 fromIfuRedirect.bits.debugIsMemVio := false.B 963 fromIfuRedirect.bits.debugIsCtrl := false.B 964 965 val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate 966 ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits) 967 ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits) 968 ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid 969 ifuRedirectCfiUpdate.target := pdWb.bits.target 970 ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid 971 ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid 972 973 val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new BranchPredictionRedirect))) 974 val ifuRedirectToBpu = WireInit(ifuRedirectReg) 975 ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid 976 977 ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid 978 ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 979 980 ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 981 982 val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate 983 toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head) 984 when (ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) { 985 toBpuCfi.target := toBpuCfi.topAddr 986 } 987 988 when (ifuRedirectReg.valid) { 989 ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B 990 } .elsewhen(RegNext(pdWb.valid)) { 991 // if pdWb and no redirect, set to false 992 ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B 993 } 994 995 // ********************************************************************* 996 // **************************** wb from exu **************************** 997 // ********************************************************************* 998 999 backendRedirect.valid := io.fromBackend.redirect.valid 1000 backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits) 1001 backendRedirect.bits.BTBMissBubble := false.B 1002 1003 1004 def extractRedirectInfo(wb: Valid[Redirect]) = { 1005 val ftqPtr = wb.bits.ftqIdx 1006 val ftqOffset = wb.bits.ftqOffset 1007 val taken = wb.bits.cfiUpdate.taken 1008 val mispred = wb.bits.cfiUpdate.isMisPred 1009 (wb.valid, ftqPtr, ftqOffset, taken, mispred) 1010 } 1011 1012 // fix mispredict entry 1013 val lastIsMispredict = RegNext( 1014 backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B 1015 ) 1016 1017 def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = { 1018 val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect) 1019 val r_idx = r_ptr.value 1020 val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits 1021 val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits 1022 when (cfiIndex_bits_wen || cfiIndex_valid_wen) { 1023 cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken 1024 } .elsewhen (r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) { 1025 cfiIndex_vec(r_idx).valid :=false.B 1026 } 1027 when (cfiIndex_bits_wen) { 1028 cfiIndex_vec(r_idx).bits := r_offset 1029 } 1030 newest_entry_target := redirect.bits.cfiUpdate.target 1031 newest_entry_ptr := r_ptr 1032 update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this 1033 if (isBackend) { 1034 mispredict_vec(r_idx)(r_offset) := r_mispred 1035 } 1036 } 1037 1038 when(fromBackendRedirect.valid) { 1039 updateCfiInfo(fromBackendRedirect) 1040 }.elsewhen (ifuRedirectToBpu.valid) { 1041 updateCfiInfo(ifuRedirectToBpu, isBackend=false) 1042 } 1043 1044 when (fromBackendRedirect.valid) { 1045 when (fromBackendRedirect.bits.ControlRedirectBubble) { 1046 when (fromBackendRedirect.bits.ControlBTBMissBubble) { 1047 topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1048 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1049 } .elsewhen (fromBackendRedirect.bits.TAGEMissBubble) { 1050 topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 1051 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 1052 } .elsewhen (fromBackendRedirect.bits.SCMissBubble) { 1053 topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B 1054 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B 1055 } .elsewhen (fromBackendRedirect.bits.ITTAGEMissBubble) { 1056 topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 1057 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 1058 } .elsewhen (fromBackendRedirect.bits.RASMissBubble) { 1059 topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B 1060 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B 1061 } 1062 1063 1064 } .elsewhen (backendRedirect.bits.MemVioRedirectBubble) { 1065 topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 1066 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 1067 } .otherwise { 1068 topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 1069 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 1070 } 1071 } .elsewhen (ifuRedirectReg.valid) { 1072 topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1073 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1074 } 1075 1076 io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble 1077 io.TAGEMissBubble := fromBackendRedirect.bits.TAGEMissBubble 1078 io.SCMissBubble := fromBackendRedirect.bits.SCMissBubble 1079 io.ITTAGEMissBubble := fromBackendRedirect.bits.ITTAGEMissBubble 1080 io.RASMissBubble := fromBackendRedirect.bits.RASMissBubble 1081 1082 // *********************************************************************************** 1083 // **************************** flush ptr and state queue **************************** 1084 // *********************************************************************************** 1085 1086 val redirectVec = VecInit(backendRedirect, fromIfuRedirect) 1087 1088 // when redirect, we should reset ptrs and status queues 1089 when(redirectVec.map(r => r.valid).reduce(_||_)){ 1090 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1091 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 1092 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 1093 val next = idx + 1.U 1094 bpuPtr := next 1095 copied_bpu_ptr.map(_ := next) 1096 ifuPtr_write := next 1097 ifuWbPtr_write := next 1098 ifuPtrPlus1_write := idx + 2.U 1099 ifuPtrPlus2_write := idx + 3.U 1100 1101 } 1102 when(RegNext(redirectVec.map(r => r.valid).reduce(_||_))){ 1103 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1104 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 1105 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 1106 when (RegNext(notIfu)) { 1107 commitStateQueue(RegNext(idx.value)).zipWithIndex.foreach({ case (s, i) => 1108 when(i.U > RegNext(offset) || i.U === RegNext(offset) && RegNext(flushItSelf)){ 1109 s := c_invalid 1110 } 1111 }) 1112 } 1113 } 1114 1115 1116 // only the valid bit is actually needed 1117 io.toIfu.redirect.bits := backendRedirect.bits 1118 io.toIfu.redirect.valid := stage2Flush 1119 io.toIfu.topdown_redirect := fromBackendRedirect 1120 1121 // commit 1122 for (c <- io.fromBackend.rob_commits) { 1123 when(c.valid) { 1124 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited 1125 // TODO: remove this 1126 // For instruction fusions, we also update the next instruction 1127 when (c.bits.commitType === 4.U) { 1128 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited 1129 }.elsewhen(c.bits.commitType === 5.U) { 1130 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited 1131 }.elsewhen(c.bits.commitType === 6.U) { 1132 val index = (c.bits.ftqIdx + 1.U).value 1133 commitStateQueue(index)(0) := c_commited 1134 }.elsewhen(c.bits.commitType === 7.U) { 1135 val index = (c.bits.ftqIdx + 1.U).value 1136 commitStateQueue(index)(1) := c_commited 1137 } 1138 } 1139 } 1140 1141 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) 1142 1143 // **************************************************************** 1144 // **************************** to bpu **************************** 1145 // **************************************************************** 1146 1147 io.toBpu.redirect := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 1148 val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_=>0.U(64.W))) 1149 val redirect_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U 1150 XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1) 1151 XSPerfHistogram("ifu_redirect_latency", redirect_latency, !fromBackendRedirect.valid && ifuRedirectToBpu.valid, 0, 60, 1) 1152 1153 XSError(io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr), "Ftq received a redirect after its commit, check backend or replay") 1154 1155 val may_have_stall_from_bpu = Wire(Bool()) 1156 val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states 1157 may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U 1158 val notInvalidSeq = commitStateQueue(commPtr.value).map(s => s =/= c_invalid).reverse 1159 // Todo: @huxuan check it 1160 // canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1161 // Cat(commitStateQueue(commPtr.value).map(s => { 1162 // s === c_invalid || s === c_commited 1163 // })).andR 1164 canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1165 (isAfter(robCommPtr, commPtr) || PriorityMuxDefault(notInvalidSeq.zip(commitStateQueue(commPtr.value).reverse), c_invalid) === c_commited) 1166 1167 val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr 1168 val mmioLastCommit = isBefore(commPtr, mmioReadPtr) && (isAfter(ifuPtr,mmioReadPtr) || mmioReadPtr === ifuPtr) && 1169 Cat(commitStateQueue(mmioReadPtr.value).map(s => { s === c_invalid || s === c_commited})).andR 1170 io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit) 1171 1172 // commit reads 1173 val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata) 1174 val commit_target = 1175 Mux(RegNext(commPtr === newest_entry_ptr), 1176 RegNext(newest_entry_target), 1177 RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr)) 1178 ftq_pd_mem.io.raddr.last := commPtr.value 1179 val commit_pd = ftq_pd_mem.io.rdata.last 1180 ftq_redirect_sram.io.ren.last := canCommit 1181 ftq_redirect_sram.io.raddr.last := commPtr.value 1182 val commit_spec_meta = ftq_redirect_sram.io.rdata.last 1183 ftq_meta_1r_sram.io.ren(0) := canCommit 1184 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 1185 val commit_meta = ftq_meta_1r_sram.io.rdata(0) 1186 ftb_entry_mem.io.raddr.last := commPtr.value 1187 val commit_ftb_entry = ftb_entry_mem.io.rdata.last 1188 1189 // need one cycle to read mem and srams 1190 val do_commit_ptr = RegNext(commPtr) 1191 val do_commit = RegNext(canCommit, init=false.B) 1192 when (canCommit) { 1193 commPtr_write := commPtrPlus1 1194 commPtrPlus1_write := commPtrPlus1 + 1.U 1195 } 1196 val commit_state = RegNext(commitStateQueue(commPtr.value)) 1197 val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value)) 1198 val do_commit_cfi = WireInit(cfiIndex_vec(do_commit_ptr.value)) 1199 // 1200 //when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) { 1201 // can_commit_cfi.valid := false.B 1202 //} 1203 val commit_cfi = RegNext(can_commit_cfi) 1204 val debug_cfi = commitStateQueue(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_commited && do_commit_cfi.valid 1205 1206 val commit_mispredict : Vec[Bool] = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map { 1207 case (mis, state) => mis && state === c_commited 1208 }) 1209 val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_commited)) // [PredictWidth] 1210 val can_commit_hit = entry_hit_status(commPtr.value) 1211 val commit_hit = RegNext(can_commit_hit) 1212 val diff_commit_target = RegNext(update_target(commPtr.value)) // TODO: remove this 1213 val commit_stage = RegNext(pred_stage(commPtr.value)) 1214 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 1215 1216 val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit 1217 switch (bpu_ftb_update_stall) { 1218 is (0.U) { 1219 when (can_commit_cfi.valid && !to_bpu_hit && canCommit) { 1220 bpu_ftb_update_stall := 2.U // 2-cycle stall 1221 } 1222 } 1223 is (2.U) { 1224 bpu_ftb_update_stall := 1.U 1225 } 1226 is (1.U) { 1227 bpu_ftb_update_stall := 0.U 1228 } 1229 is (3.U) { 1230 XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2") 1231 } 1232 } 1233 1234 // TODO: remove this 1235 XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n") 1236 1237 // update latency stats 1238 val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U 1239 XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2) 1240 1241 io.toBpu.update := DontCare 1242 io.toBpu.update.valid := commit_valid && do_commit 1243 val update = io.toBpu.update.bits 1244 update.false_hit := commit_hit === h_false_hit 1245 update.pc := commit_pc_bundle.startAddr 1246 update.meta := commit_meta.meta 1247 update.cfi_idx := commit_cfi 1248 update.full_target := commit_target 1249 update.from_stage := commit_stage 1250 update.spec_info := commit_spec_meta 1251 XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n") 1252 1253 val commit_real_hit = commit_hit === h_hit 1254 val update_ftb_entry = update.ftb_entry 1255 1256 val ftbEntryGen = Module(new FTBEntryGen).io 1257 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 1258 ftbEntryGen.old_entry := commit_ftb_entry 1259 ftbEntryGen.pd := commit_pd 1260 ftbEntryGen.cfiIndex := commit_cfi 1261 ftbEntryGen.target := commit_target 1262 ftbEntryGen.hit := commit_real_hit 1263 ftbEntryGen.mispredict_vec := commit_mispredict 1264 1265 update_ftb_entry := ftbEntryGen.new_entry 1266 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 1267 update.mispred_mask := ftbEntryGen.mispred_mask 1268 update.old_entry := ftbEntryGen.is_old_entry 1269 update.pred_hit := commit_hit === h_hit || commit_hit === h_false_hit 1270 update.br_taken_mask := ftbEntryGen.taken_mask 1271 update.br_committed := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map { 1272 case (valid, offset) => valid && commit_instCommited(offset) 1273 } 1274 update.jmp_taken := ftbEntryGen.jmp_taken 1275 1276 // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc) 1277 // update.full_pred.jalr_target := commit_target 1278 // update.full_pred.hit := true.B 1279 // when (update.full_pred.is_jalr) { 1280 // update.full_pred.targets.last := commit_target 1281 // } 1282 1283 // **************************************************************** 1284 // *********************** to prefetch **************************** 1285 // **************************************************************** 1286 /** 1287 ****************************************************************************** 1288 * prefetchPtr control 1289 * - 1. prefetchPtr plus 1 when toPrefetch fire and keep distance from bpuPtr more than 2 1290 * - 2. limit range of prefetchPtr is in [ifuPtr + minRange, ifuPtr + maxRange] 1291 * - 3. flush prefetchPtr when receive redirect from ifu or backend 1292 ****************************************************************************** 1293 */ 1294 val prefetchPtr = RegInit(FtqPtr(false.B, 0.U)) 1295 val nextPrefetchPtr = WireInit(prefetchPtr) 1296 1297 prefetchPtr := nextPrefetchPtr 1298 1299 // TODO: consider req which cross cacheline 1300 when(io.toPrefetch.req.fire) { 1301 when(prefetchPtr < bpuPtr - 2.U) { 1302 nextPrefetchPtr := prefetchPtr + 1.U 1303 } 1304 } 1305 1306 when(prefetchPtr < ifuPtr + minRangeFromIFUptr.U) { 1307 nextPrefetchPtr := ifuPtr + minRangeFromIFUptr.U 1308 }.elsewhen(prefetchPtr > ifuPtr + maxRangeFromIFUptr.U) { 1309 nextPrefetchPtr := ifuPtr + maxRangeFromIFUptr.U 1310 } 1311 1312 when(redirectVec.map(r => r.valid).reduce(_||_)){ 1313 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1314 val next = r.ftqIdx + minRangeFromIFUptr.U 1315 nextPrefetchPtr := next 1316 } 1317 1318 // data from ftq_pc_mem has 1 cycle delay 1319 io.toPrefetch.req.valid := RegNext(entry_fetch_status(nextPrefetchPtr.value) === f_to_send) 1320 ftq_pc_mem.io.other_raddrs(0) := nextPrefetchPtr.value 1321 io.toPrefetch.req.bits.target := RegNext(ftq_pc_mem.io.other_rdatas(0).startAddr) 1322 1323 // record position relationship between ifuPtr, pfPtr and bpuPtr 1324 val isWritePrefetchPtrTable = WireInit(Constantin.createRecord("isWritePrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString)) 1325 val prefetchPtrTable = ChiselDB.createTable("PrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString, new PrefetchPtrDB) 1326 val prefetchPtrDumpData = Wire(new PrefetchPtrDB) 1327 prefetchPtrDumpData.fromFtqPtr := distanceBetween(bpuPtr, prefetchPtr) 1328 prefetchPtrDumpData.fromIfuPtr := distanceBetween(prefetchPtr, ifuPtr) 1329 1330 prefetchPtrTable.log( 1331 data = prefetchPtrDumpData, 1332 en = isWritePrefetchPtrTable.orR && io.toPrefetch.req.fire, 1333 site = "FTQ" + p(XSCoreParamsKey).HartId.toString, 1334 clock = clock, 1335 reset = reset 1336 ) 1337 1338 1339 // ****************************************************************************** 1340 // **************************** commit perf counters **************************** 1341 // ****************************************************************************** 1342 1343 val commit_inst_mask = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt 1344 val commit_mispred_mask = commit_mispredict.asUInt 1345 val commit_not_mispred_mask = ~commit_mispred_mask 1346 1347 val commit_br_mask = commit_pd.brMask.asUInt 1348 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 1349 val commit_cfi_mask = (commit_br_mask | commit_jmp_mask) 1350 1351 val mbpInstrs = commit_inst_mask & commit_cfi_mask 1352 1353 val mbpRights = mbpInstrs & commit_not_mispred_mask 1354 val mbpWrongs = mbpInstrs & commit_mispred_mask 1355 1356 io.bpuInfo.bpRight := PopCount(mbpRights) 1357 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 1358 1359 val isWriteFTQTable = WireInit(Constantin.createRecord("isWriteFTQTable" + p(XSCoreParamsKey).HartId.toString)) 1360 val ftqBranchTraceDB = ChiselDB.createTable("FTQTable" + p(XSCoreParamsKey).HartId.toString, new FtqDebugBundle) 1361 // Cfi Info 1362 for (i <- 0 until PredictWidth) { 1363 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 1364 val v = commit_state(i) === c_commited 1365 val isBr = commit_pd.brMask(i) 1366 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 1367 val isCfi = isBr || isJmp 1368 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 1369 val misPred = commit_mispredict(i) 1370 // val ghist = commit_spec_meta.ghist.predHist 1371 val histPtr = commit_spec_meta.histPtr 1372 val predCycle = commit_meta.meta(63, 0) 1373 val target = commit_target 1374 1375 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}))) 1376 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_) 1377 val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)) 1378 XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 1379 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " + 1380 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 1381 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n") 1382 1383 val logbundle = Wire(new FtqDebugBundle) 1384 logbundle.pc := pc 1385 logbundle.target := target 1386 logbundle.isBr := isBr 1387 logbundle.isJmp := isJmp 1388 logbundle.isCall := isJmp && commit_pd.hasCall 1389 logbundle.isRet := isJmp && commit_pd.hasRet 1390 logbundle.misPred := misPred 1391 logbundle.isTaken := isTaken 1392 logbundle.predStage := commit_stage 1393 1394 ftqBranchTraceDB.log( 1395 data = logbundle /* hardware of type T */, 1396 en = isWriteFTQTable.orR && v && do_commit && isCfi, 1397 site = "FTQ" + p(XSCoreParamsKey).HartId.toString, 1398 clock = clock, 1399 reset = reset 1400 ) 1401 } 1402 1403 val enq = io.fromBpu.resp 1404 val perf_redirect = backendRedirect 1405 1406 XSPerfAccumulate("entry", validEntries) 1407 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 1408 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 1409 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 1410 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 1411 1412 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 1413 1414 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 1415 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 1416 XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr) 1417 XSPerfAccumulate("bpu_to_ifu_bubble_when_ftq_full", (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready) 1418 1419 XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_|_)) 1420 XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid) 1421 XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid) 1422 1423 val from_bpu = io.fromBpu.resp.bits 1424 val to_ifu = io.toIfu.req.bits 1425 1426 1427 XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth+1, 1) 1428 1429 1430 1431 1432 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 1433 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 1434 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 1435 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 1436 1437 1438 val mbpBRights = mbpRights & commit_br_mask 1439 val mbpJRights = mbpRights & commit_jal_mask 1440 val mbpIRights = mbpRights & commit_jalr_mask 1441 val mbpCRights = mbpRights & commit_call_mask 1442 val mbpRRights = mbpRights & commit_ret_mask 1443 1444 val mbpBWrongs = mbpWrongs & commit_br_mask 1445 val mbpJWrongs = mbpWrongs & commit_jal_mask 1446 val mbpIWrongs = mbpWrongs & commit_jalr_mask 1447 val mbpCWrongs = mbpWrongs & commit_call_mask 1448 val mbpRWrongs = mbpWrongs & commit_ret_mask 1449 1450 val commit_pred_stage = RegNext(pred_stage(commPtr.value)) 1451 1452 def pred_stage_map(src: UInt, name: String) = { 1453 (0 until numBpStages).map(i => 1454 f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i))) 1455 ).foldLeft(Map[String, UInt]())(_+_) 1456 } 1457 1458 val mispred_stage_map = pred_stage_map(mbpWrongs, "mispredict") 1459 val br_mispred_stage_map = pred_stage_map(mbpBWrongs, "br_mispredict") 1460 val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict") 1461 val correct_stage_map = pred_stage_map(mbpRights, "correct") 1462 val br_correct_stage_map = pred_stage_map(mbpBRights, "br_correct") 1463 val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct") 1464 1465 val update_valid = io.toBpu.update.valid 1466 def u(cond: Bool) = update_valid && cond 1467 val ftb_false_hit = u(update.false_hit) 1468 // assert(!ftb_false_hit) 1469 val ftb_hit = u(commit_hit === h_hit) 1470 1471 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1472 val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid 1473 val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0) 1474 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid 1475 1476 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1477 1478 val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified) 1479 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1480 val ftb_modified_entry_ifu_redirected = u(ifuRedirected(do_commit_ptr.value)) 1481 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1482 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1483 val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified 1484 1485 def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits 1486 val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry) 1487 XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth+1, 1) 1488 XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth+1, 1) 1489 val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry) 1490 XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth+1, 1) 1491 1492 XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize+1, 1) 1493 1494 val perfCountsMap = Map( 1495 "BpInstr" -> PopCount(mbpInstrs), 1496 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1497 "BpRight" -> PopCount(mbpRights), 1498 "BpWrong" -> PopCount(mbpWrongs), 1499 "BpBRight" -> PopCount(mbpBRights), 1500 "BpBWrong" -> PopCount(mbpBWrongs), 1501 "BpJRight" -> PopCount(mbpJRights), 1502 "BpJWrong" -> PopCount(mbpJWrongs), 1503 "BpIRight" -> PopCount(mbpIRights), 1504 "BpIWrong" -> PopCount(mbpIWrongs), 1505 "BpCRight" -> PopCount(mbpCRights), 1506 "BpCWrong" -> PopCount(mbpCWrongs), 1507 "BpRRight" -> PopCount(mbpRRights), 1508 "BpRWrong" -> PopCount(mbpRWrongs), 1509 1510 "ftb_false_hit" -> PopCount(ftb_false_hit), 1511 "ftb_hit" -> PopCount(ftb_hit), 1512 "ftb_new_entry" -> PopCount(ftb_new_entry), 1513 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1514 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1515 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1516 "ftb_old_entry" -> PopCount(ftb_old_entry), 1517 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1518 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1519 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1520 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1521 "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken) 1522 ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++ 1523 correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map 1524 1525 for((key, value) <- perfCountsMap) { 1526 XSPerfAccumulate(key, value) 1527 } 1528 1529 // --------------------------- Debug -------------------------------- 1530 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1531 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1532 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1533 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1534 XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1535 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n") 1536 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1537 1538 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1539 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1540 // case (((valid, pd), ans), taken) => 1541 // Mux(valid && pd.isBr, 1542 // isWrong ^ Mux(ans.hit.asBool, 1543 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1544 // !taken), 1545 // !taken), 1546 // false.B) 1547 // } 1548 // } 1549 1550 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1551 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1552 // case (((valid, pd), ans), taken) => 1553 // Mux(valid && pd.isBr, 1554 // isWrong ^ Mux(ans.hit.asBool, 1555 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1556 // !taken), 1557 // !taken), 1558 // false.B) 1559 // } 1560 // } 1561 1562 // def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1563 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1564 // case (((valid, pd), ans), taken) => 1565 // Mux(valid && pd.isBr, 1566 // isWrong ^ (ans.taken.asBool === taken), 1567 // false.B) 1568 // } 1569 // } 1570 1571 // def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1572 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1573 // case (((valid, pd), ans), taken) => 1574 // Mux(valid && (pd.isBr) && ans.hit.asBool, 1575 // isWrong ^ (!taken), 1576 // false.B) 1577 // } 1578 // } 1579 1580 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1581 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1582 // case (((valid, pd), ans), taken) => 1583 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1584 // isWrong ^ (ans.target === commitEntry.target), 1585 // false.B) 1586 // } 1587 // } 1588 1589 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1590 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1591 // // btb and ubtb pred jal and jalr as well 1592 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1593 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1594 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1595 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1596 1597 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1598 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1599 1600 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1601 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1602 1603 val perfEvents = Seq( 1604 ("bpu_s2_redirect ", bpu_s2_redirect ), 1605 ("bpu_s3_redirect ", bpu_s3_redirect ), 1606 ("bpu_to_ftq_stall ", enq.valid && ~enq.ready ), 1607 ("mispredictRedirect ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level), 1608 ("replayRedirect ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level) ), 1609 ("predecodeRedirect ", fromIfuRedirect.valid ), 1610 ("to_ifu_bubble ", io.toIfu.req.ready && !io.toIfu.req.valid ), 1611 ("from_bpu_real_bubble ", !enq.valid && enq.ready && allowBpuIn ), 1612 ("BpInstr ", PopCount(mbpInstrs) ), 1613 ("BpBInstr ", PopCount(mbpBRights | mbpBWrongs) ), 1614 ("BpRight ", PopCount(mbpRights) ), 1615 ("BpWrong ", PopCount(mbpWrongs) ), 1616 ("BpBRight ", PopCount(mbpBRights) ), 1617 ("BpBWrong ", PopCount(mbpBWrongs) ), 1618 ("BpJRight ", PopCount(mbpJRights) ), 1619 ("BpJWrong ", PopCount(mbpJWrongs) ), 1620 ("BpIRight ", PopCount(mbpIRights) ), 1621 ("BpIWrong ", PopCount(mbpIWrongs) ), 1622 ("BpCRight ", PopCount(mbpCRights) ), 1623 ("BpCWrong ", PopCount(mbpCWrongs) ), 1624 ("BpRRight ", PopCount(mbpRRights) ), 1625 ("BpRWrong ", PopCount(mbpRWrongs) ), 1626 ("ftb_false_hit ", PopCount(ftb_false_hit) ), 1627 ("ftb_hit ", PopCount(ftb_hit) ), 1628 ) 1629 generatePerfEvent() 1630} 1631