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