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