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