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