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