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} 216 217trait HasBackendRedirectInfo extends HasXSParameter { 218 def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself() 219} 220 221class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo { 222 // write to backend pc mem 223 val pc_mem_wen = Output(Bool()) 224 val pc_mem_waddr = Output(UInt(log2Ceil(FtqSize).W)) 225 val pc_mem_wdata = Output(new Ftq_RF_Components) 226 // newest target 227 val newest_entry_en = Output(Bool()) 228 val newest_entry_target = Output(UInt(VAddrBits.W)) 229 val newest_entry_ptr = Output(new FtqPtr) 230} 231 232class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter { 233 val io = IO(new Bundle { 234 val start_addr = Input(UInt(VAddrBits.W)) 235 val old_entry = Input(new FTBEntry) 236 val pd = Input(new Ftq_pd_Entry) 237 val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W))) 238 val target = Input(UInt(VAddrBits.W)) 239 val hit = Input(Bool()) 240 val mispredict_vec = Input(Vec(PredictWidth, Bool())) 241 242 val new_entry = Output(new FTBEntry) 243 val new_br_insert_pos = Output(Vec(numBr, Bool())) 244 val taken_mask = Output(Vec(numBr, Bool())) 245 val jmp_taken = Output(Bool()) 246 val mispred_mask = Output(Vec(numBr + 1, Bool())) 247 248 // for perf counters 249 val is_init_entry = Output(Bool()) 250 val is_old_entry = Output(Bool()) 251 val is_new_br = Output(Bool()) 252 val is_jalr_target_modified = Output(Bool()) 253 val is_strong_bias_modified = Output(Bool()) 254 val is_br_full = Output(Bool()) 255 }) 256 257 // no mispredictions detected at predecode 258 val hit = io.hit 259 val pd = io.pd 260 261 val init_entry = WireInit(0.U.asTypeOf(new FTBEntry)) 262 263 val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid 264 val entry_has_jmp = pd.jmpInfo.valid 265 val new_jmp_is_jal = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid 266 val new_jmp_is_jalr = entry_has_jmp && pd.jmpInfo.bits(0) && io.cfiIndex.valid 267 val new_jmp_is_call = entry_has_jmp && pd.jmpInfo.bits(1) && io.cfiIndex.valid 268 val new_jmp_is_ret = entry_has_jmp && pd.jmpInfo.bits(2) && io.cfiIndex.valid 269 val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth - 1).U && !pd.rvcMask.last 270 // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last 271 272 val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal 273 val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr 274 275 def carryPos = log2Ceil(PredictWidth) + instOffsetBits 276 def getLower(pc: UInt) = pc(carryPos - 1, instOffsetBits) 277 // if not hit, establish a new entry 278 init_entry.valid := true.B 279 // tag is left for ftb to assign 280 281 // case br 282 val init_br_slot = init_entry.getSlotForBr(0) 283 when(cfi_is_br) { 284 init_br_slot.valid := true.B 285 init_br_slot.offset := io.cfiIndex.bits 286 init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1) 287 init_entry.strong_bias(0) := true.B // set to strong bias on init 288 } 289 290 // case jmp 291 when(entry_has_jmp) { 292 init_entry.tailSlot.offset := pd.jmpOffset 293 init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr 294 init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare = false) 295 init_entry.strong_bias(numBr - 1) := new_jmp_is_jalr // set strong bias for the jalr on init 296 } 297 298 val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U) 299 init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr)) 300 init_entry.carry := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos - instOffsetBits), true.B) 301 init_entry.isJalr := new_jmp_is_jalr 302 init_entry.isCall := new_jmp_is_call 303 init_entry.isRet := new_jmp_is_ret 304 // that means fall thru points to the middle of an inst 305 init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth - 1).U && !pd.rvcMask(pd.jmpOffset) 306 307 // if hit, check whether a new cfi(only br is possible) is detected 308 val oe = io.old_entry 309 val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits) 310 val br_recorded = br_recorded_vec.asUInt.orR 311 val is_new_br = cfi_is_br && !br_recorded 312 val new_br_offset = io.cfiIndex.bits 313 // vec(i) means new br will be inserted BEFORE old br(i) 314 val allBrSlotsVec = oe.allSlotsForBr 315 val new_br_insert_onehot = VecInit((0 until numBr).map { 316 i => 317 i match { 318 case 0 => 319 !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset 320 case idx => 321 allBrSlotsVec(idx - 1).valid && new_br_offset > allBrSlotsVec(idx - 1).offset && 322 (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset) 323 } 324 }) 325 326 val old_entry_modified = WireInit(io.old_entry) 327 for (i <- 0 until numBr) { 328 val slot = old_entry_modified.allSlotsForBr(i) 329 when(new_br_insert_onehot(i)) { 330 slot.valid := true.B 331 slot.offset := new_br_offset 332 slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr - 1) 333 old_entry_modified.strong_bias(i) := true.B 334 }.elsewhen(new_br_offset > oe.allSlotsForBr(i).offset) { 335 old_entry_modified.strong_bias(i) := false.B 336 // all other fields remain unchanged 337 }.otherwise { 338 // case i == 0, remain unchanged 339 if (i != 0) { 340 val noNeedToMoveFromFormerSlot = (i == numBr - 1).B && !oe.brSlots.last.valid 341 when(!noNeedToMoveFromFormerSlot) { 342 slot.fromAnotherSlot(oe.allSlotsForBr(i - 1)) 343 old_entry_modified.strong_bias(i) := oe.strong_bias(i) 344 } 345 } 346 } 347 } 348 349 // two circumstances: 350 // 1. oe: | br | j |, new br should be in front of j, thus addr of j should be new pft 351 // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either 352 // the previous last br or the new br 353 val may_have_to_replace = oe.noEmptySlotForNewBr 354 val pft_need_to_change = is_new_br && may_have_to_replace 355 // it should either be the given last br or the new br 356 when(pft_need_to_change) { 357 val new_pft_offset = 358 Mux(!new_br_insert_onehot.asUInt.orR, new_br_offset, oe.allSlotsForBr.last.offset) 359 360 // set jmp to invalid 361 old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset 362 old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool 363 old_entry_modified.last_may_be_rvi_call := false.B 364 old_entry_modified.isCall := false.B 365 old_entry_modified.isRet := false.B 366 old_entry_modified.isJalr := false.B 367 } 368 369 val old_entry_jmp_target_modified = WireInit(oe) 370 val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits 371 val old_tail_is_jmp = !oe.tailSlot.sharing 372 val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target 373 when(jalr_target_modified) { 374 old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target) 375 old_entry_jmp_target_modified.strong_bias := 0.U.asTypeOf(Vec(numBr, Bool())) 376 } 377 378 val old_entry_strong_bias = WireInit(oe) 379 val strong_bias_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not 380 for (i <- 0 until numBr) { 381 when(br_recorded_vec(0)) { 382 old_entry_strong_bias.strong_bias(0) := 383 oe.strong_bias(0) && io.cfiIndex.valid && oe.brValids(0) && io.cfiIndex.bits === oe.brOffset(0) 384 }.elsewhen(br_recorded_vec(numBr - 1)) { 385 old_entry_strong_bias.strong_bias(0) := false.B 386 old_entry_strong_bias.strong_bias(numBr - 1) := 387 oe.strong_bias(numBr - 1) && io.cfiIndex.valid && oe.brValids(numBr - 1) && io.cfiIndex.bits === oe.brOffset( 388 numBr - 1 389 ) 390 } 391 strong_bias_modified_vec(i) := oe.strong_bias(i) && oe.brValids(i) && !old_entry_strong_bias.strong_bias(i) 392 } 393 val strong_bias_modified = strong_bias_modified_vec.reduce(_ || _) 394 395 val derived_from_old_entry = 396 Mux(is_new_br, old_entry_modified, Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_strong_bias)) 397 398 io.new_entry := Mux(!hit, init_entry, derived_from_old_entry) 399 400 io.new_br_insert_pos := new_br_insert_onehot 401 io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map { 402 case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v 403 }) 404 io.jmp_taken := io.new_entry.jmpValid && io.new_entry.tailSlot.offset === io.cfiIndex.bits 405 for (i <- 0 until numBr) { 406 io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i)) 407 } 408 io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset) 409 410 // for perf counters 411 io.is_init_entry := !hit 412 io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !strong_bias_modified 413 io.is_new_br := hit && is_new_br 414 io.is_jalr_target_modified := hit && jalr_target_modified 415 io.is_strong_bias_modified := hit && strong_bias_modified 416 io.is_br_full := hit && is_new_br && may_have_to_replace 417} 418 419class FtqPcMemWrapper(numOtherReads: Int)(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo { 420 val io = IO(new Bundle { 421 val ifuPtr_w = Input(new FtqPtr) 422 val ifuPtrPlus1_w = Input(new FtqPtr) 423 val ifuPtrPlus2_w = Input(new FtqPtr) 424 val pfPtr_w = Input(new FtqPtr) 425 val pfPtrPlus1_w = Input(new FtqPtr) 426 val commPtr_w = Input(new FtqPtr) 427 val commPtrPlus1_w = Input(new FtqPtr) 428 val ifuPtr_rdata = Output(new Ftq_RF_Components) 429 val ifuPtrPlus1_rdata = Output(new Ftq_RF_Components) 430 val ifuPtrPlus2_rdata = Output(new Ftq_RF_Components) 431 val pfPtr_rdata = Output(new Ftq_RF_Components) 432 val pfPtrPlus1_rdata = Output(new Ftq_RF_Components) 433 val commPtr_rdata = Output(new Ftq_RF_Components) 434 val commPtrPlus1_rdata = Output(new Ftq_RF_Components) 435 436 val wen = Input(Bool()) 437 val waddr = Input(UInt(log2Ceil(FtqSize).W)) 438 val wdata = Input(new Ftq_RF_Components) 439 }) 440 441 val num_pc_read = numOtherReads + 5 442 val mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, num_pc_read, 1, "FtqPC")) 443 mem.io.wen(0) := io.wen 444 mem.io.waddr(0) := io.waddr 445 mem.io.wdata(0) := io.wdata 446 447 // read one cycle ahead for ftq local reads 448 val raddr_vec = VecInit(Seq( 449 io.ifuPtr_w.value, 450 io.ifuPtrPlus1_w.value, 451 io.ifuPtrPlus2_w.value, 452 io.pfPtr_w.value, 453 io.pfPtrPlus1_w.value, 454 io.commPtrPlus1_w.value, 455 io.commPtr_w.value 456 )) 457 458 mem.io.raddr := raddr_vec 459 460 io.ifuPtr_rdata := mem.io.rdata.dropRight(6).last 461 io.ifuPtrPlus1_rdata := mem.io.rdata.dropRight(5).last 462 io.ifuPtrPlus2_rdata := mem.io.rdata.dropRight(4).last 463 io.pfPtr_rdata := mem.io.rdata.dropRight(3).last 464 io.pfPtrPlus1_rdata := mem.io.rdata.dropRight(2).last 465 io.commPtrPlus1_rdata := mem.io.rdata.dropRight(1).last 466 io.commPtr_rdata := mem.io.rdata.last 467} 468 469class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper 470 with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents 471 with HasICacheParameters { 472 val io = IO(new Bundle { 473 val fromBpu = Flipped(new BpuToFtqIO) 474 val fromIfu = Flipped(new IfuToFtqIO) 475 val fromBackend = Flipped(new CtrlToFtqIO) 476 477 val toBpu = new FtqToBpuIO 478 val toIfu = new FtqToIfuIO 479 val toICache = new FtqToICacheIO 480 val toBackend = new FtqToCtrlIO 481 val toPrefetch = new FtqToPrefetchIO 482 val icacheFlush = Output(Bool()) 483 484 val bpuInfo = new Bundle { 485 val bpRight = Output(UInt(XLEN.W)) 486 val bpWrong = Output(UInt(XLEN.W)) 487 } 488 489 val mmioCommitRead = Flipped(new mmioCommitRead) 490 491 // for perf 492 val ControlBTBMissBubble = Output(Bool()) 493 val TAGEMissBubble = Output(Bool()) 494 val SCMissBubble = Output(Bool()) 495 val ITTAGEMissBubble = Output(Bool()) 496 val RASMissBubble = Output(Bool()) 497 }) 498 io.bpuInfo := DontCare 499 500 val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle)) 501 // only driven by clock, not valid-ready 502 topdown_stage := io.fromBpu.resp.bits.topdown_info 503 io.toIfu.req.bits.topdown_info := topdown_stage 504 505 val ifuRedirected = RegInit(VecInit(Seq.fill(FtqSize)(false.B))) 506 507 // io.fromBackend.ftqIdxAhead: bju(BjuCnt) + ldReplay + exception 508 val ftqIdxAhead = VecInit(Seq.tabulate(FtqRedirectAheadNum)(i => io.fromBackend.ftqIdxAhead(i))) // only bju 509 val ftqIdxSelOH = io.fromBackend.ftqIdxSelOH.bits(FtqRedirectAheadNum - 1, 0) 510 511 val aheadValid = ftqIdxAhead.map(_.valid).reduce(_ | _) && !io.fromBackend.redirect.valid 512 val realAhdValid = io.fromBackend.redirect.valid && (ftqIdxSelOH > 0.U) && RegNext(aheadValid) 513 val backendRedirect = Wire(Valid(new BranchPredictionRedirect)) 514 val backendRedirectReg = Wire(Valid(new BranchPredictionRedirect)) 515 backendRedirectReg.valid := RegNext(Mux(realAhdValid, false.B, backendRedirect.valid)) 516 backendRedirectReg.bits := RegEnable(backendRedirect.bits, backendRedirect.valid) 517 val fromBackendRedirect = Wire(Valid(new BranchPredictionRedirect)) 518 fromBackendRedirect := Mux(realAhdValid, backendRedirect, backendRedirectReg) 519 520 val stage2Flush = backendRedirect.valid 521 val backendFlush = stage2Flush || RegNext(stage2Flush) 522 val ifuFlush = Wire(Bool()) 523 524 val flush = stage2Flush || RegNext(stage2Flush) 525 526 val allowBpuIn, allowToIfu = WireInit(false.B) 527 val flushToIfu = !allowToIfu 528 allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 529 allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 530 531 def copyNum = 5 532 val bpuPtr, ifuPtr, pfPtr, ifuWbPtr, commPtr, robCommPtr = RegInit(FtqPtr(false.B, 0.U)) 533 val ifuPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 534 val ifuPtrPlus2 = RegInit(FtqPtr(false.B, 2.U)) 535 val pfPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 536 val commPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 537 val copied_ifu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U))) 538 val copied_bpu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U))) 539 require(FtqSize >= 4) 540 val ifuPtr_write = WireInit(ifuPtr) 541 val ifuPtrPlus1_write = WireInit(ifuPtrPlus1) 542 val ifuPtrPlus2_write = WireInit(ifuPtrPlus2) 543 val pfPtr_write = WireInit(pfPtr) 544 val pfPtrPlus1_write = WireInit(pfPtrPlus1) 545 val ifuWbPtr_write = WireInit(ifuWbPtr) 546 val commPtr_write = WireInit(commPtr) 547 val commPtrPlus1_write = WireInit(commPtrPlus1) 548 val robCommPtr_write = WireInit(robCommPtr) 549 ifuPtr := ifuPtr_write 550 ifuPtrPlus1 := ifuPtrPlus1_write 551 ifuPtrPlus2 := ifuPtrPlus2_write 552 pfPtr := pfPtr_write 553 pfPtrPlus1 := pfPtrPlus1_write 554 ifuWbPtr := ifuWbPtr_write 555 commPtr := commPtr_write 556 commPtrPlus1 := commPtrPlus1_write 557 copied_ifu_ptr.map { ptr => 558 ptr := ifuPtr_write 559 dontTouch(ptr) 560 } 561 robCommPtr := robCommPtr_write 562 val validEntries = distanceBetween(bpuPtr, commPtr) 563 val canCommit = Wire(Bool()) 564 565 // Instruction page fault and instruction access fault are sent from backend with redirect requests. 566 // When IPF and IAF are sent, backendPcFaultIfuPtr points to the FTQ entry whose first instruction 567 // raises IPF or IAF, which is ifuWbPtr_write or IfuPtr_write. 568 // Only when IFU has written back that FTQ entry can backendIpf and backendIaf be false because this 569 // makes sure that IAF and IPF are correctly raised instead of being flushed by redirect requests. 570 val backendIpf = RegInit(false.B) 571 val backendIgpf = RegInit(false.B) 572 val backendIaf = RegInit(false.B) 573 val backendPcFaultPtr = RegInit(FtqPtr(false.B, 0.U)) 574 when(fromBackendRedirect.valid) { 575 backendIpf := fromBackendRedirect.bits.cfiUpdate.backendIPF 576 backendIgpf := fromBackendRedirect.bits.cfiUpdate.backendIGPF 577 backendIaf := fromBackendRedirect.bits.cfiUpdate.backendIAF 578 when( 579 fromBackendRedirect.bits.cfiUpdate.backendIPF || fromBackendRedirect.bits.cfiUpdate.backendIGPF || fromBackendRedirect.bits.cfiUpdate.backendIAF 580 ) { 581 backendPcFaultPtr := ifuWbPtr_write 582 } 583 }.elsewhen(ifuWbPtr =/= backendPcFaultPtr) { 584 backendIpf := false.B 585 backendIgpf := false.B 586 backendIaf := false.B 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.backendIpf := backendIpf && backendPcFaultPtr === ifuPtr 912 io.toICache.req.bits.backendIgpf := backendIgpf && backendPcFaultPtr === ifuPtr 913 io.toICache.req.bits.backendIaf := backendIaf && backendPcFaultPtr === ifuPtr 914 915 io.toPrefetch.req.valid := toPrefetchEntryToSend && pfPtr =/= bpuPtr 916 io.toPrefetch.req.bits.fromFtqPcBundle(toPrefetchPcBundle) 917 io.toPrefetch.req.bits.ftqIdx := pfPtr 918 // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr 919 // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) => 920 // bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr 921 // bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr 922 // } 923 924 // TODO: remove this 925 XSError( 926 io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr, 927 p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n" 928 ) 929 930 // when fall through is smaller in value than start address, there must be a false hit 931 when(toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) { 932 when(io.toIfu.req.fire && 933 !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && 934 !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)) { 935 entry_hit_status(ifuPtr.value) := h_false_hit 936 // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 937 } 938 XSDebug( 939 true.B, 940 "fallThruError! start:%x, fallThru:%x\n", 941 io.toIfu.req.bits.startAddr, 942 io.toIfu.req.bits.nextStartAddr 943 ) 944 } 945 946 XSPerfAccumulate( 947 f"fall_through_error_to_ifu", 948 toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit && 949 io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr) 950 ) 951 952 val ifu_req_should_be_flushed = 953 io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) || 954 io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx) 955 956 when(io.toIfu.req.fire && !ifu_req_should_be_flushed) { 957 entry_fetch_status(ifuPtr.value) := f_sent 958 } 959 960 // ********************************************************************* 961 // **************************** wb from ifu **************************** 962 // ********************************************************************* 963 val pdWb = io.fromIfu.pdWb 964 val pds = pdWb.bits.pd 965 val ifu_wb_valid = pdWb.valid 966 val ifu_wb_idx = pdWb.bits.ftqIdx.value 967 // read ports: commit update 968 val ftq_pd_mem = 969 Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, FtqRedirectAheadNum + 1, 1, hasRen = true)) 970 ftq_pd_mem.io.wen(0) := ifu_wb_valid 971 ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value 972 ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits) 973 974 val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid 975 val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid 976 val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init = false.B) 977 val pd_reg = RegEnable(pds, pdWb.valid) 978 val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid) 979 val wb_idx_reg = RegEnable(ifu_wb_idx, pdWb.valid) 980 981 when(ifu_wb_valid) { 982 val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map { 983 case (v, inRange) => v && inRange 984 }) 985 commitStateQueueEnable(ifu_wb_idx) := true.B 986 (commitStateQueueNext(ifu_wb_idx) zip comm_stq_wen).map { 987 case (qe, v) => when(v) { 988 qe := c_toCommit 989 } 990 } 991 } 992 993 when(ifu_wb_valid) { 994 ifuWbPtr_write := ifuWbPtr + 1.U 995 } 996 997 XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU") 998 999 ftb_entry_mem.io.ren.get.head := ifu_wb_valid 1000 ftb_entry_mem.io.raddr.head := ifu_wb_idx 1001 val has_false_hit = WireInit(false.B) 1002 when(RegNext(hit_pd_valid)) { 1003 // check for false hit 1004 val pred_ftb_entry = ftb_entry_mem.io.rdata.head 1005 val brSlots = pred_ftb_entry.brSlots 1006 val tailSlot = pred_ftb_entry.tailSlot 1007 // we check cfis that bpu predicted 1008 1009 // bpu predicted branches but denied by predecode 1010 val br_false_hit = 1011 brSlots.map { 1012 s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr) 1013 }.reduce(_ || _) || 1014 (tailSlot.valid && pred_ftb_entry.tailSlot.sharing && 1015 !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr)) 1016 1017 val jmpOffset = tailSlot.offset 1018 val jmp_pd = pd_reg(jmpOffset) 1019 val jal_false_hit = pred_ftb_entry.jmpValid && 1020 ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) || 1021 (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) || 1022 (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) || 1023 (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet))) 1024 1025 has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg 1026 XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0)) 1027 1028 // assert(!has_false_hit) 1029 } 1030 1031 when(has_false_hit) { 1032 entry_hit_status(wb_idx_reg) := h_false_hit 1033 } 1034 1035 // ******************************************************************************* 1036 // **************************** redirect from backend **************************** 1037 // ******************************************************************************* 1038 1039 // redirect read cfiInfo, couples to redirectGen s2 1040 // ftqIdxAhead(0-3) => ftq_redirect_mem(1-4), reuse ftq_redirect_mem(1) 1041 val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry)) 1042 val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry_FtqMem)) 1043 1044 val ftq_pd_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_pd_Entry)) 1045 for (i <- 1 until FtqRedirectAheadNum) { 1046 ftq_redirect_mem.io.ren.get(i + IfuRedirectNum) := ftqIdxAhead(i).valid 1047 ftq_redirect_mem.io.raddr(i + IfuRedirectNum) := ftqIdxAhead(i).bits.value 1048 ftb_entry_mem.io.ren.get(i + IfuRedirectNum) := ftqIdxAhead(i).valid 1049 ftb_entry_mem.io.raddr(i + IfuRedirectNum) := ftqIdxAhead(i).bits.value 1050 1051 ftq_pd_mem.io.ren.get(i) := ftqIdxAhead(i).valid 1052 ftq_pd_mem.io.raddr(i) := ftqIdxAhead(i).bits.value 1053 } 1054 ftq_redirect_mem.io.ren.get(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid) 1055 ftq_redirect_mem.io.raddr(IfuRedirectNum) := Mux( 1056 aheadValid, 1057 ftqIdxAhead(0).bits.value, 1058 backendRedirect.bits.ftqIdx.value 1059 ) 1060 ftb_entry_mem.io.ren.get(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid) 1061 ftb_entry_mem.io.raddr(IfuRedirectNum) := Mux( 1062 aheadValid, 1063 ftqIdxAhead(0).bits.value, 1064 backendRedirect.bits.ftqIdx.value 1065 ) 1066 1067 ftq_pd_mem.io.ren.get(0) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid) 1068 ftq_pd_mem.io.raddr(0) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value) 1069 1070 for (i <- 0 until FtqRedirectAheadNum) { 1071 ftq_redirect_rdata(i) := ftq_redirect_mem.io.rdata(i + IfuRedirectNum) 1072 ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + IfuRedirectNum) 1073 1074 ftq_pd_rdata(i) := ftq_pd_mem.io.rdata(i) 1075 } 1076 val stage3CfiInfo = 1077 Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_mem.io.rdata(IfuRedirectNum)) 1078 val stage3PdInfo = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_pd_rdata), ftq_pd_mem.io.rdata(0)) 1079 val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate 1080 backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo) 1081 backendRedirectCfi.pd := stage3PdInfo.toPd(fromBackendRedirect.bits.ftqOffset) 1082 1083 val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(IfuRedirectNum)) 1084 val r_ftqOffset = fromBackendRedirect.bits.ftqOffset 1085 1086 backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset) 1087 backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset 1088 // FIXME: not portable 1089 val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B))) 1090 backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux( 1091 r_ftb_entry.brSlots(0).offset === r_ftqOffset, 1092 sc_disagree(0), 1093 sc_disagree(1) 1094 ) 1095 1096 when(entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) { 1097 backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +& 1098 (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) && 1099 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 1100 1101 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) || 1102 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 1103 }.otherwise { 1104 backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt 1105 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt 1106 } 1107 1108 // *************************************************************************** 1109 // **************************** redirect from ifu **************************** 1110 // *************************************************************************** 1111 val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect))) 1112 fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush 1113 fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx 1114 fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits 1115 fromIfuRedirect.bits.level := RedirectLevel.flushAfter 1116 fromIfuRedirect.bits.BTBMissBubble := true.B 1117 fromIfuRedirect.bits.debugIsMemVio := false.B 1118 fromIfuRedirect.bits.debugIsCtrl := false.B 1119 1120 val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate 1121 ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits) 1122 ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits) 1123 ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid 1124 ifuRedirectCfiUpdate.target := pdWb.bits.target 1125 ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid 1126 ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid 1127 1128 val ifuRedirectReg = RegNextWithEnable(fromIfuRedirect, hasInit = true) 1129 val ifuRedirectToBpu = WireInit(ifuRedirectReg) 1130 ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid 1131 1132 ftq_redirect_mem.io.ren.get.head := fromIfuRedirect.valid 1133 ftq_redirect_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 1134 1135 val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate 1136 toBpuCfi.fromFtqRedirectSram(ftq_redirect_mem.io.rdata.head) 1137 when(ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) { 1138 toBpuCfi.target := toBpuCfi.topAddr 1139 } 1140 1141 when(ifuRedirectReg.valid) { 1142 ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B 1143 }.elsewhen(RegNext(pdWb.valid)) { 1144 // if pdWb and no redirect, set to false 1145 ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B 1146 } 1147 1148 // ********************************************************************** 1149 // ***************************** to backend ***************************** 1150 // ********************************************************************** 1151 // to backend pc mem / target 1152 io.toBackend.pc_mem_wen := RegNext(last_cycle_bpu_in) 1153 io.toBackend.pc_mem_waddr := RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in) 1154 io.toBackend.pc_mem_wdata := RegEnable(bpu_in_bypass_buf_for_ifu, last_cycle_bpu_in) 1155 1156 // num cycle is fixed 1157 val newest_entry_en: Bool = RegNext(last_cycle_bpu_in || backendRedirect.valid || ifuRedirectToBpu.valid) 1158 io.toBackend.newest_entry_en := RegNext(newest_entry_en) 1159 io.toBackend.newest_entry_ptr := RegEnable(newest_entry_ptr, newest_entry_en) 1160 io.toBackend.newest_entry_target := RegEnable(newest_entry_target, newest_entry_en) 1161 1162 // ********************************************************************* 1163 // **************************** wb from exu **************************** 1164 // ********************************************************************* 1165 1166 backendRedirect.valid := io.fromBackend.redirect.valid 1167 backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits) 1168 backendRedirect.bits.BTBMissBubble := false.B 1169 1170 def extractRedirectInfo(wb: Valid[Redirect]) = { 1171 val ftqPtr = wb.bits.ftqIdx 1172 val ftqOffset = wb.bits.ftqOffset 1173 val taken = wb.bits.cfiUpdate.taken 1174 val mispred = wb.bits.cfiUpdate.isMisPred 1175 (wb.valid, ftqPtr, ftqOffset, taken, mispred) 1176 } 1177 1178 // fix mispredict entry 1179 val lastIsMispredict = RegNext( 1180 backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, 1181 init = false.B 1182 ) 1183 1184 def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = { 1185 val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect) 1186 val r_idx = r_ptr.value 1187 val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits 1188 val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits 1189 when(cfiIndex_bits_wen || cfiIndex_valid_wen) { 1190 cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken 1191 }.elsewhen(r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) { 1192 cfiIndex_vec(r_idx).valid := false.B 1193 } 1194 when(cfiIndex_bits_wen) { 1195 cfiIndex_vec(r_idx).bits := r_offset 1196 } 1197 newest_entry_target_modified := true.B 1198 newest_entry_target := redirect.bits.cfiUpdate.target 1199 newest_entry_ptr_modified := true.B 1200 newest_entry_ptr := r_ptr 1201 1202 update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this 1203 if (isBackend) { 1204 mispredict_vec(r_idx)(r_offset) := r_mispred 1205 } 1206 } 1207 1208 when(fromBackendRedirect.valid) { 1209 updateCfiInfo(fromBackendRedirect) 1210 }.elsewhen(ifuRedirectToBpu.valid) { 1211 updateCfiInfo(ifuRedirectToBpu, isBackend = false) 1212 } 1213 1214 when(fromBackendRedirect.valid) { 1215 when(fromBackendRedirect.bits.ControlRedirectBubble) { 1216 when(fromBackendRedirect.bits.ControlBTBMissBubble) { 1217 topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1218 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1219 }.elsewhen(fromBackendRedirect.bits.TAGEMissBubble) { 1220 topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 1221 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 1222 }.elsewhen(fromBackendRedirect.bits.SCMissBubble) { 1223 topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B 1224 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B 1225 }.elsewhen(fromBackendRedirect.bits.ITTAGEMissBubble) { 1226 topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 1227 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 1228 }.elsewhen(fromBackendRedirect.bits.RASMissBubble) { 1229 topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B 1230 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B 1231 } 1232 1233 }.elsewhen(backendRedirect.bits.MemVioRedirectBubble) { 1234 topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 1235 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 1236 }.otherwise { 1237 topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 1238 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 1239 } 1240 }.elsewhen(ifuRedirectReg.valid) { 1241 topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1242 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1243 } 1244 1245 io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble 1246 io.TAGEMissBubble := fromBackendRedirect.bits.TAGEMissBubble 1247 io.SCMissBubble := fromBackendRedirect.bits.SCMissBubble 1248 io.ITTAGEMissBubble := fromBackendRedirect.bits.ITTAGEMissBubble 1249 io.RASMissBubble := fromBackendRedirect.bits.RASMissBubble 1250 1251 // *********************************************************************************** 1252 // **************************** flush ptr and state queue **************************** 1253 // *********************************************************************************** 1254 1255 val redirectVec = VecInit(backendRedirect, fromIfuRedirect) 1256 1257 // when redirect, we should reset ptrs and status queues 1258 io.icacheFlush := redirectVec.map(r => r.valid).reduce(_ || _) 1259 XSPerfAccumulate("icacheFlushFromBackend", backendRedirect.valid) 1260 XSPerfAccumulate("icacheFlushFromIFU", fromIfuRedirect.valid) 1261 when(redirectVec.map(r => r.valid).reduce(_ || _)) { 1262 val r = PriorityMux(redirectVec.map(r => r.valid -> r.bits)) 1263 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_ || _) 1264 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 1265 val next = idx + 1.U 1266 bpuPtr := next 1267 copied_bpu_ptr.map(_ := next) 1268 ifuPtr_write := next 1269 ifuWbPtr_write := next 1270 ifuPtrPlus1_write := idx + 2.U 1271 ifuPtrPlus2_write := idx + 3.U 1272 pfPtr_write := next 1273 pfPtrPlus1_write := idx + 2.U 1274 } 1275 when(RegNext(redirectVec.map(r => r.valid).reduce(_ || _))) { 1276 val r = PriorityMux(redirectVec.map(r => r.valid -> r.bits)) 1277 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_ || _) 1278 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 1279 when(RegNext(notIfu)) { 1280 commitStateQueueEnable(RegNext(idx.value)) := true.B 1281 commitStateQueueNext(RegNext(idx.value)).zipWithIndex.foreach { case (s, i) => 1282 when(i.U > RegNext(offset)) { 1283 s := c_empty 1284 } 1285 when(i.U === RegNext(offset) && RegNext(flushItSelf)) { 1286 s := c_flushed 1287 } 1288 } 1289 } 1290 } 1291 1292 // only the valid bit is actually needed 1293 io.toIfu.redirect.bits := backendRedirect.bits 1294 io.toIfu.redirect.valid := stage2Flush 1295 io.toIfu.topdown_redirect := fromBackendRedirect 1296 1297 // commit 1298 for (c <- io.fromBackend.rob_commits) { 1299 when(c.valid) { 1300 commitStateQueueEnable(c.bits.ftqIdx.value) := true.B 1301 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_committed 1302 // TODO: remove this 1303 // For instruction fusions, we also update the next instruction 1304 when(c.bits.commitType === 4.U) { 1305 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_committed 1306 }.elsewhen(c.bits.commitType === 5.U) { 1307 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_committed 1308 }.elsewhen(c.bits.commitType === 6.U) { 1309 val index = (c.bits.ftqIdx + 1.U).value 1310 commitStateQueueEnable(index) := true.B 1311 commitStateQueueNext(index)(0) := c_committed 1312 }.elsewhen(c.bits.commitType === 7.U) { 1313 val index = (c.bits.ftqIdx + 1.U).value 1314 commitStateQueueEnable(index) := true.B 1315 commitStateQueueNext(index)(1) := c_committed 1316 } 1317 } 1318 } 1319 1320 // **************************************************************** 1321 // **************************** to bpu **************************** 1322 // **************************************************************** 1323 1324 io.toBpu.redirctFromIFU := ifuRedirectToBpu.valid 1325 io.toBpu.redirect := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 1326 val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_ => 0.U(64.W))) 1327 val redirect_latency = 1328 GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U 1329 XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1) 1330 XSPerfHistogram( 1331 "ifu_redirect_latency", 1332 redirect_latency, 1333 !fromBackendRedirect.valid && ifuRedirectToBpu.valid, 1334 0, 1335 60, 1336 1 1337 ) 1338 1339 XSError( 1340 io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr), 1341 "Ftq received a redirect after its commit, check backend or replay" 1342 ) 1343 1344 val may_have_stall_from_bpu = Wire(Bool()) 1345 val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states 1346 may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U 1347 1348 val validInstructions = commitStateQueueReg(commPtr.value).map(s => s === c_toCommit || s === c_committed) 1349 val lastInstructionStatus = PriorityMux(validInstructions.reverse.zip(commitStateQueueReg(commPtr.value).reverse)) 1350 val firstInstructionFlushed = commitStateQueueReg(commPtr.value)(0) === c_flushed 1351 canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1352 (isAfter(robCommPtr, commPtr) || 1353 validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed) 1354 val canMoveCommPtr = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1355 (isAfter(robCommPtr, commPtr) || 1356 validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed || 1357 firstInstructionFlushed) 1358 1359 when(io.fromBackend.rob_commits.map(_.valid).reduce(_ | _)) { 1360 robCommPtr_write := ParallelPriorityMux( 1361 io.fromBackend.rob_commits.map(_.valid).reverse, 1362 io.fromBackend.rob_commits.map(_.bits.ftqIdx).reverse 1363 ) 1364 }.elsewhen(isAfter(commPtr, robCommPtr)) { 1365 robCommPtr_write := commPtr 1366 }.otherwise { 1367 robCommPtr_write := robCommPtr 1368 } 1369 1370 /** 1371 ************************************************************************************* 1372 * MMIO instruction fetch is allowed only if MMIO is the oldest instruction. 1373 ************************************************************************************* 1374 */ 1375 val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr 1376 val mmioLastCommit = isAfter(commPtr, mmioReadPtr) || 1377 commPtr === mmioReadPtr && validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed 1378 io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit) 1379 1380 // commit reads 1381 val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata) 1382 val commit_target = 1383 Mux( 1384 RegNext(commPtr === newest_entry_ptr), 1385 RegEnable(newest_entry_target, newest_entry_target_modified), 1386 RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr) 1387 ) 1388 ftq_pd_mem.io.ren.get.last := canCommit 1389 ftq_pd_mem.io.raddr.last := commPtr.value 1390 val commit_pd = ftq_pd_mem.io.rdata.last 1391 ftq_redirect_mem.io.ren.get.last := canCommit 1392 ftq_redirect_mem.io.raddr.last := commPtr.value 1393 val commit_spec_meta = ftq_redirect_mem.io.rdata.last 1394 ftq_meta_1r_sram.io.ren(0) := canCommit 1395 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 1396 val commit_meta = ftq_meta_1r_sram.io.rdata(0).meta 1397 val commit_ftb_entry = ftq_meta_1r_sram.io.rdata(0).ftb_entry 1398 1399 // need one cycle to read mem and srams 1400 val do_commit_ptr = RegEnable(commPtr, canCommit) 1401 val do_commit = RegNext(canCommit, init = false.B) 1402 when(canMoveCommPtr) { 1403 commPtr_write := commPtrPlus1 1404 commPtrPlus1_write := commPtrPlus1 + 1.U 1405 } 1406 val commit_state = RegEnable(commitStateQueueReg(commPtr.value), canCommit) 1407 val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value)) 1408 val do_commit_cfi = WireInit(cfiIndex_vec(do_commit_ptr.value)) 1409 // 1410 // when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) { 1411 // can_commit_cfi.valid := false.B 1412 // } 1413 val commit_cfi = RegEnable(can_commit_cfi, canCommit) 1414 val debug_cfi = commitStateQueueReg(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_committed && do_commit_cfi.valid 1415 1416 val commit_mispredict: Vec[Bool] = 1417 VecInit((RegEnable(mispredict_vec(commPtr.value), canCommit) zip commit_state).map { 1418 case (mis, state) => mis && state === c_committed 1419 }) 1420 val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_committed)) // [PredictWidth] 1421 val can_commit_hit = entry_hit_status(commPtr.value) 1422 val commit_hit = RegEnable(can_commit_hit, canCommit) 1423 val diff_commit_target = RegEnable(update_target(commPtr.value), canCommit) // TODO: remove this 1424 val commit_stage = RegEnable(pred_stage(commPtr.value), canCommit) 1425 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 1426 1427 val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit 1428 switch(bpu_ftb_update_stall) { 1429 is(0.U) { 1430 when(can_commit_cfi.valid && !to_bpu_hit && canCommit) { 1431 bpu_ftb_update_stall := 2.U // 2-cycle stall 1432 } 1433 } 1434 is(2.U) { 1435 bpu_ftb_update_stall := 1.U 1436 } 1437 is(1.U) { 1438 bpu_ftb_update_stall := 0.U 1439 } 1440 is(3.U) { 1441 XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2") 1442 } 1443 } 1444 1445 // TODO: remove this 1446 XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n") 1447 1448 // update latency stats 1449 val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U 1450 XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2) 1451 1452 io.toBpu.update := DontCare 1453 io.toBpu.update.valid := commit_valid && do_commit 1454 val update = io.toBpu.update.bits 1455 update.false_hit := commit_hit === h_false_hit 1456 update.pc := commit_pc_bundle.startAddr 1457 update.meta := commit_meta 1458 update.cfi_idx := commit_cfi 1459 update.full_target := commit_target 1460 update.from_stage := commit_stage 1461 update.spec_info := commit_spec_meta 1462 XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n") 1463 1464 val commit_real_hit = commit_hit === h_hit 1465 val update_ftb_entry = update.ftb_entry 1466 1467 val ftbEntryGen = Module(new FTBEntryGen).io 1468 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 1469 ftbEntryGen.old_entry := commit_ftb_entry 1470 ftbEntryGen.pd := commit_pd 1471 ftbEntryGen.cfiIndex := commit_cfi 1472 ftbEntryGen.target := commit_target 1473 ftbEntryGen.hit := commit_real_hit 1474 ftbEntryGen.mispredict_vec := commit_mispredict 1475 1476 update_ftb_entry := ftbEntryGen.new_entry 1477 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 1478 update.mispred_mask := ftbEntryGen.mispred_mask 1479 update.old_entry := ftbEntryGen.is_old_entry 1480 update.pred_hit := commit_hit === h_hit || commit_hit === h_false_hit 1481 update.br_taken_mask := ftbEntryGen.taken_mask 1482 update.br_committed := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map { 1483 case (valid, offset) => valid && commit_instCommited(offset) 1484 } 1485 update.jmp_taken := ftbEntryGen.jmp_taken 1486 1487 // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc) 1488 // update.full_pred.jalr_target := commit_target 1489 // update.full_pred.hit := true.B 1490 // when (update.full_pred.is_jalr) { 1491 // update.full_pred.targets.last := commit_target 1492 // } 1493 1494 // ****************************************************************************** 1495 // **************************** commit perf counters **************************** 1496 // ****************************************************************************** 1497 1498 val commit_inst_mask = VecInit(commit_state.map(c => c === c_committed && do_commit)).asUInt 1499 val commit_mispred_mask = commit_mispredict.asUInt 1500 val commit_not_mispred_mask = ~commit_mispred_mask 1501 1502 val commit_br_mask = commit_pd.brMask.asUInt 1503 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 1504 val commit_cfi_mask = commit_br_mask | commit_jmp_mask 1505 1506 val mbpInstrs = commit_inst_mask & commit_cfi_mask 1507 1508 val mbpRights = mbpInstrs & commit_not_mispred_mask 1509 val mbpWrongs = mbpInstrs & commit_mispred_mask 1510 1511 io.bpuInfo.bpRight := PopCount(mbpRights) 1512 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 1513 1514 val hartId = p(XSCoreParamsKey).HartId 1515 val isWriteFTQTable = Constantin.createRecord(s"isWriteFTQTable$hartId") 1516 val ftqBranchTraceDB = ChiselDB.createTable(s"FTQTable$hartId", new FtqDebugBundle) 1517 // Cfi Info 1518 for (i <- 0 until PredictWidth) { 1519 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 1520 val v = commit_state(i) === c_committed 1521 val isBr = commit_pd.brMask(i) 1522 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 1523 val isCfi = isBr || isJmp 1524 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 1525 val misPred = commit_mispredict(i) 1526 // val ghist = commit_spec_meta.ghist.predHist 1527 val histPtr = commit_spec_meta.histPtr 1528 val predCycle = commit_meta(63, 0) 1529 val target = commit_target 1530 1531 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map { case (v, offset) => 1532 v && offset === i.U 1533 }))) 1534 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map { case (v, offset) => 1535 v && offset === i.U 1536 }.reduce(_ || _) 1537 val addIntoHist = 1538 ((commit_hit === h_hit) && inFtbEntry) || (!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid) 1539 XSDebug( 1540 v && do_commit && isCfi, 1541 p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 1542 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " + 1543 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 1544 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n" 1545 ) 1546 1547 val logbundle = Wire(new FtqDebugBundle) 1548 logbundle.pc := pc 1549 logbundle.target := target 1550 logbundle.isBr := isBr 1551 logbundle.isJmp := isJmp 1552 logbundle.isCall := isJmp && commit_pd.hasCall 1553 logbundle.isRet := isJmp && commit_pd.hasRet 1554 logbundle.misPred := misPred 1555 logbundle.isTaken := isTaken 1556 logbundle.predStage := commit_stage 1557 1558 ftqBranchTraceDB.log( 1559 data = logbundle /* hardware of type T */, 1560 en = isWriteFTQTable.orR && v && do_commit && isCfi, 1561 site = "FTQ" + p(XSCoreParamsKey).HartId.toString, 1562 clock = clock, 1563 reset = reset 1564 ) 1565 } 1566 1567 val enq = io.fromBpu.resp 1568 val perf_redirect = backendRedirect 1569 1570 XSPerfAccumulate("entry", validEntries) 1571 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 1572 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 1573 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 1574 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 1575 1576 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 1577 1578 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 1579 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 1580 XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr) 1581 XSPerfAccumulate( 1582 "bpu_to_ifu_bubble_when_ftq_full", 1583 (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready 1584 ) 1585 1586 XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_ | _)) 1587 XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid) 1588 XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid) 1589 1590 val from_bpu = io.fromBpu.resp.bits 1591 val to_ifu = io.toIfu.req.bits 1592 1593 XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth + 1, 1) 1594 1595 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 1596 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 1597 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 1598 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 1599 1600 val mbpBRights = mbpRights & commit_br_mask 1601 val mbpJRights = mbpRights & commit_jal_mask 1602 val mbpIRights = mbpRights & commit_jalr_mask 1603 val mbpCRights = mbpRights & commit_call_mask 1604 val mbpRRights = mbpRights & commit_ret_mask 1605 1606 val mbpBWrongs = mbpWrongs & commit_br_mask 1607 val mbpJWrongs = mbpWrongs & commit_jal_mask 1608 val mbpIWrongs = mbpWrongs & commit_jalr_mask 1609 val mbpCWrongs = mbpWrongs & commit_call_mask 1610 val mbpRWrongs = mbpWrongs & commit_ret_mask 1611 1612 val commit_pred_stage = RegNext(pred_stage(commPtr.value)) 1613 1614 def pred_stage_map(src: UInt, name: String) = 1615 (0 until numBpStages).map(i => 1616 f"${name}_stage_${i + 1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i))) 1617 ).foldLeft(Map[String, UInt]())(_ + _) 1618 1619 val mispred_stage_map = pred_stage_map(mbpWrongs, "mispredict") 1620 val br_mispred_stage_map = pred_stage_map(mbpBWrongs, "br_mispredict") 1621 val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict") 1622 val correct_stage_map = pred_stage_map(mbpRights, "correct") 1623 val br_correct_stage_map = pred_stage_map(mbpBRights, "br_correct") 1624 val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct") 1625 1626 val update_valid = io.toBpu.update.valid 1627 def u(cond: Bool) = update_valid && cond 1628 val ftb_false_hit = u(update.false_hit) 1629 // assert(!ftb_false_hit) 1630 val ftb_hit = u(commit_hit === h_hit) 1631 1632 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1633 val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid 1634 val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0) 1635 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid 1636 1637 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1638 1639 val ftb_modified_entry = 1640 u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_strong_bias_modified) 1641 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1642 val ftb_modified_entry_ifu_redirected = u(ifuRedirected(do_commit_ptr.value)) 1643 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1644 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1645 val ftb_modified_entry_strong_bias = ftb_modified_entry && ftbEntryGen.is_strong_bias_modified 1646 1647 def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits 1648 val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry) 1649 XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth + 1, 1) 1650 XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth + 1, 1) 1651 val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry) 1652 XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth + 1, 1) 1653 1654 XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize + 1, 1) 1655 1656 val perfCountsMap = Map( 1657 "BpInstr" -> PopCount(mbpInstrs), 1658 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1659 "BpRight" -> PopCount(mbpRights), 1660 "BpWrong" -> PopCount(mbpWrongs), 1661 "BpBRight" -> PopCount(mbpBRights), 1662 "BpBWrong" -> PopCount(mbpBWrongs), 1663 "BpJRight" -> PopCount(mbpJRights), 1664 "BpJWrong" -> PopCount(mbpJWrongs), 1665 "BpIRight" -> PopCount(mbpIRights), 1666 "BpIWrong" -> PopCount(mbpIWrongs), 1667 "BpCRight" -> PopCount(mbpCRights), 1668 "BpCWrong" -> PopCount(mbpCWrongs), 1669 "BpRRight" -> PopCount(mbpRRights), 1670 "BpRWrong" -> PopCount(mbpRWrongs), 1671 "ftb_false_hit" -> PopCount(ftb_false_hit), 1672 "ftb_hit" -> PopCount(ftb_hit), 1673 "ftb_new_entry" -> PopCount(ftb_new_entry), 1674 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1675 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1676 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1677 "ftb_old_entry" -> PopCount(ftb_old_entry), 1678 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1679 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1680 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1681 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1682 "ftb_modified_entry_strong_bias" -> PopCount(ftb_modified_entry_strong_bias) 1683 ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++ 1684 correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map 1685 1686 for ((key, value) <- perfCountsMap) { 1687 XSPerfAccumulate(key, value) 1688 } 1689 1690 // --------------------------- Debug -------------------------------- 1691 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1692 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1693 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1694 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1695 XSDebug( 1696 true.B, 1697 p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1698 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n" 1699 ) 1700 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1701 1702 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1703 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1704 // case (((valid, pd), ans), taken) => 1705 // Mux(valid && pd.isBr, 1706 // isWrong ^ Mux(ans.hit.asBool, 1707 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1708 // !taken), 1709 // !taken), 1710 // false.B) 1711 // } 1712 // } 1713 1714 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1715 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1716 // case (((valid, pd), ans), taken) => 1717 // Mux(valid && pd.isBr, 1718 // isWrong ^ Mux(ans.hit.asBool, 1719 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1720 // !taken), 1721 // !taken), 1722 // false.B) 1723 // } 1724 // } 1725 1726 // def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1727 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1728 // case (((valid, pd), ans), taken) => 1729 // Mux(valid && pd.isBr, 1730 // isWrong ^ (ans.taken.asBool === taken), 1731 // false.B) 1732 // } 1733 // } 1734 1735 // def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1736 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1737 // case (((valid, pd), ans), taken) => 1738 // Mux(valid && (pd.isBr) && ans.hit.asBool, 1739 // isWrong ^ (!taken), 1740 // false.B) 1741 // } 1742 // } 1743 1744 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1745 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1746 // case (((valid, pd), ans), taken) => 1747 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1748 // isWrong ^ (ans.target === commitEntry.target), 1749 // false.B) 1750 // } 1751 // } 1752 1753 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1754 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1755 // // btb and ubtb pred jal and jalr as well 1756 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1757 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1758 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1759 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1760 1761 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1762 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1763 1764 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1765 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1766 1767 val perfEvents = Seq( 1768 ("bpu_s2_redirect ", bpu_s2_redirect), 1769 ("bpu_s3_redirect ", bpu_s3_redirect), 1770 ("bpu_to_ftq_stall ", enq.valid && ~enq.ready), 1771 ("mispredictRedirect ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level), 1772 ("replayRedirect ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)), 1773 ("predecodeRedirect ", fromIfuRedirect.valid), 1774 ("to_ifu_bubble ", io.toIfu.req.ready && !io.toIfu.req.valid), 1775 ("from_bpu_real_bubble ", !enq.valid && enq.ready && allowBpuIn), 1776 ("BpInstr ", PopCount(mbpInstrs)), 1777 ("BpBInstr ", PopCount(mbpBRights | mbpBWrongs)), 1778 ("BpRight ", PopCount(mbpRights)), 1779 ("BpWrong ", PopCount(mbpWrongs)), 1780 ("BpBRight ", PopCount(mbpBRights)), 1781 ("BpBWrong ", PopCount(mbpBWrongs)), 1782 ("BpJRight ", PopCount(mbpJRights)), 1783 ("BpJWrong ", PopCount(mbpJWrongs)), 1784 ("BpIRight ", PopCount(mbpIRights)), 1785 ("BpIWrong ", PopCount(mbpIWrongs)), 1786 ("BpCRight ", PopCount(mbpCRights)), 1787 ("BpCWrong ", PopCount(mbpCWrongs)), 1788 ("BpRRight ", PopCount(mbpRRights)), 1789 ("BpRWrong ", PopCount(mbpRWrongs)), 1790 ("ftb_false_hit ", PopCount(ftb_false_hit)), 1791 ("ftb_hit ", PopCount(ftb_hit)) 1792 ) 1793 generatePerfEvent() 1794} 1795