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