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, 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 getRoqFlushPcRead = 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)) 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 jalr_mispredicted = cfi_is_jalr && io.mispredict_vec(io.pd.jmpOffset) 363 when (jalr_mispredicted) { 364 old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target) 365 old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool())) 366 } 367 368 val old_entry_always_taken = WireInit(oe) 369 val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not 370 for (i <- 0 until numBr) { 371 old_entry_always_taken.always_taken(i) := 372 oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i) 373 always_taken_modified_vec(i) := oe.always_taken(i) && !(io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i)) 374 } 375 val always_taken_modified = always_taken_modified_vec.reduce(_||_) 376 377 378 379 val derived_from_old_entry = 380 Mux(is_new_br, old_entry_modified, 381 Mux(jalr_mispredicted, old_entry_jmp_target_modified, old_entry_always_taken)) 382 383 384 io.new_entry := Mux(!hit, init_entry, derived_from_old_entry) 385 386 io.new_br_insert_pos := new_br_insert_onehot 387 io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{ 388 case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v 389 }) 390 for (i <- 0 until numBr) { 391 io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i)) 392 } 393 io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset) 394 395 // for perf counters 396 io.is_init_entry := !hit 397 io.is_old_entry := hit && !is_new_br && !jalr_mispredicted && !always_taken_modified 398 io.is_new_br := hit && is_new_br 399 io.is_jalr_target_modified := hit && jalr_mispredicted 400 io.is_always_taken_modified := hit && always_taken_modified 401 io.is_br_full := hit && is_new_br && br_full 402} 403 404class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper 405 with HasBackendRedirectInfo with BPUUtils with HasBPUConst { 406 val io = IO(new Bundle { 407 val fromBpu = Flipped(new BpuToFtqIO) 408 val fromIfu = Flipped(new IfuToFtqIO) 409 val fromBackend = Flipped(new CtrlToFtqIO) 410 411 val toBpu = new FtqToBpuIO 412 val toIfu = new FtqToIfuIO 413 val toBackend = new FtqToCtrlIO 414 415 val bpuInfo = new Bundle { 416 val bpRight = Output(UInt(XLEN.W)) 417 val bpWrong = Output(UInt(XLEN.W)) 418 } 419 }) 420 io.bpuInfo := DontCare 421 422 val roqFlush = io.fromBackend.roqFlush 423 val stage2Redirect = io.fromBackend.stage2Redirect 424 val stage3Redirect = io.fromBackend.stage3Redirect 425 426 val stage2Flush = stage2Redirect.valid || roqFlush.valid 427 val backendFlush = stage2Flush || RegNext(stage2Flush) 428 val ifuFlush = Wire(Bool()) 429 430 val flush = stage2Flush || RegNext(stage2Flush) 431 432 val allowBpuIn, allowToIfu = WireInit(false.B) 433 val flushToIfu = !allowToIfu 434 allowBpuIn := !ifuFlush && !roqFlush.valid && !stage2Redirect.valid && !stage3Redirect.valid 435 allowToIfu := !ifuFlush && !roqFlush.valid && !stage2Redirect.valid && !stage3Redirect.valid 436 437 val bpuPtr, ifuPtr, ifuWbPtr, commPtr = RegInit(FtqPtr(false.B, 0.U)) 438 val validEntries = distanceBetween(bpuPtr, commPtr) 439 440 // ********************************************************************** 441 // **************************** enq from bpu **************************** 442 // ********************************************************************** 443 val new_entry_ready = validEntries < FtqSize.U 444 io.fromBpu.resp.ready := new_entry_ready 445 446 val bpu_s2_resp = io.fromBpu.resp.bits.s2 447 val bpu_s3_resp = io.fromBpu.resp.bits.s3 448 val bpu_s2_redirect = bpu_s2_resp.valid && bpu_s2_resp.hasRedirect 449 val bpu_s3_redirect = bpu_s3_resp.valid && bpu_s3_resp.hasRedirect 450 451 io.toBpu.enq_ptr := bpuPtr 452 val enq_fire = io.fromBpu.resp.fire() && allowBpuIn // from bpu s1 453 val bpu_in_fire = (io.fromBpu.resp.fire() || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn 454 455 val bpu_in_resp = WireInit(io.fromBpu.resp.bits.selectedResp) 456 val bpu_in_stage = WireInit(io.fromBpu.resp.bits.selectedRespIdx) 457 val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx) 458 val bpu_in_resp_idx = bpu_in_resp_ptr.value 459 460 // read ports: jumpPc + redirects + loadPred + roqFlush + ifuReq1 + ifuReq2 + commitUpdate 461 val ftq_pc_mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize, 1+numRedirect+2+1+1+1, 1)) 462 // resp from uBTB 463 ftq_pc_mem.io.wen(0) := bpu_in_fire 464 ftq_pc_mem.io.waddr(0) := bpu_in_resp_idx 465 ftq_pc_mem.io.wdata(0).fromBranchPrediction(bpu_in_resp) 466 467 // ifuRedirect + backendRedirect + commit 468 val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+1+1)) 469 // these info is intended to enq at the last stage of bpu 470 ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid 471 ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 472 ftq_redirect_sram.io.wdata.fromBranchPrediction(io.fromBpu.resp.bits.lastStage) 473 474 val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1)) 475 // these info is intended to enq at the last stage of bpu 476 ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid 477 ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value 478 ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.meta 479 // ifuRedirect + backendRedirect + commit 480 val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+1+1, 1)) 481 ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid 482 ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value 483 ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.lastStage.ftb_entry 484 485 486 // multi-write 487 val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) 488 val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))) 489 val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool()))) 490 val pred_stage = Reg(Vec(FtqSize, UInt(2.W))) 491 492 val c_invalid :: c_valid :: c_commited :: Nil = Enum(3) 493 val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) { 494 VecInit(Seq.fill(PredictWidth)(c_invalid)) 495 })) 496 497 val f_to_send :: f_sent :: Nil = Enum(2) 498 val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent))) 499 500 val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3) 501 val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit))) 502 503 504 when (bpu_in_fire) { 505 entry_fetch_status(bpu_in_resp_idx) := f_to_send 506 commitStateQueue(bpu_in_resp_idx) := VecInit(Seq.fill(PredictWidth)(c_invalid)) 507 cfiIndex_vec(bpu_in_resp_idx) := bpu_in_resp.genCfiIndex 508 mispredict_vec(bpu_in_resp_idx) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B))) 509 update_target(bpu_in_resp_idx) := bpu_in_resp.target 510 pred_stage(bpu_in_resp_idx) := bpu_in_stage 511 } 512 513 bpuPtr := bpuPtr + enq_fire 514 ifuPtr := ifuPtr + io.toIfu.req.fire 515 516 // only use ftb result to assign hit status 517 when (bpu_s2_resp.valid) { 518 entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.preds.hit, h_hit, h_not_hit) 519 } 520 521 522 io.toIfu.flushFromBpu.s2.valid := bpu_s2_resp.valid && bpu_s2_resp.hasRedirect 523 io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx 524 when (bpu_s2_resp.valid && bpu_s2_resp.hasRedirect) { 525 bpuPtr := bpu_s2_resp.ftq_idx + 1.U 526 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 527 when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) { 528 ifuPtr := bpu_s2_resp.ftq_idx 529 } 530 } 531 532 io.toIfu.flushFromBpu.s3.valid := bpu_s3_resp.valid && bpu_s3_resp.hasRedirect 533 io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx 534 when (bpu_s3_resp.valid && bpu_s3_resp.hasRedirect) { 535 bpuPtr := bpu_s3_resp.ftq_idx + 1.U 536 // only when ifuPtr runs ahead of bpu s2 resp should we recover it 537 when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) { 538 ifuPtr := bpu_s3_resp.ftq_idx 539 } 540 XSError(true.B, "\ns3_redirect mechanism not implemented!\n") 541 } 542 543 XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n") 544 545 // **************************************************************** 546 // **************************** to ifu **************************** 547 // **************************************************************** 548 val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata(0), enable=bpu_in_fire) 549 val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr) 550 val last_cycle_bpu_in = RegNext(bpu_in_fire) 551 val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire) 552 553 // read pc and target 554 ftq_pc_mem.io.raddr.init.init.last := ifuPtr.value 555 ftq_pc_mem.io.raddr.init.last := (ifuPtr+1.U).value 556 557 val toIfuReq = Wire(chiselTypeOf(io.toIfu.req)) 558 559 toIfuReq.valid := allowToIfu && entry_fetch_status(ifuPtr.value) === f_to_send && ifuPtr =/= bpuPtr 560 toIfuReq.bits.ftqIdx := ifuPtr 561 toIfuReq.bits.target := update_target(ifuPtr.value) 562 toIfuReq.bits.ftqOffset := cfiIndex_vec(ifuPtr.value) 563 toIfuReq.bits.fallThruError := false.B 564 565 when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) { 566 toIfuReq.bits.fromFtqPcBundle(bpu_in_bypass_buf) 567 }.elsewhen (last_cycle_to_ifu_fire) { 568 toIfuReq.bits.fromFtqPcBundle(ftq_pc_mem.io.rdata.init.last) 569 }.otherwise { 570 toIfuReq.bits.fromFtqPcBundle(ftq_pc_mem.io.rdata.init.init.last) 571 } 572 573 io.toIfu.req <> toIfuReq 574 575 // when fall through is smaller in value than start address, there must be a false hit 576 when (toIfuReq.bits.fallThroughError() && entry_hit_status(ifuPtr.value) === h_hit) { 577 when (io.toIfu.req.fire && 578 !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && 579 !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr) 580 ) { 581 entry_hit_status(ifuPtr.value) := h_false_hit 582 } 583 io.toIfu.req.bits.fallThruAddr := toIfuReq.bits.startAddr + (FetchWidth*4).U 584 io.toIfu.req.bits.fallThruError := true.B 585 XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", toIfuReq.bits.startAddr, toIfuReq.bits.fallThruAddr) 586 } 587 588 val ifu_req_should_be_flushed = 589 io.toIfu.flushFromBpu.shouldFlushByStage2(toIfuReq.bits.ftqIdx) || 590 io.toIfu.flushFromBpu.shouldFlushByStage3(toIfuReq.bits.ftqIdx) 591 592 when (io.toIfu.req.fire && !ifu_req_should_be_flushed) { 593 entry_fetch_status(ifuPtr.value) := f_sent 594 } 595 596 597 // ********************************************************************* 598 // **************************** wb from ifu **************************** 599 // ********************************************************************* 600 val pdWb = io.fromIfu.pdWb 601 val pds = pdWb.bits.pd 602 val ifu_wb_valid = pdWb.valid 603 val ifu_wb_idx = pdWb.bits.ftqIdx.value 604 // read ports: commit update 605 val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1)) 606 ftq_pd_mem.io.wen(0) := ifu_wb_valid 607 ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value 608 ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits) 609 610 val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid 611 val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid 612 val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B) 613 val pd_reg = RegEnable(pds, enable = pdWb.valid) 614 val start_pc_reg = RegEnable(pdWb.bits.pc(0), enable = pdWb.valid) 615 val wb_idx_reg = RegEnable(ifu_wb_idx, enable = pdWb.valid) 616 617 when (ifu_wb_valid) { 618 val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{ 619 case (v, inRange) => v && inRange 620 }) 621 (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{ 622 case (qe, v) => when (v) { qe := c_valid } 623 } 624 } 625 626 ifuWbPtr := ifuWbPtr + ifu_wb_valid 627 628 ftb_entry_mem.io.raddr.head := ifu_wb_idx 629 val has_false_hit = WireInit(false.B) 630 when (RegNext(hit_pd_valid)) { 631 // check for false hit 632 val pred_ftb_entry = ftb_entry_mem.io.rdata.head 633 // we check cfis that bpu predicted 634 val br_false_hit = (pred_ftb_entry.brValids zip pred_ftb_entry.brOffset).map{ 635 case (v, offset) => v && !(pd_reg(offset).valid && pd_reg(offset).isBr) 636 }.reduce(_||_) 637 638 val jmpOffset = pred_ftb_entry.jmpOffset 639 val jmp_pd = pd_reg(jmpOffset) 640 val jal_false_hit = pred_ftb_entry.jmpValid && 641 ((pred_ftb_entry.isJal && !(jmp_pd.valid && jmp_pd.isJal)) || 642 (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) || 643 (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) || 644 (pred_ftb_entry.isRet && !(jmp_pd.valid && jmp_pd.isRet)) 645 ) 646 647 has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg 648 } 649 650 when (has_false_hit) { 651 entry_hit_status(wb_idx_reg) := h_false_hit 652 } 653 654 655 // ********************************************************************** 656 // **************************** backend read **************************** 657 // ********************************************************************** 658 659 // pc reads 660 for ((req, i) <- io.toBackend.pc_reads.zipWithIndex) { 661 ftq_pc_mem.io.raddr(i) := req.ptr.value 662 req.data := ftq_pc_mem.io.rdata(i).getPc(RegNext(req.offset)) 663 } 664 // target read 665 io.toBackend.target_read.data := RegNext(update_target(io.toBackend.target_read.ptr.value)) 666 667 // ******************************************************************************* 668 // **************************** redirect from backend **************************** 669 // ******************************************************************************* 670 671 // redirect read cfiInfo, couples to redirectGen s2 672 ftq_redirect_sram.io.ren.init.last := io.fromBackend.stage2Redirect.valid 673 ftq_redirect_sram.io.raddr.init.last := io.fromBackend.stage2Redirect.bits.ftqIdx.value 674 675 ftb_entry_mem.io.raddr.init.last := io.fromBackend.stage2Redirect.bits.ftqIdx.value 676 677 val stage3CfiInfo = ftq_redirect_sram.io.rdata.init.last 678 val fromBackendRedirect = WireInit(io.fromBackend.stage3Redirect) 679 val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate 680 backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo) 681 682 val r_ftb_entry = ftb_entry_mem.io.rdata.init.last 683 val r_ftqOffset = fromBackendRedirect.bits.ftqOffset 684 685 when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) { 686 backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +& 687 (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) && 688 !(r_ftb_entry.brValids(numBr-1) && r_ftqOffset > r_ftb_entry.brOffset(numBr-1))) 689 690 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) || 691 !(r_ftb_entry.brValids(numBr-1) && r_ftqOffset > r_ftb_entry.brOffset(numBr-1))) 692 }.otherwise { 693 backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt 694 backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt 695 } 696 697 698 // *************************************************************************** 699 // **************************** redirect from ifu **************************** 700 // *************************************************************************** 701 val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new Redirect))) 702 fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush 703 fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx 704 fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits 705 fromIfuRedirect.bits.level := RedirectLevel.flushAfter 706 707 val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate 708 ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits) 709 ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits) 710 ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid 711 ifuRedirectCfiUpdate.target := pdWb.bits.target 712 ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid 713 ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid 714 715 val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new Redirect))) 716 val ifuRedirectToBpu = WireInit(ifuRedirectReg) 717 ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid 718 719 ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid 720 ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 721 722 ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value 723 724 val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate 725 toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head) 726 when (ifuRedirectReg.bits.cfiUpdate.pd.isRet) { 727 toBpuCfi.target := toBpuCfi.rasEntry.retAddr 728 } 729 730 // ********************************************************************* 731 // **************************** wb from exu **************************** 732 // ********************************************************************* 733 734 def extractRedirectInfo(wb: Valid[Redirect]) = { 735 val ftqIdx = wb.bits.ftqIdx.value 736 val ftqOffset = wb.bits.ftqOffset 737 val taken = wb.bits.cfiUpdate.taken 738 val mispred = wb.bits.cfiUpdate.isMisPred 739 (wb.valid, ftqIdx, ftqOffset, taken, mispred) 740 } 741 742 // fix mispredict entry 743 val lastIsMispredict = RegNext( 744 stage2Redirect.valid && stage2Redirect.bits.level === RedirectLevel.flushAfter, init = false.B 745 ) 746 747 def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = { 748 val (r_valid, r_idx, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect) 749 val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits 750 val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits 751 when (cfiIndex_bits_wen || cfiIndex_valid_wen) { 752 cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken 753 } 754 when (cfiIndex_bits_wen) { 755 cfiIndex_vec(r_idx).bits := r_offset 756 } 757 update_target(r_idx) := redirect.bits.cfiUpdate.target 758 if (isBackend) { 759 mispredict_vec(r_idx)(r_offset) := r_mispred 760 } 761 } 762 763 when(stage3Redirect.valid && lastIsMispredict) { 764 updateCfiInfo(stage3Redirect) 765 }.elsewhen (ifuRedirectToBpu.valid) { 766 updateCfiInfo(ifuRedirectToBpu, isBackend=false) 767 } 768 769 // *********************************************************************************** 770 // **************************** flush ptr and state queue **************************** 771 // *********************************************************************************** 772 773 class RedirectInfo extends Bundle { 774 val valid = Bool() 775 val ftqIdx = new FtqPtr 776 val ftqOffset = UInt(4.W) 777 val flushItSelf = Bool() 778 def apply(redirect: Valid[Redirect]) = { 779 this.valid := redirect.valid 780 this.ftqIdx := redirect.bits.ftqIdx 781 this.ftqOffset := redirect.bits.ftqOffset 782 this.flushItSelf := RedirectLevel.flushItself(redirect.bits.level) 783 this 784 } 785 } 786 val redirectVec = Wire(Vec(3, new RedirectInfo)) 787 val roqRedirect = Wire(Valid(new Redirect)) 788 roqRedirect := DontCare 789 roqRedirect.valid := roqFlush.valid 790 roqRedirect.bits.ftqIdx := roqFlush.bits.ftqIdx 791 roqRedirect.bits.ftqOffset := roqFlush.bits.ftqOffset 792 roqRedirect.bits.level := RedirectLevel.flush 793 794 redirectVec.zip(Seq(roqRedirect, 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.roq_commits) { 822 when(c.valid) { 823 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited 824 } 825 } 826 827 // **************************************************************** 828 // **************************** to bpu **************************** 829 // **************************************************************** 830 831 io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 832 833 val canCommit = commPtr =/= ifuWbPtr && 834 Cat(commitStateQueue(commPtr.value).map(s => { 835 s === c_invalid || s === c_commited 836 })).andR() 837 838 // commit reads 839 ftq_pc_mem.io.raddr.last := commPtr.value 840 val commit_pc_bundle = ftq_pc_mem.io.rdata.last 841 ftq_pd_mem.io.raddr.last := commPtr.value 842 val commit_pd = ftq_pd_mem.io.rdata.last 843 ftq_redirect_sram.io.ren.last := canCommit 844 ftq_redirect_sram.io.raddr.last := commPtr.value 845 val commit_spec_meta = ftq_redirect_sram.io.rdata.last 846 ftq_meta_1r_sram.io.ren(0) := canCommit 847 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 848 val commit_meta = ftq_meta_1r_sram.io.rdata(0) 849 ftb_entry_mem.io.raddr.last := commPtr.value 850 val commit_ftb_entry = ftb_entry_mem.io.rdata.last 851 852 // need one cycle to read mem and srams 853 val do_commit = RegNext(canCommit, init=false.B) 854 val do_commit_ptr = RegNext(commPtr) 855 when (canCommit) { commPtr := commPtr + 1.U } 856 val commit_state = RegNext(commitStateQueue(commPtr.value)) 857 val commit_cfi = WireInit(RegNext(cfiIndex_vec(commPtr.value))) 858 when (commit_state(commit_cfi.bits) =/= c_commited) { 859 commit_cfi.valid := false.B 860 } 861 862 val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map { 863 case (mis, state) => mis && state === c_commited 864 }) 865 val commit_hit = RegNext(entry_hit_status(commPtr.value)) 866 val commit_target = RegNext(update_target(commPtr.value)) 867 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 868 869 870 io.toBpu.update := DontCare 871 io.toBpu.update.valid := commit_valid && do_commit 872 val update = io.toBpu.update.bits 873 update.false_hit := commit_hit === h_false_hit 874 update.pc := commit_pc_bundle.startAddr 875 update.preds.hit := commit_hit === h_hit || commit_hit === h_false_hit 876 update.meta := commit_meta.meta 877 update.fromFtqRedirectSram(commit_spec_meta) 878 879 val commit_real_hit = commit_hit === h_hit 880 val update_ftb_entry = update.ftb_entry 881 882 val ftbEntryGen = Module(new FTBEntryGen).io 883 ftbEntryGen.start_addr := commit_pc_bundle.startAddr 884 ftbEntryGen.old_entry := commit_ftb_entry 885 ftbEntryGen.pd := commit_pd 886 ftbEntryGen.cfiIndex := commit_cfi 887 ftbEntryGen.target := commit_target 888 ftbEntryGen.hit := commit_real_hit 889 ftbEntryGen.mispredict_vec := commit_mispredict 890 891 update_ftb_entry := ftbEntryGen.new_entry 892 update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos 893 update.mispred_mask := ftbEntryGen.mispred_mask 894 update.old_entry := ftbEntryGen.is_old_entry 895 update.preds.taken_mask := ftbEntryGen.taken_mask 896 897 // ****************************************************************************** 898 // **************************** commit perf counters **************************** 899 // ****************************************************************************** 900 901 val commit_inst_mask = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt 902 val commit_mispred_mask = commit_mispredict.asUInt 903 val commit_not_mispred_mask = ~commit_mispred_mask 904 905 val commit_br_mask = commit_pd.brMask.asUInt 906 val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W))) 907 val commit_cfi_mask = (commit_br_mask | commit_jmp_mask) 908 909 val mbpInstrs = commit_inst_mask & commit_cfi_mask 910 911 val mbpRights = mbpInstrs & commit_not_mispred_mask 912 val mbpWrongs = mbpInstrs & commit_mispred_mask 913 914 io.bpuInfo.bpRight := PopCount(mbpRights) 915 io.bpuInfo.bpWrong := PopCount(mbpWrongs) 916 917 // Cfi Info 918 for (i <- 0 until PredictWidth) { 919 val pc = commit_pc_bundle.startAddr + (i * instBytes).U 920 val v = commit_state(i) === c_commited 921 val isBr = commit_pd.brMask(i) 922 val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U 923 val isCfi = isBr || isJmp 924 val isTaken = commit_cfi.valid && commit_cfi.bits === i.U 925 val misPred = commit_mispredict(i) 926 val ghist = commit_spec_meta.ghist.predHist 927 val predCycle = commit_meta.meta(63, 0) 928 val target = commit_target 929 930 val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}))) 931 val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_) 932 val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid)) 933 XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " + 934 p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${Hexadecimal(ghist)}) " + 935 p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " + 936 p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n") 937 } 938 939 val enq = io.fromBpu.resp 940 val perf_redirect = io.fromBackend.stage2Redirect 941 942 XSPerfAccumulate("entry", validEntries) 943 XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready) 944 XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level) 945 XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)) 946 XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid) 947 948 XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid) 949 950 XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready) 951 XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn) 952 953 val from_bpu = io.fromBpu.resp.bits 954 def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = { 955 val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits 956 val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U) 957 val entry_len_map = (1 to PredictWidth+1).map(i => 958 f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid) 959 ).foldLeft(Map[String, UInt]())(_+_) 960 entry_len_map 961 } 962 val s1_entry_len_map = in_entry_len_map_gen(from_bpu.s1)("s1") 963 val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2") 964 val s3_entry_len_map = in_entry_len_map_gen(from_bpu.s3)("s3") 965 966 val to_ifu = io.toIfu.req.bits 967 val to_ifu_entry_len = (to_ifu.fallThruAddr - to_ifu.startAddr) >> instOffsetBits 968 val to_ifu_entry_len_recording_vec = (1 to PredictWidth+1).map(i => to_ifu_entry_len === i.U) 969 val to_ifu_entry_len_map = (1 to PredictWidth+1).map(i => 970 f"to_ifu_ftb_entry_len_$i" -> (to_ifu_entry_len_recording_vec(i-1) && io.toIfu.req.fire) 971 ).foldLeft(Map[String, UInt]())(_+_) 972 973 974 975 val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U) 976 val commit_num_inst_map = (1 to PredictWidth).map(i => 977 f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit) 978 ).foldLeft(Map[String, UInt]())(_+_) 979 980 981 982 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 983 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 984 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 985 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 986 987 988 val mbpBRights = mbpRights & commit_br_mask 989 val mbpJRights = mbpRights & commit_jal_mask 990 val mbpIRights = mbpRights & commit_jalr_mask 991 val mbpCRights = mbpRights & commit_call_mask 992 val mbpRRights = mbpRights & commit_ret_mask 993 994 val mbpBWrongs = mbpWrongs & commit_br_mask 995 val mbpJWrongs = mbpWrongs & commit_jal_mask 996 val mbpIWrongs = mbpWrongs & commit_jalr_mask 997 val mbpCWrongs = mbpWrongs & commit_call_mask 998 val mbpRWrongs = mbpWrongs & commit_ret_mask 999 1000 val update_valid = io.toBpu.update.valid 1001 def u(cond: Bool) = update_valid && cond 1002 val ftb_false_hit = u(update.false_hit) 1003 val ftb_hit = u(commit_hit === h_hit) 1004 1005 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1006 val ftb_new_entry_only_br = ftb_new_entry && !update.ftb_entry.jmpValid 1007 val ftb_new_entry_only_jmp = ftb_new_entry && !update.ftb_entry.brValids(0) 1008 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update.ftb_entry.brValids(0) && update.ftb_entry.jmpValid 1009 1010 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1011 1012 val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified) 1013 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1014 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1015 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1016 val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified 1017 1018 val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits 1019 val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U) 1020 val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i => 1021 f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry) 1022 ).foldLeft(Map[String, UInt]())(_+_) 1023 val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i => 1024 f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry) 1025 ).foldLeft(Map[String, UInt]())(_+_) 1026 1027 val ftq_occupancy_map = (0 to FtqSize).map(i => 1028 f"ftq_has_entry_$i" ->( validEntries === i.U) 1029 ).foldLeft(Map[String, UInt]())(_+_) 1030 1031 val perfCountsMap = Map( 1032 "BpInstr" -> PopCount(mbpInstrs), 1033 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1034 "BpRight" -> PopCount(mbpRights), 1035 "BpWrong" -> PopCount(mbpWrongs), 1036 "BpBRight" -> PopCount(mbpBRights), 1037 "BpBWrong" -> PopCount(mbpBWrongs), 1038 "BpJRight" -> PopCount(mbpJRights), 1039 "BpJWrong" -> PopCount(mbpJWrongs), 1040 "BpIRight" -> PopCount(mbpIRights), 1041 "BpIWrong" -> PopCount(mbpIWrongs), 1042 "BpCRight" -> PopCount(mbpCRights), 1043 "BpCWrong" -> PopCount(mbpCWrongs), 1044 "BpRRight" -> PopCount(mbpRRights), 1045 "BpRWrong" -> PopCount(mbpRWrongs), 1046 1047 "ftb_false_hit" -> PopCount(ftb_false_hit), 1048 "ftb_hit" -> PopCount(ftb_hit), 1049 "ftb_new_entry" -> PopCount(ftb_new_entry), 1050 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1051 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1052 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1053 "ftb_old_entry" -> PopCount(ftb_old_entry), 1054 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1055 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1056 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1057 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1058 "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken) 1059 ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ s1_entry_len_map ++ 1060 s2_entry_len_map ++ s3_entry_len_map ++ 1061 to_ifu_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map 1062 1063 for((key, value) <- perfCountsMap) { 1064 XSPerfAccumulate(key, value) 1065 } 1066 1067 // --------------------------- Debug -------------------------------- 1068 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1069 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1070 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1071 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1072 XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1073 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n") 1074 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1075 1076 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1077 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1078 // case (((valid, pd), ans), taken) => 1079 // Mux(valid && pd.isBr, 1080 // isWrong ^ Mux(ans.hit.asBool, 1081 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1082 // !taken), 1083 // !taken), 1084 // false.B) 1085 // } 1086 // } 1087 1088 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1089 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1090 // case (((valid, pd), ans), taken) => 1091 // Mux(valid && pd.isBr, 1092 // isWrong ^ Mux(ans.hit.asBool, 1093 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1094 // !taken), 1095 // !taken), 1096 // false.B) 1097 // } 1098 // } 1099 1100 // def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1101 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1102 // case (((valid, pd), ans), taken) => 1103 // Mux(valid && pd.isBr, 1104 // isWrong ^ (ans.taken.asBool === taken), 1105 // false.B) 1106 // } 1107 // } 1108 1109 // def loopCheck(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) && ans.hit.asBool, 1113 // isWrong ^ (!taken), 1114 // false.B) 1115 // } 1116 // } 1117 1118 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1119 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1120 // case (((valid, pd), ans), taken) => 1121 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1122 // isWrong ^ (ans.target === commitEntry.target), 1123 // false.B) 1124 // } 1125 // } 1126 1127 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1128 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1129 // // btb and ubtb pred jal and jalr as well 1130 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1131 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1132 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1133 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1134 1135 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1136 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1137 1138 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1139 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1140 1141}