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