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