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