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