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