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 chipsalliance.rocketchip.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import utils._ 23import xiangshan._ 24import xiangshan.frontend.icache._ 25import xiangshan.backend.CtrlToFtqIO 26import xiangshan.backend.decode.ImmUnion 27 28class FtqPtr(implicit p: Parameters) extends CircularQueuePtr[FtqPtr]( 29 p => p(XSCoreParamsKey).FtqSize 30){ 31} 32 33object FtqPtr { 34 def apply(f: Bool, v: UInt)(implicit p: Parameters): FtqPtr = { 35 val ptr = Wire(new FtqPtr) 36 ptr.flag := f 37 ptr.value := v 38 ptr 39 } 40 def inverse(ptr: FtqPtr)(implicit p: Parameters): FtqPtr = { 41 apply(!ptr.flag, ptr.value) 42 } 43} 44 45class FtqNRSRAM[T <: Data](gen: T, numRead: Int)(implicit p: Parameters) extends XSModule { 46 47 val io = IO(new Bundle() { 48 val raddr = Input(Vec(numRead, UInt(log2Up(FtqSize).W))) 49 val ren = Input(Vec(numRead, Bool())) 50 val rdata = Output(Vec(numRead, gen)) 51 val waddr = Input(UInt(log2Up(FtqSize).W)) 52 val wen = Input(Bool()) 53 val wdata = Input(gen) 54 }) 55 56 for(i <- 0 until numRead){ 57 val sram = Module(new SRAMTemplate(gen, FtqSize)) 58 sram.io.r.req.valid := io.ren(i) 59 sram.io.r.req.bits.setIdx := io.raddr(i) 60 io.rdata(i) := sram.io.r.resp.data(0) 61 sram.io.w.req.valid := io.wen 62 sram.io.w.req.bits.setIdx := io.waddr 63 sram.io.w.req.bits.data := VecInit(io.wdata) 64 } 65 66} 67 68class Ftq_RF_Components(implicit p: Parameters) extends XSBundle with BPUUtils { 69 val startAddr = UInt(VAddrBits.W) 70 val nextLineAddr = UInt(VAddrBits.W) 71 val isNextMask = Vec(PredictWidth, Bool()) 72 val fallThruError = Bool() 73 // val carry = Bool() 74 def getPc(offset: UInt) = { 75 def getHigher(pc: UInt) = pc(VAddrBits-1, log2Ceil(PredictWidth)+instOffsetBits+1) 76 def getOffset(pc: UInt) = pc(log2Ceil(PredictWidth)+instOffsetBits, instOffsetBits) 77 Cat(getHigher(Mux(isNextMask(offset) && startAddr(log2Ceil(PredictWidth)+instOffsetBits), nextLineAddr, startAddr)), 78 getOffset(startAddr)+offset, 0.U(instOffsetBits.W)) 79 } 80 def fromBranchPrediction(resp: BranchPredictionBundle) = { 81 def carryPos(addr: UInt) = addr(instOffsetBits+log2Ceil(PredictWidth)+1) 82 this.startAddr := resp.pc 83 this.nextLineAddr := resp.pc + (FetchWidth * 4 * 2).U // may be broken on other configs 84 this.isNextMask := VecInit((0 until PredictWidth).map(i => 85 (resp.pc(log2Ceil(PredictWidth), 1) +& i.U)(log2Ceil(PredictWidth)).asBool() 86 )) 87 this.fallThruError := resp.fallThruError 88 this 89 } 90 override def toPrintable: Printable = { 91 p"startAddr:${Hexadecimal(startAddr)}" 92 } 93} 94 95class Ftq_pd_Entry(implicit p: Parameters) extends XSBundle { 96 val brMask = Vec(PredictWidth, Bool()) 97 val jmpInfo = ValidUndirectioned(Vec(3, Bool())) 98 val jmpOffset = UInt(log2Ceil(PredictWidth).W) 99 val jalTarget = UInt(VAddrBits.W) 100 val rvcMask = Vec(PredictWidth, Bool()) 101 def hasJal = jmpInfo.valid && !jmpInfo.bits(0) 102 def hasJalr = jmpInfo.valid && jmpInfo.bits(0) 103 def hasCall = jmpInfo.valid && jmpInfo.bits(1) 104 def hasRet = jmpInfo.valid && jmpInfo.bits(2) 105 106 def fromPdWb(pdWb: PredecodeWritebackBundle) = { 107 val pds = pdWb.pd 108 this.brMask := VecInit(pds.map(pd => pd.isBr && pd.valid)) 109 this.jmpInfo.valid := VecInit(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)).asUInt.orR 110 this.jmpInfo.bits := ParallelPriorityMux(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid), 111 pds.map(pd => VecInit(pd.isJalr, pd.isCall, pd.isRet))) 112 this.jmpOffset := ParallelPriorityEncoder(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)) 113 this.rvcMask := VecInit(pds.map(pd => pd.isRVC)) 114 this.jalTarget := pdWb.jalTarget 115 } 116 117 def toPd(offset: UInt) = { 118 require(offset.getWidth == log2Ceil(PredictWidth)) 119 val pd = Wire(new PreDecodeInfo) 120 pd.valid := true.B 121 pd.isRVC := rvcMask(offset) 122 val isBr = brMask(offset) 123 val isJalr = offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(0) 124 pd.brType := Cat(offset === jmpOffset && jmpInfo.valid, isJalr || isBr) 125 pd.isCall := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(1) 126 pd.isRet := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(2) 127 pd 128 } 129} 130 131 132 133class Ftq_Redirect_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst { 134 val rasSp = UInt(log2Ceil(RasSize).W) 135 val rasEntry = new RASEntry 136 // val specCnt = Vec(numBr, UInt(10.W)) 137 // val ghist = new ShiftingGlobalHistory 138 val folded_hist = new AllFoldedHistories(foldedGHistInfos) 139 val afhob = new AllAheadFoldedHistoryOldestBits(foldedGHistInfos) 140 val lastBrNumOH = UInt((numBr+1).W) 141 142 val histPtr = new CGHPtr 143 144 def fromBranchPrediction(resp: BranchPredictionBundle) = { 145 assert(!resp.is_minimal) 146 this.rasSp := resp.rasSp 147 this.rasEntry := resp.rasTop 148 this.folded_hist := resp.folded_hist 149 this.afhob := resp.afhob 150 this.lastBrNumOH := resp.lastBrNumOH 151 this.histPtr := resp.histPtr 152 this 153 } 154} 155 156class Ftq_1R_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst { 157 val meta = UInt(MaxMetaLength.W) 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 ptr = Output(new FtqPtr) 168 val offset = Output(UInt(log2Ceil(PredictWidth).W)) 169 val data = Input(gen) 170 def apply(ptr: FtqPtr, offset: UInt) = { 171 this.ptr := ptr 172 this.offset := offset 173 this.data 174 } 175} 176 177 178class FtqToBpuIO(implicit p: Parameters) extends XSBundle { 179 val redirect = Valid(new BranchPredictionRedirect) 180 val update = Valid(new BranchPredictionUpdate) 181 val enq_ptr = Output(new FtqPtr) 182} 183 184class FtqToIfuIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper { 185 val req = Decoupled(new FetchRequestBundle) 186 val redirect = Valid(new Redirect) 187 val flushFromBpu = new Bundle { 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} 199 200class FtqToICacheIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper { 201 //NOTE: req.bits must be prepare in T cycle 202 // while req.valid is set true in T + 1 cycle 203 val req = Decoupled(new FtqToICacheRequestBundle) 204} 205 206trait HasBackendRedirectInfo extends HasXSParameter { 207 def numRedirectPcRead = exuParameters.JmpCnt + exuParameters.AluCnt + 1 208 def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself() 209} 210 211class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo { 212 // write to backend pc mem 213 val pc_mem_wen = Output(Bool()) 214 val pc_mem_waddr = Output(UInt(log2Ceil(FtqSize).W)) 215 val pc_mem_wdata = Output(new Ftq_RF_Components) 216 val target = Output(UInt(VAddrBits.W)) 217 // predecode correct target 218 val pd_redirect_waddr = Valid(UInt(log2Ceil(FtqSize).W)) 219 val pd_redirect_target = Output(UInt(VAddrBits.W)) 220} 221 222 223class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter { 224 val io = IO(new Bundle { 225 val start_addr = Input(UInt(VAddrBits.W)) 226 val old_entry = Input(new FTBEntry) 227 val pd = Input(new Ftq_pd_Entry) 228 val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W))) 229 val target = Input(UInt(VAddrBits.W)) 230 val hit = Input(Bool()) 231 val mispredict_vec = Input(Vec(PredictWidth, Bool())) 232 233 val new_entry = Output(new FTBEntry) 234 val new_br_insert_pos = Output(Vec(numBr, Bool())) 235 val taken_mask = Output(Vec(numBr, Bool())) 236 val mispred_mask = Output(Vec(numBr+1, Bool())) 237 238 // for perf counters 239 val is_init_entry = Output(Bool()) 240 val is_old_entry = Output(Bool()) 241 val is_new_br = Output(Bool()) 242 val is_jalr_target_modified = Output(Bool()) 243 val is_always_taken_modified = Output(Bool()) 244 val is_br_full = Output(Bool()) 245 }) 246 247 // no mispredictions detected at predecode 248 val hit = io.hit 249 val pd = io.pd 250 251 val init_entry = WireInit(0.U.asTypeOf(new FTBEntry)) 252 253 254 val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid 255 val entry_has_jmp = pd.jmpInfo.valid 256 val new_jmp_is_jal = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid 257 val new_jmp_is_jalr = entry_has_jmp && pd.jmpInfo.bits(0) && io.cfiIndex.valid 258 val new_jmp_is_call = entry_has_jmp && pd.jmpInfo.bits(1) && io.cfiIndex.valid 259 val new_jmp_is_ret = entry_has_jmp && pd.jmpInfo.bits(2) && io.cfiIndex.valid 260 val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask.last 261 // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last 262 263 val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal 264 val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr 265 266 def carryPos = log2Ceil(PredictWidth)+instOffsetBits 267 def getLower(pc: UInt) = pc(carryPos-1, instOffsetBits) 268 // if not hit, establish a new entry 269 init_entry.valid := true.B 270 // tag is left for ftb to assign 271 272 // case br 273 val init_br_slot = init_entry.getSlotForBr(0) 274 when (cfi_is_br) { 275 init_br_slot.valid := true.B 276 init_br_slot.offset := io.cfiIndex.bits 277 init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1) 278 init_entry.always_taken(0) := true.B // set to always taken on init 279 } 280 281 // case jmp 282 when (entry_has_jmp) { 283 init_entry.tailSlot.offset := pd.jmpOffset 284 init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr 285 init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare=false) 286 } 287 288 val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U) 289 init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr)) 290 init_entry.carry := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos-instOffsetBits), true.B) 291 init_entry.isJalr := new_jmp_is_jalr 292 init_entry.isCall := new_jmp_is_call 293 init_entry.isRet := new_jmp_is_ret 294 // that means fall thru points to the middle of an inst 295 init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask(pd.jmpOffset) 296 297 // if hit, check whether a new cfi(only br is possible) is detected 298 val oe = io.old_entry 299 val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits) 300 val br_recorded = br_recorded_vec.asUInt.orR 301 val is_new_br = cfi_is_br && !br_recorded 302 val new_br_offset = io.cfiIndex.bits 303 // vec(i) means new br will be inserted BEFORE old br(i) 304 val allBrSlotsVec = oe.allSlotsForBr 305 val new_br_insert_onehot = VecInit((0 until numBr).map{ 306 i => i match { 307 case 0 => 308 !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset 309 case idx => 310 allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset && 311 (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset) 312 } 313 }) 314 315 val old_entry_modified = WireInit(io.old_entry) 316 for (i <- 0 until numBr) { 317 val slot = old_entry_modified.allSlotsForBr(i) 318 when (new_br_insert_onehot(i)) { 319 slot.valid := true.B 320 slot.offset := new_br_offset 321 slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr-1) 322 old_entry_modified.always_taken(i) := true.B 323 }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) { 324 old_entry_modified.always_taken(i) := false.B 325 // all other fields remain unchanged 326 }.otherwise { 327 // case i == 0, remain unchanged 328 if (i != 0) { 329 val noNeedToMoveFromFormerSlot = (i == numBr-1).B && !oe.brSlots.last.valid 330 when (!noNeedToMoveFromFormerSlot) { 331 slot.fromAnotherSlot(oe.allSlotsForBr(i-1)) 332 old_entry_modified.always_taken(i) := oe.always_taken(i) 333 } 334 } 335 } 336 } 337 338 // two circumstances: 339 // 1. oe: | br | j |, new br should be in front of j, thus addr of j should be new pft 340 // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either 341 // the previous last br or the new br 342 val may_have_to_replace = oe.noEmptySlotForNewBr 343 val pft_need_to_change = is_new_br && may_have_to_replace 344 // it should either be the given last br or the new br 345 when (pft_need_to_change) { 346 val new_pft_offset = 347 Mux(!new_br_insert_onehot.asUInt.orR, 348 new_br_offset, oe.allSlotsForBr.last.offset) 349 350 // set jmp to invalid 351 old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset 352 old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool 353 old_entry_modified.last_may_be_rvi_call := false.B 354 old_entry_modified.isCall := false.B 355 old_entry_modified.isRet := false.B 356 old_entry_modified.isJalr := false.B 357 } 358 359 val old_entry_jmp_target_modified = WireInit(oe) 360 val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits 361 val old_tail_is_jmp = !oe.tailSlot.sharing 362 val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target 363 when (jalr_target_modified) { 364 old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target) 365 old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool())) 366 } 367 368 val old_entry_always_taken = WireInit(oe) 369 val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not 370 for (i <- 0 until numBr) { 371 old_entry_always_taken.always_taken(i) := 372 oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i) 373 always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i) 374 } 375 val always_taken_modified = always_taken_modified_vec.reduce(_||_) 376 377 378 379 val derived_from_old_entry = 380 Mux(is_new_br, old_entry_modified, 381 Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken)) 382 383 384 io.new_entry := Mux(!hit, init_entry, derived_from_old_entry) 385 386 io.new_br_insert_pos := new_br_insert_onehot 387 io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{ 388 case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v 389 }) 390 for (i <- 0 until numBr) { 391 io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i)) 392 } 393 io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset) 394 395 // for perf counters 396 io.is_init_entry := !hit 397 io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified 398 io.is_new_br := hit && is_new_br 399 io.is_jalr_target_modified := hit && jalr_target_modified 400 io.is_always_taken_modified := hit && always_taken_modified 401 io.is_br_full := hit && is_new_br && may_have_to_replace 402} 403 404class FtqPcMemWrapper(numOtherReads: Int)(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo { 405 val io = IO(new Bundle { 406 val ifuPtr_w = Input(new FtqPtr) 407 val ifuPtrPlus1_w = Input(new FtqPtr) 408 val ifuPtrPlus2_w = Input(new FtqPtr) 409 val commPtr_w = Input(new FtqPtr) 410 val commPtrPlus1_w = Input(new FtqPtr) 411 val ifuPtr_rdata = Output(new Ftq_RF_Components) 412 val ifuPtrPlus1_rdata = Output(new Ftq_RF_Components) 413 val ifuPtrPlus2_rdata = Output(new Ftq_RF_Components) 414 val commPtr_rdata = Output(new Ftq_RF_Components) 415 val commPtrPlus1_rdata = Output(new Ftq_RF_Components) 416 417 val other_raddrs = Input(Vec(numOtherReads, UInt(log2Ceil(FtqSize).W))) 418 val other_rdatas = Output(Vec(numOtherReads, new Ftq_RF_Components)) 419 420 val wen = Input(Bool()) 421 val waddr = Input(UInt(log2Ceil(FtqSize).W)) 422 val wdata = Input(new Ftq_RF_Components) 423 }) 424 425 val num_pc_read = numOtherReads + 5 426 val mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, 427 num_pc_read, 1, "FtqPC", concatData=false, Some(Seq.tabulate(num_pc_read)(i => false)))) 428 mem.io.wen(0) := io.wen 429 mem.io.waddr(0) := io.waddr 430 mem.io.wdata(0) := io.wdata 431 432 // read one cycle ahead for ftq local reads 433 val raddr_vec = VecInit(io.other_raddrs ++ 434 Seq(io.ifuPtr_w.value, io.ifuPtrPlus1_w.value, io.ifuPtrPlus2_w.value, io.commPtrPlus1_w, io.commPtr_w.value)) 435 436 mem.io.raddr := raddr_vec 437 438 io.other_rdatas := mem.io.rdata.dropRight(5) 439 io.ifuPtr_rdata := mem.io.rdata.dropRight(4).last 440 io.ifuPtrPlus1_rdata := mem.io.rdata.dropRight(3).last 441 io.ifuPtrPlus2_rdata := mem.io.rdata.dropRight(2).last 442 io.commPtrPlus1_rdata := mem.io.rdata.dropRight(1).last 443 io.commPtr_rdata := mem.io.rdata.last 444} 445 446class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper 447 with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents 448 with HasICacheParameters{ 449 val io = IO(new Bundle { 450 val fromBpu = Flipped(new BpuToFtqIO) 451 val fromIfu = Flipped(new IfuToFtqIO) 452 val fromBackend = Flipped(new CtrlToFtqIO) 453 454 val toBpu = new FtqToBpuIO 455 val toIfu = new FtqToIfuIO 456 val toICache = new FtqToICacheIO 457 val toBackend = new FtqToCtrlIO 458 459 val toPrefetch = new FtqPrefechBundle 460 461 val bpuInfo = new Bundle { 462 val bpRight = Output(UInt(XLEN.W)) 463 val bpWrong = Output(UInt(XLEN.W)) 464 } 465 }) 466 io.bpuInfo := DontCare 467 468 val backendRedirect = Wire(Valid(new Redirect)) 469 val backendRedirectReg = RegNext(backendRedirect) 470 471 val stage2Flush = backendRedirect.valid 472 val backendFlush = stage2Flush || RegNext(stage2Flush) 473 val ifuFlush = Wire(Bool()) 474 475 val flush = stage2Flush || RegNext(stage2Flush) 476 477 val allowBpuIn, allowToIfu = WireInit(false.B) 478 val flushToIfu = !allowToIfu 479 allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 480 allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid 481 482 val bpuPtr, ifuPtr, ifuWbPtr, commPtr = RegInit(FtqPtr(false.B, 0.U)) 483 val ifuPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 484 val ifuPtrPlus2 = RegInit(FtqPtr(false.B, 2.U)) 485 val commPtrPlus1 = RegInit(FtqPtr(false.B, 1.U)) 486 require(FtqSize >= 4) 487 val ifuPtr_write = WireInit(ifuPtr) 488 val ifuPtrPlus1_write = WireInit(ifuPtrPlus1) 489 val ifuPtrPlus2_write = WireInit(ifuPtrPlus2) 490 val ifuWbPtr_write = WireInit(ifuWbPtr) 491 val commPtr_write = WireInit(commPtr) 492 val commPtrPlus1_write = WireInit(commPtrPlus1) 493 ifuPtr := ifuPtr_write 494 ifuPtrPlus1 := ifuPtrPlus1_write 495 ifuPtrPlus2 := ifuPtrPlus2_write 496 ifuWbPtr := ifuWbPtr_write 497 commPtr := commPtr_write 498 commPtrPlus1 := commPtr_write 499 val validEntries = distanceBetween(bpuPtr, commPtr) 500 501 // ********************************************************************** 502 // **************************** enq from bpu **************************** 503 // ********************************************************************** 504 val new_entry_ready = validEntries < FtqSize.U 505 io.fromBpu.resp.ready := new_entry_ready 506 507 val bpu_s2_resp = io.fromBpu.resp.bits.s2 508 val bpu_s3_resp = io.fromBpu.resp.bits.s3 509 val bpu_s2_redirect = bpu_s2_resp.valid && bpu_s2_resp.hasRedirect 510 val bpu_s3_redirect = bpu_s3_resp.valid && bpu_s3_resp.hasRedirect 511 512 io.toBpu.enq_ptr := bpuPtr 513 val enq_fire = io.fromBpu.resp.fire() && allowBpuIn // from bpu s1 514 val bpu_in_fire = (io.fromBpu.resp.fire() || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn 515 516 val bpu_in_resp = io.fromBpu.resp.bits.selectedResp 517 val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdx 518 val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx) 519 val bpu_in_resp_idx = bpu_in_resp_ptr.value 520 521 // read ports: prefetchReq ++ ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate 522 val ftq_pc_mem = Module(new FtqPcMemWrapper(1)) 523 // resp from uBTB 524 ftq_pc_mem.io.wen := bpu_in_fire 525 ftq_pc_mem.io.waddr := bpu_in_resp_idx 526 ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp) 527 528 // ifuRedirect + backendRedirect + commit 529 val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+1+1)) 530 // these info is intended to enq at the last stage of bpu 531 ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid 532 ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 533 ftq_redirect_sram.io.wdata.fromBranchPrediction(io.fromBpu.resp.bits.lastStage) 534 println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3") 535 println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3") 536 537 val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1)) 538 // these info is intended to enq at the last stage of bpu 539 ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid 540 ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 541 ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.meta 542 // ifuRedirect + backendRedirect + commit 543 val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+1+1, 1)) 544 ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid 545 ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value 546 ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.lastStage.ftb_entry 547 548 549 // multi-write 550 val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this 551 val newest_entry_target = Reg(UInt(VAddrBits.W)) 552 val newest_entry_ptr = Reg(new FtqPtr) 553 val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))) 554 val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool()))) 555 val pred_stage = Reg(Vec(FtqSize, UInt(2.W))) 556 557 val c_invalid :: c_valid :: c_commited :: Nil = Enum(3) 558 val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) { 559 VecInit(Seq.fill(PredictWidth)(c_invalid)) 560 })) 561 562 val f_to_send :: f_sent :: Nil = Enum(2) 563 val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent))) 564 565 val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3) 566 val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit))) 567 568 // modify registers one cycle later to cut critical path 569 val last_cycle_bpu_in = RegNext(bpu_in_fire) 570 val last_cycle_bpu_in_ptr = RegNext(bpu_in_resp_ptr) 571 val last_cycle_bpu_in_idx = last_cycle_bpu_in_ptr.value 572 val last_cycle_bpu_target = RegNext(bpu_in_resp.getTarget) 573 val last_cycle_cfiIndex = RegNext(bpu_in_resp.cfiIndex) 574 val last_cycle_bpu_in_stage = RegNext(bpu_in_stage) 575 when (last_cycle_bpu_in) { 576 entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send 577 commitStateQueue(last_cycle_bpu_in_idx) := VecInit(Seq.fill(PredictWidth)(c_invalid)) 578 cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex 579 mispredict_vec(last_cycle_bpu_in_idx) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B))) 580 pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage 581 582 update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this 583 newest_entry_target := last_cycle_bpu_target 584 newest_entry_ptr := last_cycle_bpu_in_ptr 585 } 586 587 588 bpuPtr := bpuPtr + enq_fire 589 when (io.toIfu.req.fire && allowToIfu) { 590 ifuPtr_write := ifuPtrPlus1 591 ifuPtrPlus1_write := ifuPtrPlus2 592 ifuPtrPlus2_write := ifuPtrPlus2 + 1.U 593 } 594 595 // only use ftb result to assign hit status 596 when (bpu_s2_resp.valid) { 597 entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred.hit, h_hit, h_not_hit) 598 } 599 600 601 io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect 602 io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx 603 when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect) { 604 bpuPtr := bpu_s2_resp.ftq_idx + 1.U 605 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 606 when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) { 607 ifuPtr_write := bpu_s2_resp.ftq_idx 608 ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U 609 ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U 610 } 611 } 612 613 io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect 614 io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx 615 when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect) { 616 bpuPtr := bpu_s3_resp.ftq_idx + 1.U 617 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 618 when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) { 619 ifuPtr_write := bpu_s3_resp.ftq_idx 620 ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U 621 ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U 622 } 623 } 624 625 XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n") 626 627 // **************************************************************** 628 // **************************** to ifu **************************** 629 // **************************************************************** 630 // 0 for ifu, and 1-4 for ICache 631 val bpu_in_bypass_buf = VecInit(Seq.fill(5)(RegEnable(ftq_pc_mem.io.wdata, enable=bpu_in_fire))) 632 val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr) 633 val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire) 634 635 // read pc and target 636 ftq_pc_mem.io.ifuPtr_w := ifuPtr_write 637 ftq_pc_mem.io.ifuPtrPlus1_w := ifuPtrPlus1_write 638 ftq_pc_mem.io.ifuPtrPlus2_w := ifuPtrPlus2_write 639 ftq_pc_mem.io.commPtr_w := commPtr_write 640 ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write 641 642 643 io.toIfu.req.bits.ftqIdx := ifuPtr 644 645 val toICachePcBundle = WireInit(ftq_pc_mem.io.ifuPtr_rdata) 646 val toIfuPcBundle = Wire(new Ftq_RF_Components) 647 val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send) 648 val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value)) 649 val entry_next_addr = Wire(UInt(VAddrBits.W)) 650 val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this 651 652 when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) { 653 toIfuPcBundle := bpu_in_bypass_buf.head 654 entry_is_to_send := true.B 655 entry_next_addr := last_cycle_bpu_target 656 entry_ftq_offset := last_cycle_cfiIndex 657 diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this 658 }.elsewhen (last_cycle_to_ifu_fire) { 659 toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata) 660 toICachePcBundle := ftq_pc_mem.io.ifuPtrPlus1_rdata 661 entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) || 662 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles 663 entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1), 664 bpu_in_bypass_buf.startAddr, 665 Mux(isFull(ifuPtrPlus1, commPtr), 666 newest_entry_target, 667 ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr)) // ifuPtr+2 668 }.otherwise { 669 toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata) 670 //toICachePcBundle := ftq_pc_mem.io.ifuPtr_rdata 671 entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) 672 entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1), 673 bpu_in_bypass_buf.startAddr, 674 Mux(isFull(ifuPtrPlus1, commPtr), 675 newest_entry_target, 676 ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr)) // ifuPtr+1 677 } 678 679 io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 680 io.toIfu.req.bits.nextStartAddr := entry_next_addr 681 io.toIfu.req.bits.ftqOffset := entry_ftq_offset 682 io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle) 683 684 io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 685 io.toICache.req.bits.fromFtqPcBundle(toICachePcBundle) 686 io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr 687 io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) => 688 bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr 689 bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr 690 } 691 692 // TODO: remove this 693 XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr, 694 p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n") 695 696 // when fall through is smaller in value than start address, there must be a false hit 697 when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) { 698 when (io.toIfu.req.fire && 699 !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && 700 !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr) 701 ) { 702 entry_hit_status(ifuPtr.value) := h_false_hit 703 // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 704 } 705 XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 706 } 707 708 XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit && 709 io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)) 710 711 val ifu_req_should_be_flushed = 712 io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) || 713 io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx) 714 715 when (io.toIfu.req.fire && !ifu_req_should_be_flushed) { 716 entry_fetch_status(ifuPtr.value) := f_sent 717 } 718 719 // ********************************************************************* 720 // **************************** wb from ifu **************************** 721 // ********************************************************************* 722 val pdWb = io.fromIfu.pdWb 723 val pds = pdWb.bits.pd 724 val ifu_wb_valid = pdWb.valid 725 val ifu_wb_idx = pdWb.bits.ftqIdx.value 726 // read ports: commit update 727 val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1)) 728 ftq_pd_mem.io.wen(0) := ifu_wb_valid 729 ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value 730 ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits) 731 732 val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid 733 val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid 734 val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B) 735 val pd_reg = RegEnable(pds, pdWb.valid) 736 val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid) 737 val wb_idx_reg = RegEnable(ifu_wb_idx, pdWb.valid) 738 739 when (ifu_wb_valid) { 740 val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{ 741 case (v, inRange) => v && inRange 742 }) 743 (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{ 744 case (qe, v) => when (v) { qe := c_valid } 745 } 746 } 747 748 when (ifu_wb_valid) { 749 ifuWbPtr_write := ifuWbPtr + 1.U 750 } 751 752 ftb_entry_mem.io.raddr.head := ifu_wb_idx 753 val has_false_hit = WireInit(false.B) 754 when (RegNext(hit_pd_valid)) { 755 // check for false hit 756 val pred_ftb_entry = ftb_entry_mem.io.rdata.head 757 val brSlots = pred_ftb_entry.brSlots 758 val tailSlot = pred_ftb_entry.tailSlot 759 // we check cfis that bpu predicted 760 761 // bpu predicted branches but denied by predecode 762 val br_false_hit = 763 brSlots.map{ 764 s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr) 765 }.reduce(_||_) || 766 (tailSlot.valid && pred_ftb_entry.tailSlot.sharing && 767 !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr)) 768 769 val jmpOffset = tailSlot.offset 770 val jmp_pd = pd_reg(jmpOffset) 771 val jal_false_hit = pred_ftb_entry.jmpValid && 772 ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) || 773 (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) || 774 (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) || 775 (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)) 776 ) 777 778 has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg 779 XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0)) 780 781 // assert(!has_false_hit) 782 } 783 784 when (has_false_hit) { 785 entry_hit_status(wb_idx_reg) := h_false_hit 786 } 787 788 789 // ********************************************************************** 790 // ***************************** to backend ***************************** 791 // ********************************************************************** 792 // to backend pc mem / target 793 io.toBackend.pc_mem_wen := RegNext(last_cycle_bpu_in) 794 io.toBackend.pc_mem_waddr := RegNext(last_cycle_bpu_in_idx) 795 io.toBackend.pc_mem_wdata := RegNext(bpu_in_bypass_buf.head) 796 io.toBackend.target := RegNext(last_cycle_bpu_target) 797 798 // ******************************************************************************* 799 // **************************** redirect from backend **************************** 800 // ******************************************************************************* 801 802 // redirect read cfiInfo, couples to redirectGen s2 803 ftq_redirect_sram.io.ren.init.last := backendRedirect.valid 804 ftq_redirect_sram.io.raddr.init.last := backendRedirect.bits.ftqIdx.value 805 806 ftb_entry_mem.io.raddr.init.last := backendRedirect.bits.ftqIdx.value 807 808 val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last 809 val fromBackendRedirect = WireInit(backendRedirectReg) 810 val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate 811 backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo) 812 813 val r_ftb_entry = ftb_entry_mem.io.rdata.init.last 814 val r_ftqOffset = fromBackendRedirect.bits.ftqOffset 815 816 when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) { 817 backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +& 818 (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) && 819 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 820 821 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) || 822 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 823 }.otherwise { 824 backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt 825 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt 826 } 827 828 829 // *************************************************************************** 830 // **************************** redirect from ifu **************************** 831 // *************************************************************************** 832 val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect))) 833 fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush 834 fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx 835 fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits 836 fromIfuRedirect.bits.level := RedirectLevel.flushAfter 837 838 val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate 839 ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits) 840 ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits) 841 ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid 842 ifuRedirectCfiUpdate.target := pdWb.bits.target 843 ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid 844 ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid 845 846 val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect))) 847 val ifuRedirectToBpu = WireInit(ifuRedirectReg) 848 ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid 849 850 ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid 851 ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 852 853 ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 854 855 val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate 856 toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head) 857 when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) { 858 toBpuCfi.target := toBpuCfi.rasEntry.retAddr 859 } 860 861 // ********************************************************************* 862 // **************************** wb from exu **************************** 863 // ********************************************************************* 864 865 backendRedirect := io.fromBackend.redirect 866 867 def extractRedirectInfo(wb: Valid[Redirect]) = { 868 val ftqPtr = wb.bits.ftqIdx 869 val ftqOffset = wb.bits.ftqOffset 870 val taken = wb.bits.cfiUpdate.taken 871 val mispred = wb.bits.cfiUpdate.isMisPred 872 (wb.valid, ftqPtr, ftqOffset, taken, mispred) 873 } 874 875 // fix mispredict entry 876 val lastIsMispredict = RegNext( 877 backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B 878 ) 879 880 def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = { 881 val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect) 882 val r_idx = r_ptr.value 883 val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits 884 val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits 885 when (cfiIndex_bits_wen || cfiIndex_valid_wen) { 886 cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken 887 } 888 when (cfiIndex_bits_wen) { 889 cfiIndex_vec(r_idx).bits := r_offset 890 } 891 when (newest_entry_ptr === r_ptr && isFull(newest_entry_ptr, commPtr)){ 892 newest_entry_target := redirect.bits.cfiUpdate.target 893 } 894 update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this 895 if (isBackend) { 896 mispredict_vec(r_idx)(r_offset) := r_mispred 897 } 898 } 899 900 // write to backend target vec 901 io.toBackend.pd_redirect_waddr.valid := RegNext(fromIfuRedirect.valid) 902 io.toBackend.pd_redirect_waddr.bits := RegNext(fromIfuRedirect.bits.ftqIdx.value) 903 io.toBackend.pd_redirect_target := RegNext(fromIfuRedirect.bits.cfiUpdate.target) 904 905 // write to backend target vec 906 io.toBackend.pd_redirect_waddr.valid := RegNext(fromIfuRedirect.valid) 907 io.toBackend.pd_redirect_waddr.bits := RegNext(fromIfuRedirect.bits.ftqIdx.value) 908 io.toBackend.pd_redirect_target := RegNext(fromIfuRedirect.bits.cfiUpdate.target) 909 910 io.toBackend.pd_redirect_waddr.valid := false.B 911 io.toBackend.pd_redirect_waddr.bits := ifuRedirectToBpu.bits.ftqIdx.value 912 io.toBackend.pd_redirect_target := ifuRedirectToBpu.bits.cfiUpdate.target 913 914 when(backendRedirectReg.valid && lastIsMispredict) { 915 updateCfiInfo(backendRedirectReg) 916 }.elsewhen (ifuRedirectToBpu.valid) { 917 updateCfiInfo(ifuRedirectToBpu, isBackend=false) 918 } 919 920 // *********************************************************************************** 921 // **************************** flush ptr and state queue **************************** 922 // *********************************************************************************** 923 924 val redirectVec = VecInit(backendRedirect, fromIfuRedirect) 925 926 // when redirect, we should reset ptrs and status queues 927 when(redirectVec.map(r => r.valid).reduce(_||_)){ 928 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 929 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 930 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 931 val next = idx + 1.U 932 bpuPtr := next 933 ifuPtr_write := next 934 ifuWbPtr_write := next 935 ifuPtrPlus1_write := idx + 2.U 936 ifuPtrPlus2_write := idx + 3.U 937 when (notIfu) { 938 commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) => 939 when(i.U > offset || i.U === offset && flushItSelf){ 940 s := c_invalid 941 } 942 }) 943 } 944 } 945 946 // only the valid bit is actually needed 947 io.toIfu.redirect.bits := backendRedirect.bits 948 io.toIfu.redirect.valid := stage2Flush 949 950 // commit 951 for (c <- io.fromBackend.rob_commits) { 952 when(c.valid) { 953 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited 954 // TODO: remove this 955 // For instruction fusions, we also update the next instruction 956 when (c.bits.commitType === 4.U) { 957 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited 958 }.elsewhen(c.bits.commitType === 5.U) { 959 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited 960 }.elsewhen(c.bits.commitType === 6.U) { 961 val index = (c.bits.ftqIdx + 1.U).value 962 commitStateQueue(index)(0) := c_commited 963 }.elsewhen(c.bits.commitType === 7.U) { 964 val index = (c.bits.ftqIdx + 1.U).value 965 commitStateQueue(index)(1) := c_commited 966 } 967 } 968 } 969 970 // **************************************************************** 971 // **************************** to bpu **************************** 972 // **************************************************************** 973 974 io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 975 976 val may_have_stall_from_bpu = Wire(Bool()) 977 val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states 978 may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U 979 val canCommit = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 980 Cat(commitStateQueue(commPtr.value).map(s => { 981 s === c_invalid || s === c_commited 982 })).andR() 983 984 // commit reads 985 val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata) 986 val commit_target = RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr) 987 ftq_pd_mem.io.raddr.last := commPtr.value 988 val commit_pd = ftq_pd_mem.io.rdata.last 989 ftq_redirect_sram.io.ren.last := canCommit 990 ftq_redirect_sram.io.raddr.last := commPtr.value 991 val commit_spec_meta = ftq_redirect_sram.io.rdata.last 992 ftq_meta_1r_sram.io.ren(0) := canCommit 993 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 994 val commit_meta = ftq_meta_1r_sram.io.rdata(0) 995 ftb_entry_mem.io.raddr.last := commPtr.value 996 val commit_ftb_entry = ftb_entry_mem.io.rdata.last 997 998 // need one cycle to read mem and srams 999 val do_commit_ptr = RegNext(commPtr) 1000 val do_commit = RegNext(canCommit, init=false.B) 1001 when (canCommit) { 1002 commPtr_write := commPtrPlus1 1003 commPtrPlus1_write := commPtrPlus1 + 1.U 1004 } 1005 val commit_state = RegNext(commitStateQueue(commPtr.value)) 1006 val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value)) 1007 when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) { 1008 can_commit_cfi.valid := false.B 1009 } 1010 val commit_cfi = RegNext(can_commit_cfi) 1011 1012 val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map { 1013 case (mis, state) => mis && state === c_commited 1014 }) 1015 val can_commit_hit = entry_hit_status(commPtr.value) 1016 val commit_hit = RegNext(can_commit_hit) 1017 val diff_commit_target = RegNext(update_target(commPtr.value)) // TODO: remove this 1018 val commit_stage = RegNext(pred_stage(commPtr.value)) 1019 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 1020 1021 val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit 1022 switch (bpu_ftb_update_stall) { 1023 is (0.U) { 1024 when (can_commit_cfi.valid && !to_bpu_hit && canCommit) { 1025 bpu_ftb_update_stall := 2.U // 2-cycle stall 1026 } 1027 } 1028 is (2.U) { 1029 bpu_ftb_update_stall := 1.U 1030 } 1031 is (1.U) { 1032 bpu_ftb_update_stall := 0.U 1033 } 1034 is (3.U) { 1035 XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2") 1036 } 1037 } 1038 1039 // TODO: remove this 1040 XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n") 1041 1042 io.toBpu.update := DontCare 1043 io.toBpu.update.valid := commit_valid && do_commit 1044 val update = io.toBpu.update.bits 1045 update.false_hit := commit_hit === h_false_hit 1046 update.pc := commit_pc_bundle.startAddr 1047 update.meta := commit_meta.meta 1048 update.full_target := commit_target 1049 update.from_stage := commit_stage 1050 update.fromFtqRedirectSram(commit_spec_meta) 1051 1052 val commit_real_hit = commit_hit === h_hit 1053 val update_ftb_entry = update.ftb_entry 1054 1055 val ftbEntryGen = Module(new FTBEntryGen).io 1056 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 1057 ftbEntryGen.old_entry := commit_ftb_entry 1058 ftbEntryGen.pd := commit_pd 1059 ftbEntryGen.cfiIndex := commit_cfi 1060 ftbEntryGen.target := commit_target 1061 ftbEntryGen.hit := commit_real_hit 1062 ftbEntryGen.mispredict_vec := commit_mispredict 1063 1064 update_ftb_entry := ftbEntryGen.new_entry 1065 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 1066 update.mispred_mask := ftbEntryGen.mispred_mask 1067 update.old_entry := ftbEntryGen.is_old_entry 1068 update.pred_hit := commit_hit === h_hit || commit_hit === h_false_hit 1069 1070 update.is_minimal := false.B 1071 update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc) 1072 update.full_pred.br_taken_mask := ftbEntryGen.taken_mask 1073 update.full_pred.jalr_target := commit_target 1074 update.full_pred.hit := true.B 1075 when (update.full_pred.is_jalr) { 1076 update.full_pred.targets.last := commit_target 1077 } 1078 1079 // **************************************************************** 1080 // *********************** to prefetch **************************** 1081 // **************************************************************** 1082 1083 if(cacheParams.hasPrefetch){ 1084 val prefetchPtr = RegInit(FtqPtr(false.B, 0.U)) 1085 val diff_prefetch_addr = WireInit(update_target(prefetchPtr.value)) //TODO: remove this 1086 1087 prefetchPtr := prefetchPtr + io.toPrefetch.req.fire() 1088 1089 ftq_pc_mem.io.other_raddrs(0) := prefetchPtr.value 1090 1091 when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s2_resp.ftq_idx)) { 1092 prefetchPtr := bpu_s2_resp.ftq_idx 1093 } 1094 1095 when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s3_resp.ftq_idx)) { 1096 prefetchPtr := bpu_s3_resp.ftq_idx 1097 // XSError(true.B, "\ns3_redirect mechanism not implemented!\n") 1098 } 1099 1100 1101 val prefetch_is_to_send = WireInit(entry_fetch_status(prefetchPtr.value) === f_to_send) 1102 val prefetch_addr = WireInit( ftq_pc_mem.io.other_rdatas(0).startAddr) 1103 1104 when (last_cycle_bpu_in && bpu_in_bypass_ptr === prefetchPtr) { 1105 prefetch_is_to_send := true.B 1106 prefetch_addr := last_cycle_bpu_target 1107 diff_prefetch_addr := last_cycle_bpu_target // TODO: remove this 1108 } 1109 io.toPrefetch.req.valid := prefetchPtr =/= bpuPtr && prefetch_is_to_send 1110 io.toPrefetch.req.bits.target := prefetch_addr 1111 1112 when(redirectVec.map(r => r.valid).reduce(_||_)){ 1113 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 1114 val next = r.ftqIdx + 1.U 1115 prefetchPtr := next 1116 } 1117 1118 // TODO: remove this 1119 // XSError(io.toPrefetch.req.valid && diff_prefetch_addr =/= prefetch_addr, 1120 // f"\nprefetch_req_target wrong! prefetchPtr: ${prefetchPtr}, prefetch_addr: ${Hexadecimal(prefetch_addr)} diff_prefetch_addr: ${Hexadecimal(diff_prefetch_addr)}\n") 1121 1122 1123 XSError(isBefore(bpuPtr, prefetchPtr) && !isFull(bpuPtr, prefetchPtr), "\nprefetchPtr is before bpuPtr!\n") 1124 XSError(isBefore(prefetchPtr, ifuPtr) && !isFull(ifuPtr, prefetchPtr), "\nifuPtr is before prefetchPtr!\n") 1125 } 1126 else { 1127 io.toPrefetch.req <> DontCare 1128 } 1129 1130 // ****************************************************************************** 1131 // **************************** commit perf counters **************************** 1132 // ****************************************************************************** 1133 1134 val commit_inst_mask = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt 1135 val commit_mispred_mask = commit_mispredict.asUInt 1136 val commit_not_mispred_mask = ~commit_mispred_mask 1137 1138 val commit_br_mask = commit_pd.brMask.asUInt 1139 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 1140 val commit_cfi_mask = (commit_br_mask | commit_jmp_mask) 1141 1142 val mbpInstrs = commit_inst_mask & commit_cfi_mask 1143 1144 val mbpRights = mbpInstrs & commit_not_mispred_mask 1145 val mbpWrongs = mbpInstrs & commit_mispred_mask 1146 1147 io.bpuInfo.bpRight := PopCount(mbpRights) 1148 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 1149 1150 // Cfi Info 1151 for (i <- 0 until PredictWidth) { 1152 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 1153 val v = commit_state(i) === c_commited 1154 val isBr = commit_pd.brMask(i) 1155 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 1156 val isCfi = isBr || isJmp 1157 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 1158 val misPred = commit_mispredict(i) 1159 // val ghist = commit_spec_meta.ghist.predHist 1160 val histPtr = commit_spec_meta.histPtr 1161 val predCycle = commit_meta.meta(63, 0) 1162 val target = commit_target 1163 1164 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}))) 1165 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_) 1166 val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)) 1167 XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 1168 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " + 1169 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 1170 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n") 1171 } 1172 1173 val enq = io.fromBpu.resp 1174 val perf_redirect = backendRedirect 1175 1176 XSPerfAccumulate("entry", validEntries) 1177 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 1178 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 1179 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 1180 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 1181 1182 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 1183 1184 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 1185 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 1186 XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr) 1187 1188 val from_bpu = io.fromBpu.resp.bits 1189 def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = { 1190 assert(!resp.is_minimal) 1191 val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits 1192 val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U) 1193 val entry_len_map = (1 to PredictWidth+1).map(i => 1194 f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid) 1195 ).foldLeft(Map[String, UInt]())(_+_) 1196 entry_len_map 1197 } 1198 val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2") 1199 val s3_entry_len_map = in_entry_len_map_gen(from_bpu.s3)("s3") 1200 1201 val to_ifu = io.toIfu.req.bits 1202 1203 1204 1205 val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U) 1206 val commit_num_inst_map = (1 to PredictWidth).map(i => 1207 f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit) 1208 ).foldLeft(Map[String, UInt]())(_+_) 1209 1210 1211 1212 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 1213 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 1214 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 1215 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 1216 1217 1218 val mbpBRights = mbpRights & commit_br_mask 1219 val mbpJRights = mbpRights & commit_jal_mask 1220 val mbpIRights = mbpRights & commit_jalr_mask 1221 val mbpCRights = mbpRights & commit_call_mask 1222 val mbpRRights = mbpRights & commit_ret_mask 1223 1224 val mbpBWrongs = mbpWrongs & commit_br_mask 1225 val mbpJWrongs = mbpWrongs & commit_jal_mask 1226 val mbpIWrongs = mbpWrongs & commit_jalr_mask 1227 val mbpCWrongs = mbpWrongs & commit_call_mask 1228 val mbpRWrongs = mbpWrongs & commit_ret_mask 1229 1230 val commit_pred_stage = RegNext(pred_stage(commPtr.value)) 1231 1232 def pred_stage_map(src: UInt, name: String) = { 1233 (0 until numBpStages).map(i => 1234 f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i))) 1235 ).foldLeft(Map[String, UInt]())(_+_) 1236 } 1237 1238 val mispred_stage_map = pred_stage_map(mbpWrongs, "mispredict") 1239 val br_mispred_stage_map = pred_stage_map(mbpBWrongs, "br_mispredict") 1240 val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict") 1241 val correct_stage_map = pred_stage_map(mbpRights, "correct") 1242 val br_correct_stage_map = pred_stage_map(mbpBRights, "br_correct") 1243 val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct") 1244 1245 val update_valid = io.toBpu.update.valid 1246 def u(cond: Bool) = update_valid && cond 1247 val ftb_false_hit = u(update.false_hit) 1248 // assert(!ftb_false_hit) 1249 val ftb_hit = u(commit_hit === h_hit) 1250 1251 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1252 val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid 1253 val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0) 1254 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid 1255 1256 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1257 1258 val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified) 1259 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1260 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1261 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1262 val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified 1263 1264 val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits 1265 val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U) 1266 val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i => 1267 f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry) 1268 ).foldLeft(Map[String, UInt]())(_+_) 1269 val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i => 1270 f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry) 1271 ).foldLeft(Map[String, UInt]())(_+_) 1272 1273 val ftq_occupancy_map = (0 to FtqSize).map(i => 1274 f"ftq_has_entry_$i" ->( validEntries === i.U) 1275 ).foldLeft(Map[String, UInt]())(_+_) 1276 1277 val perfCountsMap = Map( 1278 "BpInstr" -> PopCount(mbpInstrs), 1279 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1280 "BpRight" -> PopCount(mbpRights), 1281 "BpWrong" -> PopCount(mbpWrongs), 1282 "BpBRight" -> PopCount(mbpBRights), 1283 "BpBWrong" -> PopCount(mbpBWrongs), 1284 "BpJRight" -> PopCount(mbpJRights), 1285 "BpJWrong" -> PopCount(mbpJWrongs), 1286 "BpIRight" -> PopCount(mbpIRights), 1287 "BpIWrong" -> PopCount(mbpIWrongs), 1288 "BpCRight" -> PopCount(mbpCRights), 1289 "BpCWrong" -> PopCount(mbpCWrongs), 1290 "BpRRight" -> PopCount(mbpRRights), 1291 "BpRWrong" -> PopCount(mbpRWrongs), 1292 1293 "ftb_false_hit" -> PopCount(ftb_false_hit), 1294 "ftb_hit" -> PopCount(ftb_hit), 1295 "ftb_new_entry" -> PopCount(ftb_new_entry), 1296 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1297 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1298 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1299 "ftb_old_entry" -> PopCount(ftb_old_entry), 1300 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1301 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1302 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1303 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1304 "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken) 1305 ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ s2_entry_len_map ++ 1306 s3_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map ++ 1307 mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++ 1308 correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map 1309 1310 for((key, value) <- perfCountsMap) { 1311 XSPerfAccumulate(key, value) 1312 } 1313 1314 // --------------------------- Debug -------------------------------- 1315 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1316 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1317 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1318 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1319 XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1320 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n") 1321 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1322 1323 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1324 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1325 // case (((valid, pd), ans), taken) => 1326 // Mux(valid && pd.isBr, 1327 // isWrong ^ Mux(ans.hit.asBool, 1328 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1329 // !taken), 1330 // !taken), 1331 // false.B) 1332 // } 1333 // } 1334 1335 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1336 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1337 // case (((valid, pd), ans), taken) => 1338 // Mux(valid && pd.isBr, 1339 // isWrong ^ Mux(ans.hit.asBool, 1340 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1341 // !taken), 1342 // !taken), 1343 // false.B) 1344 // } 1345 // } 1346 1347 // def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1348 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1349 // case (((valid, pd), ans), taken) => 1350 // Mux(valid && pd.isBr, 1351 // isWrong ^ (ans.taken.asBool === taken), 1352 // false.B) 1353 // } 1354 // } 1355 1356 // def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1357 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1358 // case (((valid, pd), ans), taken) => 1359 // Mux(valid && (pd.isBr) && ans.hit.asBool, 1360 // isWrong ^ (!taken), 1361 // false.B) 1362 // } 1363 // } 1364 1365 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1366 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1367 // case (((valid, pd), ans), taken) => 1368 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1369 // isWrong ^ (ans.target === commitEntry.target), 1370 // false.B) 1371 // } 1372 // } 1373 1374 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1375 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1376 // // btb and ubtb pred jal and jalr as well 1377 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1378 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1379 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1380 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1381 1382 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1383 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1384 1385 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1386 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1387 1388 val perfEvents = Seq( 1389 ("bpu_s2_redirect ", bpu_s2_redirect ), 1390 ("bpu_s3_redirect ", bpu_s3_redirect ), 1391 ("bpu_to_ftq_stall ", enq.valid && ~enq.ready ), 1392 ("mispredictRedirect ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level), 1393 ("replayRedirect ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level) ), 1394 ("predecodeRedirect ", fromIfuRedirect.valid ), 1395 ("to_ifu_bubble ", io.toIfu.req.ready && !io.toIfu.req.valid ), 1396 ("from_bpu_real_bubble ", !enq.valid && enq.ready && allowBpuIn ), 1397 ("BpInstr ", PopCount(mbpInstrs) ), 1398 ("BpBInstr ", PopCount(mbpBRights | mbpBWrongs) ), 1399 ("BpRight ", PopCount(mbpRights) ), 1400 ("BpWrong ", PopCount(mbpWrongs) ), 1401 ("BpBRight ", PopCount(mbpBRights) ), 1402 ("BpBWrong ", PopCount(mbpBWrongs) ), 1403 ("BpJRight ", PopCount(mbpJRights) ), 1404 ("BpJWrong ", PopCount(mbpJWrongs) ), 1405 ("BpIRight ", PopCount(mbpIRights) ), 1406 ("BpIWrong ", PopCount(mbpIWrongs) ), 1407 ("BpCRight ", PopCount(mbpCRights) ), 1408 ("BpCWrong ", PopCount(mbpCWrongs) ), 1409 ("BpRRight ", PopCount(mbpRRights) ), 1410 ("BpRWrong ", PopCount(mbpRWrongs) ), 1411 ("ftb_false_hit ", PopCount(ftb_false_hit) ), 1412 ("ftb_hit ", PopCount(ftb_hit) ), 1413 ) 1414 generatePerfEvent() 1415}