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 val redirctFromIFU = Output(Bool()) 185} 186 187class FtqToIfuIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper { 188 val req = Decoupled(new FetchRequestBundle) 189 val redirect = Valid(new BranchPredictionRedirect) 190 val topdown_redirect = Valid(new BranchPredictionRedirect) 191 val flushFromBpu = new Bundle { 192 // when ifu pipeline is not stalled, 193 // a packet from bpu s3 can reach f1 at most 194 val s2 = Valid(new FtqPtr) 195 val s3 = Valid(new FtqPtr) 196 def shouldFlushBy(src: Valid[FtqPtr], idx_to_flush: FtqPtr) = { 197 src.valid && !isAfter(src.bits, idx_to_flush) 198 } 199 def shouldFlushByStage2(idx: FtqPtr) = shouldFlushBy(s2, idx) 200 def shouldFlushByStage3(idx: FtqPtr) = shouldFlushBy(s3, idx) 201 } 202} 203 204class FtqToICacheIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper { 205 //NOTE: req.bits must be prepare in T cycle 206 // while req.valid is set true in T + 1 cycle 207 val req = Decoupled(new FtqToICacheRequestBundle) 208} 209 210trait HasBackendRedirectInfo extends HasXSParameter { 211 def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself() 212} 213 214class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo { 215 // write to backend pc mem 216 val pc_mem_wen = Output(Bool()) 217 val pc_mem_waddr = Output(UInt(log2Ceil(FtqSize).W)) 218 val pc_mem_wdata = Output(new Ftq_RF_Components) 219 // newest target 220 val newest_entry_en = Output(Bool()) 221 val newest_entry_target = Output(UInt(VAddrBits.W)) 222 val newest_entry_ptr = Output(new FtqPtr) 223} 224 225 226class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter { 227 val io = IO(new Bundle { 228 val start_addr = Input(UInt(VAddrBits.W)) 229 val old_entry = Input(new FTBEntry) 230 val pd = Input(new Ftq_pd_Entry) 231 val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W))) 232 val target = Input(UInt(VAddrBits.W)) 233 val hit = Input(Bool()) 234 val mispredict_vec = Input(Vec(PredictWidth, Bool())) 235 236 val new_entry = Output(new FTBEntry) 237 val new_br_insert_pos = Output(Vec(numBr, Bool())) 238 val taken_mask = Output(Vec(numBr, Bool())) 239 val jmp_taken = Output(Bool()) 240 val mispred_mask = Output(Vec(numBr+1, Bool())) 241 242 // for perf counters 243 val is_init_entry = Output(Bool()) 244 val is_old_entry = Output(Bool()) 245 val is_new_br = Output(Bool()) 246 val is_jalr_target_modified = Output(Bool()) 247 val is_always_taken_modified = Output(Bool()) 248 val is_br_full = Output(Bool()) 249 }) 250 251 // no mispredictions detected at predecode 252 val hit = io.hit 253 val pd = io.pd 254 255 val init_entry = WireInit(0.U.asTypeOf(new FTBEntry)) 256 257 258 val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid 259 val entry_has_jmp = pd.jmpInfo.valid 260 val new_jmp_is_jal = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid 261 val new_jmp_is_jalr = entry_has_jmp && pd.jmpInfo.bits(0) && io.cfiIndex.valid 262 val new_jmp_is_call = entry_has_jmp && pd.jmpInfo.bits(1) && io.cfiIndex.valid 263 val new_jmp_is_ret = entry_has_jmp && pd.jmpInfo.bits(2) && io.cfiIndex.valid 264 val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask.last 265 // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last 266 267 val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal 268 val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr 269 270 def carryPos = log2Ceil(PredictWidth)+instOffsetBits 271 def getLower(pc: UInt) = pc(carryPos-1, instOffsetBits) 272 // if not hit, establish a new entry 273 init_entry.valid := true.B 274 // tag is left for ftb to assign 275 276 // case br 277 val init_br_slot = init_entry.getSlotForBr(0) 278 when (cfi_is_br) { 279 init_br_slot.valid := true.B 280 init_br_slot.offset := io.cfiIndex.bits 281 init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1) 282 init_entry.always_taken(0) := true.B // set to always taken on init 283 } 284 285 // case jmp 286 when (entry_has_jmp) { 287 init_entry.tailSlot.offset := pd.jmpOffset 288 init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr 289 init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare=false) 290 } 291 292 val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U) 293 init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr)) 294 init_entry.carry := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos-instOffsetBits), true.B) 295 init_entry.isJalr := new_jmp_is_jalr 296 init_entry.isCall := new_jmp_is_call 297 init_entry.isRet := new_jmp_is_ret 298 // that means fall thru points to the middle of an inst 299 init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask(pd.jmpOffset) 300 301 // if hit, check whether a new cfi(only br is possible) is detected 302 val oe = io.old_entry 303 val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits) 304 val br_recorded = br_recorded_vec.asUInt.orR 305 val is_new_br = cfi_is_br && !br_recorded 306 val new_br_offset = io.cfiIndex.bits 307 // vec(i) means new br will be inserted BEFORE old br(i) 308 val allBrSlotsVec = oe.allSlotsForBr 309 val new_br_insert_onehot = VecInit((0 until numBr).map{ 310 i => i match { 311 case 0 => 312 !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset 313 case idx => 314 allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset && 315 (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset) 316 } 317 }) 318 319 val old_entry_modified = WireInit(io.old_entry) 320 for (i <- 0 until numBr) { 321 val slot = old_entry_modified.allSlotsForBr(i) 322 when (new_br_insert_onehot(i)) { 323 slot.valid := true.B 324 slot.offset := new_br_offset 325 slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr-1) 326 old_entry_modified.always_taken(i) := true.B 327 }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) { 328 old_entry_modified.always_taken(i) := false.B 329 // all other fields remain unchanged 330 }.otherwise { 331 // case i == 0, remain unchanged 332 if (i != 0) { 333 val noNeedToMoveFromFormerSlot = (i == numBr-1).B && !oe.brSlots.last.valid 334 when (!noNeedToMoveFromFormerSlot) { 335 slot.fromAnotherSlot(oe.allSlotsForBr(i-1)) 336 old_entry_modified.always_taken(i) := oe.always_taken(i) 337 } 338 } 339 } 340 } 341 342 // two circumstances: 343 // 1. oe: | br | j |, new br should be in front of j, thus addr of j should be new pft 344 // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either 345 // the previous last br or the new br 346 val may_have_to_replace = oe.noEmptySlotForNewBr 347 val pft_need_to_change = is_new_br && may_have_to_replace 348 // it should either be the given last br or the new br 349 when (pft_need_to_change) { 350 val new_pft_offset = 351 Mux(!new_br_insert_onehot.asUInt.orR, 352 new_br_offset, oe.allSlotsForBr.last.offset) 353 354 // set jmp to invalid 355 old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset 356 old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool 357 old_entry_modified.last_may_be_rvi_call := false.B 358 old_entry_modified.isCall := false.B 359 old_entry_modified.isRet := false.B 360 old_entry_modified.isJalr := false.B 361 } 362 363 val old_entry_jmp_target_modified = WireInit(oe) 364 val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits 365 val old_tail_is_jmp = !oe.tailSlot.sharing 366 val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target 367 when (jalr_target_modified) { 368 old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target) 369 old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool())) 370 } 371 372 val old_entry_always_taken = WireInit(oe) 373 val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not 374 for (i <- 0 until numBr) { 375 old_entry_always_taken.always_taken(i) := 376 oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i) 377 always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i) 378 } 379 val always_taken_modified = always_taken_modified_vec.reduce(_||_) 380 381 382 383 val derived_from_old_entry = 384 Mux(is_new_br, old_entry_modified, 385 Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken)) 386 387 388 io.new_entry := Mux(!hit, init_entry, derived_from_old_entry) 389 390 io.new_br_insert_pos := new_br_insert_onehot 391 io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{ 392 case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v 393 }) 394 io.jmp_taken := io.new_entry.jmpValid && io.new_entry.tailSlot.offset === io.cfiIndex.bits 395 for (i <- 0 until numBr) { 396 io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i)) 397 } 398 io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset) 399 400 // for perf counters 401 io.is_init_entry := !hit 402 io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified 403 io.is_new_br := hit && is_new_br 404 io.is_jalr_target_modified := hit && jalr_target_modified 405 io.is_always_taken_modified := hit && always_taken_modified 406 io.is_br_full := hit && is_new_br && may_have_to_replace 407} 408 409class FtqPcMemWrapper(numOtherReads: Int)(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo { 410 val io = IO(new Bundle { 411 val ifuPtr_w = Input(new FtqPtr) 412 val ifuPtrPlus1_w = Input(new FtqPtr) 413 val ifuPtrPlus2_w = Input(new FtqPtr) 414 val commPtr_w = Input(new FtqPtr) 415 val commPtrPlus1_w = Input(new FtqPtr) 416 val ifuPtr_rdata = Output(new Ftq_RF_Components) 417 val ifuPtrPlus1_rdata = Output(new Ftq_RF_Components) 418 val ifuPtrPlus2_rdata = Output(new Ftq_RF_Components) 419 val commPtr_rdata = Output(new Ftq_RF_Components) 420 val commPtrPlus1_rdata = Output(new Ftq_RF_Components) 421 422 val other_raddrs = Input(Vec(numOtherReads, UInt(log2Ceil(FtqSize).W))) 423 val other_rdatas = Output(Vec(numOtherReads, new Ftq_RF_Components)) 424 425 val wen = Input(Bool()) 426 val waddr = Input(UInt(log2Ceil(FtqSize).W)) 427 val wdata = Input(new Ftq_RF_Components) 428 }) 429 430 val num_pc_read = numOtherReads + 5 431 val mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, 432 num_pc_read, 1, "FtqPC")) 433 mem.io.wen(0) := io.wen 434 mem.io.waddr(0) := io.waddr 435 mem.io.wdata(0) := io.wdata 436 437 // read one cycle ahead for ftq local reads 438 val raddr_vec = VecInit(io.other_raddrs ++ 439 Seq(io.ifuPtr_w.value, io.ifuPtrPlus1_w.value, io.ifuPtrPlus2_w.value, io.commPtrPlus1_w.value, io.commPtr_w.value)) 440 441 mem.io.raddr := raddr_vec 442 443 io.other_rdatas := mem.io.rdata.dropRight(5) 444 io.ifuPtr_rdata := mem.io.rdata.dropRight(4).last 445 io.ifuPtrPlus1_rdata := mem.io.rdata.dropRight(3).last 446 io.ifuPtrPlus2_rdata := mem.io.rdata.dropRight(2).last 447 io.commPtrPlus1_rdata := mem.io.rdata.dropRight(1).last 448 io.commPtr_rdata := mem.io.rdata.last 449} 450 451class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper 452 with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents 453 with HasICacheParameters{ 454 val io = IO(new Bundle { 455 val fromBpu = Flipped(new BpuToFtqIO) 456 val fromIfu = Flipped(new IfuToFtqIO) 457 val fromBackend = Flipped(new CtrlToFtqIO) 458 459 val toBpu = new FtqToBpuIO 460 val toIfu = new FtqToIfuIO 461 val toICache = new FtqToICacheIO 462 val toBackend = new FtqToCtrlIO 463 464 val toPrefetch = new FtqPrefechBundle 465 466 val bpuInfo = new Bundle { 467 val bpRight = Output(UInt(XLEN.W)) 468 val bpWrong = Output(UInt(XLEN.W)) 469 } 470 471 val mmioCommitRead = Flipped(new mmioCommitRead) 472 473 // for perf 474 val ControlBTBMissBubble = Output(Bool()) 475 val TAGEMissBubble = Output(Bool()) 476 val SCMissBubble = Output(Bool()) 477 val ITTAGEMissBubble = Output(Bool()) 478 val RASMissBubble = Output(Bool()) 479 }) 480 io.bpuInfo := DontCare 481 482 val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle)) 483 // only driven by clock, not valid-ready 484 topdown_stage := io.fromBpu.resp.bits.topdown_info 485 io.toIfu.req.bits.topdown_info := topdown_stage 486 487 val ifuRedirected = RegInit(VecInit(Seq.fill(FtqSize)(false.B))) 488 489 490 // io.fromBackend.ftqIdxAhead: bju(BjuCnt) + ldReplay + exception 491 val ftqIdxAhead = VecInit(Seq.tabulate(FtqRedirectAheadNum)(i => io.fromBackend.ftqIdxAhead(i))) // only bju 492 val ftqIdxSelOH = io.fromBackend.ftqIdxSelOH.bits(FtqRedirectAheadNum - 1, 0) 493 494 val aheadValid = ftqIdxAhead.map(_.valid).reduce(_|_) && !io.fromBackend.redirect.valid 495 val realAhdValid = io.fromBackend.redirect.valid && (ftqIdxSelOH > 0.U) && RegNext(aheadValid) 496 val backendRedirect = Wire(Valid(new BranchPredictionRedirect)) 497 val backendRedirectReg = Wire(Valid(new BranchPredictionRedirect)) 498 backendRedirectReg.valid := RegNext(Mux(realAhdValid, false.B, backendRedirect.valid)) 499 backendRedirectReg.bits := RegEnable(backendRedirect.bits, backendRedirect.valid) 500 val fromBackendRedirect = Wire(Valid(new BranchPredictionRedirect)) 501 fromBackendRedirect := Mux(realAhdValid, backendRedirect, backendRedirectReg) 502 503 val stage2Flush = backendRedirect.valid 504 val backendFlush = stage2Flush || RegNext(stage2Flush) 505 val ifuFlush = Wire(Bool()) 506 507 val flush = stage2Flush || RegNext(stage2Flush) 508 509 val allowBpuIn, allowToIfu = WireInit(false.B) 510 val flushToIfu = !allowToIfu 511 allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 512 allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 513 514 def copyNum = 5 515 val bpuPtr, ifuPtr, ifuWbPtr, commPtr, robCommPtr = RegInit(FtqPtr(false.B, 0.U)) 516 val ifuPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 517 val ifuPtrPlus2 = RegInit(FtqPtr(false.B, 2.U)) 518 val commPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 519 val copied_ifu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U))) 520 val copied_bpu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U))) 521 require(FtqSize >= 4) 522 val ifuPtr_write = WireInit(ifuPtr) 523 val ifuPtrPlus1_write = WireInit(ifuPtrPlus1) 524 val ifuPtrPlus2_write = WireInit(ifuPtrPlus2) 525 val ifuWbPtr_write = WireInit(ifuWbPtr) 526 val commPtr_write = WireInit(commPtr) 527 val commPtrPlus1_write = WireInit(commPtrPlus1) 528 val robCommPtr_write = WireInit(robCommPtr) 529 ifuPtr := ifuPtr_write 530 ifuPtrPlus1 := ifuPtrPlus1_write 531 ifuPtrPlus2 := ifuPtrPlus2_write 532 ifuWbPtr := ifuWbPtr_write 533 commPtr := commPtr_write 534 commPtrPlus1 := commPtrPlus1_write 535 copied_ifu_ptr.map{ptr => 536 ptr := ifuPtr_write 537 dontTouch(ptr) 538 } 539 robCommPtr := robCommPtr_write 540 val validEntries = distanceBetween(bpuPtr, commPtr) 541 val canCommit = Wire(Bool()) 542 543 // ********************************************************************** 544 // **************************** enq from bpu **************************** 545 // ********************************************************************** 546 val new_entry_ready = validEntries < FtqSize.U || canCommit 547 io.fromBpu.resp.ready := new_entry_ready 548 549 val bpu_s2_resp = io.fromBpu.resp.bits.s2 550 val bpu_s3_resp = io.fromBpu.resp.bits.s3 551 val bpu_s2_redirect = bpu_s2_resp.valid(3) && bpu_s2_resp.hasRedirect(3) 552 val bpu_s3_redirect = bpu_s3_resp.valid(3) && bpu_s3_resp.hasRedirect(3) 553 554 io.toBpu.enq_ptr := bpuPtr 555 val enq_fire = io.fromBpu.resp.fire && allowBpuIn // from bpu s1 556 val bpu_in_fire = (io.fromBpu.resp.fire || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn 557 558 val bpu_in_resp = io.fromBpu.resp.bits.selectedResp 559 val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdxForFtq 560 val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx) 561 val bpu_in_resp_idx = bpu_in_resp_ptr.value 562 563 // read ports: prefetchReq ++ ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate 564 val ftq_pc_mem = Module(new FtqPcMemWrapper(1)) 565 // resp from uBTB 566 ftq_pc_mem.io.wen := bpu_in_fire 567 ftq_pc_mem.io.waddr := bpu_in_resp_idx 568 ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp) 569 570 // ifuRedirect + backendRedirect + commit 571 val ftq_redirect_mem = Module(new SyncDataModuleTemplate(new Ftq_Redirect_SRAMEntry, 572 FtqSize, 1+FtqRedirectAheadNum+1, 1, hasRen = true)) 573 // these info is intended to enq at the last stage of bpu 574 ftq_redirect_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid(3) 575 ftq_redirect_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value 576 ftq_redirect_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_spec_info 577 println(f"ftq redirect MEM: entry ${ftq_redirect_mem.io.wdata(0).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.redirctFromIFU := ifuRedirectToBpu.valid 1186 io.toBpu.redirect := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 1187 val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_=>0.U(64.W))) 1188 val redirect_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U 1189 XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1) 1190 XSPerfHistogram("ifu_redirect_latency", redirect_latency, !fromBackendRedirect.valid && ifuRedirectToBpu.valid, 0, 60, 1) 1191 1192 XSError(io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr), "Ftq received a redirect after its commit, check backend or replay") 1193 1194 val may_have_stall_from_bpu = Wire(Bool()) 1195 val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states 1196 may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U 1197 val notInvalidSeq = commitStateQueueReg(commPtr.value).map(s => s =/= c_invalid).reverse 1198 // Todo: @huxuan check it 1199 // canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1200 // Cat(commitStateQueue(commPtr.value).map(s => { 1201 // s === c_invalid || s === c_commited 1202 // })).andR 1203 canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 1204 (isAfter(robCommPtr, commPtr) || 1205 PriorityMuxDefault(notInvalidSeq.zip(commitStateQueueReg(commPtr.value).reverse), c_invalid) === c_commited) 1206 1207 val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr 1208 val mmioLastCommit = isBefore(commPtr, mmioReadPtr) && (isAfter(ifuPtr,mmioReadPtr) || mmioReadPtr === ifuPtr) && 1209 Cat(commitStateQueueReg(mmioReadPtr.value).map(s => { s === c_invalid || s === c_commited})).andR 1210 io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit) 1211 1212 // commit reads 1213 val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata) 1214 val commit_target = 1215 Mux(RegNext(commPtr === newest_entry_ptr), 1216 RegEnable(newest_entry_target, newest_entry_target_modified), 1217 RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr)) 1218 ftq_pd_mem.io.ren.get.last := canCommit 1219 ftq_pd_mem.io.raddr.last := commPtr.value 1220 val commit_pd = ftq_pd_mem.io.rdata.last 1221 ftq_redirect_mem.io.ren.get.last := canCommit 1222 ftq_redirect_mem.io.raddr.last := commPtr.value 1223 val commit_spec_meta = ftq_redirect_mem.io.rdata.last 1224 ftq_meta_1r_sram.io.ren(0) := canCommit 1225 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 1226 val commit_meta = ftq_meta_1r_sram.io.rdata(0).meta 1227 val commit_ftb_entry = ftq_meta_1r_sram.io.rdata(0).ftb_entry 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 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 hartId = p(XSCoreParamsKey).HartId 1365 val isWritePrefetchPtrTable = Constantin.createRecord(s"isWritePrefetchPtrTable$hartId") 1366 val prefetchPtrTable = ChiselDB.createTable(s"PrefetchPtrTable$hartId", new PrefetchPtrDB) 1367 val prefetchPtrDumpData = Wire(new PrefetchPtrDB) 1368 prefetchPtrDumpData.fromFtqPtr := distanceBetween(bpuPtr, prefetchPtr) 1369 prefetchPtrDumpData.fromIfuPtr := distanceBetween(prefetchPtr, ifuPtr) 1370 1371 prefetchPtrTable.log( 1372 data = prefetchPtrDumpData, 1373 en = isWritePrefetchPtrTable.orR && io.toPrefetch.req.fire, 1374 site = "FTQ" + p(XSCoreParamsKey).HartId.toString, 1375 clock = clock, 1376 reset = reset 1377 ) 1378 1379 1380 // ****************************************************************************** 1381 // **************************** commit perf counters **************************** 1382 // ****************************************************************************** 1383 1384 val commit_inst_mask = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt 1385 val commit_mispred_mask = commit_mispredict.asUInt 1386 val commit_not_mispred_mask = ~commit_mispred_mask 1387 1388 val commit_br_mask = commit_pd.brMask.asUInt 1389 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 1390 val commit_cfi_mask = (commit_br_mask | commit_jmp_mask) 1391 1392 val mbpInstrs = commit_inst_mask & commit_cfi_mask 1393 1394 val mbpRights = mbpInstrs & commit_not_mispred_mask 1395 val mbpWrongs = mbpInstrs & commit_mispred_mask 1396 1397 io.bpuInfo.bpRight := PopCount(mbpRights) 1398 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 1399 1400 val isWriteFTQTable = Constantin.createRecord(s"isWriteFTQTable$hartId") 1401 val ftqBranchTraceDB = ChiselDB.createTable(s"FTQTable$hartId", new FtqDebugBundle) 1402 // Cfi Info 1403 for (i <- 0 until PredictWidth) { 1404 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 1405 val v = commit_state(i) === c_commited 1406 val isBr = commit_pd.brMask(i) 1407 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 1408 val isCfi = isBr || isJmp 1409 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 1410 val misPred = commit_mispredict(i) 1411 // val ghist = commit_spec_meta.ghist.predHist 1412 val histPtr = commit_spec_meta.histPtr 1413 val predCycle = commit_meta(63, 0) 1414 val target = commit_target 1415 1416 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}))) 1417 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_) 1418 val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)) 1419 XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 1420 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " + 1421 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 1422 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n") 1423 1424 val logbundle = Wire(new FtqDebugBundle) 1425 logbundle.pc := pc 1426 logbundle.target := target 1427 logbundle.isBr := isBr 1428 logbundle.isJmp := isJmp 1429 logbundle.isCall := isJmp && commit_pd.hasCall 1430 logbundle.isRet := isJmp && commit_pd.hasRet 1431 logbundle.misPred := misPred 1432 logbundle.isTaken := isTaken 1433 logbundle.predStage := commit_stage 1434 1435 ftqBranchTraceDB.log( 1436 data = logbundle /* hardware of type T */, 1437 en = isWriteFTQTable.orR && v && do_commit && isCfi, 1438 site = "FTQ" + p(XSCoreParamsKey).HartId.toString, 1439 clock = clock, 1440 reset = reset 1441 ) 1442 } 1443 1444 val enq = io.fromBpu.resp 1445 val perf_redirect = backendRedirect 1446 1447 XSPerfAccumulate("entry", validEntries) 1448 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 1449 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 1450 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 1451 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 1452 1453 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 1454 1455 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 1456 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 1457 XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr) 1458 XSPerfAccumulate("bpu_to_ifu_bubble_when_ftq_full", (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready) 1459 1460 XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_|_)) 1461 XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid) 1462 XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid) 1463 1464 val from_bpu = io.fromBpu.resp.bits 1465 val to_ifu = io.toIfu.req.bits 1466 1467 1468 XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth+1, 1) 1469 1470 1471 1472 1473 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 1474 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 1475 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 1476 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 1477 1478 1479 val mbpBRights = mbpRights & commit_br_mask 1480 val mbpJRights = mbpRights & commit_jal_mask 1481 val mbpIRights = mbpRights & commit_jalr_mask 1482 val mbpCRights = mbpRights & commit_call_mask 1483 val mbpRRights = mbpRights & commit_ret_mask 1484 1485 val mbpBWrongs = mbpWrongs & commit_br_mask 1486 val mbpJWrongs = mbpWrongs & commit_jal_mask 1487 val mbpIWrongs = mbpWrongs & commit_jalr_mask 1488 val mbpCWrongs = mbpWrongs & commit_call_mask 1489 val mbpRWrongs = mbpWrongs & commit_ret_mask 1490 1491 val commit_pred_stage = RegNext(pred_stage(commPtr.value)) 1492 1493 def pred_stage_map(src: UInt, name: String) = { 1494 (0 until numBpStages).map(i => 1495 f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i))) 1496 ).foldLeft(Map[String, UInt]())(_+_) 1497 } 1498 1499 val mispred_stage_map = pred_stage_map(mbpWrongs, "mispredict") 1500 val br_mispred_stage_map = pred_stage_map(mbpBWrongs, "br_mispredict") 1501 val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict") 1502 val correct_stage_map = pred_stage_map(mbpRights, "correct") 1503 val br_correct_stage_map = pred_stage_map(mbpBRights, "br_correct") 1504 val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct") 1505 1506 val update_valid = io.toBpu.update.valid 1507 def u(cond: Bool) = update_valid && cond 1508 val ftb_false_hit = u(update.false_hit) 1509 // assert(!ftb_false_hit) 1510 val ftb_hit = u(commit_hit === h_hit) 1511 1512 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1513 val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid 1514 val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0) 1515 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid 1516 1517 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1518 1519 val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified) 1520 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1521 val ftb_modified_entry_ifu_redirected = u(ifuRedirected(do_commit_ptr.value)) 1522 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1523 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1524 val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified 1525 1526 def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits 1527 val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry) 1528 XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth+1, 1) 1529 XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth+1, 1) 1530 val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry) 1531 XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth+1, 1) 1532 1533 XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize+1, 1) 1534 1535 val perfCountsMap = Map( 1536 "BpInstr" -> PopCount(mbpInstrs), 1537 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1538 "BpRight" -> PopCount(mbpRights), 1539 "BpWrong" -> PopCount(mbpWrongs), 1540 "BpBRight" -> PopCount(mbpBRights), 1541 "BpBWrong" -> PopCount(mbpBWrongs), 1542 "BpJRight" -> PopCount(mbpJRights), 1543 "BpJWrong" -> PopCount(mbpJWrongs), 1544 "BpIRight" -> PopCount(mbpIRights), 1545 "BpIWrong" -> PopCount(mbpIWrongs), 1546 "BpCRight" -> PopCount(mbpCRights), 1547 "BpCWrong" -> PopCount(mbpCWrongs), 1548 "BpRRight" -> PopCount(mbpRRights), 1549 "BpRWrong" -> PopCount(mbpRWrongs), 1550 1551 "ftb_false_hit" -> PopCount(ftb_false_hit), 1552 "ftb_hit" -> PopCount(ftb_hit), 1553 "ftb_new_entry" -> PopCount(ftb_new_entry), 1554 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1555 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1556 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1557 "ftb_old_entry" -> PopCount(ftb_old_entry), 1558 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1559 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1560 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1561 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1562 "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken) 1563 ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++ 1564 correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map 1565 1566 for((key, value) <- perfCountsMap) { 1567 XSPerfAccumulate(key, value) 1568 } 1569 1570 // --------------------------- Debug -------------------------------- 1571 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1572 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1573 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1574 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1575 XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1576 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n") 1577 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1578 1579 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1580 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1581 // case (((valid, pd), ans), taken) => 1582 // Mux(valid && pd.isBr, 1583 // isWrong ^ Mux(ans.hit.asBool, 1584 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1585 // !taken), 1586 // !taken), 1587 // false.B) 1588 // } 1589 // } 1590 1591 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1592 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1593 // case (((valid, pd), ans), taken) => 1594 // Mux(valid && pd.isBr, 1595 // isWrong ^ Mux(ans.hit.asBool, 1596 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1597 // !taken), 1598 // !taken), 1599 // false.B) 1600 // } 1601 // } 1602 1603 // def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1604 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1605 // case (((valid, pd), ans), taken) => 1606 // Mux(valid && pd.isBr, 1607 // isWrong ^ (ans.taken.asBool === taken), 1608 // false.B) 1609 // } 1610 // } 1611 1612 // def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1613 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1614 // case (((valid, pd), ans), taken) => 1615 // Mux(valid && (pd.isBr) && ans.hit.asBool, 1616 // isWrong ^ (!taken), 1617 // false.B) 1618 // } 1619 // } 1620 1621 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1622 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1623 // case (((valid, pd), ans), taken) => 1624 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1625 // isWrong ^ (ans.target === commitEntry.target), 1626 // false.B) 1627 // } 1628 // } 1629 1630 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1631 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1632 // // btb and ubtb pred jal and jalr as well 1633 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1634 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1635 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1636 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1637 1638 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1639 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1640 1641 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1642 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1643 1644 val perfEvents = Seq( 1645 ("bpu_s2_redirect ", bpu_s2_redirect ), 1646 ("bpu_s3_redirect ", bpu_s3_redirect ), 1647 ("bpu_to_ftq_stall ", enq.valid && ~enq.ready ), 1648 ("mispredictRedirect ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level), 1649 ("replayRedirect ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level) ), 1650 ("predecodeRedirect ", fromIfuRedirect.valid ), 1651 ("to_ifu_bubble ", io.toIfu.req.ready && !io.toIfu.req.valid ), 1652 ("from_bpu_real_bubble ", !enq.valid && enq.ready && allowBpuIn ), 1653 ("BpInstr ", PopCount(mbpInstrs) ), 1654 ("BpBInstr ", PopCount(mbpBRights | mbpBWrongs) ), 1655 ("BpRight ", PopCount(mbpRights) ), 1656 ("BpWrong ", PopCount(mbpWrongs) ), 1657 ("BpBRight ", PopCount(mbpBRights) ), 1658 ("BpBWrong ", PopCount(mbpBWrongs) ), 1659 ("BpJRight ", PopCount(mbpJRights) ), 1660 ("BpJWrong ", PopCount(mbpJWrongs) ), 1661 ("BpIRight ", PopCount(mbpIRights) ), 1662 ("BpIWrong ", PopCount(mbpIWrongs) ), 1663 ("BpCRight ", PopCount(mbpCRights) ), 1664 ("BpCWrong ", PopCount(mbpCWrongs) ), 1665 ("BpRRight ", PopCount(mbpRRights) ), 1666 ("BpRWrong ", PopCount(mbpRWrongs) ), 1667 ("ftb_false_hit ", PopCount(ftb_false_hit) ), 1668 ("ftb_hit ", PopCount(ftb_hit) ), 1669 ) 1670 generatePerfEvent() 1671} 1672