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) || (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 roqFlush = io.fromBackend.roqFlush 424 val stage2Redirect = io.fromBackend.stage2Redirect 425 val stage3Redirect = io.fromBackend.stage3Redirect 426 427 val stage2Flush = stage2Redirect.valid || roqFlush.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 && !roqFlush.valid && !stage2Redirect.valid && !stage3Redirect.valid 436 allowToIfu := !ifuFlush && !roqFlush.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 + roqFlush + 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 roqRedirect = Wire(Valid(new Redirect)) 793 roqRedirect := DontCare 794 roqRedirect.valid := roqFlush.valid 795 roqRedirect.bits.ftqIdx := roqFlush.bits.ftqIdx 796 roqRedirect.bits.ftqOffset := roqFlush.bits.ftqOffset 797 roqRedirect.bits.level := RedirectLevel.flush 798 799 redirectVec.zip(Seq(roqRedirect, stage2Redirect, fromIfuRedirect)).map { 800 case (ve, r) => ve(r) 801 } 802 803 // when redirect, we should reset ptrs and status queues 804 when(redirectVec.map(r => r.valid).reduce(_||_)){ 805 val r = PriorityMux(redirectVec.map(r => (r.valid -> r))) 806 val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_) 807 val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, r.flushItSelf) 808 val next = idx + 1.U 809 bpuPtr := next 810 ifuPtr := next 811 ifuWbPtr := next 812 when (notIfu) { 813 commitStateQueue(idx.value).zipWithIndex.foreach({ case (s, i) => 814 when(i.U > offset || i.U === offset && flushItSelf){ 815 s := c_invalid 816 } 817 }) 818 } 819 } 820 821 // only the valid bit is actually needed 822 io.toIfu.redirect := DontCare 823 io.toIfu.redirect.valid := stage2Flush 824 825 // commit 826 for (c <- io.fromBackend.roq_commits) { 827 when(c.valid) { 828 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited 829 // TODO: remove this 830 // For instruction fusions, we also update the next instruction 831 when (c.bits.isFused === 1.U) { 832 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited 833 }.elsewhen(c.bits.isFused === 2.U) { 834 commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited 835 }.elsewhen(c.bits.isFused === 3.U) { 836 val index = (c.bits.ftqIdx + 1.U).value 837 commitStateQueue(index)(0) := c_commited 838 }.elsewhen(c.bits.isFused === 4.U) { 839 val index = (c.bits.ftqIdx + 1.U).value 840 commitStateQueue(index)(1) := c_commited 841 } 842 } 843 } 844 845 // **************************************************************** 846 // **************************** to bpu **************************** 847 // **************************************************************** 848 849 io.toBpu.redirect <> Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu) 850 851 val canCommit = commPtr =/= ifuWbPtr && 852 Cat(commitStateQueue(commPtr.value).map(s => { 853 s === c_invalid || s === c_commited 854 })).andR() 855 856 // commit reads 857 ftq_pc_mem.io.raddr.last := commPtr.value 858 val commit_pc_bundle = ftq_pc_mem.io.rdata.last 859 ftq_pd_mem.io.raddr.last := commPtr.value 860 val commit_pd = ftq_pd_mem.io.rdata.last 861 ftq_redirect_sram.io.ren.last := canCommit 862 ftq_redirect_sram.io.raddr.last := commPtr.value 863 val commit_spec_meta = ftq_redirect_sram.io.rdata.last 864 ftq_meta_1r_sram.io.ren(0) := canCommit 865 ftq_meta_1r_sram.io.raddr(0) := commPtr.value 866 val commit_meta = ftq_meta_1r_sram.io.rdata(0) 867 ftb_entry_mem.io.raddr.last := commPtr.value 868 val commit_ftb_entry = ftb_entry_mem.io.rdata.last 869 870 // need one cycle to read mem and srams 871 val do_commit = RegNext(canCommit, init=false.B) 872 val do_commit_ptr = RegNext(commPtr) 873 when (canCommit) { commPtr := commPtr + 1.U } 874 val commit_state = RegNext(commitStateQueue(commPtr.value)) 875 val commit_cfi = WireInit(RegNext(cfiIndex_vec(commPtr.value))) 876 when (commit_state(commit_cfi.bits) =/= c_commited) { 877 commit_cfi.valid := false.B 878 } 879 880 val commit_mispredict = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map { 881 case (mis, state) => mis && state === c_commited 882 }) 883 val commit_hit = RegNext(entry_hit_status(commPtr.value)) 884 val commit_target = RegNext(update_target(commPtr.value)) 885 val commit_valid = commit_hit === h_hit || commit_cfi.valid // hit or taken 886 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 972 val from_bpu = io.fromBpu.resp.bits 973 def in_entry_len_map_gen(resp: BranchPredictionBundle)(stage: String) = { 974 val entry_len = (resp.ftb_entry.getFallThrough(resp.pc) - resp.pc) >> instOffsetBits 975 val entry_len_recording_vec = (1 to PredictWidth+1).map(i => entry_len === i.U) 976 val entry_len_map = (1 to PredictWidth+1).map(i => 977 f"${stage}_ftb_entry_len_$i" -> (entry_len_recording_vec(i-1) && resp.valid) 978 ).foldLeft(Map[String, UInt]())(_+_) 979 entry_len_map 980 } 981 val s1_entry_len_map = in_entry_len_map_gen(from_bpu.s1)("s1") 982 val s2_entry_len_map = in_entry_len_map_gen(from_bpu.s2)("s2") 983 val s3_entry_len_map = in_entry_len_map_gen(from_bpu.s3)("s3") 984 985 val to_ifu = io.toIfu.req.bits 986 val to_ifu_entry_len = (to_ifu.fallThruAddr - to_ifu.startAddr) >> instOffsetBits 987 val to_ifu_entry_len_recording_vec = (1 to PredictWidth+1).map(i => to_ifu_entry_len === i.U) 988 val to_ifu_entry_len_map = (1 to PredictWidth+1).map(i => 989 f"to_ifu_ftb_entry_len_$i" -> (to_ifu_entry_len_recording_vec(i-1) && io.toIfu.req.fire) 990 ).foldLeft(Map[String, UInt]())(_+_) 991 992 993 994 val commit_num_inst_recording_vec = (1 to PredictWidth).map(i => PopCount(commit_inst_mask) === i.U) 995 val commit_num_inst_map = (1 to PredictWidth).map(i => 996 f"commit_num_inst_$i" -> (commit_num_inst_recording_vec(i-1) && do_commit) 997 ).foldLeft(Map[String, UInt]())(_+_) 998 999 1000 1001 val commit_jal_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W))) 1002 val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W))) 1003 val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W))) 1004 val commit_ret_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W))) 1005 1006 1007 val mbpBRights = mbpRights & commit_br_mask 1008 val mbpJRights = mbpRights & commit_jal_mask 1009 val mbpIRights = mbpRights & commit_jalr_mask 1010 val mbpCRights = mbpRights & commit_call_mask 1011 val mbpRRights = mbpRights & commit_ret_mask 1012 1013 val mbpBWrongs = mbpWrongs & commit_br_mask 1014 val mbpJWrongs = mbpWrongs & commit_jal_mask 1015 val mbpIWrongs = mbpWrongs & commit_jalr_mask 1016 val mbpCWrongs = mbpWrongs & commit_call_mask 1017 val mbpRWrongs = mbpWrongs & commit_ret_mask 1018 1019 val update_valid = io.toBpu.update.valid 1020 def u(cond: Bool) = update_valid && cond 1021 val ftb_false_hit = u(update.false_hit) 1022 // assert(!ftb_false_hit) 1023 val ftb_hit = u(commit_hit === h_hit) 1024 1025 val ftb_new_entry = u(ftbEntryGen.is_init_entry) 1026 val ftb_new_entry_only_br = ftb_new_entry && !update.ftb_entry.jmpValid 1027 val ftb_new_entry_only_jmp = ftb_new_entry && !update.ftb_entry.brValids(0) 1028 val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update.ftb_entry.brValids(0) && update.ftb_entry.jmpValid 1029 1030 val ftb_old_entry = u(ftbEntryGen.is_old_entry) 1031 1032 val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified) 1033 val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br) 1034 val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified) 1035 val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full 1036 val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified 1037 1038 val ftb_entry_len = (ftbEntryGen.new_entry.getFallThrough(update.pc) - update.pc) >> instOffsetBits 1039 val ftb_entry_len_recording_vec = (1 to PredictWidth+1).map(i => ftb_entry_len === i.U) 1040 val ftb_init_entry_len_map = (1 to PredictWidth+1).map(i => 1041 f"ftb_init_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_new_entry) 1042 ).foldLeft(Map[String, UInt]())(_+_) 1043 val ftb_modified_entry_len_map = (1 to PredictWidth+1).map(i => 1044 f"ftb_modified_entry_len_$i" -> (ftb_entry_len_recording_vec(i-1) && ftb_modified_entry) 1045 ).foldLeft(Map[String, UInt]())(_+_) 1046 1047 val ftq_occupancy_map = (0 to FtqSize).map(i => 1048 f"ftq_has_entry_$i" ->( validEntries === i.U) 1049 ).foldLeft(Map[String, UInt]())(_+_) 1050 1051 val perfCountsMap = Map( 1052 "BpInstr" -> PopCount(mbpInstrs), 1053 "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs), 1054 "BpRight" -> PopCount(mbpRights), 1055 "BpWrong" -> PopCount(mbpWrongs), 1056 "BpBRight" -> PopCount(mbpBRights), 1057 "BpBWrong" -> PopCount(mbpBWrongs), 1058 "BpJRight" -> PopCount(mbpJRights), 1059 "BpJWrong" -> PopCount(mbpJWrongs), 1060 "BpIRight" -> PopCount(mbpIRights), 1061 "BpIWrong" -> PopCount(mbpIWrongs), 1062 "BpCRight" -> PopCount(mbpCRights), 1063 "BpCWrong" -> PopCount(mbpCWrongs), 1064 "BpRRight" -> PopCount(mbpRRights), 1065 "BpRWrong" -> PopCount(mbpRWrongs), 1066 1067 "ftb_false_hit" -> PopCount(ftb_false_hit), 1068 "ftb_hit" -> PopCount(ftb_hit), 1069 "ftb_new_entry" -> PopCount(ftb_new_entry), 1070 "ftb_new_entry_only_br" -> PopCount(ftb_new_entry_only_br), 1071 "ftb_new_entry_only_jmp" -> PopCount(ftb_new_entry_only_jmp), 1072 "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp), 1073 "ftb_old_entry" -> PopCount(ftb_old_entry), 1074 "ftb_modified_entry" -> PopCount(ftb_modified_entry), 1075 "ftb_modified_entry_new_br" -> PopCount(ftb_modified_entry_new_br), 1076 "ftb_jalr_target_modified" -> PopCount(ftb_modified_entry_jalr_target_modified), 1077 "ftb_modified_entry_br_full" -> PopCount(ftb_modified_entry_br_full), 1078 "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken) 1079 ) ++ ftb_init_entry_len_map ++ ftb_modified_entry_len_map ++ s1_entry_len_map ++ 1080 s2_entry_len_map ++ s3_entry_len_map ++ 1081 to_ifu_entry_len_map ++ commit_num_inst_map ++ ftq_occupancy_map 1082 1083 for((key, value) <- perfCountsMap) { 1084 XSPerfAccumulate(key, value) 1085 } 1086 1087 // --------------------------- Debug -------------------------------- 1088 // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable) 1089 XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable) 1090 XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n") 1091 XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n") 1092 XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " + 1093 p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n") 1094 XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n") 1095 1096 // def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1097 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1098 // case (((valid, pd), ans), taken) => 1099 // Mux(valid && pd.isBr, 1100 // isWrong ^ Mux(ans.hit.asBool, 1101 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1102 // !taken), 1103 // !taken), 1104 // false.B) 1105 // } 1106 // } 1107 1108 // def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1109 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1110 // case (((valid, pd), ans), taken) => 1111 // Mux(valid && pd.isBr, 1112 // isWrong ^ Mux(ans.hit.asBool, 1113 // Mux(ans.taken.asBool, taken && ans.target === commitEntry.target, 1114 // !taken), 1115 // !taken), 1116 // false.B) 1117 // } 1118 // } 1119 1120 // def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1121 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1122 // case (((valid, pd), ans), taken) => 1123 // Mux(valid && pd.isBr, 1124 // isWrong ^ (ans.taken.asBool === taken), 1125 // false.B) 1126 // } 1127 // } 1128 1129 // def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1130 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1131 // case (((valid, pd), ans), taken) => 1132 // Mux(valid && (pd.isBr) && ans.hit.asBool, 1133 // isWrong ^ (!taken), 1134 // false.B) 1135 // } 1136 // } 1137 1138 // def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { 1139 // commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { 1140 // case (((valid, pd), ans), taken) => 1141 // Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool, 1142 // isWrong ^ (ans.target === commitEntry.target), 1143 // false.B) 1144 // } 1145 // } 1146 1147 // val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B) 1148 // val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B) 1149 // // btb and ubtb pred jal and jalr as well 1150 // val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B) 1151 // val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B) 1152 // val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B) 1153 // val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B) 1154 1155 // val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) 1156 // val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) 1157 1158 // val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) 1159 // val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) 1160 1161}