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_empty :: c_toCommit :: c_committed :: c_flushed :: Nil = Enum(4) 605 val commitStateQueueReg = RegInit(VecInit(Seq.fill(FtqSize) { 606 VecInit(Seq.fill(PredictWidth)(c_empty)) 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_empty)) 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_toCommit 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)) { 1144 s := c_empty 1145 } 1146 when (i.U === RegNext(offset) && RegNext(flushItSelf)) { 1147 s := c_flushed 1148 } 1149 }) 1150 } 1151 } 1152 1153 1154 // only the valid bit is actually needed 1155 io.toIfu.redirect.bits := backendRedirect.bits 1156 io.toIfu.redirect.valid := stage2Flush 1157 io.toIfu.topdown_redirect := fromBackendRedirect 1158 1159 // commit 1160 for (c <- io.fromBackend.rob_commits) { 1161 when(c.valid) { 1162 commitStateQueueEnable(c.bits.ftqIdx.value) := true.B 1163 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_committed 1164 // TODO: remove this 1165 // For instruction fusions, we also update the next instruction 1166 when (c.bits.commitType === 4.U) { 1167 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_committed 1168 }.elsewhen(c.bits.commitType === 5.U) { 1169 commitStateQueueNext(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_committed 1170 }.elsewhen(c.bits.commitType === 6.U) { 1171 val index = (c.bits.ftqIdx + 1.U).value 1172 commitStateQueueEnable(index) := true.B 1173 commitStateQueueNext(index)(0) := c_committed 1174 }.elsewhen(c.bits.commitType === 7.U) { 1175 val index = (c.bits.ftqIdx + 1.U).value 1176 commitStateQueueEnable(index) := true.B 1177 commitStateQueueNext(index)(1) := c_committed 1178 } 1179 } 1180 } 1181 1182 // **************************************************************** 1183 // **************************** to bpu **************************** 1184 // **************************************************************** 1185 1186 io.toBpu.redirctFromIFU := ifuRedirectToBpu.valid 1187 io.toBpu.redirect := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 1188 val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_=>0.U(64.W))) 1189 val redirect_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U 1190 XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1) 1191 XSPerfHistogram("ifu_redirect_latency", redirect_latency, !fromBackendRedirect.valid && ifuRedirectToBpu.valid, 0, 60, 1) 1192 1193 XSError(io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr), "Ftq received a redirect after its commit, check backend or replay") 1194 1195 val may_have_stall_from_bpu = Wire(Bool()) 1196 val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states 1197 may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U 1198 val noToCommit = commitStateQueueReg(commPtr.value).map(s => s =/= c_toCommit).reduce(_ && _) 1199 val allEmpty = commitStateQueueReg(commPtr.value).map(s => s === c_empty).reduce(_ && _) 1200 canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && (isAfter(robCommPtr, commPtr) || noToCommit && !allEmpty) 1201 1202 when (io.fromBackend.rob_commits.map(_.valid).reduce(_ | _)) { 1203 robCommPtr_write := ParallelPriorityMux(io.fromBackend.rob_commits.map(_.valid).reverse, io.fromBackend.rob_commits.map(_.bits.ftqIdx).reverse) 1204 } .elsewhen (commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && noToCommit && !allEmpty) { 1205 robCommPtr_write := commPtr 1206 } .otherwise { 1207 robCommPtr_write := robCommPtr 1208 } 1209 1210 /** 1211 ************************************************************************************* 1212 * MMIO instruction fetch is allowed only if MMIO is the oldest instruction. 1213 ************************************************************************************* 1214 */ 1215 val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr 1216 val mmioLastCommit = (isAfter(commPtr,mmioReadPtr) || (mmioReadPtr === commPtr)) && 1217 Cat(commitStateQueueReg(mmioReadPtr.value).map(s => { s === c_empty || s === c_committed})).andR 1218 io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit) 1219 1220 // commit reads 1221 val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata) 1222 val commit_target = 1223 Mux(RegNext(commPtr === newest_entry_ptr), 1224 RegEnable(newest_entry_target, newest_entry_target_modified), 1225 RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr)) 1226 ftq_pd_mem.io.ren.get.last := canCommit 1227 ftq_pd_mem.io.raddr.last := commPtr.value 1228 val commit_pd = ftq_pd_mem.io.rdata.last 1229 ftq_redirect_mem.io.ren.get.last := canCommit 1230 ftq_redirect_mem.io.raddr.last := commPtr.value 1231 val commit_spec_meta = ftq_redirect_mem.io.rdata.last 1232 ftq_meta_1r_sram.io.ren(0) := canCommit 1233 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 1234 val commit_meta = ftq_meta_1r_sram.io.rdata(0).meta 1235 val commit_ftb_entry = ftq_meta_1r_sram.io.rdata(0).ftb_entry 1236 1237 // need one cycle to read mem and srams 1238 val do_commit_ptr = RegEnable(commPtr, canCommit) 1239 val do_commit = RegNext(canCommit, init=false.B) 1240 when (canCommit) { 1241 commPtr_write := commPtrPlus1 1242 commPtrPlus1_write := commPtrPlus1 + 1.U 1243 } 1244 val commit_state = RegEnable(commitStateQueueReg(commPtr.value), canCommit) 1245 val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value)) 1246 val do_commit_cfi = WireInit(cfiIndex_vec(do_commit_ptr.value)) 1247 // 1248 //when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) { 1249 // can_commit_cfi.valid := false.B 1250 //} 1251 val commit_cfi = RegEnable(can_commit_cfi, canCommit) 1252 val debug_cfi = commitStateQueueReg(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_committed && do_commit_cfi.valid 1253 1254 val commit_mispredict : Vec[Bool] = VecInit((RegEnable(mispredict_vec(commPtr.value), canCommit) zip commit_state).map { 1255 case (mis, state) => mis && state === c_committed 1256 }) 1257 val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_committed)) // [PredictWidth] 1258 val can_commit_hit = entry_hit_status(commPtr.value) 1259 val commit_hit = RegEnable(can_commit_hit, canCommit) 1260 val diff_commit_target = RegEnable(update_target(commPtr.value), canCommit) // TODO: remove this 1261 val commit_stage = RegEnable(pred_stage(commPtr.value), canCommit) 1262 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 1263 1264 val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit 1265 switch (bpu_ftb_update_stall) { 1266 is (0.U) { 1267 when (can_commit_cfi.valid && !to_bpu_hit && canCommit) { 1268 bpu_ftb_update_stall := 2.U // 2-cycle stall 1269 } 1270 } 1271 is (2.U) { 1272 bpu_ftb_update_stall := 1.U 1273 } 1274 is (1.U) { 1275 bpu_ftb_update_stall := 0.U 1276 } 1277 is (3.U) { 1278 XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2") 1279 } 1280 } 1281 1282 // TODO: remove this 1283 XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n") 1284 1285 // update latency stats 1286 val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U 1287 XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2) 1288 1289 io.toBpu.update := DontCare 1290 io.toBpu.update.valid := commit_valid && do_commit 1291 val update = io.toBpu.update.bits 1292 update.false_hit := commit_hit === h_false_hit 1293 update.pc := commit_pc_bundle.startAddr 1294 update.meta := commit_meta 1295 update.cfi_idx := commit_cfi 1296 update.full_target := commit_target 1297 update.from_stage := commit_stage 1298 update.spec_info := commit_spec_meta 1299 XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n") 1300 1301 val commit_real_hit = commit_hit === h_hit 1302 val update_ftb_entry = update.ftb_entry 1303 1304 val ftbEntryGen = Module(new FTBEntryGen).io 1305 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 1306 ftbEntryGen.old_entry := commit_ftb_entry 1307 ftbEntryGen.pd := commit_pd 1308 ftbEntryGen.cfiIndex := commit_cfi 1309 ftbEntryGen.target := commit_target 1310 ftbEntryGen.hit := commit_real_hit 1311 ftbEntryGen.mispredict_vec := commit_mispredict 1312 1313 update_ftb_entry := ftbEntryGen.new_entry 1314 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 1315 update.mispred_mask := ftbEntryGen.mispred_mask 1316 update.old_entry := ftbEntryGen.is_old_entry 1317 update.pred_hit := commit_hit === h_hit || commit_hit === h_false_hit 1318 update.br_taken_mask := ftbEntryGen.taken_mask 1319 update.br_committed := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map { 1320 case (valid, offset) => valid && commit_instCommited(offset) 1321 } 1322 update.jmp_taken := ftbEntryGen.jmp_taken 1323 1324 // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc) 1325 // update.full_pred.jalr_target := commit_target 1326 // update.full_pred.hit := true.B 1327 // when (update.full_pred.is_jalr) { 1328 // update.full_pred.targets.last := commit_target 1329 // } 1330 1331 // **************************************************************** 1332 // *********************** to prefetch **************************** 1333 // **************************************************************** 1334 /** 1335 ****************************************************************************** 1336 * prefetchPtr control 1337 * - 1. prefetchPtr plus 1 when toPrefetch fire and keep distance from bpuPtr more than 2 1338 * - 2. limit range of prefetchPtr is in [ifuPtr + minRange, ifuPtr + maxRange] 1339 * - 3. flush prefetchPtr when receive redirect from ifu or backend 1340 ****************************************************************************** 1341 */ 1342 val prefetchPtr = RegInit(FtqPtr(false.B, 0.U)) 1343 val nextPrefetchPtr = WireInit(prefetchPtr) 1344 1345 prefetchPtr := nextPrefetchPtr 1346 1347 // TODO: consider req which cross cacheline 1348 when(io.toPrefetch.req.fire) { 1349 when(prefetchPtr < bpuPtr - 2.U) { 1350 nextPrefetchPtr := prefetchPtr + 1.U 1351 } 1352 } 1353 1354 when(prefetchPtr < ifuPtr + minRangeFromIFUptr.U) { 1355 nextPrefetchPtr := ifuPtr + minRangeFromIFUptr.U 1356 }.elsewhen(prefetchPtr > ifuPtr + maxRangeFromIFUptr.U) { 1357 nextPrefetchPtr := ifuPtr + maxRangeFromIFUptr.U 1358 } 1359 1360 when(redirectVec.map(r => r.valid).reduce(_||_)){ 1361 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1362 val next = r.ftqIdx + minRangeFromIFUptr.U 1363 nextPrefetchPtr := next 1364 } 1365 1366 // data from ftq_pc_mem has 1 cycle delay 1367 io.toPrefetch.req.valid := RegNext(entry_fetch_status(nextPrefetchPtr.value) === f_to_send) 1368 ftq_pc_mem.io.other_raddrs(0) := nextPrefetchPtr.value 1369 io.toPrefetch.req.bits.target := RegNext(ftq_pc_mem.io.other_rdatas(0).startAddr) 1370 1371 // record position relationship between ifuPtr, pfPtr and bpuPtr 1372 val hartId = p(XSCoreParamsKey).HartId 1373 val isWritePrefetchPtrTable = Constantin.createRecord(s"isWritePrefetchPtrTable$hartId") 1374 val prefetchPtrTable = ChiselDB.createTable(s"PrefetchPtrTable$hartId", new PrefetchPtrDB) 1375 val prefetchPtrDumpData = Wire(new PrefetchPtrDB) 1376 prefetchPtrDumpData.fromFtqPtr := distanceBetween(bpuPtr, prefetchPtr) 1377 prefetchPtrDumpData.fromIfuPtr := distanceBetween(prefetchPtr, ifuPtr) 1378 1379 prefetchPtrTable.log( 1380 data = prefetchPtrDumpData, 1381 en = isWritePrefetchPtrTable.orR && io.toPrefetch.req.fire, 1382 site = "FTQ" + p(XSCoreParamsKey).HartId.toString, 1383 clock = clock, 1384 reset = reset 1385 ) 1386 1387 1388 // ****************************************************************************** 1389 // **************************** commit perf counters **************************** 1390 // ****************************************************************************** 1391 1392 val commit_inst_mask = VecInit(commit_state.map(c => c === c_committed && do_commit)).asUInt 1393 val commit_mispred_mask = commit_mispredict.asUInt 1394 val commit_not_mispred_mask = ~commit_mispred_mask 1395 1396 val commit_br_mask = commit_pd.brMask.asUInt 1397 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 1398 val commit_cfi_mask = (commit_br_mask | commit_jmp_mask) 1399 1400 val mbpInstrs = commit_inst_mask & commit_cfi_mask 1401 1402 val mbpRights = mbpInstrs & commit_not_mispred_mask 1403 val mbpWrongs = mbpInstrs & commit_mispred_mask 1404 1405 io.bpuInfo.bpRight := PopCount(mbpRights) 1406 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 1407 1408 val isWriteFTQTable = Constantin.createRecord(s"isWriteFTQTable$hartId") 1409 val ftqBranchTraceDB = ChiselDB.createTable(s"FTQTable$hartId", new FtqDebugBundle) 1410 // Cfi Info 1411 for (i <- 0 until PredictWidth) { 1412 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 1413 val v = commit_state(i) === c_committed 1414 val isBr = commit_pd.brMask(i) 1415 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 1416 val isCfi = isBr || isJmp 1417 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 1418 val misPred = commit_mispredict(i) 1419 // val ghist = commit_spec_meta.ghist.predHist 1420 val histPtr = commit_spec_meta.histPtr 1421 val predCycle = commit_meta(63, 0) 1422 val target = commit_target 1423 1424 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}))) 1425 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_) 1426 val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)) 1427 XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 1428 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " + 1429 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 1430 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n") 1431 1432 val logbundle = Wire(new FtqDebugBundle) 1433 logbundle.pc := pc 1434 logbundle.target := target 1435 logbundle.isBr := isBr 1436 logbundle.isJmp := isJmp 1437 logbundle.isCall := isJmp && commit_pd.hasCall 1438 logbundle.isRet := isJmp && commit_pd.hasRet 1439 logbundle.misPred := misPred 1440 logbundle.isTaken := isTaken 1441 logbundle.predStage := commit_stage 1442 1443 ftqBranchTraceDB.log( 1444 data = logbundle /* hardware of type T */, 1445 en = isWriteFTQTable.orR && v && do_commit && isCfi, 1446 site = "FTQ" + p(XSCoreParamsKey).HartId.toString, 1447 clock = clock, 1448 reset = reset 1449 ) 1450 } 1451 1452 val enq = io.fromBpu.resp 1453 val perf_redirect = backendRedirect 1454 1455 XSPerfAccumulate("entry", validEntries) 1456 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 1457 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 1458 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 1459 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 1460 1461 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 1462 1463 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 1464 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 1465 XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr) 1466 XSPerfAccumulate("bpu_to_ifu_bubble_when_ftq_full", (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready) 1467 1468 XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_|_)) 1469 XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid) 1470 XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid) 1471 1472 val from_bpu = io.fromBpu.resp.bits 1473 val to_ifu = io.toIfu.req.bits 1474 1475 1476 XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth+1, 1) 1477 1478 1479 1480 1481 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 1482 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 1483 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 1484 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 1485 1486 1487 val mbpBRights = mbpRights & commit_br_mask 1488 val mbpJRights = mbpRights & commit_jal_mask 1489 val mbpIRights = mbpRights & commit_jalr_mask 1490 val mbpCRights = mbpRights & commit_call_mask 1491 val mbpRRights = mbpRights & commit_ret_mask 1492 1493 val mbpBWrongs = mbpWrongs & commit_br_mask 1494 val mbpJWrongs = mbpWrongs & commit_jal_mask 1495 val mbpIWrongs = mbpWrongs & commit_jalr_mask 1496 val mbpCWrongs = mbpWrongs & commit_call_mask 1497 val mbpRWrongs = mbpWrongs & commit_ret_mask 1498 1499 val commit_pred_stage = RegNext(pred_stage(commPtr.value)) 1500 1501 def pred_stage_map(src: UInt, name: String) = { 1502 (0 until numBpStages).map(i => 1503 f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i))) 1504 ).foldLeft(Map[String, UInt]())(_+_) 1505 } 1506 1507 val mispred_stage_map = pred_stage_map(mbpWrongs, "mispredict") 1508 val br_mispred_stage_map = pred_stage_map(mbpBWrongs, "br_mispredict") 1509 val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict") 1510 val correct_stage_map = pred_stage_map(mbpRights, "correct") 1511 val br_correct_stage_map = pred_stage_map(mbpBRights, "br_correct") 1512 val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct") 1513 1514 val update_valid = io.toBpu.update.valid 1515 def u(cond: Bool) = update_valid && cond 1516 val ftb_false_hit = u(update.false_hit) 1517 // assert(!ftb_false_hit) 1518 val ftb_hit = u(commit_hit === h_hit) 1519 1520 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1521 val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid 1522 val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0) 1523 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid 1524 1525 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1526 1527 val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified) 1528 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1529 val ftb_modified_entry_ifu_redirected = u(ifuRedirected(do_commit_ptr.value)) 1530 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1531 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1532 val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified 1533 1534 def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits 1535 val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry) 1536 XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth+1, 1) 1537 XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth+1, 1) 1538 val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry) 1539 XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth+1, 1) 1540 1541 XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize+1, 1) 1542 1543 val perfCountsMap = Map( 1544 "BpInstr" -> PopCount(mbpInstrs), 1545 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1546 "BpRight" -> PopCount(mbpRights), 1547 "BpWrong" -> PopCount(mbpWrongs), 1548 "BpBRight" -> PopCount(mbpBRights), 1549 "BpBWrong" -> PopCount(mbpBWrongs), 1550 "BpJRight" -> PopCount(mbpJRights), 1551 "BpJWrong" -> PopCount(mbpJWrongs), 1552 "BpIRight" -> PopCount(mbpIRights), 1553 "BpIWrong" -> PopCount(mbpIWrongs), 1554 "BpCRight" -> PopCount(mbpCRights), 1555 "BpCWrong" -> PopCount(mbpCWrongs), 1556 "BpRRight" -> PopCount(mbpRRights), 1557 "BpRWrong" -> PopCount(mbpRWrongs), 1558 1559 "ftb_false_hit" -> PopCount(ftb_false_hit), 1560 "ftb_hit" -> PopCount(ftb_hit), 1561 "ftb_new_entry" -> PopCount(ftb_new_entry), 1562 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1563 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1564 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1565 "ftb_old_entry" -> PopCount(ftb_old_entry), 1566 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1567 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1568 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1569 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1570 "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken) 1571 ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++ 1572 correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map 1573 1574 for((key, value) <- perfCountsMap) { 1575 XSPerfAccumulate(key, value) 1576 } 1577 1578 // --------------------------- Debug -------------------------------- 1579 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1580 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1581 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1582 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1583 XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1584 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n") 1585 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1586 1587 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1588 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1589 // case (((valid, pd), ans), taken) => 1590 // Mux(valid && pd.isBr, 1591 // isWrong ^ Mux(ans.hit.asBool, 1592 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1593 // !taken), 1594 // !taken), 1595 // false.B) 1596 // } 1597 // } 1598 1599 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1600 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1601 // case (((valid, pd), ans), taken) => 1602 // Mux(valid && pd.isBr, 1603 // isWrong ^ Mux(ans.hit.asBool, 1604 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1605 // !taken), 1606 // !taken), 1607 // false.B) 1608 // } 1609 // } 1610 1611 // def tageCheck(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, 1615 // isWrong ^ (ans.taken.asBool === taken), 1616 // false.B) 1617 // } 1618 // } 1619 1620 // def loopCheck(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.isBr) && ans.hit.asBool, 1624 // isWrong ^ (!taken), 1625 // false.B) 1626 // } 1627 // } 1628 1629 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1630 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1631 // case (((valid, pd), ans), taken) => 1632 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1633 // isWrong ^ (ans.target === commitEntry.target), 1634 // false.B) 1635 // } 1636 // } 1637 1638 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1639 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1640 // // btb and ubtb pred jal and jalr as well 1641 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1642 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1643 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1644 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1645 1646 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1647 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1648 1649 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1650 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1651 1652 val perfEvents = Seq( 1653 ("bpu_s2_redirect ", bpu_s2_redirect ), 1654 ("bpu_s3_redirect ", bpu_s3_redirect ), 1655 ("bpu_to_ftq_stall ", enq.valid && ~enq.ready ), 1656 ("mispredictRedirect ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level), 1657 ("replayRedirect ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level) ), 1658 ("predecodeRedirect ", fromIfuRedirect.valid ), 1659 ("to_ifu_bubble ", io.toIfu.req.ready && !io.toIfu.req.valid ), 1660 ("from_bpu_real_bubble ", !enq.valid && enq.ready && allowBpuIn ), 1661 ("BpInstr ", PopCount(mbpInstrs) ), 1662 ("BpBInstr ", PopCount(mbpBRights | mbpBWrongs) ), 1663 ("BpRight ", PopCount(mbpRights) ), 1664 ("BpWrong ", PopCount(mbpWrongs) ), 1665 ("BpBRight ", PopCount(mbpBRights) ), 1666 ("BpBWrong ", PopCount(mbpBWrongs) ), 1667 ("BpJRight ", PopCount(mbpJRights) ), 1668 ("BpJWrong ", PopCount(mbpJWrongs) ), 1669 ("BpIRight ", PopCount(mbpIRights) ), 1670 ("BpIWrong ", PopCount(mbpIWrongs) ), 1671 ("BpCRight ", PopCount(mbpCRights) ), 1672 ("BpCWrong ", PopCount(mbpCWrongs) ), 1673 ("BpRRight ", PopCount(mbpRRights) ), 1674 ("BpRWrong ", PopCount(mbpRWrongs) ), 1675 ("ftb_false_hit ", PopCount(ftb_false_hit) ), 1676 ("ftb_hit ", PopCount(ftb_hit) ), 1677 ) 1678 generatePerfEvent() 1679} 1680