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