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