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