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