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