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