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.{AsyncDataModuleTemplate, CircularQueuePtr, DataModuleTemplate, HasCircularQueuePtrHelper, SRAMTemplate, SyncDataModuleTemplate, XSDebug, XSPerfAccumulate, PerfBundle, PerfEventsBundle, XSError} 23import xiangshan._ 24import scala.tools.nsc.doc.model.Val 25import utils.{ParallelPriorityMux, ParallelPriorityEncoder} 26import xiangshan.backend.{CtrlToFtqIO} 27import firrtl.annotations.MemoryLoadFileType 28 29class FtqPtr(implicit p: Parameters) extends CircularQueuePtr[FtqPtr]( 30 p => p(XSCoreParamsKey).FtqSize 31){ 32 override def cloneType = (new FtqPtr).asInstanceOf[this.type] 33} 34 35object FtqPtr { 36 def apply(f: Bool, v: UInt)(implicit p: Parameters): FtqPtr = { 37 val ptr = Wire(new FtqPtr) 38 ptr.flag := f 39 ptr.value := v 40 ptr 41 } 42 def inverse(ptr: FtqPtr)(implicit p: Parameters): FtqPtr = { 43 apply(!ptr.flag, ptr.value) 44 } 45} 46 47class FtqNRSRAM[T <: Data](gen: T, numRead: Int)(implicit p: Parameters) extends XSModule { 48 49 val io = IO(new Bundle() { 50 val raddr = Input(Vec(numRead, UInt(log2Up(FtqSize).W))) 51 val ren = Input(Vec(numRead, Bool())) 52 val rdata = Output(Vec(numRead, gen)) 53 val waddr = Input(UInt(log2Up(FtqSize).W)) 54 val wen = Input(Bool()) 55 val wdata = Input(gen) 56 }) 57 58 for(i <- 0 until numRead){ 59 val sram = Module(new SRAMTemplate(gen, FtqSize)) 60 sram.io.r.req.valid := io.ren(i) 61 sram.io.r.req.bits.setIdx := io.raddr(i) 62 io.rdata(i) := sram.io.r.resp.data(0) 63 sram.io.w.req.valid := io.wen 64 sram.io.w.req.bits.setIdx := io.waddr 65 sram.io.w.req.bits.data := VecInit(io.wdata) 66 } 67 68} 69 70class Ftq_RF_Components(implicit p: Parameters) extends XSBundle with BPUUtils { 71 // TODO: move pftAddr, oversize, carry to another mem 72 val startAddr = UInt(VAddrBits.W) 73 val nextRangeAddr = UInt(VAddrBits.W) 74 val pftAddr = UInt((log2Ceil(PredictWidth)+1).W) 75 val isNextMask = Vec(PredictWidth, Bool()) 76 val oversize = Bool() 77 val carry = Bool() 78 def getPc(offset: UInt) = { 79 def getHigher(pc: UInt) = pc(VAddrBits-1, log2Ceil(PredictWidth)+instOffsetBits) 80 def getOffset(pc: UInt) = pc(log2Ceil(PredictWidth)+instOffsetBits-1, instOffsetBits) 81 Cat(getHigher(Mux(isNextMask(offset), nextRangeAddr, startAddr)), 82 getOffset(startAddr)+offset, 0.U(instOffsetBits.W)) 83 } 84 def getFallThrough() = { 85 getFallThroughAddr(this.startAddr, this.carry, this.pftAddr) 86 } 87 def fallThroughError() = { 88 !carry && startAddr(instOffsetBits+log2Ceil(PredictWidth), instOffsetBits) > pftAddr 89 } 90 def fromBranchPrediction(resp: BranchPredictionBundle) = { 91 this.startAddr := resp.pc 92 this.nextRangeAddr := resp.pc + (FetchWidth * 4).U 93 this.pftAddr := resp.ftb_entry.pftAddr 94 this.isNextMask := VecInit((0 until PredictWidth).map(i => 95 (resp.pc(log2Ceil(PredictWidth), 1) +& i.U)(log2Ceil(PredictWidth)).asBool() 96 )) 97 this.oversize := resp.ftb_entry.oversize 98 this.carry := resp.ftb_entry.carry 99 this 100 } 101 override def toPrintable: Printable = { 102 p"startAddr:${Hexadecimal(startAddr)}, fallThru:${Hexadecimal(getFallThrough())}" 103 } 104} 105 106class Ftq_pd_Entry(implicit p: Parameters) extends XSBundle { 107 val brMask = Vec(PredictWidth, Bool()) 108 val jmpInfo = ValidUndirectioned(Vec(3, Bool())) 109 val jmpOffset = UInt(log2Ceil(PredictWidth).W) 110 val jalTarget = UInt(VAddrBits.W) 111 val rvcMask = Vec(PredictWidth, Bool()) 112 def hasJal = jmpInfo.valid && !jmpInfo.bits(0) 113 def hasJalr = jmpInfo.valid && jmpInfo.bits(0) 114 def hasCall = jmpInfo.valid && jmpInfo.bits(1) 115 def hasRet = jmpInfo.valid && jmpInfo.bits(2) 116 117 def fromPdWb(pdWb: PredecodeWritebackBundle) = { 118 val pds = pdWb.pd 119 this.brMask := VecInit(pds.map(pd => pd.isBr && pd.valid)) 120 this.jmpInfo.valid := VecInit(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)).asUInt.orR 121 this.jmpInfo.bits := ParallelPriorityMux(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid), 122 pds.map(pd => VecInit(pd.isJalr, pd.isCall, pd.isRet))) 123 this.jmpOffset := ParallelPriorityEncoder(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)) 124 this.rvcMask := VecInit(pds.map(pd => pd.isRVC)) 125 this.jalTarget := pdWb.jalTarget 126 } 127 128 def toPd(offset: UInt) = { 129 require(offset.getWidth == log2Ceil(PredictWidth)) 130 val pd = Wire(new PreDecodeInfo) 131 pd.valid := true.B 132 pd.isRVC := rvcMask(offset) 133 val isBr = brMask(offset) 134 val isJalr = offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(0) 135 pd.brType := Cat(offset === jmpOffset && jmpInfo.valid, isJalr || isBr) 136 pd.isCall := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(1) 137 pd.isRet := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(2) 138 pd 139 } 140} 141 142 143 144class Ftq_Redirect_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst { 145 val rasSp = UInt(log2Ceil(RasSize).W) 146 val rasEntry = new RASEntry 147 val specCnt = Vec(numBr, UInt(10.W)) 148 // val ghist = new ShiftingGlobalHistory 149 val histPtr = new CGHPtr 150 val phist = UInt(PathHistoryLength.W) 151 val phNewBit = UInt(1.W) 152 153 def fromBranchPrediction(resp: BranchPredictionBundle) = { 154 this.rasSp := resp.rasSp 155 this.rasEntry := resp.rasTop 156 this.specCnt := resp.specCnt 157 // this.ghist := resp.ghist 158 this.histPtr := resp.histPtr 159 this.phist := resp.phist 160 this.phNewBit := resp.pc(instOffsetBits) 161 this 162 } 163} 164 165class Ftq_1R_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst { 166 val meta = UInt(MaxMetaLength.W) 167} 168 169class Ftq_Pred_Info(implicit p: Parameters) extends XSBundle { 170 val target = UInt(VAddrBits.W) 171 val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)) 172} 173 174// class FtqEntry(implicit p: Parameters) extends XSBundle with HasBPUConst { 175// val startAddr = UInt(VAddrBits.W) 176// val fallThruAddr = UInt(VAddrBits.W) 177// val isNextMask = Vec(PredictWidth, Bool()) 178 179// val meta = UInt(MaxMetaLength.W) 180 181// val rasSp = UInt(log2Ceil(RasSize).W) 182// val rasEntry = new RASEntry 183// val hist = new ShiftingGlobalHistory 184// val specCnt = Vec(numBr, UInt(10.W)) 185 186// val valids = Vec(PredictWidth, Bool()) 187// val brMask = Vec(PredictWidth, Bool()) 188// // isJalr, isCall, isRet 189// val jmpInfo = ValidUndirectioned(Vec(3, Bool())) 190// val jmpOffset = UInt(log2Ceil(PredictWidth).W) 191 192// val mispredVec = Vec(PredictWidth, Bool()) 193// val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)) 194// val target = UInt(VAddrBits.W) 195// } 196 197class FtqRead[T <: Data](private val gen: T)(implicit p: Parameters) extends XSBundle { 198 val ptr = Output(new FtqPtr) 199 val offset = Output(UInt(log2Ceil(PredictWidth).W)) 200 val data = Input(gen) 201 def apply(ptr: FtqPtr, offset: UInt) = { 202 this.ptr := ptr 203 this.offset := offset 204 this.data 205 } 206 override def cloneType = (new FtqRead(gen)).asInstanceOf[this.type] 207} 208 209 210class FtqToBpuIO(implicit p: Parameters) extends XSBundle { 211 val redirect = Valid(new BranchPredictionRedirect) 212 val update = Valid(new BranchPredictionUpdate) 213 val enq_ptr = Output(new FtqPtr) 214} 215 216class FtqToIfuIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper { 217 val req = Decoupled(new FetchRequestBundle) 218 val redirect = Valid(new Redirect) 219 val flushFromBpu = new Bundle { 220 // when ifu pipeline is not stalled, 221 // a packet from bpu s3 can reach f1 at most 222 val s2 = Valid(new FtqPtr) 223 val s3 = Valid(new FtqPtr) 224 def shouldFlushBy(src: Valid[FtqPtr], idx_to_flush: FtqPtr) = { 225 src.valid && !isAfter(src.bits, idx_to_flush) 226 } 227 def shouldFlushByStage2(idx: FtqPtr) = shouldFlushBy(s2, idx) 228 def shouldFlushByStage3(idx: FtqPtr) = shouldFlushBy(s3, idx) 229 } 230} 231 232trait HasBackendRedirectInfo extends HasXSParameter { 233 def numRedirect = exuParameters.JmpCnt + exuParameters.AluCnt + 1 234 def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself() 235} 236 237class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo { 238 val pc_reads = Vec(1 + numRedirect + 1 + 1, Flipped(new FtqRead(UInt(VAddrBits.W)))) 239 val target_read = Flipped(new FtqRead(UInt(VAddrBits.W))) 240 def getJumpPcRead = pc_reads.head 241 def getRedirectPcRead = VecInit(pc_reads.tail.dropRight(2)) 242 def getMemPredPcRead = pc_reads.init.last 243 def getRobFlushPcRead = pc_reads.last 244} 245 246 247class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter { 248 val io = IO(new Bundle { 249 val start_addr = Input(UInt(VAddrBits.W)) 250 val old_entry = Input(new FTBEntry) 251 val pd = Input(new Ftq_pd_Entry) 252 val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W))) 253 val target = Input(UInt(VAddrBits.W)) 254 val hit = Input(Bool()) 255 val mispredict_vec = Input(Vec(PredictWidth, Bool())) 256 257 val new_entry = Output(new FTBEntry) 258 val new_br_insert_pos = Output(Vec(numBr, Bool())) 259 val taken_mask = Output(Vec(numBr, Bool())) 260 val mispred_mask = Output(Vec(numBr+1, Bool())) 261 262 // for perf counters 263 val is_init_entry = Output(Bool()) 264 val is_old_entry = Output(Bool()) 265 val is_new_br = Output(Bool()) 266 val is_jalr_target_modified = Output(Bool()) 267 val is_always_taken_modified = Output(Bool()) 268 val is_br_full = Output(Bool()) 269 }) 270 271 // no mispredictions detected at predecode 272 val hit = io.hit 273 val pd = io.pd 274 275 val init_entry = WireInit(0.U.asTypeOf(new FTBEntry)) 276 277 278 val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid 279 val entry_has_jmp = pd.jmpInfo.valid 280 val new_jmp_is_jal = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid 281 val new_jmp_is_jalr = entry_has_jmp && pd.jmpInfo.bits(0) && io.cfiIndex.valid 282 val new_jmp_is_call = entry_has_jmp && pd.jmpInfo.bits(1) && io.cfiIndex.valid 283 val new_jmp_is_ret = entry_has_jmp && pd.jmpInfo.bits(2) && io.cfiIndex.valid 284 val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask.last 285 val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last 286 287 val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal 288 val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr 289 290 def carryPos = log2Ceil(PredictWidth)+instOffsetBits+1 291 def getLower(pc: UInt) = pc(carryPos-1, instOffsetBits) 292 // if not hit, establish a new entry 293 init_entry.valid := true.B 294 // tag is left for ftb to assign 295 296 // case br 297 val init_br_slot = init_entry.getSlotForBr(0) 298 when (cfi_is_br) { 299 init_br_slot.valid := true.B 300 init_br_slot.offset := io.cfiIndex.bits 301 init_br_slot.setLowerStatByTarget(io.start_addr, io.target, shareTailSlot && numBr == 1) 302 init_entry.always_taken(0) := true.B // set to always taken on init 303 } 304 // init_entry.isBrSharing := shareTailSlot.B && (numBr == 1).B && cfi_is_br 305 306 // case jmp 307 when (entry_has_jmp) { 308 init_entry.tailSlot.offset := pd.jmpOffset 309 init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr 310 init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare=false) 311 } 312 313 val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U) 314 init_entry.pftAddr := Mux(entry_has_jmp, jmpPft, getLower(io.start_addr) + ((FetchWidth*4)>>instOffsetBits).U + Mux(last_br_rvi, 1.U, 0.U)) 315 init_entry.carry := Mux(entry_has_jmp, jmpPft(carryPos-instOffsetBits), io.start_addr(carryPos-1) || (io.start_addr(carryPos-2, instOffsetBits).andR && last_br_rvi)) 316 init_entry.isJalr := new_jmp_is_jalr 317 init_entry.isCall := new_jmp_is_call 318 init_entry.isRet := new_jmp_is_ret 319 init_entry.last_is_rvc := Mux(entry_has_jmp, pd.rvcMask(pd.jmpOffset), pd.rvcMask.last) 320 321 init_entry.oversize := last_br_rvi || last_jmp_rvi 322 323 // if hit, check whether a new cfi(only br is possible) is detected 324 val oe = io.old_entry 325 val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits) 326 val br_recorded = br_recorded_vec.asUInt.orR 327 val is_new_br = cfi_is_br && !br_recorded 328 val new_br_offset = io.cfiIndex.bits 329 // vec(i) means new br will be inserted BEFORE old br(i) 330 val allBrSlotsVec = oe.allSlotsForBr 331 val new_br_insert_onehot = VecInit((0 until numBr).map{ 332 i => i match { 333 case 0 => 334 !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset 335 case idx => 336 allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset && 337 (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset) 338 } 339 }) 340 341 val old_entry_modified = WireInit(io.old_entry) 342 for (i <- 0 until numBr) { 343 val slot = old_entry_modified.allSlotsForBr(i) 344 when (new_br_insert_onehot(i)) { 345 slot.valid := true.B 346 slot.offset := new_br_offset 347 slot.setLowerStatByTarget(io.start_addr, io.target, shareTailSlot && i == numBr-1) 348 old_entry_modified.always_taken(i) := true.B 349 }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) { 350 old_entry_modified.always_taken(i) := false.B 351 // all other fields remain unchanged 352 }.otherwise { 353 // case i == 0, remain unchanged 354 if (i != 0) { 355 val noNeedToMoveFromFormerSlot = (shareTailSlot && i == numBr-1).B && !oe.brSlots.last.valid 356 when (!noNeedToMoveFromFormerSlot) { 357 slot.fromAnotherSlot(oe.allSlotsForBr(i-1)) 358 old_entry_modified.always_taken(i) := oe.always_taken(i) 359 } 360 } 361 } 362 } 363 364 // two circumstances: 365 // 1. oe: | br | j |, new br should be in front of j, thus addr of j should be new pft 366 // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either 367 // the previous last br or the new br 368 val may_have_to_replace = oe.noEmptySlotForNewBr 369 val pft_need_to_change = is_new_br && may_have_to_replace 370 // it should either be the given last br or the new br 371 when (pft_need_to_change) { 372 val new_pft_offset = 373 Mux(!new_br_insert_onehot.asUInt.orR, 374 new_br_offset, oe.allSlotsForBr.last.offset) 375 376 // set jmp to invalid 377 if (!shareTailSlot) { 378 old_entry_modified.tailSlot.valid := false.B 379 } 380 old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset 381 old_entry_modified.last_is_rvc := pd.rvcMask(new_pft_offset - 1.U) // TODO: fix this 382 old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool 383 old_entry_modified.oversize := false.B 384 old_entry_modified.isCall := false.B 385 old_entry_modified.isRet := false.B 386 old_entry_modified.isJalr := false.B 387 } 388 389 val old_entry_jmp_target_modified = WireInit(oe) 390 val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits 391 val old_tail_is_jmp = !oe.tailSlot.sharing || !shareTailSlot.B 392 val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target 393 when (jalr_target_modified) { 394 old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target) 395 old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool())) 396 } 397 398 val old_entry_always_taken = WireInit(oe) 399 val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not 400 for (i <- 0 until numBr) { 401 old_entry_always_taken.always_taken(i) := 402 oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i) 403 always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i) 404 } 405 val always_taken_modified = always_taken_modified_vec.reduce(_||_) 406 407 408 409 val derived_from_old_entry = 410 Mux(is_new_br, old_entry_modified, 411 Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken)) 412 413 414 io.new_entry := Mux(!hit, init_entry, derived_from_old_entry) 415 416 io.new_br_insert_pos := new_br_insert_onehot 417 io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{ 418 case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v 419 }) 420 for (i <- 0 until numBr) { 421 io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i)) 422 } 423 io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset) 424 425 // for perf counters 426 io.is_init_entry := !hit 427 io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified 428 io.is_new_br := hit && is_new_br 429 io.is_jalr_target_modified := hit && jalr_target_modified 430 io.is_always_taken_modified := hit && always_taken_modified 431 io.is_br_full := hit && is_new_br && may_have_to_replace 432} 433 434class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper 435 with HasBackendRedirectInfo with BPUUtils with HasBPUConst { 436 val io = IO(new Bundle { 437 val fromBpu = Flipped(new BpuToFtqIO) 438 val fromIfu = Flipped(new IfuToFtqIO) 439 val fromBackend = Flipped(new CtrlToFtqIO) 440 441 val toBpu = new FtqToBpuIO 442 val toIfu = new FtqToIfuIO 443 val toBackend = new FtqToCtrlIO 444 445 val bpuInfo = new Bundle { 446 val bpRight = Output(UInt(XLEN.W)) 447 val bpWrong = Output(UInt(XLEN.W)) 448 } 449 }) 450 io.bpuInfo := DontCare 451 452 val robFlush = io.fromBackend.robFlush 453 val stage2Redirect = io.fromBackend.stage2Redirect 454 val stage3Redirect = io.fromBackend.stage3Redirect 455 456 val stage2Flush = stage2Redirect.valid || robFlush.valid 457 val backendFlush = stage2Flush || RegNext(stage2Flush) 458 val ifuFlush = Wire(Bool()) 459 460 val flush = stage2Flush || RegNext(stage2Flush) 461 462 val allowBpuIn, allowToIfu = WireInit(false.B) 463 val flushToIfu = !allowToIfu 464 allowBpuIn := !ifuFlush && !robFlush.valid && !stage2Redirect.valid && !stage3Redirect.valid 465 allowToIfu := !ifuFlush && !robFlush.valid && !stage2Redirect.valid && !stage3Redirect.valid 466 467 val bpuPtr, ifuPtr, ifuWbPtr, commPtr = RegInit(FtqPtr(false.B, 0.U)) 468 val validEntries = distanceBetween(bpuPtr, commPtr) 469 470 // ********************************************************************** 471 // **************************** enq from bpu **************************** 472 // ********************************************************************** 473 val new_entry_ready = validEntries < FtqSize.U 474 io.fromBpu.resp.ready := new_entry_ready 475 476 val bpu_s2_resp = io.fromBpu.resp.bits.s2 477 val bpu_s3_resp = io.fromBpu.resp.bits.s3 478 val bpu_s2_redirect = bpu_s2_resp.valid && bpu_s2_resp.hasRedirect 479 val bpu_s3_redirect = bpu_s3_resp.valid && bpu_s3_resp.hasRedirect 480 481 io.toBpu.enq_ptr := bpuPtr 482 val enq_fire = io.fromBpu.resp.fire() && allowBpuIn // from bpu s1 483 val bpu_in_fire = (io.fromBpu.resp.fire() || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn 484 485 val bpu_in_resp = WireInit(io.fromBpu.resp.bits.selectedResp) 486 val bpu_in_stage = WireInit(io.fromBpu.resp.bits.selectedRespIdx) 487 val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx) 488 val bpu_in_resp_idx = bpu_in_resp_ptr.value 489 490 // read ports: jumpPc + redirects + loadPred + robFlush + ifuReq1 + ifuReq2 + commitUpdate 491 val ftq_pc_mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, 1+numRedirect+2+1+1+1, 1)) 492 // resp from uBTB 493 ftq_pc_mem.io.wen(0) := bpu_in_fire 494 ftq_pc_mem.io.waddr(0) := bpu_in_resp_idx 495 ftq_pc_mem.io.wdata(0).fromBranchPrediction(bpu_in_resp) 496 497 // ifuRedirect + backendRedirect + commit 498 val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+1+1)) 499 // these info is intended to enq at the last stage of bpu 500 ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid 501 ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 502 ftq_redirect_sram.io.wdata.fromBranchPrediction(io.fromBpu.resp.bits.lastStage) 503 504 val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1)) 505 // these info is intended to enq at the last stage of bpu 506 ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid 507 ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 508 ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.meta 509 // ifuRedirect + backendRedirect + commit 510 val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+1+1, 1)) 511 ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid 512 ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value 513 ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.lastStage.ftb_entry 514 515 516 // multi-write 517 val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) 518 val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))) 519 val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool()))) 520 val pred_stage = Reg(Vec(FtqSize, UInt(2.W))) 521 522 val c_invalid :: c_valid :: c_commited :: Nil = Enum(3) 523 val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) { 524 VecInit(Seq.fill(PredictWidth)(c_invalid)) 525 })) 526 527 val f_to_send :: f_sent :: Nil = Enum(2) 528 val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent))) 529 530 val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3) 531 val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit))) 532 533 534 when (bpu_in_fire) { 535 entry_fetch_status(bpu_in_resp_idx) := f_to_send 536 commitStateQueue(bpu_in_resp_idx) := VecInit(Seq.fill(PredictWidth)(c_invalid)) 537 cfiIndex_vec(bpu_in_resp_idx) := bpu_in_resp.genCfiIndex 538 mispredict_vec(bpu_in_resp_idx) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B))) 539 update_target(bpu_in_resp_idx) := bpu_in_resp.target 540 pred_stage(bpu_in_resp_idx) := bpu_in_stage 541 } 542 543 bpuPtr := bpuPtr + enq_fire 544 ifuPtr := ifuPtr + io.toIfu.req.fire 545 546 // only use ftb result to assign hit status 547 when (bpu_s2_resp.valid) { 548 entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.preds.hit, h_hit, h_not_hit) 549 } 550 551 552 io.toIfu.flushFromBpu.s2.valid := bpu_s2_resp.valid && bpu_s2_resp.hasRedirect 553 io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx 554 when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect) { 555 bpuPtr := bpu_s2_resp.ftq_idx + 1.U 556 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 557 when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) { 558 ifuPtr := bpu_s2_resp.ftq_idx 559 } 560 } 561 562 io.toIfu.flushFromBpu.s3.valid := bpu_s3_resp.valid && bpu_s3_resp.hasRedirect 563 io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx 564 when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect) { 565 bpuPtr := bpu_s3_resp.ftq_idx + 1.U 566 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 567 when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) { 568 ifuPtr := bpu_s3_resp.ftq_idx 569 } 570 XSError(true.B, "\ns3_redirect mechanism not implemented!\n") 571 } 572 573 XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n") 574 575 // **************************************************************** 576 // **************************** to ifu **************************** 577 // **************************************************************** 578 val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata(0), enable=bpu_in_fire) 579 val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr) 580 val last_cycle_bpu_in = RegNext(bpu_in_fire) 581 val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire) 582 583 // read pc and target 584 ftq_pc_mem.io.raddr.init.init.last := ifuPtr.value 585 ftq_pc_mem.io.raddr.init.last := (ifuPtr+1.U).value 586 587 val toIfuReq = Wire(chiselTypeOf(io.toIfu.req)) 588 589 toIfuReq.valid := allowToIfu && entry_fetch_status(ifuPtr.value) === f_to_send && ifuPtr =/= bpuPtr 590 toIfuReq.bits.ftqIdx := ifuPtr 591 toIfuReq.bits.target := update_target(ifuPtr.value) 592 toIfuReq.bits.ftqOffset := cfiIndex_vec(ifuPtr.value) 593 toIfuReq.bits.fallThruError := false.B 594 595 when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) { 596 toIfuReq.bits.fromFtqPcBundle(bpu_in_bypass_buf) 597 }.elsewhen (last_cycle_to_ifu_fire) { 598 toIfuReq.bits.fromFtqPcBundle(ftq_pc_mem.io.rdata.init.last) 599 }.otherwise { 600 toIfuReq.bits.fromFtqPcBundle(ftq_pc_mem.io.rdata.init.init.last) 601 } 602 603 io.toIfu.req <> toIfuReq 604 605 // when fall through is smaller in value than start address, there must be a false hit 606 when (toIfuReq.bits.fallThroughError() && entry_hit_status(ifuPtr.value) === h_hit) { 607 when (io.toIfu.req.fire && 608 !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && 609 !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr) 610 ) { 611 entry_hit_status(ifuPtr.value) := h_false_hit 612 XSDebug(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", toIfuReq.bits.startAddr, toIfuReq.bits.fallThruAddr) 613 } 614 io.toIfu.req.bits.fallThruAddr := toIfuReq.bits.startAddr + (FetchWidth*4).U 615 io.toIfu.req.bits.fallThruError := true.B 616 XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", toIfuReq.bits.startAddr, toIfuReq.bits.fallThruAddr) 617 } 618 619 val ifu_req_should_be_flushed = 620 io.toIfu.flushFromBpu.shouldFlushByStage2(toIfuReq.bits.ftqIdx) || 621 io.toIfu.flushFromBpu.shouldFlushByStage3(toIfuReq.bits.ftqIdx) 622 623 when (io.toIfu.req.fire && !ifu_req_should_be_flushed) { 624 entry_fetch_status(ifuPtr.value) := f_sent 625 } 626 627 628 // ********************************************************************* 629 // **************************** wb from ifu **************************** 630 // ********************************************************************* 631 val pdWb = io.fromIfu.pdWb 632 val pds = pdWb.bits.pd 633 val ifu_wb_valid = pdWb.valid 634 val ifu_wb_idx = pdWb.bits.ftqIdx.value 635 // read ports: commit update 636 val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1)) 637 ftq_pd_mem.io.wen(0) := ifu_wb_valid 638 ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value 639 ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits) 640 641 val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid 642 val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid 643 val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B) 644 val pd_reg = RegEnable(pds, enable = pdWb.valid) 645 val start_pc_reg = RegEnable(pdWb.bits.pc(0), enable = pdWb.valid) 646 val wb_idx_reg = RegEnable(ifu_wb_idx, enable = pdWb.valid) 647 648 when (ifu_wb_valid) { 649 val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{ 650 case (v, inRange) => v && inRange 651 }) 652 (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{ 653 case (qe, v) => when (v) { qe := c_valid } 654 } 655 } 656 657 ifuWbPtr := ifuWbPtr + ifu_wb_valid 658 659 ftb_entry_mem.io.raddr.head := ifu_wb_idx 660 val has_false_hit = WireInit(false.B) 661 when (RegNext(hit_pd_valid)) { 662 // check for false hit 663 val pred_ftb_entry = ftb_entry_mem.io.rdata.head 664 val brSlots = pred_ftb_entry.brSlots 665 val tailSlot = pred_ftb_entry.tailSlot 666 // we check cfis that bpu predicted 667 668 // bpu predicted branches but denied by predecode 669 val br_false_hit = 670 brSlots.map{ 671 s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr) 672 }.reduce(_||_) || 673 (shareTailSlot.B && tailSlot.valid && pred_ftb_entry.tailSlot.sharing && 674 !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr)) 675 676 val jmpOffset = tailSlot.offset 677 val jmp_pd = pd_reg(jmpOffset) 678 val jal_false_hit = pred_ftb_entry.jmpValid && 679 ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) || 680 (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) || 681 (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) || 682 (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)) 683 ) 684 685 has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg 686 XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0)) 687 688 // assert(!has_false_hit) 689 } 690 691 when (has_false_hit) { 692 entry_hit_status(wb_idx_reg) := h_false_hit 693 } 694 695 696 // ********************************************************************** 697 // **************************** backend read **************************** 698 // ********************************************************************** 699 700 // pc reads 701 for ((req, i) <- io.toBackend.pc_reads.zipWithIndex) { 702 ftq_pc_mem.io.raddr(i) := req.ptr.value 703 req.data := ftq_pc_mem.io.rdata(i).getPc(RegNext(req.offset)) 704 } 705 // target read 706 io.toBackend.target_read.data := RegNext(update_target(io.toBackend.target_read.ptr.value)) 707 708 // ******************************************************************************* 709 // **************************** redirect from backend **************************** 710 // ******************************************************************************* 711 712 // redirect read cfiInfo, couples to redirectGen s2 713 ftq_redirect_sram.io.ren.init.last := io.fromBackend.stage2Redirect.valid 714 ftq_redirect_sram.io.raddr.init.last := io.fromBackend.stage2Redirect.bits.ftqIdx.value 715 716 ftb_entry_mem.io.raddr.init.last := io.fromBackend.stage2Redirect.bits.ftqIdx.value 717 718 val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last 719 val fromBackendRedirect = WireInit(io.fromBackend.stage3Redirect) 720 val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate 721 backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo) 722 723 val r_ftb_entry = ftb_entry_mem.io.rdata.init.last 724 val r_ftqOffset = fromBackendRedirect.bits.ftqOffset 725 726 when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) { 727 backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +& 728 (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) && 729 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 730 731 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) || 732 !r_ftb_entry.newBrCanNotInsert(r_ftqOffset)) 733 }.otherwise { 734 backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt 735 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt 736 } 737 738 739 // *************************************************************************** 740 // **************************** redirect from ifu **************************** 741 // *************************************************************************** 742 val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect))) 743 fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush 744 fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx 745 fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits 746 fromIfuRedirect.bits.level := RedirectLevel.flushAfter 747 748 val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate 749 ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits) 750 ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits) 751 ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid 752 ifuRedirectCfiUpdate.target := pdWb.bits.target 753 ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid 754 ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid 755 756 val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect))) 757 val ifuRedirectToBpu = WireInit(ifuRedirectReg) 758 ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid 759 760 ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid 761 ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 762 763 ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 764 765 val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate 766 toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head) 767 when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) { 768 toBpuCfi.target := toBpuCfi.rasEntry.retAddr 769 } 770 771 // ********************************************************************* 772 // **************************** wb from exu **************************** 773 // ********************************************************************* 774 775 def extractRedirectInfo(wb: Valid[Redirect]) = { 776 val ftqIdx = wb.bits.ftqIdx.value 777 val ftqOffset = wb.bits.ftqOffset 778 val taken = wb.bits.cfiUpdate.taken 779 val mispred = wb.bits.cfiUpdate.isMisPred 780 (wb.valid, ftqIdx, ftqOffset, taken, mispred) 781 } 782 783 // fix mispredict entry 784 val lastIsMispredict = RegNext( 785 stage2Redirect.valid && stage2Redirect.bits.level === RedirectLevel.flushAfter, init = false.B 786 ) 787 788 def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = { 789 val (r_valid, r_idx, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect) 790 val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits 791 val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits 792 when (cfiIndex_bits_wen || cfiIndex_valid_wen) { 793 cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken 794 } 795 when (cfiIndex_bits_wen) { 796 cfiIndex_vec(r_idx).bits := r_offset 797 } 798 update_target(r_idx) := redirect.bits.cfiUpdate.target 799 if (isBackend) { 800 mispredict_vec(r_idx)(r_offset) := r_mispred 801 } 802 } 803 804 when(stage3Redirect.valid && lastIsMispredict) { 805 updateCfiInfo(stage3Redirect) 806 }.elsewhen (ifuRedirectToBpu.valid) { 807 updateCfiInfo(ifuRedirectToBpu, isBackend=false) 808 } 809 810 // *********************************************************************************** 811 // **************************** flush ptr and state queue **************************** 812 // *********************************************************************************** 813 814 class RedirectInfo extends Bundle { 815 val valid = Bool() 816 val ftqIdx = new FtqPtr 817 val ftqOffset = UInt(log2Ceil(PredictWidth).W) 818 val flushItSelf = Bool() 819 def apply(redirect: Valid[Redirect]) = { 820 this.valid := redirect.valid 821 this.ftqIdx := redirect.bits.ftqIdx 822 this.ftqOffset := redirect.bits.ftqOffset 823 this.flushItSelf := RedirectLevel.flushItself(redirect.bits.level) 824 this 825 } 826 } 827 val redirectVec = Wire(Vec(3, new RedirectInfo)) 828 val robRedirect = robFlush 829 830 redirectVec.zip(Seq(robRedirect, stage2Redirect, fromIfuRedirect)).map { 831 case (ve, r) => ve(r) 832 } 833 834 // when redirect, we should reset ptrs and status queues 835 when(redirectVec.map(r => r.valid).reduce(_||_)){ 836 val r = PriorityMux(redirectVec.map(r => (r.valid -> r))) 837 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 838 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, r.flushItSelf) 839 val next = idx + 1.U 840 bpuPtr := next 841 ifuPtr := next 842 ifuWbPtr := next 843 when (notIfu) { 844 commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) => 845 when(i.U > offset || i.U === offset && flushItSelf){ 846 s := c_invalid 847 } 848 }) 849 } 850 } 851 852 // only the valid bit is actually needed 853 io.toIfu.redirect.bits := Mux(robFlush.valid, robFlush.bits, stage2Redirect.bits) 854 io.toIfu.redirect.valid := stage2Flush 855 856 // commit 857 for (c <- io.fromBackend.rob_commits) { 858 when(c.valid) { 859 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited 860 // TODO: remove this 861 // For instruction fusions, we also update the next instruction 862 when (c.bits.commitType === 4.U) { 863 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited 864 }.elsewhen(c.bits.commitType === 5.U) { 865 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited 866 }.elsewhen(c.bits.commitType === 6.U) { 867 val index = (c.bits.ftqIdx + 1.U).value 868 commitStateQueue(index)(0) := c_commited 869 }.elsewhen(c.bits.commitType === 7.U) { 870 val index = (c.bits.ftqIdx + 1.U).value 871 commitStateQueue(index)(1) := c_commited 872 } 873 } 874 } 875 876 // **************************************************************** 877 // **************************** to bpu **************************** 878 // **************************************************************** 879 880 io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 881 882 val may_have_stall_from_bpu = RegInit(false.B) 883 val canCommit = commPtr =/= ifuWbPtr && !may_have_stall_from_bpu && 884 Cat(commitStateQueue(commPtr.value).map(s => { 885 s === c_invalid || s === c_commited 886 })).andR() 887 888 // commit reads 889 ftq_pc_mem.io.raddr.last := commPtr.value 890 val commit_pc_bundle = ftq_pc_mem.io.rdata.last 891 ftq_pd_mem.io.raddr.last := commPtr.value 892 val commit_pd = ftq_pd_mem.io.rdata.last 893 ftq_redirect_sram.io.ren.last := canCommit 894 ftq_redirect_sram.io.raddr.last := commPtr.value 895 val commit_spec_meta = ftq_redirect_sram.io.rdata.last 896 ftq_meta_1r_sram.io.ren(0) := canCommit 897 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 898 val commit_meta = ftq_meta_1r_sram.io.rdata(0) 899 ftb_entry_mem.io.raddr.last := commPtr.value 900 val commit_ftb_entry = ftb_entry_mem.io.rdata.last 901 902 // need one cycle to read mem and srams 903 val do_commit_ptr = RegNext(commPtr) 904 val do_commit = RegNext(canCommit, init=false.B) 905 when (canCommit) { commPtr := commPtr + 1.U } 906 val commit_state = RegNext(commitStateQueue(commPtr.value)) 907 val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value)) 908 when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) { 909 can_commit_cfi.valid := false.B 910 } 911 val commit_cfi = RegNext(can_commit_cfi) 912 913 val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map { 914 case (mis, state) => mis && state === c_commited 915 }) 916 val can_commit_hit = entry_hit_status(commPtr.value) 917 val commit_hit = RegNext(can_commit_hit) 918 val commit_target = RegNext(update_target(commPtr.value)) 919 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 920 921 val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit 922 may_have_stall_from_bpu := can_commit_cfi.valid && !to_bpu_hit && !may_have_stall_from_bpu 923 924 io.toBpu.update := DontCare 925 io.toBpu.update.valid := commit_valid && do_commit 926 val update = io.toBpu.update.bits 927 update.false_hit := commit_hit === h_false_hit 928 update.pc := commit_pc_bundle.startAddr 929 update.preds.hit := commit_hit === h_hit || commit_hit === h_false_hit 930 update.meta := commit_meta.meta 931 update.full_target := commit_target 932 update.fromFtqRedirectSram(commit_spec_meta) 933 934 val commit_real_hit = commit_hit === h_hit 935 val update_ftb_entry = update.ftb_entry 936 937 val ftbEntryGen = Module(new FTBEntryGen).io 938 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 939 ftbEntryGen.old_entry := commit_ftb_entry 940 ftbEntryGen.pd := commit_pd 941 ftbEntryGen.cfiIndex := commit_cfi 942 ftbEntryGen.target := commit_target 943 ftbEntryGen.hit := commit_real_hit 944 ftbEntryGen.mispredict_vec := commit_mispredict 945 946 update_ftb_entry := ftbEntryGen.new_entry 947 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 948 update.mispred_mask := ftbEntryGen.mispred_mask 949 update.old_entry := ftbEntryGen.is_old_entry 950 update.preds.br_taken_mask := ftbEntryGen.taken_mask 951 952 // ****************************************************************************** 953 // **************************** commit perf counters **************************** 954 // ****************************************************************************** 955 956 val commit_inst_mask = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt 957 val commit_mispred_mask = commit_mispredict.asUInt 958 val commit_not_mispred_mask = ~commit_mispred_mask 959 960 val commit_br_mask = commit_pd.brMask.asUInt 961 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 962 val commit_cfi_mask = (commit_br_mask | commit_jmp_mask) 963 964 val mbpInstrs = commit_inst_mask & commit_cfi_mask 965 966 val mbpRights = mbpInstrs & commit_not_mispred_mask 967 val mbpWrongs = mbpInstrs & commit_mispred_mask 968 969 io.bpuInfo.bpRight := PopCount(mbpRights) 970 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 971 972 // Cfi Info 973 for (i <- 0 until PredictWidth) { 974 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 975 val v = commit_state(i) === c_commited 976 val isBr = commit_pd.brMask(i) 977 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 978 val isCfi = isBr || isJmp 979 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 980 val misPred = commit_mispredict(i) 981 // val ghist = commit_spec_meta.ghist.predHist 982 val histPtr = commit_spec_meta.histPtr 983 val predCycle = commit_meta.meta(63, 0) 984 val target = commit_target 985 986 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}))) 987 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_) 988 val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)) 989 XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 990 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " + 991 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 992 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n") 993 } 994 995 val enq = io.fromBpu.resp 996 val perf_redirect = io.fromBackend.stage2Redirect 997 998 XSPerfAccumulate("entry", validEntries) 999 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 1000 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 1001 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 1002 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 1003 1004 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 1005 1006 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 1007 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 1008 XSPerfAccumulate("bpu_to_ftq_bubble", bpuPtr === ifuPtr) 1009 1010 val from_bpu = io.fromBpu.resp.bits 1011 def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = { 1012 val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits 1013 val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U) 1014 val entry_len_map = (1 to PredictWidth+1).map(i => 1015 f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid) 1016 ).foldLeft(Map[String, UInt]())(_+_) 1017 entry_len_map 1018 } 1019 val s1_entry_len_map = in_entry_len_map_gen(from_bpu.s1)("s1") 1020 val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2") 1021 val s3_entry_len_map = in_entry_len_map_gen(from_bpu.s3)("s3") 1022 1023 val to_ifu = io.toIfu.req.bits 1024 val to_ifu_entry_len = (to_ifu.fallThruAddr - to_ifu.startAddr) >> instOffsetBits 1025 val to_ifu_entry_len_recording_vec = (1 to PredictWidth+1).map(i => to_ifu_entry_len === i.U) 1026 val to_ifu_entry_len_map = (1 to PredictWidth+1).map(i => 1027 f"to_ifu_ftb_entry_len_$i" -> (to_ifu_entry_len_recording_vec(i-1) && io.toIfu.req.fire) 1028 ).foldLeft(Map[String, UInt]())(_+_) 1029 1030 1031 1032 val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U) 1033 val commit_num_inst_map = (1 to PredictWidth).map(i => 1034 f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit) 1035 ).foldLeft(Map[String, UInt]())(_+_) 1036 1037 1038 1039 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 1040 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 1041 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 1042 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 1043 1044 1045 val mbpBRights = mbpRights & commit_br_mask 1046 val mbpJRights = mbpRights & commit_jal_mask 1047 val mbpIRights = mbpRights & commit_jalr_mask 1048 val mbpCRights = mbpRights & commit_call_mask 1049 val mbpRRights = mbpRights & commit_ret_mask 1050 1051 val mbpBWrongs = mbpWrongs & commit_br_mask 1052 val mbpJWrongs = mbpWrongs & commit_jal_mask 1053 val mbpIWrongs = mbpWrongs & commit_jalr_mask 1054 val mbpCWrongs = mbpWrongs & commit_call_mask 1055 val mbpRWrongs = mbpWrongs & commit_ret_mask 1056 1057 val commit_pred_stage = RegNext(pred_stage(commPtr.value)) 1058 1059 def pred_stage_map(src: UInt, name: String) = { 1060 (0 until numBpStages).map(i => 1061 f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i))) 1062 ).foldLeft(Map[String, UInt]())(_+_) 1063 } 1064 1065 val mispred_stage_map = pred_stage_map(mbpWrongs, "mispredict") 1066 val br_mispred_stage_map = pred_stage_map(mbpBWrongs, "br_mispredict") 1067 val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict") 1068 val correct_stage_map = pred_stage_map(mbpRights, "correct") 1069 val br_correct_stage_map = pred_stage_map(mbpBRights, "br_correct") 1070 val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct") 1071 1072 val update_valid = io.toBpu.update.valid 1073 def u(cond: Bool) = update_valid && cond 1074 val ftb_false_hit = u(update.false_hit) 1075 // assert(!ftb_false_hit) 1076 val ftb_hit = u(commit_hit === h_hit) 1077 1078 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1079 val ftb_new_entry_only_br = ftb_new_entry && !update.ftb_entry.jmpValid 1080 val ftb_new_entry_only_jmp = ftb_new_entry && !update.ftb_entry.brValids(0) 1081 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update.ftb_entry.brValids(0) && update.ftb_entry.jmpValid 1082 1083 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1084 1085 val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified) 1086 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1087 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1088 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1089 val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified 1090 1091 val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits 1092 val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U) 1093 val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i => 1094 f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry) 1095 ).foldLeft(Map[String, UInt]())(_+_) 1096 val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i => 1097 f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry) 1098 ).foldLeft(Map[String, UInt]())(_+_) 1099 1100 val ftq_occupancy_map = (0 to FtqSize).map(i => 1101 f"ftq_has_entry_$i" ->( validEntries === i.U) 1102 ).foldLeft(Map[String, UInt]())(_+_) 1103 1104 val perfCountsMap = Map( 1105 "BpInstr" -> PopCount(mbpInstrs), 1106 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1107 "BpRight" -> PopCount(mbpRights), 1108 "BpWrong" -> PopCount(mbpWrongs), 1109 "BpBRight" -> PopCount(mbpBRights), 1110 "BpBWrong" -> PopCount(mbpBWrongs), 1111 "BpJRight" -> PopCount(mbpJRights), 1112 "BpJWrong" -> PopCount(mbpJWrongs), 1113 "BpIRight" -> PopCount(mbpIRights), 1114 "BpIWrong" -> PopCount(mbpIWrongs), 1115 "BpCRight" -> PopCount(mbpCRights), 1116 "BpCWrong" -> PopCount(mbpCWrongs), 1117 "BpRRight" -> PopCount(mbpRRights), 1118 "BpRWrong" -> PopCount(mbpRWrongs), 1119 1120 "ftb_false_hit" -> PopCount(ftb_false_hit), 1121 "ftb_hit" -> PopCount(ftb_hit), 1122 "ftb_new_entry" -> PopCount(ftb_new_entry), 1123 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1124 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1125 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1126 "ftb_old_entry" -> PopCount(ftb_old_entry), 1127 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1128 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1129 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1130 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1131 "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken) 1132 ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ s1_entry_len_map ++ 1133 s2_entry_len_map ++ s3_entry_len_map ++ 1134 to_ifu_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map ++ 1135 mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++ 1136 correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map 1137 1138 for((key, value) <- perfCountsMap) { 1139 XSPerfAccumulate(key, value) 1140 } 1141 1142 // --------------------------- Debug -------------------------------- 1143 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1144 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1145 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1146 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1147 XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1148 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n") 1149 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1150 1151 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1152 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1153 // case (((valid, pd), ans), taken) => 1154 // Mux(valid && pd.isBr, 1155 // isWrong ^ Mux(ans.hit.asBool, 1156 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1157 // !taken), 1158 // !taken), 1159 // false.B) 1160 // } 1161 // } 1162 1163 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1164 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1165 // case (((valid, pd), ans), taken) => 1166 // Mux(valid && pd.isBr, 1167 // isWrong ^ Mux(ans.hit.asBool, 1168 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1169 // !taken), 1170 // !taken), 1171 // false.B) 1172 // } 1173 // } 1174 1175 // def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1176 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1177 // case (((valid, pd), ans), taken) => 1178 // Mux(valid && pd.isBr, 1179 // isWrong ^ (ans.taken.asBool === taken), 1180 // false.B) 1181 // } 1182 // } 1183 1184 // def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1185 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1186 // case (((valid, pd), ans), taken) => 1187 // Mux(valid && (pd.isBr) && ans.hit.asBool, 1188 // isWrong ^ (!taken), 1189 // false.B) 1190 // } 1191 // } 1192 1193 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1194 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1195 // case (((valid, pd), ans), taken) => 1196 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1197 // isWrong ^ (ans.target === commitEntry.target), 1198 // false.B) 1199 // } 1200 // } 1201 1202 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1203 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1204 // // btb and ubtb pred jal and jalr as well 1205 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1206 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1207 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1208 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1209 1210 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1211 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1212 1213 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1214 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1215 val perfinfo = IO(new Bundle(){ 1216 val perfEvents = Output(new PerfEventsBundle(22)) 1217 }) 1218 val perfEvents = Seq( 1219 ("bpu_s2_redirect ", bpu_s2_redirect ), 1220 ("bpu_s3_redirect ", bpu_s3_redirect ), 1221 ("bpu_to_ftq_stall ", enq.valid && ~enq.ready ), 1222 ("mispredictRedirect ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level), 1223 ("replayRedirect ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level) ), 1224 ("predecodeRedirect ", fromIfuRedirect.valid ), 1225 ("to_ifu_bubble ", io.toIfu.req.ready && !io.toIfu.req.valid ), 1226 ("from_bpu_real_bubble ", !enq.valid && enq.ready && allowBpuIn ), 1227 ("BpInstr ", PopCount(mbpInstrs) ), 1228 ("BpBInstr ", PopCount(mbpBRights | mbpBWrongs) ), 1229 ("BpRight ", PopCount(mbpRights) ), 1230 ("BpWrong ", PopCount(mbpWrongs) ), 1231 ("BpBRight ", PopCount(mbpBRights) ), 1232 ("BpBWrong ", PopCount(mbpBWrongs) ), 1233 ("BpJRight ", PopCount(mbpJRights) ), 1234 ("BpJWrong ", PopCount(mbpJWrongs) ), 1235 ("BpIRight ", PopCount(mbpIRights) ), 1236 ("BpIWrong ", PopCount(mbpIWrongs) ), 1237 ("BpCRight ", PopCount(mbpCRights) ), 1238 ("BpCWrong ", PopCount(mbpCWrongs) ), 1239 ("BpRRight ", PopCount(mbpRRights) ), 1240 ("BpRWrong ", PopCount(mbpRWrongs) ), 1241 ("ftb_false_hit ", PopCount(ftb_false_hit) ), 1242 ("ftb_hit ", PopCount(ftb_hit) ), 1243 ) 1244 1245 for (((perf_out,(perf_name,perf)),i) <- perfinfo.perfEvents.perf_events.zip(perfEvents).zipWithIndex) { 1246 perf_out.incr_step := RegNext(perf) 1247 } 1248} 1249