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