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 // XSError(true.B, "\ns3_redirect mechanism not implemented!\n") 558 // } 559 560 XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n") 561 562 // **************************************************************** 563 // **************************** to ifu **************************** 564 // **************************************************************** 565 val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata(0), enable=bpu_in_fire) 566 val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr) 567 val last_cycle_bpu_in = RegNext(bpu_in_fire) 568 val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire) 569 570 // read pc and target 571 ftq_pc_mem.io.raddr.init.init.last := ifuPtr.value 572 ftq_pc_mem.io.raddr.init.last := (ifuPtr+1.U).value 573 574 io.toIfu.req.valid := allowToIfu && entry_fetch_status(ifuPtr.value) === f_to_send && ifuPtr =/= bpuPtr 575 io.toIfu.req.bits.ftqIdx := ifuPtr 576 io.toIfu.req.bits.nextStartAddr := update_target(ifuPtr.value) 577 io.toIfu.req.bits.ftqOffset := cfiIndex_vec(ifuPtr.value) 578 579 val toIfuPcBundle = Wire(new Ftq_RF_Components) 580 581 when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) { 582 toIfuPcBundle := bpu_in_bypass_buf 583 }.elsewhen (last_cycle_to_ifu_fire) { 584 toIfuPcBundle := ftq_pc_mem.io.rdata.init.last 585 }.otherwise { 586 toIfuPcBundle := ftq_pc_mem.io.rdata.init.init.last 587 } 588 589 io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle) 590 591 // when fall through is smaller in value than start address, there must be a false hit 592 when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) { 593 when (io.toIfu.req.fire && 594 !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr)/* && 595 !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr) */ 596 ) { 597 entry_hit_status(ifuPtr.value) := h_false_hit 598 XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 599 } 600 XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr) 601 } 602 603 val ifu_req_should_be_flushed = 604 io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx)/* || 605 io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx) */ 606 607 when (io.toIfu.req.fire && !ifu_req_should_be_flushed) { 608 entry_fetch_status(ifuPtr.value) := f_sent 609 } 610 611 io.toPrefetch.req.valid := allowToIfu && prefetchPtr =/= bpuPtr && entry_fetch_status(prefetchPtr.value) === f_to_send 612 io.toPrefetch.req.bits.target := update_target(prefetchPtr.value) 613 614 // ********************************************************************* 615 // **************************** wb from ifu **************************** 616 // ********************************************************************* 617 val pdWb = io.fromIfu.pdWb 618 val pds = pdWb.bits.pd 619 val ifu_wb_valid = pdWb.valid 620 val ifu_wb_idx = pdWb.bits.ftqIdx.value 621 // read ports: commit update 622 val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1)) 623 ftq_pd_mem.io.wen(0) := ifu_wb_valid 624 ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value 625 ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits) 626 627 val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid 628 val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid 629 val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B) 630 val pd_reg = RegEnable(pds, enable = pdWb.valid) 631 val start_pc_reg = RegEnable(pdWb.bits.pc(0), enable = pdWb.valid) 632 val wb_idx_reg = RegEnable(ifu_wb_idx, enable = pdWb.valid) 633 634 when (ifu_wb_valid) { 635 val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{ 636 case (v, inRange) => v && inRange 637 }) 638 (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{ 639 case (qe, v) => when (v) { qe := c_valid } 640 } 641 } 642 643 ifuWbPtr := ifuWbPtr + ifu_wb_valid 644 645 ftb_entry_mem.io.raddr.head := ifu_wb_idx 646 val has_false_hit = WireInit(false.B) 647 when (RegNext(hit_pd_valid)) { 648 // check for false hit 649 val pred_ftb_entry = ftb_entry_mem.io.rdata.head 650 val brSlots = pred_ftb_entry.brSlots 651 val tailSlot = pred_ftb_entry.tailSlot 652 // we check cfis that bpu predicted 653 654 // bpu predicted branches but denied by predecode 655 val br_false_hit = 656 brSlots.map{ 657 s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr) 658 }.reduce(_||_) || 659 (tailSlot.valid && pred_ftb_entry.tailSlot.sharing && 660 !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr)) 661 662 val jmpOffset = tailSlot.offset 663 val jmp_pd = pd_reg(jmpOffset) 664 val jal_false_hit = pred_ftb_entry.jmpValid && 665 ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) || 666 (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) || 667 (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) || 668 (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)) 669 ) 670 671 has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg 672 XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0)) 673 674 assert(!has_false_hit) 675 } 676 677 when (has_false_hit) { 678 entry_hit_status(wb_idx_reg) := h_false_hit 679 } 680 681 682 // ********************************************************************** 683 // **************************** backend read **************************** 684 // ********************************************************************** 685 686 // pc reads 687 for ((req, i) <- io.toBackend.pc_reads.zipWithIndex) { 688 ftq_pc_mem.io.raddr(i) := req.ptr.value 689 req.data := ftq_pc_mem.io.rdata(i).getPc(RegNext(req.offset)) 690 } 691 // target read 692 io.toBackend.target_read.data := RegNext(update_target(io.toBackend.target_read.ptr.value)) 693 694 // ******************************************************************************* 695 // **************************** redirect from backend **************************** 696 // ******************************************************************************* 697 698 // redirect read cfiInfo, couples to redirectGen s2 699 ftq_redirect_sram.io.ren.init.last := io.fromBackend.redirect.valid 700 ftq_redirect_sram.io.raddr.init.last := io.fromBackend.redirect.bits.ftqIdx.value 701 702 ftb_entry_mem.io.raddr.init.last := io.fromBackend.redirect.bits.ftqIdx.value 703 704 val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last 705 val fromBackendRedirect = WireInit(backendRedirectReg) 706 val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate 707 backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo) 708 709 val r_ftb_entry = ftb_entry_mem.io.rdata.init.last 710 val r_ftqOffset = fromBackendRedirect.bits.ftqOffset 711 712 when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) { 713 backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +& 714 (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) && 715 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 716 717 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) || 718 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 719 }.otherwise { 720 backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt 721 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt 722 } 723 724 725 // *************************************************************************** 726 // **************************** redirect from ifu **************************** 727 // *************************************************************************** 728 val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect))) 729 fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush 730 fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx 731 fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits 732 fromIfuRedirect.bits.level := RedirectLevel.flushAfter 733 734 val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate 735 ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits) 736 ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits) 737 ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid 738 ifuRedirectCfiUpdate.target := pdWb.bits.target 739 ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid 740 ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid 741 742 val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect))) 743 val ifuRedirectToBpu = WireInit(ifuRedirectReg) 744 ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid 745 746 ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid 747 ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 748 749 ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 750 751 val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate 752 toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head) 753 when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) { 754 toBpuCfi.target := toBpuCfi.rasEntry.retAddr 755 } 756 757 // ********************************************************************* 758 // **************************** wb from exu **************************** 759 // ********************************************************************* 760 761 def extractRedirectInfo(wb: Valid[Redirect]) = { 762 val ftqIdx = wb.bits.ftqIdx.value 763 val ftqOffset = wb.bits.ftqOffset 764 val taken = wb.bits.cfiUpdate.taken 765 val mispred = wb.bits.cfiUpdate.isMisPred 766 (wb.valid, ftqIdx, ftqOffset, taken, mispred) 767 } 768 769 // fix mispredict entry 770 val lastIsMispredict = RegNext( 771 backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B 772 ) 773 774 def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = { 775 val (r_valid, r_idx, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect) 776 val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits 777 val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits 778 when (cfiIndex_bits_wen || cfiIndex_valid_wen) { 779 cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken 780 } 781 when (cfiIndex_bits_wen) { 782 cfiIndex_vec(r_idx).bits := r_offset 783 } 784 update_target(r_idx) := redirect.bits.cfiUpdate.target 785 if (isBackend) { 786 mispredict_vec(r_idx)(r_offset) := r_mispred 787 } 788 } 789 790 when(backendRedirectReg.valid && lastIsMispredict) { 791 updateCfiInfo(backendRedirectReg) 792 }.elsewhen (ifuRedirectToBpu.valid) { 793 updateCfiInfo(ifuRedirectToBpu, isBackend=false) 794 } 795 796 // *********************************************************************************** 797 // **************************** flush ptr and state queue **************************** 798 // *********************************************************************************** 799 800 val redirectVec = VecInit(backendRedirect, fromIfuRedirect) 801 802 // when redirect, we should reset ptrs and status queues 803 when(redirectVec.map(r => r.valid).reduce(_||_)){ 804 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 805 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 806 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 807 val next = idx + 1.U 808 bpuPtr := next 809 ifuPtr := next 810 ifuWbPtr := next 811 when (notIfu) { 812 commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) => 813 when(i.U > offset || i.U === offset && flushItSelf){ 814 s := c_invalid 815 } 816 }) 817 } 818 } 819 820 // only the valid bit is actually needed 821 io.toIfu.redirect.bits := backendRedirect.bits 822 io.toIfu.redirect.valid := stage2Flush 823 824 // commit 825 for (c <- io.fromBackend.rob_commits) { 826 when(c.valid) { 827 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited 828 // TODO: remove this 829 // For instruction fusions, we also update the next instruction 830 when (c.bits.commitType === 4.U) { 831 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited 832 }.elsewhen(c.bits.commitType === 5.U) { 833 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited 834 }.elsewhen(c.bits.commitType === 6.U) { 835 val index = (c.bits.ftqIdx + 1.U).value 836 commitStateQueue(index)(0) := c_commited 837 }.elsewhen(c.bits.commitType === 7.U) { 838 val index = (c.bits.ftqIdx + 1.U).value 839 commitStateQueue(index)(1) := c_commited 840 } 841 } 842 } 843 844 // **************************************************************** 845 // **************************** to bpu **************************** 846 // **************************************************************** 847 848 io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 849 850 val may_have_stall_from_bpu = RegInit(false.B) 851 val canCommit = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 852 Cat(commitStateQueue(commPtr.value).map(s => { 853 s === c_invalid || s === c_commited 854 })).andR() 855 856 // commit reads 857 ftq_pc_mem.io.raddr.last := commPtr.value 858 val commit_pc_bundle = ftq_pc_mem.io.rdata.last 859 ftq_pd_mem.io.raddr.last := commPtr.value 860 val commit_pd = ftq_pd_mem.io.rdata.last 861 ftq_redirect_sram.io.ren.last := canCommit 862 ftq_redirect_sram.io.raddr.last := commPtr.value 863 val commit_spec_meta = ftq_redirect_sram.io.rdata.last 864 ftq_meta_1r_sram.io.ren(0) := canCommit 865 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 866 val commit_meta = ftq_meta_1r_sram.io.rdata(0) 867 ftb_entry_mem.io.raddr.last := commPtr.value 868 val commit_ftb_entry = ftb_entry_mem.io.rdata.last 869 870 // need one cycle to read mem and srams 871 val do_commit_ptr = RegNext(commPtr) 872 val do_commit = RegNext(canCommit, init=false.B) 873 when (canCommit) { commPtr := commPtr + 1.U } 874 val commit_state = RegNext(commitStateQueue(commPtr.value)) 875 val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value)) 876 when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) { 877 can_commit_cfi.valid := false.B 878 } 879 val commit_cfi = RegNext(can_commit_cfi) 880 881 val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map { 882 case (mis, state) => mis && state === c_commited 883 }) 884 val can_commit_hit = entry_hit_status(commPtr.value) 885 val commit_hit = RegNext(can_commit_hit) 886 val commit_target = RegNext(update_target(commPtr.value)) 887 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 888 889 val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit 890 may_have_stall_from_bpu := can_commit_cfi.valid && !to_bpu_hit && !may_have_stall_from_bpu 891 892 io.toBpu.update := DontCare 893 io.toBpu.update.valid := commit_valid && do_commit 894 val update = io.toBpu.update.bits 895 update.false_hit := commit_hit === h_false_hit 896 update.pc := commit_pc_bundle.startAddr 897 update.meta := commit_meta.meta 898 update.full_target := commit_target 899 update.fromFtqRedirectSram(commit_spec_meta) 900 901 val commit_real_hit = commit_hit === h_hit 902 val update_ftb_entry = update.ftb_entry 903 904 val ftbEntryGen = Module(new FTBEntryGen).io 905 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 906 ftbEntryGen.old_entry := commit_ftb_entry 907 ftbEntryGen.pd := commit_pd 908 ftbEntryGen.cfiIndex := commit_cfi 909 ftbEntryGen.target := commit_target 910 ftbEntryGen.hit := commit_real_hit 911 ftbEntryGen.mispredict_vec := commit_mispredict 912 913 update_ftb_entry := ftbEntryGen.new_entry 914 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 915 update.mispred_mask := ftbEntryGen.mispred_mask 916 update.old_entry := ftbEntryGen.is_old_entry 917 918 update.is_minimal := false.B 919 update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc) 920 update.full_pred.br_taken_mask := ftbEntryGen.taken_mask 921 update.full_pred.jalr_target := commit_target 922 update.full_pred.hit := true.B 923 when (update.full_pred.is_jalr) { 924 update.full_pred.targets.last := commit_target 925 } 926 927 // **************************************************************** 928 // *********************** to prefetch **************************** 929 // **************************************************************** 930 931 if(cacheParams.hasPrefetch){ 932 val prefetchPtr = RegInit(FtqPtr(false.B, 0.U)) 933 prefetchPtr := prefetchPtr + io.toPrefetch.req.fire() 934 935 when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s2_resp.ftq_idx)) { 936 prefetchPtr := bpu_s2_resp.ftq_idx 937 } 938 939 when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s3_resp.ftq_idx)) { 940 prefetchPtr := bpu_s3_resp.ftq_idx 941 XSError(true.B, "\ns3_redirect mechanism not implemented!\n") 942 } 943 944 io.toPrefetch.req.valid := allowToIfu && prefetchPtr =/= bpuPtr && entry_fetch_status(prefetchPtr.value) === f_to_send 945 io.toPrefetch.req.bits.target := update_target(prefetchPtr.value) 946 947 when(redirectVec.map(r => r.valid).reduce(_||_)){ 948 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 949 val next = r.ftqIdx + 1.U 950 prefetchPtr := next 951 } 952 953 XSError(isBefore(bpuPtr, prefetchPtr) && !isFull(bpuPtr, prefetchPtr), "\nprefetchPtr is before bpuPtr!\n") 954 } 955 else { 956 io.toPrefetch.req <> DontCare 957 } 958 959 // ****************************************************************************** 960 // **************************** commit perf counters **************************** 961 // ****************************************************************************** 962 963 val commit_inst_mask = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt 964 val commit_mispred_mask = commit_mispredict.asUInt 965 val commit_not_mispred_mask = ~commit_mispred_mask 966 967 val commit_br_mask = commit_pd.brMask.asUInt 968 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 969 val commit_cfi_mask = (commit_br_mask | commit_jmp_mask) 970 971 val mbpInstrs = commit_inst_mask & commit_cfi_mask 972 973 val mbpRights = mbpInstrs & commit_not_mispred_mask 974 val mbpWrongs = mbpInstrs & commit_mispred_mask 975 976 io.bpuInfo.bpRight := PopCount(mbpRights) 977 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 978 979 // Cfi Info 980 for (i <- 0 until PredictWidth) { 981 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 982 val v = commit_state(i) === c_commited 983 val isBr = commit_pd.brMask(i) 984 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 985 val isCfi = isBr || isJmp 986 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 987 val misPred = commit_mispredict(i) 988 // val ghist = commit_spec_meta.ghist.predHist 989 val histPtr = commit_spec_meta.histPtr 990 val predCycle = commit_meta.meta(63, 0) 991 val target = commit_target 992 993 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}))) 994 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_) 995 val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)) 996 XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 997 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " + 998 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 999 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n") 1000 } 1001 1002 val enq = io.fromBpu.resp 1003 val perf_redirect = io.fromBackend.redirect 1004 1005 XSPerfAccumulate("entry", validEntries) 1006 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 1007 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 1008 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 1009 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 1010 1011 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 1012 1013 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 1014 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 1015 XSPerfAccumulate("bpu_to_ftq_bubble", bpuPtr === ifuPtr) 1016 1017 val from_bpu = io.fromBpu.resp.bits 1018 def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = { 1019 assert(!resp.is_minimal) 1020 val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits 1021 val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U) 1022 val entry_len_map = (1 to PredictWidth+1).map(i => 1023 f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid) 1024 ).foldLeft(Map[String, UInt]())(_+_) 1025 entry_len_map 1026 } 1027 val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2") 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 ++ 1134 s2_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