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