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