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