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