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