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