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 // ********************************************************************* 612 // **************************** wb from ifu **************************** 613 // ********************************************************************* 614 val pdWb = io.fromIfu.pdWb 615 val pds = pdWb.bits.pd 616 val ifu_wb_valid = pdWb.valid 617 val ifu_wb_idx = pdWb.bits.ftqIdx.value 618 // read ports: commit update 619 val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1)) 620 ftq_pd_mem.io.wen(0) := ifu_wb_valid 621 ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value 622 ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits) 623 624 val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid 625 val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid 626 val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B) 627 val pd_reg = RegEnable(pds, enable = pdWb.valid) 628 val start_pc_reg = RegEnable(pdWb.bits.pc(0), enable = pdWb.valid) 629 val wb_idx_reg = RegEnable(ifu_wb_idx, enable = pdWb.valid) 630 631 when (ifu_wb_valid) { 632 val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{ 633 case (v, inRange) => v && inRange 634 }) 635 (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{ 636 case (qe, v) => when (v) { qe := c_valid } 637 } 638 } 639 640 ifuWbPtr := ifuWbPtr + ifu_wb_valid 641 642 ftb_entry_mem.io.raddr.head := ifu_wb_idx 643 val has_false_hit = WireInit(false.B) 644 when (RegNext(hit_pd_valid)) { 645 // check for false hit 646 val pred_ftb_entry = ftb_entry_mem.io.rdata.head 647 val brSlots = pred_ftb_entry.brSlots 648 val tailSlot = pred_ftb_entry.tailSlot 649 // we check cfis that bpu predicted 650 651 // bpu predicted branches but denied by predecode 652 val br_false_hit = 653 brSlots.map{ 654 s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr) 655 }.reduce(_||_) || 656 (tailSlot.valid && pred_ftb_entry.tailSlot.sharing && 657 !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr)) 658 659 val jmpOffset = tailSlot.offset 660 val jmp_pd = pd_reg(jmpOffset) 661 val jal_false_hit = pred_ftb_entry.jmpValid && 662 ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) || 663 (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) || 664 (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) || 665 (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)) 666 ) 667 668 has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg 669 XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0)) 670 671 // assert(!has_false_hit) 672 } 673 674 when (has_false_hit) { 675 entry_hit_status(wb_idx_reg) := h_false_hit 676 } 677 678 679 // ********************************************************************** 680 // **************************** backend read **************************** 681 // ********************************************************************** 682 683 // pc reads 684 for ((req, i) <- io.toBackend.pc_reads.zipWithIndex) { 685 ftq_pc_mem.io.raddr(i) := req.ptr.value 686 req.data := ftq_pc_mem.io.rdata(i).getPc(RegNext(req.offset)) 687 } 688 // target read 689 io.toBackend.target_read.data := RegNext(update_target(io.toBackend.target_read.ptr.value)) 690 691 // ******************************************************************************* 692 // **************************** redirect from backend **************************** 693 // ******************************************************************************* 694 695 // redirect read cfiInfo, couples to redirectGen s2 696 ftq_redirect_sram.io.ren.init.last := io.fromBackend.redirect.valid 697 ftq_redirect_sram.io.raddr.init.last := io.fromBackend.redirect.bits.ftqIdx.value 698 699 ftb_entry_mem.io.raddr.init.last := io.fromBackend.redirect.bits.ftqIdx.value 700 701 val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last 702 val fromBackendRedirect = WireInit(backendRedirectReg) 703 val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate 704 backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo) 705 706 val r_ftb_entry = ftb_entry_mem.io.rdata.init.last 707 val r_ftqOffset = fromBackendRedirect.bits.ftqOffset 708 709 when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) { 710 backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +& 711 (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) && 712 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 713 714 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) || 715 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 716 }.otherwise { 717 backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt 718 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt 719 } 720 721 722 // *************************************************************************** 723 // **************************** redirect from ifu **************************** 724 // *************************************************************************** 725 val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect))) 726 fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush 727 fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx 728 fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits 729 fromIfuRedirect.bits.level := RedirectLevel.flushAfter 730 731 val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate 732 ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits) 733 ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits) 734 ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid 735 ifuRedirectCfiUpdate.target := pdWb.bits.target 736 ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid 737 ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid 738 739 val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect))) 740 val ifuRedirectToBpu = WireInit(ifuRedirectReg) 741 ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid 742 743 ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid 744 ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 745 746 ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 747 748 val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate 749 toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head) 750 when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) { 751 toBpuCfi.target := toBpuCfi.rasEntry.retAddr 752 } 753 754 // ********************************************************************* 755 // **************************** wb from exu **************************** 756 // ********************************************************************* 757 758 def extractRedirectInfo(wb: Valid[Redirect]) = { 759 val ftqIdx = wb.bits.ftqIdx.value 760 val ftqOffset = wb.bits.ftqOffset 761 val taken = wb.bits.cfiUpdate.taken 762 val mispred = wb.bits.cfiUpdate.isMisPred 763 (wb.valid, ftqIdx, ftqOffset, taken, mispred) 764 } 765 766 // fix mispredict entry 767 val lastIsMispredict = RegNext( 768 backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B 769 ) 770 771 def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = { 772 val (r_valid, r_idx, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect) 773 val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits 774 val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits 775 when (cfiIndex_bits_wen || cfiIndex_valid_wen) { 776 cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken 777 } 778 when (cfiIndex_bits_wen) { 779 cfiIndex_vec(r_idx).bits := r_offset 780 } 781 update_target(r_idx) := redirect.bits.cfiUpdate.target 782 if (isBackend) { 783 mispredict_vec(r_idx)(r_offset) := r_mispred 784 } 785 } 786 787 when(backendRedirectReg.valid && lastIsMispredict) { 788 updateCfiInfo(backendRedirectReg) 789 }.elsewhen (ifuRedirectToBpu.valid) { 790 updateCfiInfo(ifuRedirectToBpu, isBackend=false) 791 } 792 793 // *********************************************************************************** 794 // **************************** flush ptr and state queue **************************** 795 // *********************************************************************************** 796 797 val redirectVec = VecInit(backendRedirect, fromIfuRedirect) 798 799 // when redirect, we should reset ptrs and status queues 800 when(redirectVec.map(r => r.valid).reduce(_||_)){ 801 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 802 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 803 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level)) 804 val next = idx + 1.U 805 bpuPtr := next 806 ifuPtr := next 807 ifuWbPtr := next 808 when (notIfu) { 809 commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) => 810 when(i.U > offset || i.U === offset && flushItSelf){ 811 s := c_invalid 812 } 813 }) 814 } 815 } 816 817 // only the valid bit is actually needed 818 io.toIfu.redirect.bits := backendRedirect.bits 819 io.toIfu.redirect.valid := stage2Flush 820 821 // commit 822 for (c <- io.fromBackend.rob_commits) { 823 when(c.valid) { 824 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited 825 // TODO: remove this 826 // For instruction fusions, we also update the next instruction 827 when (c.bits.commitType === 4.U) { 828 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited 829 }.elsewhen(c.bits.commitType === 5.U) { 830 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited 831 }.elsewhen(c.bits.commitType === 6.U) { 832 val index = (c.bits.ftqIdx + 1.U).value 833 commitStateQueue(index)(0) := c_commited 834 }.elsewhen(c.bits.commitType === 7.U) { 835 val index = (c.bits.ftqIdx + 1.U).value 836 commitStateQueue(index)(1) := c_commited 837 } 838 } 839 } 840 841 // **************************************************************** 842 // **************************** to bpu **************************** 843 // **************************************************************** 844 845 io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 846 847 val may_have_stall_from_bpu = RegInit(false.B) 848 val canCommit = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 849 Cat(commitStateQueue(commPtr.value).map(s => { 850 s === c_invalid || s === c_commited 851 })).andR() 852 853 // commit reads 854 ftq_pc_mem.io.raddr.last := commPtr.value 855 val commit_pc_bundle = ftq_pc_mem.io.rdata.last 856 ftq_pd_mem.io.raddr.last := commPtr.value 857 val commit_pd = ftq_pd_mem.io.rdata.last 858 ftq_redirect_sram.io.ren.last := canCommit 859 ftq_redirect_sram.io.raddr.last := commPtr.value 860 val commit_spec_meta = ftq_redirect_sram.io.rdata.last 861 ftq_meta_1r_sram.io.ren(0) := canCommit 862 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 863 val commit_meta = ftq_meta_1r_sram.io.rdata(0) 864 ftb_entry_mem.io.raddr.last := commPtr.value 865 val commit_ftb_entry = ftb_entry_mem.io.rdata.last 866 867 // need one cycle to read mem and srams 868 val do_commit_ptr = RegNext(commPtr) 869 val do_commit = RegNext(canCommit, init=false.B) 870 when (canCommit) { commPtr := commPtr + 1.U } 871 val commit_state = RegNext(commitStateQueue(commPtr.value)) 872 val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value)) 873 when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) { 874 can_commit_cfi.valid := false.B 875 } 876 val commit_cfi = RegNext(can_commit_cfi) 877 878 val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map { 879 case (mis, state) => mis && state === c_commited 880 }) 881 val can_commit_hit = entry_hit_status(commPtr.value) 882 val commit_hit = RegNext(can_commit_hit) 883 val commit_target = RegNext(update_target(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.fromFtqRedirectSram(commit_spec_meta) 897 898 val commit_real_hit = commit_hit === h_hit 899 val update_ftb_entry = update.ftb_entry 900 901 val ftbEntryGen = Module(new FTBEntryGen).io 902 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 903 ftbEntryGen.old_entry := commit_ftb_entry 904 ftbEntryGen.pd := commit_pd 905 ftbEntryGen.cfiIndex := commit_cfi 906 ftbEntryGen.target := commit_target 907 ftbEntryGen.hit := commit_real_hit 908 ftbEntryGen.mispredict_vec := commit_mispredict 909 910 update_ftb_entry := ftbEntryGen.new_entry 911 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 912 update.mispred_mask := ftbEntryGen.mispred_mask 913 update.old_entry := ftbEntryGen.is_old_entry 914 915 update.is_minimal := false.B 916 update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc) 917 update.full_pred.br_taken_mask := ftbEntryGen.taken_mask 918 update.full_pred.jalr_target := commit_target 919 update.full_pred.hit := true.B 920 when (update.full_pred.is_jalr) { 921 update.full_pred.targets.last := commit_target 922 } 923 924 // **************************************************************** 925 // *********************** to prefetch **************************** 926 // **************************************************************** 927 928 if(cacheParams.hasPrefetch){ 929 val prefetchPtr = RegInit(FtqPtr(false.B, 0.U)) 930 prefetchPtr := prefetchPtr + io.toPrefetch.req.fire() 931 932 when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect && !isBefore(prefetchPtr, bpu_s2_resp.ftq_idx)) { 933 prefetchPtr := bpu_s2_resp.ftq_idx 934 } 935 936 io.toPrefetch.req.valid := allowToIfu && prefetchPtr =/= bpuPtr && entry_fetch_status(prefetchPtr.value) === f_to_send 937 io.toPrefetch.req.bits.target := update_target(prefetchPtr.value) 938 939 when(redirectVec.map(r => r.valid).reduce(_||_)){ 940 val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits))) 941 val next = r.ftqIdx + 1.U 942 prefetchPtr := next 943 } 944 945 XSError(isBefore(bpuPtr, prefetchPtr) && !isFull(bpuPtr, prefetchPtr), "\nprefetchPtr is before bpuPtr!\n") 946 } 947 else { 948 io.toPrefetch.req <> DontCare 949 } 950 951 // ****************************************************************************** 952 // **************************** commit perf counters **************************** 953 // ****************************************************************************** 954 955 val commit_inst_mask = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt 956 val commit_mispred_mask = commit_mispredict.asUInt 957 val commit_not_mispred_mask = ~commit_mispred_mask 958 959 val commit_br_mask = commit_pd.brMask.asUInt 960 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 961 val commit_cfi_mask = (commit_br_mask | commit_jmp_mask) 962 963 val mbpInstrs = commit_inst_mask & commit_cfi_mask 964 965 val mbpRights = mbpInstrs & commit_not_mispred_mask 966 val mbpWrongs = mbpInstrs & commit_mispred_mask 967 968 io.bpuInfo.bpRight := PopCount(mbpRights) 969 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 970 971 // Cfi Info 972 for (i <- 0 until PredictWidth) { 973 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 974 val v = commit_state(i) === c_commited 975 val isBr = commit_pd.brMask(i) 976 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 977 val isCfi = isBr || isJmp 978 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 979 val misPred = commit_mispredict(i) 980 // val ghist = commit_spec_meta.ghist.predHist 981 val histPtr = commit_spec_meta.histPtr 982 val predCycle = commit_meta.meta(63, 0) 983 val target = commit_target 984 985 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}))) 986 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_) 987 val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)) 988 XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 989 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " + 990 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 991 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n") 992 } 993 994 val enq = io.fromBpu.resp 995 val perf_redirect = io.fromBackend.redirect 996 997 XSPerfAccumulate("entry", validEntries) 998 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 999 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 1000 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 1001 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 1002 1003 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 1004 1005 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 1006 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 1007 XSPerfAccumulate("bpu_to_ftq_bubble", bpuPtr === ifuPtr) 1008 1009 val from_bpu = io.fromBpu.resp.bits 1010 def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = { 1011 assert(!resp.is_minimal) 1012 val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits 1013 val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U) 1014 val entry_len_map = (1 to PredictWidth+1).map(i => 1015 f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid) 1016 ).foldLeft(Map[String, UInt]())(_+_) 1017 entry_len_map 1018 } 1019 val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2") 1020 1021 val to_ifu = io.toIfu.req.bits 1022 1023 1024 1025 val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U) 1026 val commit_num_inst_map = (1 to PredictWidth).map(i => 1027 f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit) 1028 ).foldLeft(Map[String, UInt]())(_+_) 1029 1030 1031 1032 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 1033 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 1034 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 1035 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 1036 1037 1038 val mbpBRights = mbpRights & commit_br_mask 1039 val mbpJRights = mbpRights & commit_jal_mask 1040 val mbpIRights = mbpRights & commit_jalr_mask 1041 val mbpCRights = mbpRights & commit_call_mask 1042 val mbpRRights = mbpRights & commit_ret_mask 1043 1044 val mbpBWrongs = mbpWrongs & commit_br_mask 1045 val mbpJWrongs = mbpWrongs & commit_jal_mask 1046 val mbpIWrongs = mbpWrongs & commit_jalr_mask 1047 val mbpCWrongs = mbpWrongs & commit_call_mask 1048 val mbpRWrongs = mbpWrongs & commit_ret_mask 1049 1050 val commit_pred_stage = RegNext(pred_stage(commPtr.value)) 1051 1052 def pred_stage_map(src: UInt, name: String) = { 1053 (0 until numBpStages).map(i => 1054 f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i))) 1055 ).foldLeft(Map[String, UInt]())(_+_) 1056 } 1057 1058 val mispred_stage_map = pred_stage_map(mbpWrongs, "mispredict") 1059 val br_mispred_stage_map = pred_stage_map(mbpBWrongs, "br_mispredict") 1060 val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict") 1061 val correct_stage_map = pred_stage_map(mbpRights, "correct") 1062 val br_correct_stage_map = pred_stage_map(mbpBRights, "br_correct") 1063 val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct") 1064 1065 val update_valid = io.toBpu.update.valid 1066 def u(cond: Bool) = update_valid && cond 1067 val ftb_false_hit = u(update.false_hit) 1068 // assert(!ftb_false_hit) 1069 val ftb_hit = u(commit_hit === h_hit) 1070 1071 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1072 val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid 1073 val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0) 1074 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid 1075 1076 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1077 1078 val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified) 1079 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1080 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1081 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1082 val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified 1083 1084 val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits 1085 val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U) 1086 val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i => 1087 f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry) 1088 ).foldLeft(Map[String, UInt]())(_+_) 1089 val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i => 1090 f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry) 1091 ).foldLeft(Map[String, UInt]())(_+_) 1092 1093 val ftq_occupancy_map = (0 to FtqSize).map(i => 1094 f"ftq_has_entry_$i" ->( validEntries === i.U) 1095 ).foldLeft(Map[String, UInt]())(_+_) 1096 1097 val perfCountsMap = Map( 1098 "BpInstr" -> PopCount(mbpInstrs), 1099 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1100 "BpRight" -> PopCount(mbpRights), 1101 "BpWrong" -> PopCount(mbpWrongs), 1102 "BpBRight" -> PopCount(mbpBRights), 1103 "BpBWrong" -> PopCount(mbpBWrongs), 1104 "BpJRight" -> PopCount(mbpJRights), 1105 "BpJWrong" -> PopCount(mbpJWrongs), 1106 "BpIRight" -> PopCount(mbpIRights), 1107 "BpIWrong" -> PopCount(mbpIWrongs), 1108 "BpCRight" -> PopCount(mbpCRights), 1109 "BpCWrong" -> PopCount(mbpCWrongs), 1110 "BpRRight" -> PopCount(mbpRRights), 1111 "BpRWrong" -> PopCount(mbpRWrongs), 1112 1113 "ftb_false_hit" -> PopCount(ftb_false_hit), 1114 "ftb_hit" -> PopCount(ftb_hit), 1115 "ftb_new_entry" -> PopCount(ftb_new_entry), 1116 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1117 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1118 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1119 "ftb_old_entry" -> PopCount(ftb_old_entry), 1120 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1121 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1122 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1123 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1124 "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken) 1125 ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ 1126 s2_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map ++ 1127 mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++ 1128 correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map 1129 1130 for((key, value) <- perfCountsMap) { 1131 XSPerfAccumulate(key, value) 1132 } 1133 1134 // --------------------------- Debug -------------------------------- 1135 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1136 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1137 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1138 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1139 XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1140 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n") 1141 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1142 1143 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1144 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1145 // case (((valid, pd), ans), taken) => 1146 // Mux(valid && pd.isBr, 1147 // isWrong ^ Mux(ans.hit.asBool, 1148 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1149 // !taken), 1150 // !taken), 1151 // false.B) 1152 // } 1153 // } 1154 1155 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1156 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1157 // case (((valid, pd), ans), taken) => 1158 // Mux(valid && pd.isBr, 1159 // isWrong ^ Mux(ans.hit.asBool, 1160 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1161 // !taken), 1162 // !taken), 1163 // false.B) 1164 // } 1165 // } 1166 1167 // def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1168 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1169 // case (((valid, pd), ans), taken) => 1170 // Mux(valid && pd.isBr, 1171 // isWrong ^ (ans.taken.asBool === taken), 1172 // false.B) 1173 // } 1174 // } 1175 1176 // def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1177 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1178 // case (((valid, pd), ans), taken) => 1179 // Mux(valid && (pd.isBr) && ans.hit.asBool, 1180 // isWrong ^ (!taken), 1181 // false.B) 1182 // } 1183 // } 1184 1185 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1186 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1187 // case (((valid, pd), ans), taken) => 1188 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1189 // isWrong ^ (ans.target === commitEntry.target), 1190 // false.B) 1191 // } 1192 // } 1193 1194 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1195 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1196 // // btb and ubtb pred jal and jalr as well 1197 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1198 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1199 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1200 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1201 1202 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1203 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1204 1205 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1206 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1207 1208 val perfEvents = Seq( 1209 ("bpu_s2_redirect ", bpu_s2_redirect ), 1210 // ("bpu_s3_redirect ", bpu_s3_redirect ), 1211 ("bpu_to_ftq_stall ", enq.valid && ~enq.ready ), 1212 ("mispredictRedirect ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level), 1213 ("replayRedirect ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level) ), 1214 ("predecodeRedirect ", fromIfuRedirect.valid ), 1215 ("to_ifu_bubble ", io.toIfu.req.ready && !io.toIfu.req.valid ), 1216 ("from_bpu_real_bubble ", !enq.valid && enq.ready && allowBpuIn ), 1217 ("BpInstr ", PopCount(mbpInstrs) ), 1218 ("BpBInstr ", PopCount(mbpBRights | mbpBWrongs) ), 1219 ("BpRight ", PopCount(mbpRights) ), 1220 ("BpWrong ", PopCount(mbpWrongs) ), 1221 ("BpBRight ", PopCount(mbpBRights) ), 1222 ("BpBWrong ", PopCount(mbpBWrongs) ), 1223 ("BpJRight ", PopCount(mbpJRights) ), 1224 ("BpJWrong ", PopCount(mbpJWrongs) ), 1225 ("BpIRight ", PopCount(mbpIRights) ), 1226 ("BpIWrong ", PopCount(mbpIWrongs) ), 1227 ("BpCRight ", PopCount(mbpCRights) ), 1228 ("BpCWrong ", PopCount(mbpCWrongs) ), 1229 ("BpRRight ", PopCount(mbpRRights) ), 1230 ("BpRWrong ", PopCount(mbpRWrongs) ), 1231 ("ftb_false_hit ", PopCount(ftb_false_hit) ), 1232 ("ftb_hit ", PopCount(ftb_hit) ), 1233 ) 1234 generatePerfEvent() 1235} 1236