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