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