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 toPrefetchPcBundle = Wire(new Ftq_RF_Components) 810 val toPrefetchEntryToSend = Wire(Bool()) 811 val toIfuPcBundle = Wire(new Ftq_RF_Components) 812 val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send) 813 val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value)) 814 val entry_next_addr = Wire(UInt(VAddrBits.W)) 815 816 val pc_mem_ifu_ptr_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata))) 817 val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata))) 818 val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this 819 820 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)))) 821 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))) 822 823 for(i <- 0 until copyNum){ 824 when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)){ 825 toICachePcBundle(i) := copied_bpu_in_bypass_buf(i) 826 toICacheEntryToSend(i) := true.B 827 }.elsewhen(copied_last_cycle_to_ifu_fire(i)){ 828 toICachePcBundle(i) := pc_mem_ifu_plus1_rdata(i) 829 toICacheEntryToSend(i) := copied_ifu_plus1_to_send(i) 830 }.otherwise{ 831 toICachePcBundle(i) := pc_mem_ifu_ptr_rdata(i) 832 toICacheEntryToSend(i) := copied_ifu_ptr_to_send(i) 833 } 834 } 835 836 when(last_cycle_bpu_in && bpu_in_bypass_ptr === pfPtr){ 837 toPrefetchPcBundle := bpu_in_bypass_buf 838 toPrefetchEntryToSend := true.B 839 }.elsewhen(last_cycle_to_pf_fire){ 840 toPrefetchPcBundle := RegNext(ftq_pc_mem.io.pfPtrPlus1_rdata) 841 toPrefetchEntryToSend := RegNext(entry_fetch_status(pfPtrPlus1.value) === f_to_send) || 842 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (pfPtrPlus1)) 843 }.otherwise{ 844 toPrefetchPcBundle := RegNext(ftq_pc_mem.io.pfPtr_rdata) 845 toPrefetchEntryToSend := RegNext(entry_fetch_status(pfPtr.value) === f_to_send) || 846 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === pfPtr) // reduce potential bubbles 847 } 848 849 // TODO: reconsider target address bypass logic 850 when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) { 851 toIfuPcBundle := bpu_in_bypass_buf_for_ifu 852 entry_is_to_send := true.B 853 entry_next_addr := last_cycle_bpu_target 854 entry_ftq_offset := last_cycle_cfiIndex 855 diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this 856 }.elsewhen (last_cycle_to_ifu_fire) { 857 toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata) 858 entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) || 859 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles 860 entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1), 861 bpu_in_bypass_buf_for_ifu.startAddr, 862 Mux(ifuPtr === newest_entry_ptr, 863 newest_entry_target, 864 RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))) // ifuPtr+2 865 }.otherwise { 866 toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata) 867 entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) || 868 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles 869 entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1), 870 bpu_in_bypass_buf_for_ifu.startAddr, 871 Mux(ifuPtr === newest_entry_ptr, 872 newest_entry_target, 873 RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))) // ifuPtr+1 874 } 875 876 io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 877 io.toIfu.req.bits.nextStartAddr := entry_next_addr 878 io.toIfu.req.bits.ftqOffset := entry_ftq_offset 879 io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle) 880 881 io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 882 io.toICache.req.bits.readValid.zipWithIndex.map{case(copy, i) => copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)} 883 io.toICache.req.bits.pcMemRead.zipWithIndex.foreach{case(copy,i) => 884 copy.fromFtqPcBundle(toICachePcBundle(i)) 885 copy.ftqIdx := ifuPtr 886 } 887 io.toICache.req.bits.backendIpf := backendIpf && backendPcFaultPtr === ifuPtr 888 io.toICache.req.bits.backendIgpf := backendIgpf && backendPcFaultPtr === ifuPtr 889 io.toICache.req.bits.backendIaf := backendIaf && backendPcFaultPtr === ifuPtr 890 891 io.toPrefetch.req.valid := toPrefetchEntryToSend && pfPtr =/= bpuPtr 892 io.toPrefetch.req.bits.fromFtqPcBundle(toPrefetchPcBundle) 893 io.toPrefetch.req.bits.ftqIdx := pfPtr 894 // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr 895 // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) => 896 // bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr 897 // bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr 898 // } 899 900 // TODO: remove this 901 XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr, 902 p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n") 903 904 // when fall through is smaller in value than start address, there must be a false hit 905 when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) { 906 when (io.toIfu.req.fire && 907 !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && 908 !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr) 909 ) { 910 entry_hit_status(ifuPtr.value) := h_false_hit 911 // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 912 } 913 XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 914 } 915 916 XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit && 917 io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)) 918 919 val ifu_req_should_be_flushed = 920 io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) || 921 io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx) 922 923 when (io.toIfu.req.fire && !ifu_req_should_be_flushed) { 924 entry_fetch_status(ifuPtr.value) := f_sent 925 } 926 927 // ********************************************************************* 928 // **************************** wb from ifu **************************** 929 // ********************************************************************* 930 val pdWb = io.fromIfu.pdWb 931 val pds = pdWb.bits.pd 932 val ifu_wb_valid = pdWb.valid 933 val ifu_wb_idx = pdWb.bits.ftqIdx.value 934 // read ports: commit update 935 val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, FtqRedirectAheadNum+1, 1, hasRen = true)) 936 ftq_pd_mem.io.wen(0) := ifu_wb_valid 937 ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value 938 ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits) 939 940 val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid 941 val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid 942 val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B) 943 val pd_reg = RegEnable(pds, pdWb.valid) 944 val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid) 945 val wb_idx_reg = RegEnable(ifu_wb_idx, pdWb.valid) 946 947 when (ifu_wb_valid) { 948 val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{ 949 case (v, inRange) => v && inRange 950 }) 951 commitStateQueueEnable(ifu_wb_idx) := true.B 952 (commitStateQueueNext(ifu_wb_idx) zip comm_stq_wen).map { 953 case (qe, v) => when(v) { 954 qe := c_toCommit 955 } 956 } 957 } 958 959 when (ifu_wb_valid) { 960 ifuWbPtr_write := ifuWbPtr + 1.U 961 } 962 963 XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU") 964 965 ftb_entry_mem.io.ren.get.head := ifu_wb_valid 966 ftb_entry_mem.io.raddr.head := ifu_wb_idx 967 val has_false_hit = WireInit(false.B) 968 when (RegNext(hit_pd_valid)) { 969 // check for false hit 970 val pred_ftb_entry = ftb_entry_mem.io.rdata.head 971 val brSlots = pred_ftb_entry.brSlots 972 val tailSlot = pred_ftb_entry.tailSlot 973 // we check cfis that bpu predicted 974 975 // bpu predicted branches but denied by predecode 976 val br_false_hit = 977 brSlots.map{ 978 s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr) 979 }.reduce(_||_) || 980 (tailSlot.valid && pred_ftb_entry.tailSlot.sharing && 981 !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr)) 982 983 val jmpOffset = tailSlot.offset 984 val jmp_pd = pd_reg(jmpOffset) 985 val jal_false_hit = pred_ftb_entry.jmpValid && 986 ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) || 987 (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) || 988 (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) || 989 (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)) 990 ) 991 992 has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg 993 XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0)) 994 995 // assert(!has_false_hit) 996 } 997 998 when (has_false_hit) { 999 entry_hit_status(wb_idx_reg) := h_false_hit 1000 } 1001 1002 // ******************************************************************************* 1003 // **************************** redirect from backend **************************** 1004 // ******************************************************************************* 1005 1006 // redirect read cfiInfo, couples to redirectGen s2 1007 // ftqIdxAhead(0-3) => ftq_redirect_mem(1-4), reuse ftq_redirect_mem(1) 1008 val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry)) 1009 val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry_FtqMem)) 1010 1011 val ftq_pd_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_pd_Entry)) 1012 for (i <- 1 until FtqRedirectAheadNum) { 1013 ftq_redirect_mem.io.ren.get(i + IfuRedirectNum) := ftqIdxAhead(i).valid 1014 ftq_redirect_mem.io.raddr(i + IfuRedirectNum) := ftqIdxAhead(i).bits.value 1015 ftb_entry_mem.io.ren.get(i + IfuRedirectNum) := ftqIdxAhead(i).valid 1016 ftb_entry_mem.io.raddr(i + IfuRedirectNum) := ftqIdxAhead(i).bits.value 1017 1018 ftq_pd_mem.io.ren.get(i) := ftqIdxAhead(i).valid 1019 ftq_pd_mem.io.raddr(i) := ftqIdxAhead(i).bits.value 1020 } 1021 ftq_redirect_mem.io.ren.get(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid) 1022 ftq_redirect_mem.io.raddr(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value) 1023 ftb_entry_mem.io.ren.get(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid) 1024 ftb_entry_mem.io.raddr(IfuRedirectNum) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value) 1025 1026 ftq_pd_mem.io.ren.get(0) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid) 1027 ftq_pd_mem.io.raddr(0) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value) 1028 1029 for (i <- 0 until FtqRedirectAheadNum) { 1030 ftq_redirect_rdata(i) := ftq_redirect_mem.io.rdata(i + IfuRedirectNum) 1031 ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + IfuRedirectNum) 1032 1033 ftq_pd_rdata(i) := ftq_pd_mem.io.rdata(i) 1034 } 1035 val stage3CfiInfo = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_mem.io.rdata(IfuRedirectNum)) 1036 val stage3PdInfo = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_pd_rdata), ftq_pd_mem.io.rdata(0)) 1037 val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate 1038 backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo) 1039 backendRedirectCfi.pd := stage3PdInfo.toPd(fromBackendRedirect.bits.ftqOffset) 1040 1041 1042 val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(IfuRedirectNum)) 1043 val r_ftqOffset = fromBackendRedirect.bits.ftqOffset 1044 1045 backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset) 1046 backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset 1047 // FIXME: not portable 1048 val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B))) 1049 backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(r_ftb_entry.brSlots(0).offset === r_ftqOffset, 1050 sc_disagree(0), sc_disagree(1)) 1051 1052 when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) { 1053 backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +& 1054 (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) && 1055 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 1056 1057 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) || 1058 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 1059 }.otherwise { 1060 backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt 1061 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt 1062 } 1063 1064 1065 // *************************************************************************** 1066 // **************************** redirect from ifu **************************** 1067 // *************************************************************************** 1068 val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect))) 1069 fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush 1070 fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx 1071 fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits 1072 fromIfuRedirect.bits.level := RedirectLevel.flushAfter 1073 fromIfuRedirect.bits.BTBMissBubble := true.B 1074 fromIfuRedirect.bits.debugIsMemVio := false.B 1075 fromIfuRedirect.bits.debugIsCtrl := false.B 1076 1077 val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate 1078 ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits) 1079 ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits) 1080 ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid 1081 ifuRedirectCfiUpdate.target := pdWb.bits.target 1082 ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid 1083 ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid 1084 1085 val ifuRedirectReg = RegNextWithEnable(fromIfuRedirect, hasInit = true) 1086 val ifuRedirectToBpu = WireInit(ifuRedirectReg) 1087 ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid 1088 1089 ftq_redirect_mem.io.ren.get.head := fromIfuRedirect.valid 1090 ftq_redirect_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 1091 1092 val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate 1093 toBpuCfi.fromFtqRedirectSram(ftq_redirect_mem.io.rdata.head) 1094 when (ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) { 1095 toBpuCfi.target := toBpuCfi.topAddr 1096 } 1097 1098 when (ifuRedirectReg.valid) { 1099 ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B 1100 } .elsewhen(RegNext(pdWb.valid)) { 1101 // if pdWb and no redirect, set to false 1102 ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B 1103 } 1104 1105 // ********************************************************************** 1106 // ***************************** to backend ***************************** 1107 // ********************************************************************** 1108 // to backend pc mem / target 1109 io.toBackend.pc_mem_wen := RegNext(last_cycle_bpu_in) 1110 io.toBackend.pc_mem_waddr := RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in) 1111 io.toBackend.pc_mem_wdata := RegEnable(bpu_in_bypass_buf_for_ifu, last_cycle_bpu_in) 1112 1113 // num cycle is fixed 1114 val newest_entry_en: Bool = RegNext(last_cycle_bpu_in || backendRedirect.valid || ifuRedirectToBpu.valid) 1115 io.toBackend.newest_entry_en := RegNext(newest_entry_en) 1116 io.toBackend.newest_entry_ptr := RegEnable(newest_entry_ptr, newest_entry_en) 1117 io.toBackend.newest_entry_target := RegEnable(newest_entry_target, newest_entry_en) 1118 1119 // ********************************************************************* 1120 // **************************** wb from exu **************************** 1121 // ********************************************************************* 1122 1123 backendRedirect.valid := io.fromBackend.redirect.valid 1124 backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits) 1125 backendRedirect.bits.BTBMissBubble := false.B 1126 1127 1128 def extractRedirectInfo(wb: Valid[Redirect]) = { 1129 val ftqPtr = wb.bits.ftqIdx 1130 val ftqOffset = wb.bits.ftqOffset 1131 val taken = wb.bits.cfiUpdate.taken 1132 val mispred = wb.bits.cfiUpdate.isMisPred 1133 (wb.valid, ftqPtr, ftqOffset, taken, mispred) 1134 } 1135 1136 // fix mispredict entry 1137 val lastIsMispredict = RegNext( 1138 backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B 1139 ) 1140 1141 def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = { 1142 val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect) 1143 val r_idx = r_ptr.value 1144 val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits 1145 val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits 1146 when (cfiIndex_bits_wen || cfiIndex_valid_wen) { 1147 cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken 1148 } .elsewhen (r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) { 1149 cfiIndex_vec(r_idx).valid :=false.B 1150 } 1151 when (cfiIndex_bits_wen) { 1152 cfiIndex_vec(r_idx).bits := r_offset 1153 } 1154 newest_entry_target_modified := true.B 1155 newest_entry_target := redirect.bits.cfiUpdate.target 1156 newest_entry_ptr_modified := true.B 1157 newest_entry_ptr := r_ptr 1158 1159 update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this 1160 if (isBackend) { 1161 mispredict_vec(r_idx)(r_offset) := r_mispred 1162 } 1163 } 1164 1165 when(fromBackendRedirect.valid) { 1166 updateCfiInfo(fromBackendRedirect) 1167 }.elsewhen (ifuRedirectToBpu.valid) { 1168 updateCfiInfo(ifuRedirectToBpu, isBackend=false) 1169 } 1170 1171 when (fromBackendRedirect.valid) { 1172 when (fromBackendRedirect.bits.ControlRedirectBubble) { 1173 when (fromBackendRedirect.bits.ControlBTBMissBubble) { 1174 topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1175 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1176 } .elsewhen (fromBackendRedirect.bits.TAGEMissBubble) { 1177 topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 1178 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 1179 } .elsewhen (fromBackendRedirect.bits.SCMissBubble) { 1180 topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B 1181 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B 1182 } .elsewhen (fromBackendRedirect.bits.ITTAGEMissBubble) { 1183 topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 1184 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 1185 } .elsewhen (fromBackendRedirect.bits.RASMissBubble) { 1186 topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B 1187 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B 1188 } 1189 1190 1191 } .elsewhen (backendRedirect.bits.MemVioRedirectBubble) { 1192 topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 1193 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 1194 } .otherwise { 1195 topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 1196 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 1197 } 1198 } .elsewhen (ifuRedirectReg.valid) { 1199 topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1200 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1201 } 1202 1203 io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble 1204 io.TAGEMissBubble := fromBackendRedirect.bits.TAGEMissBubble 1205 io.SCMissBubble := fromBackendRedirect.bits.SCMissBubble 1206 io.ITTAGEMissBubble := fromBackendRedirect.bits.ITTAGEMissBubble 1207 io.RASMissBubble := fromBackendRedirect.bits.RASMissBubble 1208 1209 // *********************************************************************************** 1210 // **************************** flush ptr and state queue **************************** 1211 // *********************************************************************************** 1212 1213 val redirectVec = VecInit(backendRedirect, fromIfuRedirect) 1214 1215 // when redirect, we should reset ptrs and status queues 1216 io.icacheFlush := redirectVec.map(r => r.valid).reduce(_||_) 1217 XSPerfAccumulate("icacheFlushFromBackend", backendRedirect.valid) 1218 XSPerfAccumulate("icacheFlushFromIFU", fromIfuRedirect.valid) 1219 when(redirectVec.map(r => r.valid).reduce(_||_)){ 1220 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1221 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 1222 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 1223 val next = idx + 1.U 1224 bpuPtr := next 1225 copied_bpu_ptr.map(_ := next) 1226 ifuPtr_write := next 1227 ifuWbPtr_write := next 1228 ifuPtrPlus1_write := idx + 2.U 1229 ifuPtrPlus2_write := idx + 3.U 1230 pfPtr_write := next 1231 pfPtrPlus1_write := idx + 2.U 1232 } 1233 when(RegNext(redirectVec.map(r => r.valid).reduce(_||_))){ 1234 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1235 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 1236 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 1237 when (RegNext(notIfu)) { 1238 commitStateQueueEnable(RegNext(idx.value)) := true.B 1239 commitStateQueueNext(RegNext(idx.value)).zipWithIndex.foreach({ case (s, i) => 1240 when(i.U > RegNext(offset)) { 1241 s := c_empty 1242 } 1243 when (i.U === RegNext(offset) && RegNext(flushItSelf)) { 1244 s := c_flushed 1245 } 1246 }) 1247 } 1248 } 1249 1250 1251 // only the valid bit is actually needed 1252 io.toIfu.redirect.bits := backendRedirect.bits 1253 io.toIfu.redirect.valid := stage2Flush 1254 io.toIfu.topdown_redirect := fromBackendRedirect 1255 1256 // commit 1257 for (c <- io.fromBackend.rob_commits) { 1258 when(c.valid) { 1259 commitStateQueueEnable(c.bits.ftqIdx.value) := true.B 1260 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_committed 1261 // TODO: remove this 1262 // For instruction fusions, we also update the next instruction 1263 when (c.bits.commitType === 4.U) { 1264 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_committed 1265 }.elsewhen(c.bits.commitType === 5.U) { 1266 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_committed 1267 }.elsewhen(c.bits.commitType === 6.U) { 1268 val index = (c.bits.ftqIdx + 1.U).value 1269 commitStateQueueEnable(index) := true.B 1270 commitStateQueueNext(index)(0) := c_committed 1271 }.elsewhen(c.bits.commitType === 7.U) { 1272 val index = (c.bits.ftqIdx + 1.U).value 1273 commitStateQueueEnable(index) := true.B 1274 commitStateQueueNext(index)(1) := c_committed 1275 } 1276 } 1277 } 1278 1279 // **************************************************************** 1280 // **************************** to bpu **************************** 1281 // **************************************************************** 1282 1283 io.toBpu.redirctFromIFU := ifuRedirectToBpu.valid 1284 io.toBpu.redirect := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 1285 val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_=>0.U(64.W))) 1286 val redirect_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U 1287 XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1) 1288 XSPerfHistogram("ifu_redirect_latency", redirect_latency, !fromBackendRedirect.valid && ifuRedirectToBpu.valid, 0, 60, 1) 1289 1290 XSError(io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr), "Ftq received a redirect after its commit, check backend or replay") 1291 1292 val may_have_stall_from_bpu = Wire(Bool()) 1293 val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states 1294 may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U 1295 1296 val validInstructions = commitStateQueueReg(commPtr.value).map(s => s === c_toCommit || s === c_committed) 1297 val lastInstructionStatus = PriorityMux(validInstructions.reverse.zip(commitStateQueueReg(commPtr.value).reverse)) 1298 val firstInstructionFlushed = commitStateQueueReg(commPtr.value)(0) === c_flushed 1299 canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1300 (isAfter(robCommPtr, commPtr) || 1301 validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed) 1302 val canMoveCommPtr = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1303 (isAfter(robCommPtr, commPtr) || 1304 validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed || 1305 firstInstructionFlushed) 1306 1307 when (io.fromBackend.rob_commits.map(_.valid).reduce(_ | _)) { 1308 robCommPtr_write := ParallelPriorityMux(io.fromBackend.rob_commits.map(_.valid).reverse, io.fromBackend.rob_commits.map(_.bits.ftqIdx).reverse) 1309 } .elsewhen (isAfter(commPtr, robCommPtr)) { 1310 robCommPtr_write := commPtr 1311 } .otherwise { 1312 robCommPtr_write := robCommPtr 1313 } 1314 1315 /** 1316 ************************************************************************************* 1317 * MMIO instruction fetch is allowed only if MMIO is the oldest instruction. 1318 ************************************************************************************* 1319 */ 1320 val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr 1321 val mmioLastCommit = isAfter(commPtr, mmioReadPtr) || 1322 commPtr === mmioReadPtr && validInstructions.reduce(_ || _) && lastInstructionStatus === c_committed 1323 io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit) 1324 1325 // commit reads 1326 val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata) 1327 val commit_target = 1328 Mux(RegNext(commPtr === newest_entry_ptr), 1329 RegEnable(newest_entry_target, newest_entry_target_modified), 1330 RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr)) 1331 ftq_pd_mem.io.ren.get.last := canCommit 1332 ftq_pd_mem.io.raddr.last := commPtr.value 1333 val commit_pd = ftq_pd_mem.io.rdata.last 1334 ftq_redirect_mem.io.ren.get.last := canCommit 1335 ftq_redirect_mem.io.raddr.last := commPtr.value 1336 val commit_spec_meta = ftq_redirect_mem.io.rdata.last 1337 ftq_meta_1r_sram.io.ren(0) := canCommit 1338 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 1339 val commit_meta = ftq_meta_1r_sram.io.rdata(0).meta 1340 val commit_ftb_entry = ftq_meta_1r_sram.io.rdata(0).ftb_entry 1341 1342 // need one cycle to read mem and srams 1343 val do_commit_ptr = RegEnable(commPtr, canCommit) 1344 val do_commit = RegNext(canCommit, init=false.B) 1345 when (canMoveCommPtr) { 1346 commPtr_write := commPtrPlus1 1347 commPtrPlus1_write := commPtrPlus1 + 1.U 1348 } 1349 val commit_state = RegEnable(commitStateQueueReg(commPtr.value), canCommit) 1350 val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value)) 1351 val do_commit_cfi = WireInit(cfiIndex_vec(do_commit_ptr.value)) 1352 // 1353 //when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) { 1354 // can_commit_cfi.valid := false.B 1355 //} 1356 val commit_cfi = RegEnable(can_commit_cfi, canCommit) 1357 val debug_cfi = commitStateQueueReg(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_committed && do_commit_cfi.valid 1358 1359 val commit_mispredict : Vec[Bool] = VecInit((RegEnable(mispredict_vec(commPtr.value), canCommit) zip commit_state).map { 1360 case (mis, state) => mis && state === c_committed 1361 }) 1362 val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_committed)) // [PredictWidth] 1363 val can_commit_hit = entry_hit_status(commPtr.value) 1364 val commit_hit = RegEnable(can_commit_hit, canCommit) 1365 val diff_commit_target = RegEnable(update_target(commPtr.value), canCommit) // TODO: remove this 1366 val commit_stage = RegEnable(pred_stage(commPtr.value), canCommit) 1367 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 1368 1369 val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit 1370 switch (bpu_ftb_update_stall) { 1371 is (0.U) { 1372 when (can_commit_cfi.valid && !to_bpu_hit && canCommit) { 1373 bpu_ftb_update_stall := 2.U // 2-cycle stall 1374 } 1375 } 1376 is (2.U) { 1377 bpu_ftb_update_stall := 1.U 1378 } 1379 is (1.U) { 1380 bpu_ftb_update_stall := 0.U 1381 } 1382 is (3.U) { 1383 XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2") 1384 } 1385 } 1386 1387 // TODO: remove this 1388 XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n") 1389 1390 // update latency stats 1391 val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U 1392 XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2) 1393 1394 io.toBpu.update := DontCare 1395 io.toBpu.update.valid := commit_valid && do_commit 1396 val update = io.toBpu.update.bits 1397 update.false_hit := commit_hit === h_false_hit 1398 update.pc := commit_pc_bundle.startAddr 1399 update.meta := commit_meta 1400 update.cfi_idx := commit_cfi 1401 update.full_target := commit_target 1402 update.from_stage := commit_stage 1403 update.spec_info := commit_spec_meta 1404 XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n") 1405 1406 val commit_real_hit = commit_hit === h_hit 1407 val update_ftb_entry = update.ftb_entry 1408 1409 val ftbEntryGen = Module(new FTBEntryGen).io 1410 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 1411 ftbEntryGen.old_entry := commit_ftb_entry 1412 ftbEntryGen.pd := commit_pd 1413 ftbEntryGen.cfiIndex := commit_cfi 1414 ftbEntryGen.target := commit_target 1415 ftbEntryGen.hit := commit_real_hit 1416 ftbEntryGen.mispredict_vec := commit_mispredict 1417 1418 update_ftb_entry := ftbEntryGen.new_entry 1419 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 1420 update.mispred_mask := ftbEntryGen.mispred_mask 1421 update.old_entry := ftbEntryGen.is_old_entry 1422 update.pred_hit := commit_hit === h_hit || commit_hit === h_false_hit 1423 update.br_taken_mask := ftbEntryGen.taken_mask 1424 update.br_committed := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map { 1425 case (valid, offset) => valid && commit_instCommited(offset) 1426 } 1427 update.jmp_taken := ftbEntryGen.jmp_taken 1428 1429 // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc) 1430 // update.full_pred.jalr_target := commit_target 1431 // update.full_pred.hit := true.B 1432 // when (update.full_pred.is_jalr) { 1433 // update.full_pred.targets.last := commit_target 1434 // } 1435 1436 // ****************************************************************************** 1437 // **************************** commit perf counters **************************** 1438 // ****************************************************************************** 1439 1440 val commit_inst_mask = VecInit(commit_state.map(c => c === c_committed && do_commit)).asUInt 1441 val commit_mispred_mask = commit_mispredict.asUInt 1442 val commit_not_mispred_mask = ~commit_mispred_mask 1443 1444 val commit_br_mask = commit_pd.brMask.asUInt 1445 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 1446 val commit_cfi_mask = (commit_br_mask | commit_jmp_mask) 1447 1448 val mbpInstrs = commit_inst_mask & commit_cfi_mask 1449 1450 val mbpRights = mbpInstrs & commit_not_mispred_mask 1451 val mbpWrongs = mbpInstrs & commit_mispred_mask 1452 1453 io.bpuInfo.bpRight := PopCount(mbpRights) 1454 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 1455 1456 val hartId = p(XSCoreParamsKey).HartId 1457 val isWriteFTQTable = Constantin.createRecord(s"isWriteFTQTable$hartId") 1458 val ftqBranchTraceDB = ChiselDB.createTable(s"FTQTable$hartId", new FtqDebugBundle) 1459 // Cfi Info 1460 for (i <- 0 until PredictWidth) { 1461 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 1462 val v = commit_state(i) === c_committed 1463 val isBr = commit_pd.brMask(i) 1464 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 1465 val isCfi = isBr || isJmp 1466 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 1467 val misPred = commit_mispredict(i) 1468 // val ghist = commit_spec_meta.ghist.predHist 1469 val histPtr = commit_spec_meta.histPtr 1470 val predCycle = commit_meta(63, 0) 1471 val target = commit_target 1472 1473 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}))) 1474 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_) 1475 val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)) 1476 XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 1477 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " + 1478 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 1479 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n") 1480 1481 val logbundle = Wire(new FtqDebugBundle) 1482 logbundle.pc := pc 1483 logbundle.target := target 1484 logbundle.isBr := isBr 1485 logbundle.isJmp := isJmp 1486 logbundle.isCall := isJmp && commit_pd.hasCall 1487 logbundle.isRet := isJmp && commit_pd.hasRet 1488 logbundle.misPred := misPred 1489 logbundle.isTaken := isTaken 1490 logbundle.predStage := commit_stage 1491 1492 ftqBranchTraceDB.log( 1493 data = logbundle /* hardware of type T */, 1494 en = isWriteFTQTable.orR && v && do_commit && isCfi, 1495 site = "FTQ" + p(XSCoreParamsKey).HartId.toString, 1496 clock = clock, 1497 reset = reset 1498 ) 1499 } 1500 1501 val enq = io.fromBpu.resp 1502 val perf_redirect = backendRedirect 1503 1504 XSPerfAccumulate("entry", validEntries) 1505 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 1506 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 1507 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 1508 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 1509 1510 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 1511 1512 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 1513 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 1514 XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr) 1515 XSPerfAccumulate("bpu_to_ifu_bubble_when_ftq_full", (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready) 1516 1517 XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_|_)) 1518 XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid) 1519 XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid) 1520 1521 val from_bpu = io.fromBpu.resp.bits 1522 val to_ifu = io.toIfu.req.bits 1523 1524 1525 XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth+1, 1) 1526 1527 1528 1529 1530 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 1531 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 1532 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 1533 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 1534 1535 1536 val mbpBRights = mbpRights & commit_br_mask 1537 val mbpJRights = mbpRights & commit_jal_mask 1538 val mbpIRights = mbpRights & commit_jalr_mask 1539 val mbpCRights = mbpRights & commit_call_mask 1540 val mbpRRights = mbpRights & commit_ret_mask 1541 1542 val mbpBWrongs = mbpWrongs & commit_br_mask 1543 val mbpJWrongs = mbpWrongs & commit_jal_mask 1544 val mbpIWrongs = mbpWrongs & commit_jalr_mask 1545 val mbpCWrongs = mbpWrongs & commit_call_mask 1546 val mbpRWrongs = mbpWrongs & commit_ret_mask 1547 1548 val commit_pred_stage = RegNext(pred_stage(commPtr.value)) 1549 1550 def pred_stage_map(src: UInt, name: String) = { 1551 (0 until numBpStages).map(i => 1552 f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i))) 1553 ).foldLeft(Map[String, UInt]())(_+_) 1554 } 1555 1556 val mispred_stage_map = pred_stage_map(mbpWrongs, "mispredict") 1557 val br_mispred_stage_map = pred_stage_map(mbpBWrongs, "br_mispredict") 1558 val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict") 1559 val correct_stage_map = pred_stage_map(mbpRights, "correct") 1560 val br_correct_stage_map = pred_stage_map(mbpBRights, "br_correct") 1561 val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct") 1562 1563 val update_valid = io.toBpu.update.valid 1564 def u(cond: Bool) = update_valid && cond 1565 val ftb_false_hit = u(update.false_hit) 1566 // assert(!ftb_false_hit) 1567 val ftb_hit = u(commit_hit === h_hit) 1568 1569 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1570 val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid 1571 val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0) 1572 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid 1573 1574 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1575 1576 val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified) 1577 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1578 val ftb_modified_entry_ifu_redirected = u(ifuRedirected(do_commit_ptr.value)) 1579 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1580 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1581 val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified 1582 1583 def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits 1584 val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry) 1585 XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth+1, 1) 1586 XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth+1, 1) 1587 val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry) 1588 XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth+1, 1) 1589 1590 XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize+1, 1) 1591 1592 val perfCountsMap = Map( 1593 "BpInstr" -> PopCount(mbpInstrs), 1594 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1595 "BpRight" -> PopCount(mbpRights), 1596 "BpWrong" -> PopCount(mbpWrongs), 1597 "BpBRight" -> PopCount(mbpBRights), 1598 "BpBWrong" -> PopCount(mbpBWrongs), 1599 "BpJRight" -> PopCount(mbpJRights), 1600 "BpJWrong" -> PopCount(mbpJWrongs), 1601 "BpIRight" -> PopCount(mbpIRights), 1602 "BpIWrong" -> PopCount(mbpIWrongs), 1603 "BpCRight" -> PopCount(mbpCRights), 1604 "BpCWrong" -> PopCount(mbpCWrongs), 1605 "BpRRight" -> PopCount(mbpRRights), 1606 "BpRWrong" -> PopCount(mbpRWrongs), 1607 1608 "ftb_false_hit" -> PopCount(ftb_false_hit), 1609 "ftb_hit" -> PopCount(ftb_hit), 1610 "ftb_new_entry" -> PopCount(ftb_new_entry), 1611 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1612 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1613 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1614 "ftb_old_entry" -> PopCount(ftb_old_entry), 1615 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1616 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1617 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1618 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1619 "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken) 1620 ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++ 1621 correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map 1622 1623 for((key, value) <- perfCountsMap) { 1624 XSPerfAccumulate(key, value) 1625 } 1626 1627 // --------------------------- Debug -------------------------------- 1628 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1629 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1630 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1631 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1632 XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1633 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n") 1634 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1635 1636 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1637 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1638 // case (((valid, pd), ans), taken) => 1639 // Mux(valid && pd.isBr, 1640 // isWrong ^ Mux(ans.hit.asBool, 1641 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1642 // !taken), 1643 // !taken), 1644 // false.B) 1645 // } 1646 // } 1647 1648 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1649 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1650 // case (((valid, pd), ans), taken) => 1651 // Mux(valid && pd.isBr, 1652 // isWrong ^ Mux(ans.hit.asBool, 1653 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1654 // !taken), 1655 // !taken), 1656 // false.B) 1657 // } 1658 // } 1659 1660 // def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1661 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1662 // case (((valid, pd), ans), taken) => 1663 // Mux(valid && pd.isBr, 1664 // isWrong ^ (ans.taken.asBool === taken), 1665 // false.B) 1666 // } 1667 // } 1668 1669 // def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1670 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1671 // case (((valid, pd), ans), taken) => 1672 // Mux(valid && (pd.isBr) && ans.hit.asBool, 1673 // isWrong ^ (!taken), 1674 // false.B) 1675 // } 1676 // } 1677 1678 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1679 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1680 // case (((valid, pd), ans), taken) => 1681 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1682 // isWrong ^ (ans.target === commitEntry.target), 1683 // false.B) 1684 // } 1685 // } 1686 1687 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1688 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1689 // // btb and ubtb pred jal and jalr as well 1690 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1691 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1692 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1693 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1694 1695 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1696 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1697 1698 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1699 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1700 1701 val perfEvents = Seq( 1702 ("bpu_s2_redirect ", bpu_s2_redirect ), 1703 ("bpu_s3_redirect ", bpu_s3_redirect ), 1704 ("bpu_to_ftq_stall ", enq.valid && ~enq.ready ), 1705 ("mispredictRedirect ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level), 1706 ("replayRedirect ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level) ), 1707 ("predecodeRedirect ", fromIfuRedirect.valid ), 1708 ("to_ifu_bubble ", io.toIfu.req.ready && !io.toIfu.req.valid ), 1709 ("from_bpu_real_bubble ", !enq.valid && enq.ready && allowBpuIn ), 1710 ("BpInstr ", PopCount(mbpInstrs) ), 1711 ("BpBInstr ", PopCount(mbpBRights | mbpBWrongs) ), 1712 ("BpRight ", PopCount(mbpRights) ), 1713 ("BpWrong ", PopCount(mbpWrongs) ), 1714 ("BpBRight ", PopCount(mbpBRights) ), 1715 ("BpBWrong ", PopCount(mbpBWrongs) ), 1716 ("BpJRight ", PopCount(mbpJRights) ), 1717 ("BpJWrong ", PopCount(mbpJWrongs) ), 1718 ("BpIRight ", PopCount(mbpIRights) ), 1719 ("BpIWrong ", PopCount(mbpIWrongs) ), 1720 ("BpCRight ", PopCount(mbpCRights) ), 1721 ("BpCWrong ", PopCount(mbpCWrongs) ), 1722 ("BpRRight ", PopCount(mbpRRights) ), 1723 ("BpRWrong ", PopCount(mbpRWrongs) ), 1724 ("ftb_false_hit ", PopCount(ftb_false_hit) ), 1725 ("ftb_hit ", PopCount(ftb_hit) ), 1726 ) 1727 generatePerfEvent() 1728} 1729