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} 158 159class Ftq_Pred_Info(implicit p: Parameters) extends XSBundle { 160 val target = UInt(VAddrBits.W) 161 val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)) 162} 163 164 165class FtqRead[T <: Data](private val gen: T)(implicit p: Parameters) extends XSBundle { 166 val vld = Output(Bool()) 167 val ptr = Output(new FtqPtr) 168 val offset = Output(UInt(log2Ceil(PredictWidth).W)) 169 val data = Input(gen) 170 def apply(vld: Bool, ptr: FtqPtr, offset: UInt) = { 171 this.vld := vld 172 this.ptr := ptr 173 this.offset := offset 174 this.data 175 } 176} 177 178 179class FtqToBpuIO(implicit p: Parameters) extends XSBundle { 180 val redirect = Valid(new BranchPredictionRedirect) 181 val update = Valid(new BranchPredictionUpdate) 182 val enq_ptr = Output(new FtqPtr) 183} 184 185class FtqToIfuIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper { 186 val req = Decoupled(new FetchRequestBundle) 187 val redirect = Valid(new BranchPredictionRedirect) 188 val topdown_redirect = Valid(new BranchPredictionRedirect) 189 val flushFromBpu = new Bundle { 190 // when ifu pipeline is not stalled, 191 // a packet from bpu s3 can reach f1 at most 192 val s2 = Valid(new FtqPtr) 193 val s3 = Valid(new FtqPtr) 194 def shouldFlushBy(src: Valid[FtqPtr], idx_to_flush: FtqPtr) = { 195 src.valid && !isAfter(src.bits, idx_to_flush) 196 } 197 def shouldFlushByStage2(idx: FtqPtr) = shouldFlushBy(s2, idx) 198 def shouldFlushByStage3(idx: FtqPtr) = shouldFlushBy(s3, idx) 199 } 200} 201 202class FtqToICacheIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper { 203 //NOTE: req.bits must be prepare in T cycle 204 // while req.valid is set true in T + 1 cycle 205 val req = Decoupled(new FtqToICacheRequestBundle) 206} 207 208trait HasBackendRedirectInfo extends HasXSParameter { 209 def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself() 210} 211 212class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo { 213 // write to backend pc mem 214 val pc_mem_wen = Output(Bool()) 215 val pc_mem_waddr = Output(UInt(log2Ceil(FtqSize).W)) 216 val pc_mem_wdata = Output(new Ftq_RF_Components) 217 // newest target 218 val newest_entry_en = Output(Bool()) 219 val newest_entry_target = Output(UInt(VAddrBits.W)) 220 val newest_entry_ptr = Output(new FtqPtr) 221} 222 223 224class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter { 225 val io = IO(new Bundle { 226 val start_addr = Input(UInt(VAddrBits.W)) 227 val old_entry = Input(new FTBEntry) 228 val pd = Input(new Ftq_pd_Entry) 229 val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W))) 230 val target = Input(UInt(VAddrBits.W)) 231 val hit = Input(Bool()) 232 val mispredict_vec = Input(Vec(PredictWidth, Bool())) 233 234 val new_entry = Output(new FTBEntry) 235 val new_br_insert_pos = Output(Vec(numBr, Bool())) 236 val taken_mask = Output(Vec(numBr, Bool())) 237 val jmp_taken = Output(Bool()) 238 val mispred_mask = Output(Vec(numBr+1, Bool())) 239 240 // for perf counters 241 val is_init_entry = Output(Bool()) 242 val is_old_entry = Output(Bool()) 243 val is_new_br = Output(Bool()) 244 val is_jalr_target_modified = Output(Bool()) 245 val is_always_taken_modified = Output(Bool()) 246 val is_br_full = Output(Bool()) 247 }) 248 249 // no mispredictions detected at predecode 250 val hit = io.hit 251 val pd = io.pd 252 253 val init_entry = WireInit(0.U.asTypeOf(new FTBEntry)) 254 255 256 val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid 257 val entry_has_jmp = pd.jmpInfo.valid 258 val new_jmp_is_jal = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid 259 val new_jmp_is_jalr = entry_has_jmp && pd.jmpInfo.bits(0) && io.cfiIndex.valid 260 val new_jmp_is_call = entry_has_jmp && pd.jmpInfo.bits(1) && io.cfiIndex.valid 261 val new_jmp_is_ret = entry_has_jmp && pd.jmpInfo.bits(2) && io.cfiIndex.valid 262 val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask.last 263 // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last 264 265 val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal 266 val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr 267 268 def carryPos = log2Ceil(PredictWidth)+instOffsetBits 269 def getLower(pc: UInt) = pc(carryPos-1, instOffsetBits) 270 // if not hit, establish a new entry 271 init_entry.valid := true.B 272 // tag is left for ftb to assign 273 274 // case br 275 val init_br_slot = init_entry.getSlotForBr(0) 276 when (cfi_is_br) { 277 init_br_slot.valid := true.B 278 init_br_slot.offset := io.cfiIndex.bits 279 init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1) 280 init_entry.always_taken(0) := true.B // set to always taken on init 281 } 282 283 // case jmp 284 when (entry_has_jmp) { 285 init_entry.tailSlot.offset := pd.jmpOffset 286 init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr 287 init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare=false) 288 } 289 290 val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U) 291 init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr)) 292 init_entry.carry := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos-instOffsetBits), true.B) 293 init_entry.isJalr := new_jmp_is_jalr 294 init_entry.isCall := new_jmp_is_call 295 init_entry.isRet := new_jmp_is_ret 296 // that means fall thru points to the middle of an inst 297 init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask(pd.jmpOffset) 298 299 // if hit, check whether a new cfi(only br is possible) is detected 300 val oe = io.old_entry 301 val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits) 302 val br_recorded = br_recorded_vec.asUInt.orR 303 val is_new_br = cfi_is_br && !br_recorded 304 val new_br_offset = io.cfiIndex.bits 305 // vec(i) means new br will be inserted BEFORE old br(i) 306 val allBrSlotsVec = oe.allSlotsForBr 307 val new_br_insert_onehot = VecInit((0 until numBr).map{ 308 i => i match { 309 case 0 => 310 !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset 311 case idx => 312 allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset && 313 (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset) 314 } 315 }) 316 317 val old_entry_modified = WireInit(io.old_entry) 318 for (i <- 0 until numBr) { 319 val slot = old_entry_modified.allSlotsForBr(i) 320 when (new_br_insert_onehot(i)) { 321 slot.valid := true.B 322 slot.offset := new_br_offset 323 slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr-1) 324 old_entry_modified.always_taken(i) := true.B 325 }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) { 326 old_entry_modified.always_taken(i) := false.B 327 // all other fields remain unchanged 328 }.otherwise { 329 // case i == 0, remain unchanged 330 if (i != 0) { 331 val noNeedToMoveFromFormerSlot = (i == numBr-1).B && !oe.brSlots.last.valid 332 when (!noNeedToMoveFromFormerSlot) { 333 slot.fromAnotherSlot(oe.allSlotsForBr(i-1)) 334 old_entry_modified.always_taken(i) := oe.always_taken(i) 335 } 336 } 337 } 338 } 339 340 // two circumstances: 341 // 1. oe: | br | j |, new br should be in front of j, thus addr of j should be new pft 342 // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either 343 // the previous last br or the new br 344 val may_have_to_replace = oe.noEmptySlotForNewBr 345 val pft_need_to_change = is_new_br && may_have_to_replace 346 // it should either be the given last br or the new br 347 when (pft_need_to_change) { 348 val new_pft_offset = 349 Mux(!new_br_insert_onehot.asUInt.orR, 350 new_br_offset, oe.allSlotsForBr.last.offset) 351 352 // set jmp to invalid 353 old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset 354 old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool 355 old_entry_modified.last_may_be_rvi_call := false.B 356 old_entry_modified.isCall := false.B 357 old_entry_modified.isRet := false.B 358 old_entry_modified.isJalr := false.B 359 } 360 361 val old_entry_jmp_target_modified = WireInit(oe) 362 val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits 363 val old_tail_is_jmp = !oe.tailSlot.sharing 364 val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target 365 when (jalr_target_modified) { 366 old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target) 367 old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool())) 368 } 369 370 val old_entry_always_taken = WireInit(oe) 371 val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not 372 for (i <- 0 until numBr) { 373 old_entry_always_taken.always_taken(i) := 374 oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i) 375 always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i) 376 } 377 val always_taken_modified = always_taken_modified_vec.reduce(_||_) 378 379 380 381 val derived_from_old_entry = 382 Mux(is_new_br, old_entry_modified, 383 Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken)) 384 385 386 io.new_entry := Mux(!hit, init_entry, derived_from_old_entry) 387 388 io.new_br_insert_pos := new_br_insert_onehot 389 io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{ 390 case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v 391 }) 392 io.jmp_taken := io.new_entry.jmpValid && io.new_entry.tailSlot.offset === io.cfiIndex.bits 393 for (i <- 0 until numBr) { 394 io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i)) 395 } 396 io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset) 397 398 // for perf counters 399 io.is_init_entry := !hit 400 io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified 401 io.is_new_br := hit && is_new_br 402 io.is_jalr_target_modified := hit && jalr_target_modified 403 io.is_always_taken_modified := hit && always_taken_modified 404 io.is_br_full := hit && is_new_br && may_have_to_replace 405} 406 407class FtqPcMemWrapper(numOtherReads: Int)(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo { 408 val io = IO(new Bundle { 409 val ifuPtr_w = Input(new FtqPtr) 410 val ifuPtrPlus1_w = Input(new FtqPtr) 411 val ifuPtrPlus2_w = Input(new FtqPtr) 412 val commPtr_w = Input(new FtqPtr) 413 val commPtrPlus1_w = Input(new FtqPtr) 414 val ifuPtr_rdata = Output(new Ftq_RF_Components) 415 val ifuPtrPlus1_rdata = Output(new Ftq_RF_Components) 416 val ifuPtrPlus2_rdata = Output(new Ftq_RF_Components) 417 val commPtr_rdata = Output(new Ftq_RF_Components) 418 val commPtrPlus1_rdata = Output(new Ftq_RF_Components) 419 420 val other_raddrs = Input(Vec(numOtherReads, UInt(log2Ceil(FtqSize).W))) 421 val other_rdatas = Output(Vec(numOtherReads, new Ftq_RF_Components)) 422 423 val wen = Input(Bool()) 424 val waddr = Input(UInt(log2Ceil(FtqSize).W)) 425 val wdata = Input(new Ftq_RF_Components) 426 }) 427 428 val num_pc_read = numOtherReads + 5 429 val mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, 430 num_pc_read, 1, "FtqPC")) 431 mem.io.wen(0) := io.wen 432 mem.io.waddr(0) := io.waddr 433 mem.io.wdata(0) := io.wdata 434 435 // read one cycle ahead for ftq local reads 436 val raddr_vec = VecInit(io.other_raddrs ++ 437 Seq(io.ifuPtr_w.value, io.ifuPtrPlus1_w.value, io.ifuPtrPlus2_w.value, io.commPtrPlus1_w.value, io.commPtr_w.value)) 438 439 mem.io.raddr := raddr_vec 440 441 io.other_rdatas := mem.io.rdata.dropRight(5) 442 io.ifuPtr_rdata := mem.io.rdata.dropRight(4).last 443 io.ifuPtrPlus1_rdata := mem.io.rdata.dropRight(3).last 444 io.ifuPtrPlus2_rdata := mem.io.rdata.dropRight(2).last 445 io.commPtrPlus1_rdata := mem.io.rdata.dropRight(1).last 446 io.commPtr_rdata := mem.io.rdata.last 447} 448 449class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper 450 with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents 451 with HasICacheParameters{ 452 val io = IO(new Bundle { 453 val fromBpu = Flipped(new BpuToFtqIO) 454 val fromIfu = Flipped(new IfuToFtqIO) 455 val fromBackend = Flipped(new CtrlToFtqIO) 456 457 val toBpu = new FtqToBpuIO 458 val toIfu = new FtqToIfuIO 459 val toICache = new FtqToICacheIO 460 val toBackend = new FtqToCtrlIO 461 462 val toPrefetch = new FtqPrefechBundle 463 464 val bpuInfo = new Bundle { 465 val bpRight = Output(UInt(XLEN.W)) 466 val bpWrong = Output(UInt(XLEN.W)) 467 } 468 469 val mmioCommitRead = Flipped(new mmioCommitRead) 470 471 // for perf 472 val ControlBTBMissBubble = Output(Bool()) 473 val TAGEMissBubble = Output(Bool()) 474 val SCMissBubble = Output(Bool()) 475 val ITTAGEMissBubble = Output(Bool()) 476 val RASMissBubble = Output(Bool()) 477 }) 478 io.bpuInfo := DontCare 479 480 val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle)) 481 // only driven by clock, not valid-ready 482 topdown_stage := io.fromBpu.resp.bits.topdown_info 483 io.toIfu.req.bits.topdown_info := topdown_stage 484 485 val ifuRedirected = RegInit(VecInit(Seq.fill(FtqSize)(false.B))) 486 487 488 // io.fromBackend.ftqIdxAhead: bju(BjuCnt) + ldReplay + exception 489 val ftqIdxAhead = VecInit(Seq.tabulate(FtqRedirectAheadNum)(i => io.fromBackend.ftqIdxAhead(i))) // only bju 490 val ftqIdxSelOH = io.fromBackend.ftqIdxSelOH.bits(FtqRedirectAheadNum - 1, 0) 491 492 val aheadValid = ftqIdxAhead.map(_.valid).reduce(_|_) && !io.fromBackend.redirect.valid 493 val realAhdValid = io.fromBackend.redirect.valid && (ftqIdxSelOH > 0.U) && RegNext(aheadValid) 494 val backendRedirect = Wire(Valid(new BranchPredictionRedirect)) 495 val backendRedirectReg = Wire(Valid(new BranchPredictionRedirect)) 496 backendRedirectReg.valid := RegNext(Mux(realAhdValid, false.B, backendRedirect.valid)) 497 backendRedirectReg.bits := RegEnable(backendRedirect.bits, backendRedirect.valid) 498 val fromBackendRedirect = Wire(Valid(new BranchPredictionRedirect)) 499 fromBackendRedirect := Mux(realAhdValid, backendRedirect, backendRedirectReg) 500 501 val stage2Flush = backendRedirect.valid 502 val backendFlush = stage2Flush || RegNext(stage2Flush) 503 val ifuFlush = Wire(Bool()) 504 505 val flush = stage2Flush || RegNext(stage2Flush) 506 507 val allowBpuIn, allowToIfu = WireInit(false.B) 508 val flushToIfu = !allowToIfu 509 allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 510 allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 511 512 def copyNum = 5 513 val bpuPtr, ifuPtr, ifuWbPtr, commPtr, robCommPtr = RegInit(FtqPtr(false.B, 0.U)) 514 val ifuPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 515 val ifuPtrPlus2 = RegInit(FtqPtr(false.B, 2.U)) 516 val commPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 517 val copied_ifu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U))) 518 val copied_bpu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U))) 519 require(FtqSize >= 4) 520 val ifuPtr_write = WireInit(ifuPtr) 521 val ifuPtrPlus1_write = WireInit(ifuPtrPlus1) 522 val ifuPtrPlus2_write = WireInit(ifuPtrPlus2) 523 val ifuWbPtr_write = WireInit(ifuWbPtr) 524 val commPtr_write = WireInit(commPtr) 525 val commPtrPlus1_write = WireInit(commPtrPlus1) 526 val robCommPtr_write = WireInit(robCommPtr) 527 ifuPtr := ifuPtr_write 528 ifuPtrPlus1 := ifuPtrPlus1_write 529 ifuPtrPlus2 := ifuPtrPlus2_write 530 ifuWbPtr := ifuWbPtr_write 531 commPtr := commPtr_write 532 commPtrPlus1 := commPtrPlus1_write 533 copied_ifu_ptr.map{ptr => 534 ptr := ifuPtr_write 535 dontTouch(ptr) 536 } 537 robCommPtr := robCommPtr_write 538 val validEntries = distanceBetween(bpuPtr, commPtr) 539 val canCommit = Wire(Bool()) 540 541 // ********************************************************************** 542 // **************************** enq from bpu **************************** 543 // ********************************************************************** 544 val new_entry_ready = validEntries < FtqSize.U || canCommit 545 io.fromBpu.resp.ready := new_entry_ready 546 547 val bpu_s2_resp = io.fromBpu.resp.bits.s2 548 val bpu_s3_resp = io.fromBpu.resp.bits.s3 549 val bpu_s2_redirect = bpu_s2_resp.valid(3) && bpu_s2_resp.hasRedirect(3) 550 val bpu_s3_redirect = bpu_s3_resp.valid(3) && bpu_s3_resp.hasRedirect(3) 551 552 io.toBpu.enq_ptr := bpuPtr 553 val enq_fire = io.fromBpu.resp.fire && allowBpuIn // from bpu s1 554 val bpu_in_fire = (io.fromBpu.resp.fire || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn 555 556 val bpu_in_resp = io.fromBpu.resp.bits.selectedResp 557 val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdxForFtq 558 val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx) 559 val bpu_in_resp_idx = bpu_in_resp_ptr.value 560 561 // read ports: prefetchReq ++ ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate 562 val ftq_pc_mem = Module(new FtqPcMemWrapper(1)) 563 // resp from uBTB 564 ftq_pc_mem.io.wen := bpu_in_fire 565 ftq_pc_mem.io.waddr := bpu_in_resp_idx 566 ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp) 567 568 // ifuRedirect + backendRedirect + commit 569 val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+FtqRedirectAheadNum+1)) 570 // these info is intended to enq at the last stage of bpu 571 ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3) 572 ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 573 ftq_redirect_sram.io.wdata := io.fromBpu.resp.bits.last_stage_spec_info 574 println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3") 575 println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3") 576 577 val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1)) 578 // these info is intended to enq at the last stage of bpu 579 ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3) 580 ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 581 ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.last_stage_meta 582 // ifuRedirect + backendRedirect + commit 583 val ftb_entry_mem = Module(new SyncDataModuleTemplate( 584 new FTBEntry, FtqSize, 1+FtqRedirectAheadNum+1, 1, hasRen = true)) 585 ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid(3) 586 ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value 587 ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_ftb_entry 588 589 590 // multi-write 591 val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this 592 val newest_entry_target = Reg(UInt(VAddrBits.W)) 593 val newest_entry_target_modified = RegInit(false.B) 594 val newest_entry_ptr = Reg(new FtqPtr) 595 val newest_entry_ptr_modified = RegInit(false.B) 596 val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))) 597 val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool()))) 598 val pred_stage = Reg(Vec(FtqSize, UInt(2.W))) 599 val pred_s1_cycle = if (!env.FPGAPlatform) Some(Reg(Vec(FtqSize, UInt(64.W)))) else None 600 601 val c_invalid :: c_valid :: c_commited :: Nil = Enum(3) 602 val commitStateQueueReg = RegInit(VecInit(Seq.fill(FtqSize) { 603 VecInit(Seq.fill(PredictWidth)(c_invalid)) 604 })) 605 val commitStateQueueEnable = WireInit(VecInit(Seq.fill(FtqSize)(false.B))) 606 val commitStateQueueNext = WireInit(commitStateQueueReg) 607 608 for (f <- 0 until FtqSize) { 609 when(commitStateQueueEnable(f)) { 610 commitStateQueueReg(f) := commitStateQueueNext(f) 611 } 612 } 613 614 val f_to_send :: f_sent :: Nil = Enum(2) 615 val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent))) 616 617 val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3) 618 val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit))) 619 620 // modify registers one cycle later to cut critical path 621 val last_cycle_bpu_in = RegNext(bpu_in_fire) 622 val last_cycle_bpu_in_ptr = RegEnable(bpu_in_resp_ptr, bpu_in_fire) 623 val last_cycle_bpu_in_idx = last_cycle_bpu_in_ptr.value 624 val last_cycle_bpu_target = RegEnable(bpu_in_resp.getTarget(3), bpu_in_fire) 625 val last_cycle_cfiIndex = RegEnable(bpu_in_resp.cfiIndex(3), bpu_in_fire) 626 val last_cycle_bpu_in_stage = RegEnable(bpu_in_stage, bpu_in_fire) 627 628 def extra_copyNum_for_commitStateQueue = 2 629 val copied_last_cycle_bpu_in = 630 VecInit(Seq.fill(copyNum + extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_fire))) 631 val copied_last_cycle_bpu_in_ptr_for_ftq = 632 VecInit(Seq.fill(extra_copyNum_for_commitStateQueue)(RegEnable(bpu_in_resp_ptr, bpu_in_fire))) 633 634 newest_entry_target_modified := false.B 635 newest_entry_ptr_modified := false.B 636 when (last_cycle_bpu_in) { 637 entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send 638 cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex 639 pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage 640 641 update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this 642 newest_entry_target_modified := true.B 643 newest_entry_target := last_cycle_bpu_target 644 newest_entry_ptr_modified := true.B 645 newest_entry_ptr := last_cycle_bpu_in_ptr 646 } 647 648 // reduce fanout by delay write for a cycle 649 when (RegNext(last_cycle_bpu_in)) { 650 mispredict_vec(RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in)) := 651 WireInit(VecInit(Seq.fill(PredictWidth)(false.B))) 652 } 653 654 // record s1 pred cycles 655 pred_s1_cycle.map(vec => { 656 when (bpu_in_fire && (bpu_in_stage === BP_S1)) { 657 vec(bpu_in_resp_ptr.value) := bpu_in_resp.full_pred(0).predCycle.getOrElse(0.U) 658 } 659 }) 660 661 // reduce fanout using copied last_cycle_bpu_in and copied last_cycle_bpu_in_ptr 662 val copied_last_cycle_bpu_in_for_ftq = copied_last_cycle_bpu_in.takeRight(extra_copyNum_for_commitStateQueue) 663 copied_last_cycle_bpu_in_for_ftq.zip(copied_last_cycle_bpu_in_ptr_for_ftq).zipWithIndex.map { 664 case ((in, ptr), i) => 665 when (in) { 666 val perSetEntries = FtqSize / extra_copyNum_for_commitStateQueue // 32 667 require(FtqSize % extra_copyNum_for_commitStateQueue == 0) 668 for (j <- 0 until perSetEntries) { 669 when (ptr.value === (i * perSetEntries + j).U) { 670 commitStateQueueNext(i * perSetEntries + j) := VecInit(Seq.fill(PredictWidth)(c_invalid)) 671 // Clock gating optimization, use 1 gate cell to control a row 672 commitStateQueueEnable(i * perSetEntries + j) := true.B 673 } 674 } 675 } 676 } 677 678 bpuPtr := bpuPtr + enq_fire 679 copied_bpu_ptr.map(_ := bpuPtr + enq_fire) 680 when (io.toIfu.req.fire && allowToIfu) { 681 ifuPtr_write := ifuPtrPlus1 682 ifuPtrPlus1_write := ifuPtrPlus2 683 ifuPtrPlus2_write := ifuPtrPlus2 + 1.U 684 } 685 686 // only use ftb result to assign hit status 687 when (bpu_s2_resp.valid(3)) { 688 entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred(3).hit, h_hit, h_not_hit) 689 } 690 691 692 io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect 693 io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx 694 when (bpu_s2_redirect) { 695 bpuPtr := bpu_s2_resp.ftq_idx + 1.U 696 copied_bpu_ptr.map(_ := bpu_s2_resp.ftq_idx + 1.U) 697 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 698 when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) { 699 ifuPtr_write := bpu_s2_resp.ftq_idx 700 ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U 701 ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U 702 } 703 } 704 705 io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect 706 io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx 707 when (bpu_s3_redirect) { 708 bpuPtr := bpu_s3_resp.ftq_idx + 1.U 709 copied_bpu_ptr.map(_ := bpu_s3_resp.ftq_idx + 1.U) 710 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 711 when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) { 712 ifuPtr_write := bpu_s3_resp.ftq_idx 713 ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U 714 ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U 715 } 716 } 717 718 XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n") 719 XSError(isBefore(ifuWbPtr, commPtr) && !isFull(ifuWbPtr, commPtr), "\ncommPtr is before ifuWbPtr!\n") 720 721 (0 until copyNum).map{i => 722 XSError(copied_bpu_ptr(i) =/= bpuPtr, "\ncopiedBpuPtr is different from bpuPtr!\n") 723 } 724 725 // **************************************************************** 726 // **************************** to ifu **************************** 727 // **************************************************************** 728 // 0 for ifu, and 1-4 for ICache 729 val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire) 730 val copied_bpu_in_bypass_buf = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire))) 731 val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf 732 val bpu_in_bypass_ptr = RegEnable(bpu_in_resp_ptr, bpu_in_fire) 733 val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire) 734 735 val copied_bpu_in_bypass_ptr = VecInit(Seq.fill(copyNum)(RegEnable(bpu_in_resp_ptr, bpu_in_fire))) 736 val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire))) 737 738 // read pc and target 739 ftq_pc_mem.io.ifuPtr_w := ifuPtr_write 740 ftq_pc_mem.io.ifuPtrPlus1_w := ifuPtrPlus1_write 741 ftq_pc_mem.io.ifuPtrPlus2_w := ifuPtrPlus2_write 742 ftq_pc_mem.io.commPtr_w := commPtr_write 743 ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write 744 745 746 io.toIfu.req.bits.ftqIdx := ifuPtr 747 748 val toICachePcBundle = Wire(Vec(copyNum,new Ftq_RF_Components)) 749 val toICacheEntryToSend = Wire(Vec(copyNum,Bool())) 750 val toIfuPcBundle = Wire(new Ftq_RF_Components) 751 val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send) 752 val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value)) 753 val entry_next_addr = Wire(UInt(VAddrBits.W)) 754 755 val pc_mem_ifu_ptr_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata))) 756 val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata))) 757 val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this 758 759 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)))) 760 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))) 761 762 for(i <- 0 until copyNum){ 763 when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)){ 764 toICachePcBundle(i) := copied_bpu_in_bypass_buf(i) 765 toICacheEntryToSend(i) := true.B 766 }.elsewhen(copied_last_cycle_to_ifu_fire(i)){ 767 toICachePcBundle(i) := pc_mem_ifu_plus1_rdata(i) 768 toICacheEntryToSend(i) := copied_ifu_plus1_to_send(i) 769 }.otherwise{ 770 toICachePcBundle(i) := pc_mem_ifu_ptr_rdata(i) 771 toICacheEntryToSend(i) := copied_ifu_ptr_to_send(i) 772 } 773 } 774 775 // TODO: reconsider target address bypass logic 776 when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) { 777 toIfuPcBundle := bpu_in_bypass_buf_for_ifu 778 entry_is_to_send := true.B 779 entry_next_addr := last_cycle_bpu_target 780 entry_ftq_offset := last_cycle_cfiIndex 781 diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this 782 }.elsewhen (last_cycle_to_ifu_fire) { 783 toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata) 784 entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) || 785 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles 786 entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1), 787 bpu_in_bypass_buf_for_ifu.startAddr, 788 Mux(ifuPtr === newest_entry_ptr, 789 newest_entry_target, 790 RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))) // ifuPtr+2 791 }.otherwise { 792 toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata) 793 entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) || 794 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles 795 entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1), 796 bpu_in_bypass_buf_for_ifu.startAddr, 797 Mux(ifuPtr === newest_entry_ptr, 798 newest_entry_target, 799 RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))) // ifuPtr+1 800 } 801 802 io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 803 io.toIfu.req.bits.nextStartAddr := entry_next_addr 804 io.toIfu.req.bits.ftqOffset := entry_ftq_offset 805 io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle) 806 807 io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 808 io.toICache.req.bits.readValid.zipWithIndex.map{case(copy, i) => copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)} 809 io.toICache.req.bits.pcMemRead.zipWithIndex.map{case(copy,i) => copy.fromFtqPcBundle(toICachePcBundle(i))} 810 // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr 811 // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) => 812 // bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr 813 // bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr 814 // } 815 816 // TODO: remove this 817 XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr, 818 p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n") 819 820 // when fall through is smaller in value than start address, there must be a false hit 821 when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) { 822 when (io.toIfu.req.fire && 823 !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && 824 !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr) 825 ) { 826 entry_hit_status(ifuPtr.value) := h_false_hit 827 // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 828 } 829 XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 830 } 831 832 XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit && 833 io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)) 834 835 val ifu_req_should_be_flushed = 836 io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) || 837 io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx) 838 839 when (io.toIfu.req.fire && !ifu_req_should_be_flushed) { 840 entry_fetch_status(ifuPtr.value) := f_sent 841 } 842 843 // ********************************************************************* 844 // **************************** wb from ifu **************************** 845 // ********************************************************************* 846 val pdWb = io.fromIfu.pdWb 847 val pds = pdWb.bits.pd 848 val ifu_wb_valid = pdWb.valid 849 val ifu_wb_idx = pdWb.bits.ftqIdx.value 850 // read ports: commit update 851 val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1, hasRen = true)) 852 ftq_pd_mem.io.wen(0) := ifu_wb_valid 853 ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value 854 ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits) 855 856 val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid 857 val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid 858 val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B) 859 val pd_reg = RegEnable(pds, pdWb.valid) 860 val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid) 861 val wb_idx_reg = RegEnable(ifu_wb_idx, pdWb.valid) 862 863 when (ifu_wb_valid) { 864 val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{ 865 case (v, inRange) => v && inRange 866 }) 867 commitStateQueueEnable(ifu_wb_idx) := true.B 868 (commitStateQueueNext(ifu_wb_idx) zip comm_stq_wen).map { 869 case (qe, v) => when(v) { 870 qe := c_valid 871 } 872 } 873 } 874 875 when (ifu_wb_valid) { 876 ifuWbPtr_write := ifuWbPtr + 1.U 877 } 878 879 XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU") 880 881 ftb_entry_mem.io.ren.get.head := ifu_wb_valid 882 ftb_entry_mem.io.raddr.head := ifu_wb_idx 883 val has_false_hit = WireInit(false.B) 884 when (RegNext(hit_pd_valid)) { 885 // check for false hit 886 val pred_ftb_entry = ftb_entry_mem.io.rdata.head 887 val brSlots = pred_ftb_entry.brSlots 888 val tailSlot = pred_ftb_entry.tailSlot 889 // we check cfis that bpu predicted 890 891 // bpu predicted branches but denied by predecode 892 val br_false_hit = 893 brSlots.map{ 894 s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr) 895 }.reduce(_||_) || 896 (tailSlot.valid && pred_ftb_entry.tailSlot.sharing && 897 !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr)) 898 899 val jmpOffset = tailSlot.offset 900 val jmp_pd = pd_reg(jmpOffset) 901 val jal_false_hit = pred_ftb_entry.jmpValid && 902 ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) || 903 (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) || 904 (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) || 905 (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)) 906 ) 907 908 has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg 909 XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0)) 910 911 // assert(!has_false_hit) 912 } 913 914 when (has_false_hit) { 915 entry_hit_status(wb_idx_reg) := h_false_hit 916 } 917 918 // ******************************************************************************* 919 // **************************** redirect from backend **************************** 920 // ******************************************************************************* 921 922 // redirect read cfiInfo, couples to redirectGen s2 923 val redirectReadStart = 1 // 0 for ifuRedirect 924 val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry)) 925 val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry)) 926 for (i <- redirectReadStart until FtqRedirectAheadNum) { 927 ftq_redirect_sram.io.ren(i + redirectReadStart) := ftqIdxAhead(i).valid 928 ftq_redirect_sram.io.raddr(i + redirectReadStart) := ftqIdxAhead(i).bits.value 929 ftb_entry_mem.io.ren.get(i + redirectReadStart) := ftqIdxAhead(i).valid 930 ftb_entry_mem.io.raddr(i + redirectReadStart) := ftqIdxAhead(i).bits.value 931 } 932 ftq_redirect_sram.io.ren(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid) 933 ftq_redirect_sram.io.raddr(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).bits.value, 934 backendRedirect.bits.ftqIdx.value) 935 ftb_entry_mem.io.ren.get(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).valid, backendRedirect.valid) 936 ftb_entry_mem.io.raddr(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).bits.value, 937 backendRedirect.bits.ftqIdx.value) 938 939 for (i <- 0 until FtqRedirectAheadNum) { 940 ftq_redirect_rdata(i) := ftq_redirect_sram.io.rdata(i + redirectReadStart) 941 ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + redirectReadStart) 942 } 943 val stage3CfiInfo = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_sram.io.rdata(redirectReadStart)) 944 val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate 945 backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo) 946 947 948 val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(redirectReadStart)) 949 val r_ftqOffset = fromBackendRedirect.bits.ftqOffset 950 951 backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset) 952 backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset 953 // FIXME: not portable 954 val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B))) 955 backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(r_ftb_entry.brSlots(0).offset === r_ftqOffset, 956 sc_disagree(0), sc_disagree(1)) 957 958 when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) { 959 backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +& 960 (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) && 961 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 962 963 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) || 964 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 965 }.otherwise { 966 backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt 967 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt 968 } 969 970 971 // *************************************************************************** 972 // **************************** redirect from ifu **************************** 973 // *************************************************************************** 974 val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect))) 975 fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush 976 fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx 977 fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits 978 fromIfuRedirect.bits.level := RedirectLevel.flushAfter 979 fromIfuRedirect.bits.BTBMissBubble := true.B 980 fromIfuRedirect.bits.debugIsMemVio := false.B 981 fromIfuRedirect.bits.debugIsCtrl := false.B 982 983 val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate 984 ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits) 985 ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits) 986 ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid 987 ifuRedirectCfiUpdate.target := pdWb.bits.target 988 ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid 989 ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid 990 991 val ifuRedirectReg = RegNextWithEnable(fromIfuRedirect, hasInit = true) 992 val ifuRedirectToBpu = WireInit(ifuRedirectReg) 993 ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid 994 995 ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid 996 ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 997 998 val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate 999 toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head) 1000 when (ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) { 1001 toBpuCfi.target := toBpuCfi.topAddr 1002 } 1003 1004 when (ifuRedirectReg.valid) { 1005 ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B 1006 } .elsewhen(RegNext(pdWb.valid)) { 1007 // if pdWb and no redirect, set to false 1008 ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B 1009 } 1010 1011 // ********************************************************************** 1012 // ***************************** to backend ***************************** 1013 // ********************************************************************** 1014 // to backend pc mem / target 1015 io.toBackend.pc_mem_wen := RegNext(last_cycle_bpu_in) 1016 io.toBackend.pc_mem_waddr := RegEnable(last_cycle_bpu_in_idx, last_cycle_bpu_in) 1017 io.toBackend.pc_mem_wdata := RegEnable(bpu_in_bypass_buf_for_ifu, last_cycle_bpu_in) 1018 1019 // num cycle is fixed 1020 val newest_entry_en: Bool = RegNext(last_cycle_bpu_in || backendRedirect.valid || ifuRedirectToBpu.valid) 1021 io.toBackend.newest_entry_en := RegNext(newest_entry_en) 1022 io.toBackend.newest_entry_ptr := RegEnable(newest_entry_ptr, newest_entry_en) 1023 io.toBackend.newest_entry_target := RegEnable(newest_entry_target, newest_entry_en) 1024 1025 // ********************************************************************* 1026 // **************************** wb from exu **************************** 1027 // ********************************************************************* 1028 1029 backendRedirect.valid := io.fromBackend.redirect.valid 1030 backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits) 1031 backendRedirect.bits.BTBMissBubble := false.B 1032 1033 1034 def extractRedirectInfo(wb: Valid[Redirect]) = { 1035 val ftqPtr = wb.bits.ftqIdx 1036 val ftqOffset = wb.bits.ftqOffset 1037 val taken = wb.bits.cfiUpdate.taken 1038 val mispred = wb.bits.cfiUpdate.isMisPred 1039 (wb.valid, ftqPtr, ftqOffset, taken, mispred) 1040 } 1041 1042 // fix mispredict entry 1043 val lastIsMispredict = RegNext( 1044 backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B 1045 ) 1046 1047 def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = { 1048 val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect) 1049 val r_idx = r_ptr.value 1050 val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits 1051 val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits 1052 when (cfiIndex_bits_wen || cfiIndex_valid_wen) { 1053 cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken 1054 } .elsewhen (r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) { 1055 cfiIndex_vec(r_idx).valid :=false.B 1056 } 1057 when (cfiIndex_bits_wen) { 1058 cfiIndex_vec(r_idx).bits := r_offset 1059 } 1060 newest_entry_target_modified := true.B 1061 newest_entry_target := redirect.bits.cfiUpdate.target 1062 newest_entry_ptr_modified := true.B 1063 newest_entry_ptr := r_ptr 1064 1065 update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this 1066 if (isBackend) { 1067 mispredict_vec(r_idx)(r_offset) := r_mispred 1068 } 1069 } 1070 1071 when(fromBackendRedirect.valid) { 1072 updateCfiInfo(fromBackendRedirect) 1073 }.elsewhen (ifuRedirectToBpu.valid) { 1074 updateCfiInfo(ifuRedirectToBpu, isBackend=false) 1075 } 1076 1077 when (fromBackendRedirect.valid) { 1078 when (fromBackendRedirect.bits.ControlRedirectBubble) { 1079 when (fromBackendRedirect.bits.ControlBTBMissBubble) { 1080 topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1081 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1082 } .elsewhen (fromBackendRedirect.bits.TAGEMissBubble) { 1083 topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 1084 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B 1085 } .elsewhen (fromBackendRedirect.bits.SCMissBubble) { 1086 topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B 1087 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B 1088 } .elsewhen (fromBackendRedirect.bits.ITTAGEMissBubble) { 1089 topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 1090 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B 1091 } .elsewhen (fromBackendRedirect.bits.RASMissBubble) { 1092 topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B 1093 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B 1094 } 1095 1096 1097 } .elsewhen (backendRedirect.bits.MemVioRedirectBubble) { 1098 topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 1099 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B 1100 } .otherwise { 1101 topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 1102 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B 1103 } 1104 } .elsewhen (ifuRedirectReg.valid) { 1105 topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1106 io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B 1107 } 1108 1109 io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble 1110 io.TAGEMissBubble := fromBackendRedirect.bits.TAGEMissBubble 1111 io.SCMissBubble := fromBackendRedirect.bits.SCMissBubble 1112 io.ITTAGEMissBubble := fromBackendRedirect.bits.ITTAGEMissBubble 1113 io.RASMissBubble := fromBackendRedirect.bits.RASMissBubble 1114 1115 // *********************************************************************************** 1116 // **************************** flush ptr and state queue **************************** 1117 // *********************************************************************************** 1118 1119 val redirectVec = VecInit(backendRedirect, fromIfuRedirect) 1120 1121 // when redirect, we should reset ptrs and status queues 1122 when(redirectVec.map(r => r.valid).reduce(_||_)){ 1123 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1124 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 1125 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 1126 val next = idx + 1.U 1127 bpuPtr := next 1128 copied_bpu_ptr.map(_ := next) 1129 ifuPtr_write := next 1130 ifuWbPtr_write := next 1131 ifuPtrPlus1_write := idx + 2.U 1132 ifuPtrPlus2_write := idx + 3.U 1133 1134 } 1135 when(RegNext(redirectVec.map(r => r.valid).reduce(_||_))){ 1136 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1137 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 1138 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 1139 when (RegNext(notIfu)) { 1140 commitStateQueueEnable(RegNext(idx.value)) := true.B 1141 commitStateQueueNext(RegNext(idx.value)).zipWithIndex.foreach({ case (s, i) => 1142 when(i.U > RegNext(offset) || i.U === RegNext(offset) && RegNext(flushItSelf)) { 1143 s := c_invalid 1144 } 1145 }) 1146 } 1147 } 1148 1149 1150 // only the valid bit is actually needed 1151 io.toIfu.redirect.bits := backendRedirect.bits 1152 io.toIfu.redirect.valid := stage2Flush 1153 io.toIfu.topdown_redirect := fromBackendRedirect 1154 1155 // commit 1156 for (c <- io.fromBackend.rob_commits) { 1157 when(c.valid) { 1158 commitStateQueueEnable(c.bits.ftqIdx.value) := true.B 1159 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited 1160 // TODO: remove this 1161 // For instruction fusions, we also update the next instruction 1162 when (c.bits.commitType === 4.U) { 1163 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited 1164 }.elsewhen(c.bits.commitType === 5.U) { 1165 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited 1166 }.elsewhen(c.bits.commitType === 6.U) { 1167 val index = (c.bits.ftqIdx + 1.U).value 1168 commitStateQueueEnable(index) := true.B 1169 commitStateQueueNext(index)(0) := c_commited 1170 }.elsewhen(c.bits.commitType === 7.U) { 1171 val index = (c.bits.ftqIdx + 1.U).value 1172 commitStateQueueEnable(index) := true.B 1173 commitStateQueueNext(index)(1) := c_commited 1174 } 1175 } 1176 } 1177 1178 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) 1179 1180 // **************************************************************** 1181 // **************************** to bpu **************************** 1182 // **************************************************************** 1183 1184 io.toBpu.redirect := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 1185 val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_=>0.U(64.W))) 1186 val redirect_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U 1187 XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1) 1188 XSPerfHistogram("ifu_redirect_latency", redirect_latency, !fromBackendRedirect.valid && ifuRedirectToBpu.valid, 0, 60, 1) 1189 1190 XSError(io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr), "Ftq received a redirect after its commit, check backend or replay") 1191 1192 val may_have_stall_from_bpu = Wire(Bool()) 1193 val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states 1194 may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U 1195 val notInvalidSeq = commitStateQueueReg(commPtr.value).map(s => s =/= c_invalid).reverse 1196 // Todo: @huxuan check it 1197 // canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1198 // Cat(commitStateQueue(commPtr.value).map(s => { 1199 // s === c_invalid || s === c_commited 1200 // })).andR 1201 canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1202 (isAfter(robCommPtr, commPtr) || 1203 PriorityMuxDefault(notInvalidSeq.zip(commitStateQueueReg(commPtr.value).reverse), c_invalid) === c_commited) 1204 1205 val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr 1206 val mmioLastCommit = isBefore(commPtr, mmioReadPtr) && (isAfter(ifuPtr,mmioReadPtr) || mmioReadPtr === ifuPtr) && 1207 Cat(commitStateQueueReg(mmioReadPtr.value).map(s => { s === c_invalid || s === c_commited})).andR 1208 io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit) 1209 1210 // commit reads 1211 val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata) 1212 val commit_target = 1213 Mux(RegNext(commPtr === newest_entry_ptr), 1214 RegEnable(newest_entry_target, newest_entry_target_modified), 1215 RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr)) 1216 ftq_pd_mem.io.ren.get.last := canCommit 1217 ftq_pd_mem.io.raddr.last := commPtr.value 1218 val commit_pd = ftq_pd_mem.io.rdata.last 1219 ftq_redirect_sram.io.ren.last := canCommit 1220 ftq_redirect_sram.io.raddr.last := commPtr.value 1221 val commit_spec_meta = ftq_redirect_sram.io.rdata.last 1222 ftq_meta_1r_sram.io.ren(0) := canCommit 1223 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 1224 val commit_meta = ftq_meta_1r_sram.io.rdata(0) 1225 ftb_entry_mem.io.ren.get.last := canCommit 1226 ftb_entry_mem.io.raddr.last := commPtr.value 1227 val commit_ftb_entry = ftb_entry_mem.io.rdata.last 1228 1229 // need one cycle to read mem and srams 1230 val do_commit_ptr = RegEnable(commPtr, canCommit) 1231 val do_commit = RegNext(canCommit, init=false.B) 1232 when (canCommit) { 1233 commPtr_write := commPtrPlus1 1234 commPtrPlus1_write := commPtrPlus1 + 1.U 1235 } 1236 val commit_state = RegEnable(commitStateQueueReg(commPtr.value), canCommit) 1237 val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value)) 1238 val do_commit_cfi = WireInit(cfiIndex_vec(do_commit_ptr.value)) 1239 // 1240 //when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) { 1241 // can_commit_cfi.valid := false.B 1242 //} 1243 val commit_cfi = RegEnable(can_commit_cfi, canCommit) 1244 val debug_cfi = commitStateQueueReg(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_commited && do_commit_cfi.valid 1245 1246 val commit_mispredict : Vec[Bool] = VecInit((RegEnable(mispredict_vec(commPtr.value), canCommit) zip commit_state).map { 1247 case (mis, state) => mis && state === c_commited 1248 }) 1249 val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_commited)) // [PredictWidth] 1250 val can_commit_hit = entry_hit_status(commPtr.value) 1251 val commit_hit = RegEnable(can_commit_hit, canCommit) 1252 val diff_commit_target = RegEnable(update_target(commPtr.value), canCommit) // TODO: remove this 1253 val commit_stage = RegEnable(pred_stage(commPtr.value), canCommit) 1254 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 1255 1256 val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit 1257 switch (bpu_ftb_update_stall) { 1258 is (0.U) { 1259 when (can_commit_cfi.valid && !to_bpu_hit && canCommit) { 1260 bpu_ftb_update_stall := 2.U // 2-cycle stall 1261 } 1262 } 1263 is (2.U) { 1264 bpu_ftb_update_stall := 1.U 1265 } 1266 is (1.U) { 1267 bpu_ftb_update_stall := 0.U 1268 } 1269 is (3.U) { 1270 XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2") 1271 } 1272 } 1273 1274 // TODO: remove this 1275 XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n") 1276 1277 // update latency stats 1278 val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U 1279 XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2) 1280 1281 io.toBpu.update := DontCare 1282 io.toBpu.update.valid := commit_valid && do_commit 1283 val update = io.toBpu.update.bits 1284 update.false_hit := commit_hit === h_false_hit 1285 update.pc := commit_pc_bundle.startAddr 1286 update.meta := commit_meta.meta 1287 update.cfi_idx := commit_cfi 1288 update.full_target := commit_target 1289 update.from_stage := commit_stage 1290 update.spec_info := commit_spec_meta 1291 XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n") 1292 1293 val commit_real_hit = commit_hit === h_hit 1294 val update_ftb_entry = update.ftb_entry 1295 1296 val ftbEntryGen = Module(new FTBEntryGen).io 1297 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 1298 ftbEntryGen.old_entry := commit_ftb_entry 1299 ftbEntryGen.pd := commit_pd 1300 ftbEntryGen.cfiIndex := commit_cfi 1301 ftbEntryGen.target := commit_target 1302 ftbEntryGen.hit := commit_real_hit 1303 ftbEntryGen.mispredict_vec := commit_mispredict 1304 1305 update_ftb_entry := ftbEntryGen.new_entry 1306 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 1307 update.mispred_mask := ftbEntryGen.mispred_mask 1308 update.old_entry := ftbEntryGen.is_old_entry 1309 update.pred_hit := commit_hit === h_hit || commit_hit === h_false_hit 1310 update.br_taken_mask := ftbEntryGen.taken_mask 1311 update.br_committed := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map { 1312 case (valid, offset) => valid && commit_instCommited(offset) 1313 } 1314 update.jmp_taken := ftbEntryGen.jmp_taken 1315 1316 // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc) 1317 // update.full_pred.jalr_target := commit_target 1318 // update.full_pred.hit := true.B 1319 // when (update.full_pred.is_jalr) { 1320 // update.full_pred.targets.last := commit_target 1321 // } 1322 1323 // **************************************************************** 1324 // *********************** to prefetch **************************** 1325 // **************************************************************** 1326 /** 1327 ****************************************************************************** 1328 * prefetchPtr control 1329 * - 1. prefetchPtr plus 1 when toPrefetch fire and keep distance from bpuPtr more than 2 1330 * - 2. limit range of prefetchPtr is in [ifuPtr + minRange, ifuPtr + maxRange] 1331 * - 3. flush prefetchPtr when receive redirect from ifu or backend 1332 ****************************************************************************** 1333 */ 1334 val prefetchPtr = RegInit(FtqPtr(false.B, 0.U)) 1335 val nextPrefetchPtr = WireInit(prefetchPtr) 1336 1337 prefetchPtr := nextPrefetchPtr 1338 1339 // TODO: consider req which cross cacheline 1340 when(io.toPrefetch.req.fire) { 1341 when(prefetchPtr < bpuPtr - 2.U) { 1342 nextPrefetchPtr := prefetchPtr + 1.U 1343 } 1344 } 1345 1346 when(prefetchPtr < ifuPtr + minRangeFromIFUptr.U) { 1347 nextPrefetchPtr := ifuPtr + minRangeFromIFUptr.U 1348 }.elsewhen(prefetchPtr > ifuPtr + maxRangeFromIFUptr.U) { 1349 nextPrefetchPtr := ifuPtr + maxRangeFromIFUptr.U 1350 } 1351 1352 when(redirectVec.map(r => r.valid).reduce(_||_)){ 1353 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1354 val next = r.ftqIdx + minRangeFromIFUptr.U 1355 nextPrefetchPtr := next 1356 } 1357 1358 // data from ftq_pc_mem has 1 cycle delay 1359 io.toPrefetch.req.valid := RegNext(entry_fetch_status(nextPrefetchPtr.value) === f_to_send) 1360 ftq_pc_mem.io.other_raddrs(0) := nextPrefetchPtr.value 1361 io.toPrefetch.req.bits.target := RegNext(ftq_pc_mem.io.other_rdatas(0).startAddr) 1362 1363 // record position relationship between ifuPtr, pfPtr and bpuPtr 1364 val isWritePrefetchPtrTable = WireInit(Constantin.createRecord("isWritePrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString)) 1365 val prefetchPtrTable = ChiselDB.createTable("PrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString, 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 = WireInit(Constantin.createRecord("isWriteFTQTable" + p(XSCoreParamsKey).HartId.toString)) 1400 val ftqBranchTraceDB = ChiselDB.createTable("FTQTable" + p(XSCoreParamsKey).HartId.toString, 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.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