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