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