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