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