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, 586 FtqSize, 1+FtqRedirectAheadNum, 1, hasRen = true)) 587 ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid(3) 588 ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value 589 ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_ftb_entry 590 591 592 // multi-write 593 val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this 594 val newest_entry_target = Reg(UInt(VAddrBits.W)) 595 val newest_entry_target_modified = RegInit(false.B) 596 val newest_entry_ptr = Reg(new FtqPtr) 597 val newest_entry_ptr_modified = RegInit(false.B) 598 val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))) 599 val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool()))) 600 val pred_stage = Reg(Vec(FtqSize, UInt(2.W))) 601 val pred_s1_cycle = if (!env.FPGAPlatform) Some(Reg(Vec(FtqSize, UInt(64.W)))) else None 602 603 val c_invalid :: c_valid :: c_commited :: Nil = Enum(3) 604 val commitStateQueueReg = RegInit(VecInit(Seq.fill(FtqSize) { 605 VecInit(Seq.fill(PredictWidth)(c_invalid)) 606 })) 607 val commitStateQueueEnable = WireInit(VecInit(Seq.fill(FtqSize)(false.B))) 608 val commitStateQueueNext = WireInit(commitStateQueueReg) 609 610 for (f <- 0 until FtqSize) { 611 when(commitStateQueueEnable(f)) { 612 commitStateQueueReg(f) := commitStateQueueNext(f) 613 } 614 } 615 616 val f_to_send :: f_sent :: Nil = Enum(2) 617 val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent))) 618 619 val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3) 620 val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit))) 621 622 // modify registers one cycle later to cut critical path 623 val last_cycle_bpu_in = RegNext(bpu_in_fire) 624 val last_cycle_bpu_in_ptr = RegEnable(bpu_in_resp_ptr, bpu_in_fire) 625 val last_cycle_bpu_in_idx = last_cycle_bpu_in_ptr.value 626 val last_cycle_bpu_target = RegEnable(bpu_in_resp.getTarget(3), bpu_in_fire) 627 val last_cycle_cfiIndex = RegEnable(bpu_in_resp.cfiIndex(3), bpu_in_fire) 628 val last_cycle_bpu_in_stage = RegEnable(bpu_in_stage, bpu_in_fire) 629 630 def extra_copyNum_for_commitStateQueue = 2 631 val copied_last_cycle_bpu_in = 632 VecInit(Seq.fill(copyNum + extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_fire))) 633 val copied_last_cycle_bpu_in_ptr_for_ftq = 634 VecInit(Seq.fill(extra_copyNum_for_commitStateQueue)(RegEnable(bpu_in_resp_ptr, bpu_in_fire))) 635 636 newest_entry_target_modified := false.B 637 newest_entry_ptr_modified := false.B 638 when (last_cycle_bpu_in) { 639 entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send 640 cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex 641 pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage 642 643 update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this 644 newest_entry_target_modified := true.B 645 newest_entry_target := last_cycle_bpu_target 646 newest_entry_ptr_modified := true.B 647 newest_entry_ptr := last_cycle_bpu_in_ptr 648 } 649 650 // reduce fanout by delay write for a cycle 651 when (RegNext(last_cycle_bpu_in)) { 652 mispredict_vec(RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in)) := 653 WireInit(VecInit(Seq.fill(PredictWidth)(false.B))) 654 } 655 656 // record s1 pred cycles 657 pred_s1_cycle.map(vec => { 658 when (bpu_in_fire && (bpu_in_stage === BP_S1)) { 659 vec(bpu_in_resp_ptr.value) := bpu_in_resp.full_pred(0).predCycle.getOrElse(0.U) 660 } 661 }) 662 663 // reduce fanout using copied last_cycle_bpu_in and copied last_cycle_bpu_in_ptr 664 val copied_last_cycle_bpu_in_for_ftq = copied_last_cycle_bpu_in.takeRight(extra_copyNum_for_commitStateQueue) 665 copied_last_cycle_bpu_in_for_ftq.zip(copied_last_cycle_bpu_in_ptr_for_ftq).zipWithIndex.map { 666 case ((in, ptr), i) => 667 when (in) { 668 val perSetEntries = FtqSize / extra_copyNum_for_commitStateQueue // 32 669 require(FtqSize % extra_copyNum_for_commitStateQueue == 0) 670 for (j <- 0 until perSetEntries) { 671 when (ptr.value === (i * perSetEntries + j).U) { 672 commitStateQueueNext(i * perSetEntries + j) := VecInit(Seq.fill(PredictWidth)(c_invalid)) 673 // Clock gating optimization, use 1 gate cell to control a row 674 commitStateQueueEnable(i * perSetEntries + j) := true.B 675 } 676 } 677 } 678 } 679 680 bpuPtr := bpuPtr + enq_fire 681 copied_bpu_ptr.map(_ := bpuPtr + enq_fire) 682 when (io.toIfu.req.fire && allowToIfu) { 683 ifuPtr_write := ifuPtrPlus1 684 ifuPtrPlus1_write := ifuPtrPlus2 685 ifuPtrPlus2_write := ifuPtrPlus2 + 1.U 686 } 687 688 // only use ftb result to assign hit status 689 when (bpu_s2_resp.valid(3)) { 690 entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred(3).hit, h_hit, h_not_hit) 691 } 692 693 694 io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect 695 io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx 696 when (bpu_s2_redirect) { 697 bpuPtr := bpu_s2_resp.ftq_idx + 1.U 698 copied_bpu_ptr.map(_ := bpu_s2_resp.ftq_idx + 1.U) 699 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 700 when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) { 701 ifuPtr_write := bpu_s2_resp.ftq_idx 702 ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U 703 ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U 704 } 705 } 706 707 io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect 708 io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx 709 when (bpu_s3_redirect) { 710 bpuPtr := bpu_s3_resp.ftq_idx + 1.U 711 copied_bpu_ptr.map(_ := bpu_s3_resp.ftq_idx + 1.U) 712 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 713 when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) { 714 ifuPtr_write := bpu_s3_resp.ftq_idx 715 ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U 716 ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U 717 } 718 } 719 720 XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n") 721 XSError(isBefore(ifuWbPtr, commPtr) && !isFull(ifuWbPtr, commPtr), "\ncommPtr is before ifuWbPtr!\n") 722 723 (0 until copyNum).map{i => 724 XSError(copied_bpu_ptr(i) =/= bpuPtr, "\ncopiedBpuPtr is different from bpuPtr!\n") 725 } 726 727 // **************************************************************** 728 // **************************** to ifu **************************** 729 // **************************************************************** 730 // 0 for ifu, and 1-4 for ICache 731 val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire) 732 val copied_bpu_in_bypass_buf = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire))) 733 val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf 734 val bpu_in_bypass_ptr = RegEnable(bpu_in_resp_ptr, bpu_in_fire) 735 val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire) 736 737 val copied_bpu_in_bypass_ptr = VecInit(Seq.fill(copyNum)(RegEnable(bpu_in_resp_ptr, bpu_in_fire))) 738 val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire))) 739 740 // read pc and target 741 ftq_pc_mem.io.ifuPtr_w := ifuPtr_write 742 ftq_pc_mem.io.ifuPtrPlus1_w := ifuPtrPlus1_write 743 ftq_pc_mem.io.ifuPtrPlus2_w := ifuPtrPlus2_write 744 ftq_pc_mem.io.commPtr_w := commPtr_write 745 ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write 746 747 748 io.toIfu.req.bits.ftqIdx := ifuPtr 749 750 val toICachePcBundle = Wire(Vec(copyNum,new Ftq_RF_Components)) 751 val toICacheEntryToSend = Wire(Vec(copyNum,Bool())) 752 val toIfuPcBundle = Wire(new Ftq_RF_Components) 753 val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send) 754 val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value)) 755 val entry_next_addr = Wire(UInt(VAddrBits.W)) 756 757 val pc_mem_ifu_ptr_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata))) 758 val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata))) 759 val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this 760 761 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)))) 762 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))) 763 764 for(i <- 0 until copyNum){ 765 when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)){ 766 toICachePcBundle(i) := copied_bpu_in_bypass_buf(i) 767 toICacheEntryToSend(i) := true.B 768 }.elsewhen(copied_last_cycle_to_ifu_fire(i)){ 769 toICachePcBundle(i) := pc_mem_ifu_plus1_rdata(i) 770 toICacheEntryToSend(i) := copied_ifu_plus1_to_send(i) 771 }.otherwise{ 772 toICachePcBundle(i) := pc_mem_ifu_ptr_rdata(i) 773 toICacheEntryToSend(i) := copied_ifu_ptr_to_send(i) 774 } 775 } 776 777 // TODO: reconsider target address bypass logic 778 when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) { 779 toIfuPcBundle := bpu_in_bypass_buf_for_ifu 780 entry_is_to_send := true.B 781 entry_next_addr := last_cycle_bpu_target 782 entry_ftq_offset := last_cycle_cfiIndex 783 diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this 784 }.elsewhen (last_cycle_to_ifu_fire) { 785 toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata) 786 entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) || 787 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles 788 entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1), 789 bpu_in_bypass_buf_for_ifu.startAddr, 790 Mux(ifuPtr === newest_entry_ptr, 791 newest_entry_target, 792 RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))) // ifuPtr+2 793 }.otherwise { 794 toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata) 795 entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) || 796 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles 797 entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1), 798 bpu_in_bypass_buf_for_ifu.startAddr, 799 Mux(ifuPtr === newest_entry_ptr, 800 newest_entry_target, 801 RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))) // ifuPtr+1 802 } 803 804 io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 805 io.toIfu.req.bits.nextStartAddr := entry_next_addr 806 io.toIfu.req.bits.ftqOffset := entry_ftq_offset 807 io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle) 808 809 io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 810 io.toICache.req.bits.readValid.zipWithIndex.map{case(copy, i) => copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)} 811 io.toICache.req.bits.pcMemRead.zipWithIndex.map{case(copy,i) => copy.fromFtqPcBundle(toICachePcBundle(i))} 812 // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr 813 // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) => 814 // bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr 815 // bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr 816 // } 817 818 // TODO: remove this 819 XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr, 820 p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n") 821 822 // when fall through is smaller in value than start address, there must be a false hit 823 when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) { 824 when (io.toIfu.req.fire && 825 !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && 826 !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr) 827 ) { 828 entry_hit_status(ifuPtr.value) := h_false_hit 829 // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 830 } 831 XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 832 } 833 834 XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit && 835 io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)) 836 837 val ifu_req_should_be_flushed = 838 io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) || 839 io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx) 840 841 when (io.toIfu.req.fire && !ifu_req_should_be_flushed) { 842 entry_fetch_status(ifuPtr.value) := f_sent 843 } 844 845 // ********************************************************************* 846 // **************************** wb from ifu **************************** 847 // ********************************************************************* 848 val pdWb = io.fromIfu.pdWb 849 val pds = pdWb.bits.pd 850 val ifu_wb_valid = pdWb.valid 851 val ifu_wb_idx = pdWb.bits.ftqIdx.value 852 // read ports: commit update 853 val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1, hasRen = true)) 854 ftq_pd_mem.io.wen(0) := ifu_wb_valid 855 ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value 856 ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits) 857 858 val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid 859 val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid 860 val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B) 861 val pd_reg = RegEnable(pds, pdWb.valid) 862 val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid) 863 val wb_idx_reg = RegEnable(ifu_wb_idx, pdWb.valid) 864 865 when (ifu_wb_valid) { 866 val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{ 867 case (v, inRange) => v && inRange 868 }) 869 commitStateQueueEnable(ifu_wb_idx) := true.B 870 (commitStateQueueNext(ifu_wb_idx) zip comm_stq_wen).map { 871 case (qe, v) => when(v) { 872 qe := c_valid 873 } 874 } 875 } 876 877 when (ifu_wb_valid) { 878 ifuWbPtr_write := ifuWbPtr + 1.U 879 } 880 881 XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU") 882 883 ftb_entry_mem.io.ren.get.head := ifu_wb_valid 884 ftb_entry_mem.io.raddr.head := ifu_wb_idx 885 val has_false_hit = WireInit(false.B) 886 when (RegNext(hit_pd_valid)) { 887 // check for false hit 888 val pred_ftb_entry = ftb_entry_mem.io.rdata.head 889 val brSlots = pred_ftb_entry.brSlots 890 val tailSlot = pred_ftb_entry.tailSlot 891 // we check cfis that bpu predicted 892 893 // bpu predicted branches but denied by predecode 894 val br_false_hit = 895 brSlots.map{ 896 s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr) 897 }.reduce(_||_) || 898 (tailSlot.valid && pred_ftb_entry.tailSlot.sharing && 899 !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr)) 900 901 val jmpOffset = tailSlot.offset 902 val jmp_pd = pd_reg(jmpOffset) 903 val jal_false_hit = pred_ftb_entry.jmpValid && 904 ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) || 905 (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) || 906 (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) || 907 (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)) 908 ) 909 910 has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg 911 XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0)) 912 913 // assert(!has_false_hit) 914 } 915 916 when (has_false_hit) { 917 entry_hit_status(wb_idx_reg) := h_false_hit 918 } 919 920 // ******************************************************************************* 921 // **************************** redirect from backend **************************** 922 // ******************************************************************************* 923 924 // redirect read cfiInfo, couples to redirectGen s2 925 val redirectReadStart = 1 // 0 for ifuRedirect 926 val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry)) 927 val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry_FtqMem)) 928 for (i <- redirectReadStart until FtqRedirectAheadNum) { 929 ftq_redirect_mem.io.raddr(i + redirectReadStart) := ftqIdxAhead(i).bits.value 930 ftb_entry_mem.io.raddr(i + redirectReadStart) := ftqIdxAhead(i).bits.value 931 } 932 ftq_redirect_mem.io.raddr(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value) 933 ftb_entry_mem.io.raddr(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value) 934 935 for (i <- 0 until FtqRedirectAheadNum) { 936 ftq_redirect_rdata(i) := ftq_redirect_mem.io.rdata(i + redirectReadStart) 937 ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + redirectReadStart) 938 } 939 val stage3CfiInfo = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_mem.io.rdata(redirectReadStart)) 940 val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate 941 backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo) 942 943 944 val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(redirectReadStart)) 945 val r_ftqOffset = fromBackendRedirect.bits.ftqOffset 946 947 backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset) 948 backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset 949 // FIXME: not portable 950 val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B))) 951 backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(r_ftb_entry.brSlots(0).offset === r_ftqOffset, 952 sc_disagree(0), sc_disagree(1)) 953 954 when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) { 955 backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +& 956 (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) && 957 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 958 959 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) || 960 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 961 }.otherwise { 962 backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt 963 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt 964 } 965 966 967 // *************************************************************************** 968 // **************************** redirect from ifu **************************** 969 // *************************************************************************** 970 val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect))) 971 fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush 972 fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx 973 fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits 974 fromIfuRedirect.bits.level := RedirectLevel.flushAfter 975 fromIfuRedirect.bits.BTBMissBubble := true.B 976 fromIfuRedirect.bits.debugIsMemVio := false.B 977 fromIfuRedirect.bits.debugIsCtrl := false.B 978 979 val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate 980 ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits) 981 ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits) 982 ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid 983 ifuRedirectCfiUpdate.target := pdWb.bits.target 984 ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid 985 ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid 986 987 val ifuRedirectReg = RegNextWithEnable(fromIfuRedirect, hasInit = true) 988 val ifuRedirectToBpu = WireInit(ifuRedirectReg) 989 ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid 990 991 ftq_redirect_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 992 993 val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate 994 toBpuCfi.fromFtqRedirectSram(ftq_redirect_mem.io.rdata.head) 995 when (ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) { 996 toBpuCfi.target := toBpuCfi.topAddr 997 } 998 999 when (ifuRedirectReg.valid) { 1000 ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B 1001 } .elsewhen(RegNext(pdWb.valid)) { 1002 // if pdWb and no redirect, set to false 1003 ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B 1004 } 1005 1006 // ********************************************************************** 1007 // ***************************** to backend ***************************** 1008 // ********************************************************************** 1009 // to backend pc mem / target 1010 io.toBackend.pc_mem_wen := RegNext(last_cycle_bpu_in) 1011 io.toBackend.pc_mem_waddr := RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in) 1012 io.toBackend.pc_mem_wdata := RegEnable(bpu_in_bypass_buf_for_ifu, last_cycle_bpu_in) 1013 1014 // num cycle is fixed 1015 val newest_entry_en: Bool = RegNext(last_cycle_bpu_in || backendRedirect.valid || ifuRedirectToBpu.valid) 1016 io.toBackend.newest_entry_en := RegNext(newest_entry_en) 1017 io.toBackend.newest_entry_ptr := RegEnable(newest_entry_ptr, newest_entry_en) 1018 io.toBackend.newest_entry_target := RegEnable(newest_entry_target, newest_entry_en) 1019 1020 // ********************************************************************* 1021 // **************************** wb from exu **************************** 1022 // ********************************************************************* 1023 1024 backendRedirect.valid := io.fromBackend.redirect.valid 1025 backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits) 1026 backendRedirect.bits.BTBMissBubble := false.B 1027 1028 1029 def extractRedirectInfo(wb: Valid[Redirect]) = { 1030 val ftqPtr = wb.bits.ftqIdx 1031 val ftqOffset = wb.bits.ftqOffset 1032 val taken = wb.bits.cfiUpdate.taken 1033 val mispred = wb.bits.cfiUpdate.isMisPred 1034 (wb.valid, ftqPtr, ftqOffset, taken, mispred) 1035 } 1036 1037 // fix mispredict entry 1038 val lastIsMispredict = RegNext( 1039 backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B 1040 ) 1041 1042 def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = { 1043 val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect) 1044 val r_idx = r_ptr.value 1045 val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits 1046 val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits 1047 when (cfiIndex_bits_wen || cfiIndex_valid_wen) { 1048 cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken 1049 } .elsewhen (r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) { 1050 cfiIndex_vec(r_idx).valid :=false.B 1051 } 1052 when (cfiIndex_bits_wen) { 1053 cfiIndex_vec(r_idx).bits := r_offset 1054 } 1055 newest_entry_target_modified := true.B 1056 newest_entry_target := redirect.bits.cfiUpdate.target 1057 newest_entry_ptr_modified := true.B 1058 newest_entry_ptr := r_ptr 1059 1060 update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this 1061 if (isBackend) { 1062 mispredict_vec(r_idx)(r_offset) := r_mispred 1063 } 1064 } 1065 1066 when(fromBackendRedirect.valid) { 1067 updateCfiInfo(fromBackendRedirect) 1068 }.elsewhen (ifuRedirectToBpu.valid) { 1069 updateCfiInfo(ifuRedirectToBpu, isBackend=false) 1070 } 1071 1072 when (fromBackendRedirect.valid) { 1073 when (fromBackendRedirect.bits.ControlRedirectBubble) { 1074 when (fromBackendRedirect.bits.ControlBTBMissBubble) { 1075 topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1076 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1077 } .elsewhen (fromBackendRedirect.bits.TAGEMissBubble) { 1078 topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 1079 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 1080 } .elsewhen (fromBackendRedirect.bits.SCMissBubble) { 1081 topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B 1082 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B 1083 } .elsewhen (fromBackendRedirect.bits.ITTAGEMissBubble) { 1084 topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 1085 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 1086 } .elsewhen (fromBackendRedirect.bits.RASMissBubble) { 1087 topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B 1088 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B 1089 } 1090 1091 1092 } .elsewhen (backendRedirect.bits.MemVioRedirectBubble) { 1093 topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 1094 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 1095 } .otherwise { 1096 topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 1097 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 1098 } 1099 } .elsewhen (ifuRedirectReg.valid) { 1100 topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1101 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1102 } 1103 1104 io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble 1105 io.TAGEMissBubble := fromBackendRedirect.bits.TAGEMissBubble 1106 io.SCMissBubble := fromBackendRedirect.bits.SCMissBubble 1107 io.ITTAGEMissBubble := fromBackendRedirect.bits.ITTAGEMissBubble 1108 io.RASMissBubble := fromBackendRedirect.bits.RASMissBubble 1109 1110 // *********************************************************************************** 1111 // **************************** flush ptr and state queue **************************** 1112 // *********************************************************************************** 1113 1114 val redirectVec = VecInit(backendRedirect, fromIfuRedirect) 1115 1116 // when redirect, we should reset ptrs and status queues 1117 when(redirectVec.map(r => r.valid).reduce(_||_)){ 1118 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1119 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 1120 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 1121 val next = idx + 1.U 1122 bpuPtr := next 1123 copied_bpu_ptr.map(_ := next) 1124 ifuPtr_write := next 1125 ifuWbPtr_write := next 1126 ifuPtrPlus1_write := idx + 2.U 1127 ifuPtrPlus2_write := idx + 3.U 1128 1129 } 1130 when(RegNext(redirectVec.map(r => r.valid).reduce(_||_))){ 1131 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1132 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 1133 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 1134 when (RegNext(notIfu)) { 1135 commitStateQueueEnable(RegNext(idx.value)) := true.B 1136 commitStateQueueNext(RegNext(idx.value)).zipWithIndex.foreach({ case (s, i) => 1137 when(i.U > RegNext(offset) || i.U === RegNext(offset) && RegNext(flushItSelf)) { 1138 s := c_invalid 1139 } 1140 }) 1141 } 1142 } 1143 1144 1145 // only the valid bit is actually needed 1146 io.toIfu.redirect.bits := backendRedirect.bits 1147 io.toIfu.redirect.valid := stage2Flush 1148 io.toIfu.topdown_redirect := fromBackendRedirect 1149 1150 // commit 1151 for (c <- io.fromBackend.rob_commits) { 1152 when(c.valid) { 1153 commitStateQueueEnable(c.bits.ftqIdx.value) := true.B 1154 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited 1155 // TODO: remove this 1156 // For instruction fusions, we also update the next instruction 1157 when (c.bits.commitType === 4.U) { 1158 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited 1159 }.elsewhen(c.bits.commitType === 5.U) { 1160 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited 1161 }.elsewhen(c.bits.commitType === 6.U) { 1162 val index = (c.bits.ftqIdx + 1.U).value 1163 commitStateQueueEnable(index) := true.B 1164 commitStateQueueNext(index)(0) := c_commited 1165 }.elsewhen(c.bits.commitType === 7.U) { 1166 val index = (c.bits.ftqIdx + 1.U).value 1167 commitStateQueueEnable(index) := true.B 1168 commitStateQueueNext(index)(1) := c_commited 1169 } 1170 } 1171 } 1172 1173 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) 1174 1175 // **************************************************************** 1176 // **************************** to bpu **************************** 1177 // **************************************************************** 1178 1179 io.toBpu.redirect := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 1180 val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_=>0.U(64.W))) 1181 val redirect_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U 1182 XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1) 1183 XSPerfHistogram("ifu_redirect_latency", redirect_latency, !fromBackendRedirect.valid && ifuRedirectToBpu.valid, 0, 60, 1) 1184 1185 XSError(io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr), "Ftq received a redirect after its commit, check backend or replay") 1186 1187 val may_have_stall_from_bpu = Wire(Bool()) 1188 val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states 1189 may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U 1190 val notInvalidSeq = commitStateQueueReg(commPtr.value).map(s => s =/= c_invalid).reverse 1191 // Todo: @huxuan check it 1192 // canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1193 // Cat(commitStateQueue(commPtr.value).map(s => { 1194 // s === c_invalid || s === c_commited 1195 // })).andR 1196 canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1197 (isAfter(robCommPtr, commPtr) || 1198 PriorityMuxDefault(notInvalidSeq.zip(commitStateQueueReg(commPtr.value).reverse), c_invalid) === c_commited) 1199 1200 val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr 1201 val mmioLastCommit = isBefore(commPtr, mmioReadPtr) && (isAfter(ifuPtr,mmioReadPtr) || mmioReadPtr === ifuPtr) && 1202 Cat(commitStateQueueReg(mmioReadPtr.value).map(s => { s === c_invalid || s === c_commited})).andR 1203 io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit) 1204 1205 // commit reads 1206 val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata) 1207 val commit_target = 1208 Mux(RegNext(commPtr === newest_entry_ptr), 1209 RegEnable(newest_entry_target, newest_entry_target_modified), 1210 RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr)) 1211 ftq_pd_mem.io.ren.get.last := canCommit 1212 ftq_pd_mem.io.raddr.last := commPtr.value 1213 val commit_pd = ftq_pd_mem.io.rdata.last 1214 ftq_redirect_mem.io.raddr.last := commPtr.value 1215 val commit_spec_meta = ftq_redirect_mem.io.rdata.last 1216 ftq_meta_1r_sram.io.ren(0) := canCommit 1217 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 1218 val commit_meta = ftq_meta_1r_sram.io.rdata(0).meta 1219 val commit_ftb_entry = ftq_meta_1r_sram.io.rdata(0).ftb_entry 1220 1221 // need one cycle to read mem and srams 1222 val do_commit_ptr = RegEnable(commPtr, canCommit) 1223 val do_commit = RegNext(canCommit, init=false.B) 1224 when (canCommit) { 1225 commPtr_write := commPtrPlus1 1226 commPtrPlus1_write := commPtrPlus1 + 1.U 1227 } 1228 val commit_state = RegEnable(commitStateQueueReg(commPtr.value), canCommit) 1229 val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value)) 1230 val do_commit_cfi = WireInit(cfiIndex_vec(do_commit_ptr.value)) 1231 // 1232 //when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) { 1233 // can_commit_cfi.valid := false.B 1234 //} 1235 val commit_cfi = RegEnable(can_commit_cfi, canCommit) 1236 val debug_cfi = commitStateQueueReg(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_commited && do_commit_cfi.valid 1237 1238 val commit_mispredict : Vec[Bool] = VecInit((RegEnable(mispredict_vec(commPtr.value), canCommit) zip commit_state).map { 1239 case (mis, state) => mis && state === c_commited 1240 }) 1241 val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_commited)) // [PredictWidth] 1242 val can_commit_hit = entry_hit_status(commPtr.value) 1243 val commit_hit = RegEnable(can_commit_hit, canCommit) 1244 val diff_commit_target = RegEnable(update_target(commPtr.value), canCommit) // TODO: remove this 1245 val commit_stage = RegEnable(pred_stage(commPtr.value), canCommit) 1246 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 1247 1248 val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit 1249 switch (bpu_ftb_update_stall) { 1250 is (0.U) { 1251 when (can_commit_cfi.valid && !to_bpu_hit && canCommit) { 1252 bpu_ftb_update_stall := 2.U // 2-cycle stall 1253 } 1254 } 1255 is (2.U) { 1256 bpu_ftb_update_stall := 1.U 1257 } 1258 is (1.U) { 1259 bpu_ftb_update_stall := 0.U 1260 } 1261 is (3.U) { 1262 XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2") 1263 } 1264 } 1265 1266 // TODO: remove this 1267 XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n") 1268 1269 // update latency stats 1270 val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U 1271 XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2) 1272 1273 io.toBpu.update := DontCare 1274 io.toBpu.update.valid := commit_valid && do_commit 1275 val update = io.toBpu.update.bits 1276 update.false_hit := commit_hit === h_false_hit 1277 update.pc := commit_pc_bundle.startAddr 1278 update.meta := commit_meta 1279 update.cfi_idx := commit_cfi 1280 update.full_target := commit_target 1281 update.from_stage := commit_stage 1282 update.spec_info := commit_spec_meta 1283 XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n") 1284 1285 val commit_real_hit = commit_hit === h_hit 1286 val update_ftb_entry = update.ftb_entry 1287 1288 val ftbEntryGen = Module(new FTBEntryGen).io 1289 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 1290 ftbEntryGen.old_entry := commit_ftb_entry 1291 ftbEntryGen.pd := commit_pd 1292 ftbEntryGen.cfiIndex := commit_cfi 1293 ftbEntryGen.target := commit_target 1294 ftbEntryGen.hit := commit_real_hit 1295 ftbEntryGen.mispredict_vec := commit_mispredict 1296 1297 update_ftb_entry := ftbEntryGen.new_entry 1298 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 1299 update.mispred_mask := ftbEntryGen.mispred_mask 1300 update.old_entry := ftbEntryGen.is_old_entry 1301 update.pred_hit := commit_hit === h_hit || commit_hit === h_false_hit 1302 update.br_taken_mask := ftbEntryGen.taken_mask 1303 update.br_committed := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map { 1304 case (valid, offset) => valid && commit_instCommited(offset) 1305 } 1306 update.jmp_taken := ftbEntryGen.jmp_taken 1307 1308 // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc) 1309 // update.full_pred.jalr_target := commit_target 1310 // update.full_pred.hit := true.B 1311 // when (update.full_pred.is_jalr) { 1312 // update.full_pred.targets.last := commit_target 1313 // } 1314 1315 // **************************************************************** 1316 // *********************** to prefetch **************************** 1317 // **************************************************************** 1318 /** 1319 ****************************************************************************** 1320 * prefetchPtr control 1321 * - 1. prefetchPtr plus 1 when toPrefetch fire and keep distance from bpuPtr more than 2 1322 * - 2. limit range of prefetchPtr is in [ifuPtr + minRange, ifuPtr + maxRange] 1323 * - 3. flush prefetchPtr when receive redirect from ifu or backend 1324 ****************************************************************************** 1325 */ 1326 val prefetchPtr = RegInit(FtqPtr(false.B, 0.U)) 1327 val nextPrefetchPtr = WireInit(prefetchPtr) 1328 1329 prefetchPtr := nextPrefetchPtr 1330 1331 // TODO: consider req which cross cacheline 1332 when(io.toPrefetch.req.fire) { 1333 when(prefetchPtr < bpuPtr - 2.U) { 1334 nextPrefetchPtr := prefetchPtr + 1.U 1335 } 1336 } 1337 1338 when(prefetchPtr < ifuPtr + minRangeFromIFUptr.U) { 1339 nextPrefetchPtr := ifuPtr + minRangeFromIFUptr.U 1340 }.elsewhen(prefetchPtr > ifuPtr + maxRangeFromIFUptr.U) { 1341 nextPrefetchPtr := ifuPtr + maxRangeFromIFUptr.U 1342 } 1343 1344 when(redirectVec.map(r => r.valid).reduce(_||_)){ 1345 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1346 val next = r.ftqIdx + minRangeFromIFUptr.U 1347 nextPrefetchPtr := next 1348 } 1349 1350 // data from ftq_pc_mem has 1 cycle delay 1351 io.toPrefetch.req.valid := RegNext(entry_fetch_status(nextPrefetchPtr.value) === f_to_send) 1352 ftq_pc_mem.io.other_raddrs(0) := nextPrefetchPtr.value 1353 io.toPrefetch.req.bits.target := RegNext(ftq_pc_mem.io.other_rdatas(0).startAddr) 1354 1355 // record position relationship between ifuPtr, pfPtr and bpuPtr 1356 val hartId = p(XSCoreParamsKey).HartId 1357 val isWritePrefetchPtrTable = Constantin.createRecord(s"isWritePrefetchPtrTable$hartId") 1358 val prefetchPtrTable = ChiselDB.createTable(s"PrefetchPtrTable$hartId", new PrefetchPtrDB) 1359 val prefetchPtrDumpData = Wire(new PrefetchPtrDB) 1360 prefetchPtrDumpData.fromFtqPtr := distanceBetween(bpuPtr, prefetchPtr) 1361 prefetchPtrDumpData.fromIfuPtr := distanceBetween(prefetchPtr, ifuPtr) 1362 1363 prefetchPtrTable.log( 1364 data = prefetchPtrDumpData, 1365 en = isWritePrefetchPtrTable.orR && io.toPrefetch.req.fire, 1366 site = "FTQ" + p(XSCoreParamsKey).HartId.toString, 1367 clock = clock, 1368 reset = reset 1369 ) 1370 1371 1372 // ****************************************************************************** 1373 // **************************** commit perf counters **************************** 1374 // ****************************************************************************** 1375 1376 val commit_inst_mask = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt 1377 val commit_mispred_mask = commit_mispredict.asUInt 1378 val commit_not_mispred_mask = ~commit_mispred_mask 1379 1380 val commit_br_mask = commit_pd.brMask.asUInt 1381 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 1382 val commit_cfi_mask = (commit_br_mask | commit_jmp_mask) 1383 1384 val mbpInstrs = commit_inst_mask & commit_cfi_mask 1385 1386 val mbpRights = mbpInstrs & commit_not_mispred_mask 1387 val mbpWrongs = mbpInstrs & commit_mispred_mask 1388 1389 io.bpuInfo.bpRight := PopCount(mbpRights) 1390 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 1391 1392 val isWriteFTQTable = Constantin.createRecord(s"isWriteFTQTable$hartId") 1393 val ftqBranchTraceDB = ChiselDB.createTable(s"FTQTable$hartId", new FtqDebugBundle) 1394 // Cfi Info 1395 for (i <- 0 until PredictWidth) { 1396 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 1397 val v = commit_state(i) === c_commited 1398 val isBr = commit_pd.brMask(i) 1399 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 1400 val isCfi = isBr || isJmp 1401 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 1402 val misPred = commit_mispredict(i) 1403 // val ghist = commit_spec_meta.ghist.predHist 1404 val histPtr = commit_spec_meta.histPtr 1405 val predCycle = commit_meta(63, 0) 1406 val target = commit_target 1407 1408 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}))) 1409 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_) 1410 val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)) 1411 XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 1412 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " + 1413 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 1414 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n") 1415 1416 val logbundle = Wire(new FtqDebugBundle) 1417 logbundle.pc := pc 1418 logbundle.target := target 1419 logbundle.isBr := isBr 1420 logbundle.isJmp := isJmp 1421 logbundle.isCall := isJmp && commit_pd.hasCall 1422 logbundle.isRet := isJmp && commit_pd.hasRet 1423 logbundle.misPred := misPred 1424 logbundle.isTaken := isTaken 1425 logbundle.predStage := commit_stage 1426 1427 ftqBranchTraceDB.log( 1428 data = logbundle /* hardware of type T */, 1429 en = isWriteFTQTable.orR && v && do_commit && isCfi, 1430 site = "FTQ" + p(XSCoreParamsKey).HartId.toString, 1431 clock = clock, 1432 reset = reset 1433 ) 1434 } 1435 1436 val enq = io.fromBpu.resp 1437 val perf_redirect = backendRedirect 1438 1439 XSPerfAccumulate("entry", validEntries) 1440 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 1441 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 1442 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 1443 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 1444 1445 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 1446 1447 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 1448 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 1449 XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr) 1450 XSPerfAccumulate("bpu_to_ifu_bubble_when_ftq_full", (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready) 1451 1452 XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_|_)) 1453 XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid) 1454 XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid) 1455 1456 val from_bpu = io.fromBpu.resp.bits 1457 val to_ifu = io.toIfu.req.bits 1458 1459 1460 XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth+1, 1) 1461 1462 1463 1464 1465 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 1466 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 1467 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 1468 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 1469 1470 1471 val mbpBRights = mbpRights & commit_br_mask 1472 val mbpJRights = mbpRights & commit_jal_mask 1473 val mbpIRights = mbpRights & commit_jalr_mask 1474 val mbpCRights = mbpRights & commit_call_mask 1475 val mbpRRights = mbpRights & commit_ret_mask 1476 1477 val mbpBWrongs = mbpWrongs & commit_br_mask 1478 val mbpJWrongs = mbpWrongs & commit_jal_mask 1479 val mbpIWrongs = mbpWrongs & commit_jalr_mask 1480 val mbpCWrongs = mbpWrongs & commit_call_mask 1481 val mbpRWrongs = mbpWrongs & commit_ret_mask 1482 1483 val commit_pred_stage = RegNext(pred_stage(commPtr.value)) 1484 1485 def pred_stage_map(src: UInt, name: String) = { 1486 (0 until numBpStages).map(i => 1487 f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i))) 1488 ).foldLeft(Map[String, UInt]())(_+_) 1489 } 1490 1491 val mispred_stage_map = pred_stage_map(mbpWrongs, "mispredict") 1492 val br_mispred_stage_map = pred_stage_map(mbpBWrongs, "br_mispredict") 1493 val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict") 1494 val correct_stage_map = pred_stage_map(mbpRights, "correct") 1495 val br_correct_stage_map = pred_stage_map(mbpBRights, "br_correct") 1496 val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct") 1497 1498 val update_valid = io.toBpu.update.valid 1499 def u(cond: Bool) = update_valid && cond 1500 val ftb_false_hit = u(update.false_hit) 1501 // assert(!ftb_false_hit) 1502 val ftb_hit = u(commit_hit === h_hit) 1503 1504 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1505 val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid 1506 val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0) 1507 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid 1508 1509 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1510 1511 val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified) 1512 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1513 val ftb_modified_entry_ifu_redirected = u(ifuRedirected(do_commit_ptr.value)) 1514 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1515 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1516 val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified 1517 1518 def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits 1519 val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry) 1520 XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth+1, 1) 1521 XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth+1, 1) 1522 val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry) 1523 XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth+1, 1) 1524 1525 XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize+1, 1) 1526 1527 val perfCountsMap = Map( 1528 "BpInstr" -> PopCount(mbpInstrs), 1529 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1530 "BpRight" -> PopCount(mbpRights), 1531 "BpWrong" -> PopCount(mbpWrongs), 1532 "BpBRight" -> PopCount(mbpBRights), 1533 "BpBWrong" -> PopCount(mbpBWrongs), 1534 "BpJRight" -> PopCount(mbpJRights), 1535 "BpJWrong" -> PopCount(mbpJWrongs), 1536 "BpIRight" -> PopCount(mbpIRights), 1537 "BpIWrong" -> PopCount(mbpIWrongs), 1538 "BpCRight" -> PopCount(mbpCRights), 1539 "BpCWrong" -> PopCount(mbpCWrongs), 1540 "BpRRight" -> PopCount(mbpRRights), 1541 "BpRWrong" -> PopCount(mbpRWrongs), 1542 1543 "ftb_false_hit" -> PopCount(ftb_false_hit), 1544 "ftb_hit" -> PopCount(ftb_hit), 1545 "ftb_new_entry" -> PopCount(ftb_new_entry), 1546 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1547 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1548 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1549 "ftb_old_entry" -> PopCount(ftb_old_entry), 1550 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1551 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1552 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1553 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1554 "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken) 1555 ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++ 1556 correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map 1557 1558 for((key, value) <- perfCountsMap) { 1559 XSPerfAccumulate(key, value) 1560 } 1561 1562 // --------------------------- Debug -------------------------------- 1563 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1564 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1565 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1566 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1567 XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1568 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n") 1569 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1570 1571 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1572 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1573 // case (((valid, pd), ans), taken) => 1574 // Mux(valid && pd.isBr, 1575 // isWrong ^ Mux(ans.hit.asBool, 1576 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1577 // !taken), 1578 // !taken), 1579 // false.B) 1580 // } 1581 // } 1582 1583 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1584 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1585 // case (((valid, pd), ans), taken) => 1586 // Mux(valid && pd.isBr, 1587 // isWrong ^ Mux(ans.hit.asBool, 1588 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1589 // !taken), 1590 // !taken), 1591 // false.B) 1592 // } 1593 // } 1594 1595 // def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1596 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1597 // case (((valid, pd), ans), taken) => 1598 // Mux(valid && pd.isBr, 1599 // isWrong ^ (ans.taken.asBool === taken), 1600 // false.B) 1601 // } 1602 // } 1603 1604 // def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1605 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1606 // case (((valid, pd), ans), taken) => 1607 // Mux(valid && (pd.isBr) && ans.hit.asBool, 1608 // isWrong ^ (!taken), 1609 // false.B) 1610 // } 1611 // } 1612 1613 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1614 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1615 // case (((valid, pd), ans), taken) => 1616 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1617 // isWrong ^ (ans.target === commitEntry.target), 1618 // false.B) 1619 // } 1620 // } 1621 1622 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1623 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1624 // // btb and ubtb pred jal and jalr as well 1625 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1626 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1627 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1628 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1629 1630 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1631 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1632 1633 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1634 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1635 1636 val perfEvents = Seq( 1637 ("bpu_s2_redirect ", bpu_s2_redirect ), 1638 ("bpu_s3_redirect ", bpu_s3_redirect ), 1639 ("bpu_to_ftq_stall ", enq.valid && ~enq.ready ), 1640 ("mispredictRedirect ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level), 1641 ("replayRedirect ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level) ), 1642 ("predecodeRedirect ", fromIfuRedirect.valid ), 1643 ("to_ifu_bubble ", io.toIfu.req.ready && !io.toIfu.req.valid ), 1644 ("from_bpu_real_bubble ", !enq.valid && enq.ready && allowBpuIn ), 1645 ("BpInstr ", PopCount(mbpInstrs) ), 1646 ("BpBInstr ", PopCount(mbpBRights | mbpBWrongs) ), 1647 ("BpRight ", PopCount(mbpRights) ), 1648 ("BpWrong ", PopCount(mbpWrongs) ), 1649 ("BpBRight ", PopCount(mbpBRights) ), 1650 ("BpBWrong ", PopCount(mbpBWrongs) ), 1651 ("BpJRight ", PopCount(mbpJRights) ), 1652 ("BpJWrong ", PopCount(mbpJWrongs) ), 1653 ("BpIRight ", PopCount(mbpIRights) ), 1654 ("BpIWrong ", PopCount(mbpIWrongs) ), 1655 ("BpCRight ", PopCount(mbpCRights) ), 1656 ("BpCWrong ", PopCount(mbpCWrongs) ), 1657 ("BpRRight ", PopCount(mbpRRights) ), 1658 ("BpRWrong ", PopCount(mbpRWrongs) ), 1659 ("ftb_false_hit ", PopCount(ftb_false_hit) ), 1660 ("ftb_hit ", PopCount(ftb_hit) ), 1661 ) 1662 generatePerfEvent() 1663} 1664