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)) 459 // resp from uBTB 460 ftq_pc_mem.io.wen(0) := bpu_in_fire 461 ftq_pc_mem.io.waddr(0) := bpu_in_resp_idx 462 ftq_pc_mem.io.wdata(0).fromBranchPrediction(bpu_in_resp) 463 464 // ifuRedirect + backendRedirect + commit 465 val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+1+1)) 466 // these info is intended to enq at the last stage of bpu 467 ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid 468 ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 469 ftq_redirect_sram.io.wdata.fromBranchPrediction(io.fromBpu.resp.bits.lastStage) 470 println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3") 471 println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3") 472 473 val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1)) 474 // these info is intended to enq at the last stage of bpu 475 ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid 476 ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 477 ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.meta 478 // ifuRedirect + backendRedirect + commit 479 val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+1+1, 1)) 480 ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid 481 ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value 482 ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.lastStage.ftb_entry 483 484 485 // multi-write 486 val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough 487 val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))) 488 val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool()))) 489 val pred_stage = Reg(Vec(FtqSize, UInt(2.W))) 490 491 val c_invalid :: c_valid :: c_commited :: Nil = Enum(3) 492 val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) { 493 VecInit(Seq.fill(PredictWidth)(c_invalid)) 494 })) 495 496 val f_to_send :: f_sent :: Nil = Enum(2) 497 val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent))) 498 499 val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3) 500 val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit))) 501 502 // modify registers one cycle later to cut critical path 503 val last_cycle_bpu_in = RegNext(bpu_in_fire) 504 val last_cycle_bpu_in_idx = RegNext(bpu_in_resp_idx) 505 val last_cycle_update_target = RegNext(bpu_in_resp.getTarget) 506 val last_cycle_cfiIndex = RegNext(bpu_in_resp.cfiIndex) 507 val last_cycle_bpu_in_stage = RegNext(bpu_in_stage) 508 when (last_cycle_bpu_in) { 509 entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send 510 commitStateQueue(last_cycle_bpu_in_idx) := VecInit(Seq.fill(PredictWidth)(c_invalid)) 511 cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex 512 mispredict_vec(last_cycle_bpu_in_idx) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B))) 513 update_target(last_cycle_bpu_in_idx) := last_cycle_update_target 514 pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage 515 } 516 517 518 bpuPtr := bpuPtr + enq_fire 519 when (io.toIfu.req.fire && allowToIfu) { 520 ifuPtr := ifuPtrPlus1 521 ifuPtrPlus1 := ifuPtrPlus1 + 1.U 522 } 523 524 // only use ftb result to assign hit status 525 when (bpu_s2_resp.valid) { 526 entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred.hit, h_hit, h_not_hit) 527 } 528 529 530 io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect 531 io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx 532 when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect) { 533 bpuPtr := bpu_s2_resp.ftq_idx + 1.U 534 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 535 when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) { 536 ifuPtr := bpu_s2_resp.ftq_idx 537 ifuPtrPlus1 := bpu_s2_resp.ftq_idx + 1.U 538 } 539 } 540 541 io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect 542 io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx 543 when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect) { 544 bpuPtr := bpu_s3_resp.ftq_idx + 1.U 545 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 546 when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) { 547 ifuPtr := bpu_s3_resp.ftq_idx 548 ifuPtrPlus1 := bpu_s3_resp.ftq_idx + 1.U 549 } 550 } 551 552 XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n") 553 554 // **************************************************************** 555 // **************************** to ifu **************************** 556 // **************************************************************** 557 val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata(0), bpu_in_fire) 558 val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr) 559 val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire) 560 561 // read pc and target 562 ftq_pc_mem.io.raddr.init.init.last := ifuPtr.value 563 ftq_pc_mem.io.raddr.init.last := ifuPtrPlus1.value 564 565 io.toIfu.req.bits.ftqIdx := ifuPtr 566 567 568 val toIfuPcBundle = Wire(new Ftq_RF_Components) 569 val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send) 570 val entry_next_addr = WireInit(update_target(ifuPtr.value)) 571 val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value)) 572 573 574 when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) { 575 toIfuPcBundle := bpu_in_bypass_buf 576 entry_is_to_send := true.B 577 entry_next_addr := last_cycle_update_target 578 entry_ftq_offset := last_cycle_cfiIndex 579 }.elsewhen (last_cycle_to_ifu_fire) { 580 toIfuPcBundle := ftq_pc_mem.io.rdata.init.last 581 entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) || 582 RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles 583 }.otherwise { 584 toIfuPcBundle := ftq_pc_mem.io.rdata.init.init.last 585 entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) 586 } 587 588 io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr 589 io.toIfu.req.bits.nextStartAddr := entry_next_addr 590 io.toIfu.req.bits.ftqOffset := entry_ftq_offset 591 io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle) 592 593 // when fall through is smaller in value than start address, there must be a false hit 594 when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) { 595 when (io.toIfu.req.fire && 596 !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && 597 !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr) 598 ) { 599 entry_hit_status(ifuPtr.value) := h_false_hit 600 // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 601 } 602 XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 603 } 604 605 XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit && 606 io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)) 607 608 val ifu_req_should_be_flushed = 609 io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) || 610 io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx) 611 612 when (io.toIfu.req.fire && !ifu_req_should_be_flushed) { 613 entry_fetch_status(ifuPtr.value) := f_sent 614 } 615 616 // ********************************************************************* 617 // **************************** wb from ifu **************************** 618 // ********************************************************************* 619 val pdWb = io.fromIfu.pdWb 620 val pds = pdWb.bits.pd 621 val ifu_wb_valid = pdWb.valid 622 val ifu_wb_idx = pdWb.bits.ftqIdx.value 623 // read ports: commit update 624 val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1)) 625 ftq_pd_mem.io.wen(0) := ifu_wb_valid 626 ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value 627 ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits) 628 629 val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid 630 val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid 631 val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B) 632 val pd_reg = RegEnable(pds, pdWb.valid) 633 val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid) 634 val wb_idx_reg = RegEnable(ifu_wb_idx, pdWb.valid) 635 636 when (ifu_wb_valid) { 637 val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{ 638 case (v, inRange) => v && inRange 639 }) 640 (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{ 641 case (qe, v) => when (v) { qe := c_valid } 642 } 643 } 644 645 ifuWbPtr := ifuWbPtr + ifu_wb_valid 646 647 ftb_entry_mem.io.raddr.head := ifu_wb_idx 648 val has_false_hit = WireInit(false.B) 649 when (RegNext(hit_pd_valid)) { 650 // check for false hit 651 val pred_ftb_entry = ftb_entry_mem.io.rdata.head 652 val brSlots = pred_ftb_entry.brSlots 653 val tailSlot = pred_ftb_entry.tailSlot 654 // we check cfis that bpu predicted 655 656 // bpu predicted branches but denied by predecode 657 val br_false_hit = 658 brSlots.map{ 659 s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr) 660 }.reduce(_||_) || 661 (tailSlot.valid && pred_ftb_entry.tailSlot.sharing && 662 !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr)) 663 664 val jmpOffset = tailSlot.offset 665 val jmp_pd = pd_reg(jmpOffset) 666 val jal_false_hit = pred_ftb_entry.jmpValid && 667 ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) || 668 (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) || 669 (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) || 670 (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)) 671 ) 672 673 has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg 674 XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0)) 675 676 // assert(!has_false_hit) 677 } 678 679 when (has_false_hit) { 680 entry_hit_status(wb_idx_reg) := h_false_hit 681 } 682 683 684 // ********************************************************************** 685 // ***************************** to backend ***************************** 686 // ********************************************************************** 687 // to backend pc mem / target 688 io.toBackend.pc_mem_wen := RegNext(last_cycle_bpu_in) 689 io.toBackend.pc_mem_waddr := RegNext(last_cycle_bpu_in_idx) 690 io.toBackend.pc_mem_wdata := RegNext(bpu_in_bypass_buf) 691 io.toBackend.target := RegNext(last_cycle_update_target) 692 693 // ******************************************************************************* 694 // **************************** redirect from backend **************************** 695 // ******************************************************************************* 696 697 // redirect read cfiInfo, couples to redirectGen s2 698 ftq_redirect_sram.io.ren.init.last := backendRedirect.valid 699 ftq_redirect_sram.io.raddr.init.last := backendRedirect.bits.ftqIdx.value 700 701 ftb_entry_mem.io.raddr.init.last := backendRedirect.bits.ftqIdx.value 702 703 val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last 704 val fromBackendRedirect = WireInit(backendRedirectReg) 705 val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate 706 backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo) 707 708 val r_ftb_entry = ftb_entry_mem.io.rdata.init.last 709 val r_ftqOffset = fromBackendRedirect.bits.ftqOffset 710 711 when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) { 712 backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +& 713 (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) && 714 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 715 716 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) || 717 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 718 }.otherwise { 719 backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt 720 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt 721 } 722 723 724 // *************************************************************************** 725 // **************************** redirect from ifu **************************** 726 // *************************************************************************** 727 val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect))) 728 fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush 729 fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx 730 fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits 731 fromIfuRedirect.bits.level := RedirectLevel.flushAfter 732 733 val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate 734 ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits) 735 ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits) 736 ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid 737 ifuRedirectCfiUpdate.target := pdWb.bits.target 738 ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid 739 ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid 740 741 val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect))) 742 val ifuRedirectToBpu = WireInit(ifuRedirectReg) 743 ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid 744 745 ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid 746 ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 747 748 ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 749 750 val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate 751 toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head) 752 when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) { 753 toBpuCfi.target := toBpuCfi.rasEntry.retAddr 754 } 755 756 // ********************************************************************* 757 // **************************** wb from exu **************************** 758 // ********************************************************************* 759 760 backendRedirect := io.fromBackend.redirect 761 762 def extractRedirectInfo(wb: Valid[Redirect]) = { 763 val ftqIdx = wb.bits.ftqIdx.value 764 val ftqOffset = wb.bits.ftqOffset 765 val taken = wb.bits.cfiUpdate.taken 766 val mispred = wb.bits.cfiUpdate.isMisPred 767 (wb.valid, ftqIdx, ftqOffset, taken, mispred) 768 } 769 770 // fix mispredict entry 771 val lastIsMispredict = RegNext( 772 backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B 773 ) 774 775 def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = { 776 val (r_valid, r_idx, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect) 777 val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits 778 val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits 779 when (cfiIndex_bits_wen || cfiIndex_valid_wen) { 780 cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken 781 } 782 when (cfiIndex_bits_wen) { 783 cfiIndex_vec(r_idx).bits := r_offset 784 } 785 update_target(r_idx) := redirect.bits.cfiUpdate.target 786 if (isBackend) { 787 mispredict_vec(r_idx)(r_offset) := r_mispred 788 } 789 } 790 791 // write to backend target vec 792 io.toBackend.pd_redirect_waddr.valid := RegNext(fromIfuRedirect.valid) 793 io.toBackend.pd_redirect_waddr.bits := RegNext(fromIfuRedirect.bits.ftqIdx.value) 794 io.toBackend.pd_redirect_target := RegNext(fromIfuRedirect.bits.cfiUpdate.target) 795 796 when(backendRedirectReg.valid && lastIsMispredict) { 797 updateCfiInfo(backendRedirectReg) 798 }.elsewhen (ifuRedirectToBpu.valid) { 799 updateCfiInfo(ifuRedirectToBpu, isBackend=false) 800 } 801 802 // *********************************************************************************** 803 // **************************** flush ptr and state queue **************************** 804 // *********************************************************************************** 805 806 val redirectVec = VecInit(backendRedirect, fromIfuRedirect) 807 808 // when redirect, we should reset ptrs and status queues 809 when(redirectVec.map(r => r.valid).reduce(_||_)){ 810 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 811 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 812 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 813 val next = idx + 1.U 814 bpuPtr := next 815 ifuPtr := next 816 ifuWbPtr := next 817 ifuPtrPlus1 := idx + 2.U 818 when (notIfu) { 819 commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) => 820 when(i.U > offset || i.U === offset && flushItSelf){ 821 s := c_invalid 822 } 823 }) 824 } 825 } 826 827 // only the valid bit is actually needed 828 io.toIfu.redirect.bits := backendRedirect.bits 829 io.toIfu.redirect.valid := stage2Flush 830 831 // commit 832 for (c <- io.fromBackend.rob_commits) { 833 when(c.valid) { 834 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited 835 // TODO: remove this 836 // For instruction fusions, we also update the next instruction 837 when (c.bits.commitType === 4.U) { 838 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited 839 }.elsewhen(c.bits.commitType === 5.U) { 840 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited 841 }.elsewhen(c.bits.commitType === 6.U) { 842 val index = (c.bits.ftqIdx + 1.U).value 843 commitStateQueue(index)(0) := c_commited 844 }.elsewhen(c.bits.commitType === 7.U) { 845 val index = (c.bits.ftqIdx + 1.U).value 846 commitStateQueue(index)(1) := c_commited 847 } 848 } 849 } 850 851 // **************************************************************** 852 // **************************** to bpu **************************** 853 // **************************************************************** 854 855 io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 856 857 val may_have_stall_from_bpu = Wire(Bool()) 858 val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states 859 may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U 860 val canCommit = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 861 Cat(commitStateQueue(commPtr.value).map(s => { 862 s === c_invalid || s === c_commited 863 })).andR() 864 865 // commit reads 866 ftq_pc_mem.io.raddr.last := commPtr.value 867 val commit_pc_bundle = ftq_pc_mem.io.rdata.last 868 ftq_pd_mem.io.raddr.last := commPtr.value 869 val commit_pd = ftq_pd_mem.io.rdata.last 870 ftq_redirect_sram.io.ren.last := canCommit 871 ftq_redirect_sram.io.raddr.last := commPtr.value 872 val commit_spec_meta = ftq_redirect_sram.io.rdata.last 873 ftq_meta_1r_sram.io.ren(0) := canCommit 874 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 875 val commit_meta = ftq_meta_1r_sram.io.rdata(0) 876 ftb_entry_mem.io.raddr.last := commPtr.value 877 val commit_ftb_entry = ftb_entry_mem.io.rdata.last 878 879 // need one cycle to read mem and srams 880 val do_commit_ptr = RegNext(commPtr) 881 val do_commit = RegNext(canCommit, init=false.B) 882 when (canCommit) { commPtr := commPtr + 1.U } 883 val commit_state = RegNext(commitStateQueue(commPtr.value)) 884 val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value)) 885 when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) { 886 can_commit_cfi.valid := false.B 887 } 888 val commit_cfi = RegNext(can_commit_cfi) 889 890 val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map { 891 case (mis, state) => mis && state === c_commited 892 }) 893 val can_commit_hit = entry_hit_status(commPtr.value) 894 val commit_hit = RegNext(can_commit_hit) 895 val commit_target = RegNext(update_target(commPtr.value)) 896 val commit_stage = RegNext(pred_stage(commPtr.value)) 897 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 898 899 val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit 900 switch (bpu_ftb_update_stall) { 901 is (0.U) { 902 when (can_commit_cfi.valid && !to_bpu_hit && canCommit) { 903 bpu_ftb_update_stall := 2.U // 2-cycle stall 904 } 905 } 906 is (2.U) { 907 bpu_ftb_update_stall := 1.U 908 } 909 is (1.U) { 910 bpu_ftb_update_stall := 0.U 911 } 912 is (3.U) { 913 XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2") 914 } 915 } 916 917 io.toBpu.update := DontCare 918 io.toBpu.update.valid := commit_valid && do_commit 919 val update = io.toBpu.update.bits 920 update.false_hit := commit_hit === h_false_hit 921 update.pc := commit_pc_bundle.startAddr 922 update.meta := commit_meta.meta 923 update.full_target := commit_target 924 update.from_stage := commit_stage 925 update.fromFtqRedirectSram(commit_spec_meta) 926 927 val commit_real_hit = commit_hit === h_hit 928 val update_ftb_entry = update.ftb_entry 929 930 val ftbEntryGen = Module(new FTBEntryGen).io 931 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 932 ftbEntryGen.old_entry := commit_ftb_entry 933 ftbEntryGen.pd := commit_pd 934 ftbEntryGen.cfiIndex := commit_cfi 935 ftbEntryGen.target := commit_target 936 ftbEntryGen.hit := commit_real_hit 937 ftbEntryGen.mispredict_vec := commit_mispredict 938 939 update_ftb_entry := ftbEntryGen.new_entry 940 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 941 update.mispred_mask := ftbEntryGen.mispred_mask 942 update.old_entry := ftbEntryGen.is_old_entry 943 update.pred_hit := commit_hit === h_hit || commit_hit === h_false_hit 944 945 update.is_minimal := false.B 946 update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc) 947 update.full_pred.br_taken_mask := ftbEntryGen.taken_mask 948 update.full_pred.jalr_target := commit_target 949 update.full_pred.hit := true.B 950 when (update.full_pred.is_jalr) { 951 update.full_pred.targets.last := commit_target 952 } 953 954 // **************************************************************** 955 // *********************** to prefetch **************************** 956 // **************************************************************** 957 958 if(cacheParams.hasPrefetch){ 959 val prefetchPtr = RegInit(FtqPtr(false.B, 0.U)) 960 prefetchPtr := prefetchPtr + io.toPrefetch.req.fire() 961 962 when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s2_resp.ftq_idx)) { 963 prefetchPtr := bpu_s2_resp.ftq_idx 964 } 965 966 when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s3_resp.ftq_idx)) { 967 prefetchPtr := bpu_s3_resp.ftq_idx 968 // XSError(true.B, "\ns3_redirect mechanism not implemented!\n") 969 } 970 971 972 val prefetch_is_to_send = WireInit(entry_fetch_status(prefetchPtr.value) === f_to_send) 973 val prefetch_addr = WireInit(update_target(prefetchPtr.value)) 974 975 when (last_cycle_bpu_in && bpu_in_bypass_ptr === prefetchPtr) { 976 prefetch_is_to_send := true.B 977 prefetch_addr := last_cycle_update_target 978 } 979 io.toPrefetch.req.valid := prefetchPtr =/= bpuPtr && prefetch_is_to_send 980 io.toPrefetch.req.bits.target := prefetch_addr 981 982 when(redirectVec.map(r => r.valid).reduce(_||_)){ 983 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 984 val next = r.ftqIdx + 1.U 985 prefetchPtr := next 986 } 987 988 XSError(isBefore(bpuPtr, prefetchPtr) && !isFull(bpuPtr, prefetchPtr), "\nprefetchPtr is before bpuPtr!\n") 989 XSError(isBefore(prefetchPtr, ifuPtr) && !isFull(ifuPtr, prefetchPtr), "\nifuPtr is before prefetchPtr!\n") 990 } 991 else { 992 io.toPrefetch.req <> DontCare 993 } 994 995 // ****************************************************************************** 996 // **************************** commit perf counters **************************** 997 // ****************************************************************************** 998 999 val commit_inst_mask = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt 1000 val commit_mispred_mask = commit_mispredict.asUInt 1001 val commit_not_mispred_mask = ~commit_mispred_mask 1002 1003 val commit_br_mask = commit_pd.brMask.asUInt 1004 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 1005 val commit_cfi_mask = (commit_br_mask | commit_jmp_mask) 1006 1007 val mbpInstrs = commit_inst_mask & commit_cfi_mask 1008 1009 val mbpRights = mbpInstrs & commit_not_mispred_mask 1010 val mbpWrongs = mbpInstrs & commit_mispred_mask 1011 1012 io.bpuInfo.bpRight := PopCount(mbpRights) 1013 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 1014 1015 // Cfi Info 1016 for (i <- 0 until PredictWidth) { 1017 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 1018 val v = commit_state(i) === c_commited 1019 val isBr = commit_pd.brMask(i) 1020 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 1021 val isCfi = isBr || isJmp 1022 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 1023 val misPred = commit_mispredict(i) 1024 // val ghist = commit_spec_meta.ghist.predHist 1025 val histPtr = commit_spec_meta.histPtr 1026 val predCycle = commit_meta.meta(63, 0) 1027 val target = commit_target 1028 1029 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}))) 1030 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_) 1031 val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)) 1032 XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 1033 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " + 1034 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 1035 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n") 1036 } 1037 1038 val enq = io.fromBpu.resp 1039 val perf_redirect = backendRedirect 1040 1041 XSPerfAccumulate("entry", validEntries) 1042 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 1043 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 1044 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 1045 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 1046 1047 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 1048 1049 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 1050 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 1051 XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr) 1052 1053 val from_bpu = io.fromBpu.resp.bits 1054 def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = { 1055 assert(!resp.is_minimal) 1056 val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits 1057 val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U) 1058 val entry_len_map = (1 to PredictWidth+1).map(i => 1059 f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid) 1060 ).foldLeft(Map[String, UInt]())(_+_) 1061 entry_len_map 1062 } 1063 val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2") 1064 val s3_entry_len_map = in_entry_len_map_gen(from_bpu.s3)("s3") 1065 1066 val to_ifu = io.toIfu.req.bits 1067 1068 1069 1070 val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U) 1071 val commit_num_inst_map = (1 to PredictWidth).map(i => 1072 f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit) 1073 ).foldLeft(Map[String, UInt]())(_+_) 1074 1075 1076 1077 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 1078 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 1079 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 1080 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 1081 1082 1083 val mbpBRights = mbpRights & commit_br_mask 1084 val mbpJRights = mbpRights & commit_jal_mask 1085 val mbpIRights = mbpRights & commit_jalr_mask 1086 val mbpCRights = mbpRights & commit_call_mask 1087 val mbpRRights = mbpRights & commit_ret_mask 1088 1089 val mbpBWrongs = mbpWrongs & commit_br_mask 1090 val mbpJWrongs = mbpWrongs & commit_jal_mask 1091 val mbpIWrongs = mbpWrongs & commit_jalr_mask 1092 val mbpCWrongs = mbpWrongs & commit_call_mask 1093 val mbpRWrongs = mbpWrongs & commit_ret_mask 1094 1095 val commit_pred_stage = RegNext(pred_stage(commPtr.value)) 1096 1097 def pred_stage_map(src: UInt, name: String) = { 1098 (0 until numBpStages).map(i => 1099 f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i))) 1100 ).foldLeft(Map[String, UInt]())(_+_) 1101 } 1102 1103 val mispred_stage_map = pred_stage_map(mbpWrongs, "mispredict") 1104 val br_mispred_stage_map = pred_stage_map(mbpBWrongs, "br_mispredict") 1105 val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict") 1106 val correct_stage_map = pred_stage_map(mbpRights, "correct") 1107 val br_correct_stage_map = pred_stage_map(mbpBRights, "br_correct") 1108 val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct") 1109 1110 val update_valid = io.toBpu.update.valid 1111 def u(cond: Bool) = update_valid && cond 1112 val ftb_false_hit = u(update.false_hit) 1113 // assert(!ftb_false_hit) 1114 val ftb_hit = u(commit_hit === h_hit) 1115 1116 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1117 val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid 1118 val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0) 1119 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid 1120 1121 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1122 1123 val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified) 1124 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1125 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1126 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1127 val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified 1128 1129 val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits 1130 val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U) 1131 val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i => 1132 f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry) 1133 ).foldLeft(Map[String, UInt]())(_+_) 1134 val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i => 1135 f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry) 1136 ).foldLeft(Map[String, UInt]())(_+_) 1137 1138 val ftq_occupancy_map = (0 to FtqSize).map(i => 1139 f"ftq_has_entry_$i" ->( validEntries === i.U) 1140 ).foldLeft(Map[String, UInt]())(_+_) 1141 1142 val perfCountsMap = Map( 1143 "BpInstr" -> PopCount(mbpInstrs), 1144 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1145 "BpRight" -> PopCount(mbpRights), 1146 "BpWrong" -> PopCount(mbpWrongs), 1147 "BpBRight" -> PopCount(mbpBRights), 1148 "BpBWrong" -> PopCount(mbpBWrongs), 1149 "BpJRight" -> PopCount(mbpJRights), 1150 "BpJWrong" -> PopCount(mbpJWrongs), 1151 "BpIRight" -> PopCount(mbpIRights), 1152 "BpIWrong" -> PopCount(mbpIWrongs), 1153 "BpCRight" -> PopCount(mbpCRights), 1154 "BpCWrong" -> PopCount(mbpCWrongs), 1155 "BpRRight" -> PopCount(mbpRRights), 1156 "BpRWrong" -> PopCount(mbpRWrongs), 1157 1158 "ftb_false_hit" -> PopCount(ftb_false_hit), 1159 "ftb_hit" -> PopCount(ftb_hit), 1160 "ftb_new_entry" -> PopCount(ftb_new_entry), 1161 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1162 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1163 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1164 "ftb_old_entry" -> PopCount(ftb_old_entry), 1165 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1166 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1167 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1168 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1169 "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken) 1170 ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ s2_entry_len_map ++ 1171 s3_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map ++ 1172 mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++ 1173 correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map 1174 1175 for((key, value) <- perfCountsMap) { 1176 XSPerfAccumulate(key, value) 1177 } 1178 1179 // --------------------------- Debug -------------------------------- 1180 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1181 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1182 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1183 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1184 XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1185 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n") 1186 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1187 1188 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1189 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1190 // case (((valid, pd), ans), taken) => 1191 // Mux(valid && pd.isBr, 1192 // isWrong ^ Mux(ans.hit.asBool, 1193 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1194 // !taken), 1195 // !taken), 1196 // false.B) 1197 // } 1198 // } 1199 1200 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1201 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1202 // case (((valid, pd), ans), taken) => 1203 // Mux(valid && pd.isBr, 1204 // isWrong ^ Mux(ans.hit.asBool, 1205 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1206 // !taken), 1207 // !taken), 1208 // false.B) 1209 // } 1210 // } 1211 1212 // def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1213 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1214 // case (((valid, pd), ans), taken) => 1215 // Mux(valid && pd.isBr, 1216 // isWrong ^ (ans.taken.asBool === taken), 1217 // false.B) 1218 // } 1219 // } 1220 1221 // def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1222 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1223 // case (((valid, pd), ans), taken) => 1224 // Mux(valid && (pd.isBr) && ans.hit.asBool, 1225 // isWrong ^ (!taken), 1226 // false.B) 1227 // } 1228 // } 1229 1230 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1231 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1232 // case (((valid, pd), ans), taken) => 1233 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1234 // isWrong ^ (ans.target === commitEntry.target), 1235 // false.B) 1236 // } 1237 // } 1238 1239 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1240 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1241 // // btb and ubtb pred jal and jalr as well 1242 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1243 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1244 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1245 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1246 1247 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1248 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1249 1250 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1251 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1252 1253 val perfEvents = Seq( 1254 ("bpu_s2_redirect ", bpu_s2_redirect ), 1255 ("bpu_s3_redirect ", bpu_s3_redirect ), 1256 ("bpu_to_ftq_stall ", enq.valid && ~enq.ready ), 1257 ("mispredictRedirect ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level), 1258 ("replayRedirect ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level) ), 1259 ("predecodeRedirect ", fromIfuRedirect.valid ), 1260 ("to_ifu_bubble ", io.toIfu.req.ready && !io.toIfu.req.valid ), 1261 ("from_bpu_real_bubble ", !enq.valid && enq.ready && allowBpuIn ), 1262 ("BpInstr ", PopCount(mbpInstrs) ), 1263 ("BpBInstr ", PopCount(mbpBRights | mbpBWrongs) ), 1264 ("BpRight ", PopCount(mbpRights) ), 1265 ("BpWrong ", PopCount(mbpWrongs) ), 1266 ("BpBRight ", PopCount(mbpBRights) ), 1267 ("BpBWrong ", PopCount(mbpBWrongs) ), 1268 ("BpJRight ", PopCount(mbpJRights) ), 1269 ("BpJWrong ", PopCount(mbpJWrongs) ), 1270 ("BpIRight ", PopCount(mbpIRights) ), 1271 ("BpIWrong ", PopCount(mbpIWrongs) ), 1272 ("BpCRight ", PopCount(mbpCRights) ), 1273 ("BpCWrong ", PopCount(mbpCWrongs) ), 1274 ("BpRRight ", PopCount(mbpRRights) ), 1275 ("BpRWrong ", PopCount(mbpRWrongs) ), 1276 ("ftb_false_hit ", PopCount(ftb_false_hit) ), 1277 ("ftb_hit ", PopCount(ftb_hit) ), 1278 ) 1279 generatePerfEvent() 1280} 1281