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