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