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