xref: /XiangShan/src/main/scala/xiangshan/frontend/NewFtq.scala (revision bace178ae3d831d15ac470c048b100856882c1a7)
109c6f1ddSLingrui98/***************************************************************************************
209c6f1ddSLingrui98* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
309c6f1ddSLingrui98* Copyright (c) 2020-2021 Peng Cheng Laboratory
409c6f1ddSLingrui98*
509c6f1ddSLingrui98* XiangShan is licensed under Mulan PSL v2.
609c6f1ddSLingrui98* You can use this software according to the terms and conditions of the Mulan PSL v2.
709c6f1ddSLingrui98* You may obtain a copy of Mulan PSL v2 at:
809c6f1ddSLingrui98*          http://license.coscl.org.cn/MulanPSL2
909c6f1ddSLingrui98*
1009c6f1ddSLingrui98* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
1109c6f1ddSLingrui98* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
1209c6f1ddSLingrui98* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
1309c6f1ddSLingrui98*
1409c6f1ddSLingrui98* See the Mulan PSL v2 for more details.
1509c6f1ddSLingrui98***************************************************************************************/
1609c6f1ddSLingrui98
1709c6f1ddSLingrui98package xiangshan.frontend
1809c6f1ddSLingrui98
198891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters
2009c6f1ddSLingrui98import chisel3._
2109c6f1ddSLingrui98import chisel3.util._
221ca0e4f3SYinan Xuimport utils._
233c02ee8fSwakafaimport utility._
2409c6f1ddSLingrui98import xiangshan._
25e30430c2SJayimport xiangshan.frontend.icache._
261ca0e4f3SYinan Xuimport xiangshan.backend.CtrlToFtqIO
272e1be6e1SSteve Gouimport xiangshan.backend.decode.ImmUnion
283c02ee8fSwakafaimport utility.ChiselDB
2951532d8bSGuokai Chen
3051532d8bSGuokai Chenclass FtqDebugBundle extends Bundle {
3151532d8bSGuokai Chen  val pc = UInt(39.W)
3251532d8bSGuokai Chen  val target = UInt(39.W)
3351532d8bSGuokai Chen  val isBr = Bool()
3451532d8bSGuokai Chen  val isJmp = Bool()
3551532d8bSGuokai Chen  val isCall = Bool()
3651532d8bSGuokai Chen  val isRet = Bool()
3751532d8bSGuokai Chen  val misPred = Bool()
3851532d8bSGuokai Chen  val isTaken = Bool()
3951532d8bSGuokai Chen  val predStage = UInt(2.W)
4051532d8bSGuokai Chen}
4109c6f1ddSLingrui98
4209c6f1ddSLingrui98class FtqPtr(implicit p: Parameters) extends CircularQueuePtr[FtqPtr](
4309c6f1ddSLingrui98  p => p(XSCoreParamsKey).FtqSize
4409c6f1ddSLingrui98){
4509c6f1ddSLingrui98}
4609c6f1ddSLingrui98
4709c6f1ddSLingrui98object FtqPtr {
4809c6f1ddSLingrui98  def apply(f: Bool, v: UInt)(implicit p: Parameters): FtqPtr = {
4909c6f1ddSLingrui98    val ptr = Wire(new FtqPtr)
5009c6f1ddSLingrui98    ptr.flag := f
5109c6f1ddSLingrui98    ptr.value := v
5209c6f1ddSLingrui98    ptr
5309c6f1ddSLingrui98  }
5409c6f1ddSLingrui98  def inverse(ptr: FtqPtr)(implicit p: Parameters): FtqPtr = {
5509c6f1ddSLingrui98    apply(!ptr.flag, ptr.value)
5609c6f1ddSLingrui98  }
5709c6f1ddSLingrui98}
5809c6f1ddSLingrui98
5909c6f1ddSLingrui98class FtqNRSRAM[T <: Data](gen: T, numRead: Int)(implicit p: Parameters) extends XSModule {
6009c6f1ddSLingrui98
6109c6f1ddSLingrui98  val io = IO(new Bundle() {
6209c6f1ddSLingrui98    val raddr = Input(Vec(numRead, UInt(log2Up(FtqSize).W)))
6309c6f1ddSLingrui98    val ren = Input(Vec(numRead, Bool()))
6409c6f1ddSLingrui98    val rdata = Output(Vec(numRead, gen))
6509c6f1ddSLingrui98    val waddr = Input(UInt(log2Up(FtqSize).W))
6609c6f1ddSLingrui98    val wen = Input(Bool())
6709c6f1ddSLingrui98    val wdata = Input(gen)
6809c6f1ddSLingrui98  })
6909c6f1ddSLingrui98
7009c6f1ddSLingrui98  for(i <- 0 until numRead){
7109c6f1ddSLingrui98    val sram = Module(new SRAMTemplate(gen, FtqSize))
7209c6f1ddSLingrui98    sram.io.r.req.valid := io.ren(i)
7309c6f1ddSLingrui98    sram.io.r.req.bits.setIdx := io.raddr(i)
7409c6f1ddSLingrui98    io.rdata(i) := sram.io.r.resp.data(0)
7509c6f1ddSLingrui98    sram.io.w.req.valid := io.wen
7609c6f1ddSLingrui98    sram.io.w.req.bits.setIdx := io.waddr
7709c6f1ddSLingrui98    sram.io.w.req.bits.data := VecInit(io.wdata)
7809c6f1ddSLingrui98  }
7909c6f1ddSLingrui98
8009c6f1ddSLingrui98}
8109c6f1ddSLingrui98
8209c6f1ddSLingrui98class Ftq_RF_Components(implicit p: Parameters) extends XSBundle with BPUUtils {
8309c6f1ddSLingrui98  val startAddr = UInt(VAddrBits.W)
84b37e4b45SLingrui98  val nextLineAddr = UInt(VAddrBits.W)
8509c6f1ddSLingrui98  val isNextMask = Vec(PredictWidth, Bool())
86b37e4b45SLingrui98  val fallThruError = Bool()
87b37e4b45SLingrui98  // val carry = Bool()
8809c6f1ddSLingrui98  def getPc(offset: UInt) = {
8985215037SLingrui98    def getHigher(pc: UInt) = pc(VAddrBits-1, log2Ceil(PredictWidth)+instOffsetBits+1)
9085215037SLingrui98    def getOffset(pc: UInt) = pc(log2Ceil(PredictWidth)+instOffsetBits, instOffsetBits)
91b37e4b45SLingrui98    Cat(getHigher(Mux(isNextMask(offset) && startAddr(log2Ceil(PredictWidth)+instOffsetBits), nextLineAddr, startAddr)),
9209c6f1ddSLingrui98        getOffset(startAddr)+offset, 0.U(instOffsetBits.W))
9309c6f1ddSLingrui98  }
9409c6f1ddSLingrui98  def fromBranchPrediction(resp: BranchPredictionBundle) = {
95a229ab6cSLingrui98    def carryPos(addr: UInt) = addr(instOffsetBits+log2Ceil(PredictWidth)+1)
96adc0b8dfSGuokai Chen    this.startAddr := resp.pc(3)
97adc0b8dfSGuokai Chen    this.nextLineAddr := resp.pc(3) + (FetchWidth * 4 * 2).U // may be broken on other configs
9809c6f1ddSLingrui98    this.isNextMask := VecInit((0 until PredictWidth).map(i =>
99935edac4STang Haojin      (resp.pc(3)(log2Ceil(PredictWidth), 1) +& i.U)(log2Ceil(PredictWidth)).asBool
10009c6f1ddSLingrui98    ))
101adc0b8dfSGuokai Chen    this.fallThruError := resp.fallThruError(3)
10209c6f1ddSLingrui98    this
10309c6f1ddSLingrui98  }
10409c6f1ddSLingrui98  override def toPrintable: Printable = {
105b37e4b45SLingrui98    p"startAddr:${Hexadecimal(startAddr)}"
10609c6f1ddSLingrui98  }
10709c6f1ddSLingrui98}
10809c6f1ddSLingrui98
10909c6f1ddSLingrui98class Ftq_pd_Entry(implicit p: Parameters) extends XSBundle {
11009c6f1ddSLingrui98  val brMask = Vec(PredictWidth, Bool())
11109c6f1ddSLingrui98  val jmpInfo = ValidUndirectioned(Vec(3, Bool()))
11209c6f1ddSLingrui98  val jmpOffset = UInt(log2Ceil(PredictWidth).W)
11309c6f1ddSLingrui98  val jalTarget = UInt(VAddrBits.W)
11409c6f1ddSLingrui98  val rvcMask = Vec(PredictWidth, Bool())
11509c6f1ddSLingrui98  def hasJal  = jmpInfo.valid && !jmpInfo.bits(0)
11609c6f1ddSLingrui98  def hasJalr = jmpInfo.valid && jmpInfo.bits(0)
11709c6f1ddSLingrui98  def hasCall = jmpInfo.valid && jmpInfo.bits(1)
11809c6f1ddSLingrui98  def hasRet  = jmpInfo.valid && jmpInfo.bits(2)
11909c6f1ddSLingrui98
12009c6f1ddSLingrui98  def fromPdWb(pdWb: PredecodeWritebackBundle) = {
12109c6f1ddSLingrui98    val pds = pdWb.pd
12209c6f1ddSLingrui98    this.brMask := VecInit(pds.map(pd => pd.isBr && pd.valid))
12309c6f1ddSLingrui98    this.jmpInfo.valid := VecInit(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid)).asUInt.orR
12409c6f1ddSLingrui98    this.jmpInfo.bits := ParallelPriorityMux(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid),
12509c6f1ddSLingrui98                                             pds.map(pd => VecInit(pd.isJalr, pd.isCall, pd.isRet)))
12609c6f1ddSLingrui98    this.jmpOffset := ParallelPriorityEncoder(pds.map(pd => (pd.isJal || pd.isJalr) && pd.valid))
12709c6f1ddSLingrui98    this.rvcMask := VecInit(pds.map(pd => pd.isRVC))
12809c6f1ddSLingrui98    this.jalTarget := pdWb.jalTarget
12909c6f1ddSLingrui98  }
13009c6f1ddSLingrui98
13109c6f1ddSLingrui98  def toPd(offset: UInt) = {
13209c6f1ddSLingrui98    require(offset.getWidth == log2Ceil(PredictWidth))
13309c6f1ddSLingrui98    val pd = Wire(new PreDecodeInfo)
13409c6f1ddSLingrui98    pd.valid := true.B
13509c6f1ddSLingrui98    pd.isRVC := rvcMask(offset)
13609c6f1ddSLingrui98    val isBr = brMask(offset)
13709c6f1ddSLingrui98    val isJalr = offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(0)
13809c6f1ddSLingrui98    pd.brType := Cat(offset === jmpOffset && jmpInfo.valid, isJalr || isBr)
13909c6f1ddSLingrui98    pd.isCall := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(1)
14009c6f1ddSLingrui98    pd.isRet  := offset === jmpOffset && jmpInfo.valid && jmpInfo.bits(2)
14109c6f1ddSLingrui98    pd
14209c6f1ddSLingrui98  }
14309c6f1ddSLingrui98}
14409c6f1ddSLingrui98
145f9c51548Sssszwicclass PrefetchPtrDB(implicit p: Parameters) extends Bundle {
146f9c51548Sssszwic  val fromFtqPtr  = UInt(log2Up(p(XSCoreParamsKey).FtqSize).W)
147f9c51548Sssszwic  val fromIfuPtr  = UInt(log2Up(p(XSCoreParamsKey).FtqSize).W)
148f9c51548Sssszwic}
14909c6f1ddSLingrui98
1503711cf36S小造xu_zhclass Ftq_Redirect_SRAMEntry(implicit p: Parameters) extends SpeculativeInfo {
151abdc3a32Sxu_zh  val sc_disagree = if (!env.FPGAPlatform) Some(Vec(numBr, Bool())) else None
1523711cf36S小造xu_zh}
15309c6f1ddSLingrui98
15409c6f1ddSLingrui98class Ftq_1R_SRAMEntry(implicit p: Parameters) extends XSBundle with HasBPUConst {
15509c6f1ddSLingrui98  val meta = UInt(MaxMetaLength.W)
15609c6f1ddSLingrui98}
15709c6f1ddSLingrui98
15809c6f1ddSLingrui98class Ftq_Pred_Info(implicit p: Parameters) extends XSBundle {
15909c6f1ddSLingrui98  val target = UInt(VAddrBits.W)
16009c6f1ddSLingrui98  val cfiIndex = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
16109c6f1ddSLingrui98}
16209c6f1ddSLingrui98
16309c6f1ddSLingrui98
16409c6f1ddSLingrui98class FtqRead[T <: Data](private val gen: T)(implicit p: Parameters) extends XSBundle {
16509c6f1ddSLingrui98  val ptr = Output(new FtqPtr)
16609c6f1ddSLingrui98  val offset = Output(UInt(log2Ceil(PredictWidth).W))
16709c6f1ddSLingrui98  val data = Input(gen)
16809c6f1ddSLingrui98  def apply(ptr: FtqPtr, offset: UInt) = {
16909c6f1ddSLingrui98    this.ptr := ptr
17009c6f1ddSLingrui98    this.offset := offset
17109c6f1ddSLingrui98    this.data
17209c6f1ddSLingrui98  }
17309c6f1ddSLingrui98}
17409c6f1ddSLingrui98
17509c6f1ddSLingrui98
17609c6f1ddSLingrui98class FtqToBpuIO(implicit p: Parameters) extends XSBundle {
17709c6f1ddSLingrui98  val redirect = Valid(new BranchPredictionRedirect)
17809c6f1ddSLingrui98  val update = Valid(new BranchPredictionUpdate)
17909c6f1ddSLingrui98  val enq_ptr = Output(new FtqPtr)
18009c6f1ddSLingrui98}
18109c6f1ddSLingrui98
18209c6f1ddSLingrui98class FtqToIfuIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper {
18309c6f1ddSLingrui98  val req = Decoupled(new FetchRequestBundle)
184d2b20d1aSTang Haojin  val redirect = Valid(new BranchPredictionRedirect)
185d2b20d1aSTang Haojin  val topdown_redirect = Valid(new BranchPredictionRedirect)
18609c6f1ddSLingrui98  val flushFromBpu = new Bundle {
18709c6f1ddSLingrui98    // when ifu pipeline is not stalled,
18809c6f1ddSLingrui98    // a packet from bpu s3 can reach f1 at most
18909c6f1ddSLingrui98    val s2 = Valid(new FtqPtr)
190cb4f77ceSLingrui98    val s3 = Valid(new FtqPtr)
19109c6f1ddSLingrui98    def shouldFlushBy(src: Valid[FtqPtr], idx_to_flush: FtqPtr) = {
19209c6f1ddSLingrui98      src.valid && !isAfter(src.bits, idx_to_flush)
19309c6f1ddSLingrui98    }
19409c6f1ddSLingrui98    def shouldFlushByStage2(idx: FtqPtr) = shouldFlushBy(s2, idx)
195cb4f77ceSLingrui98    def shouldFlushByStage3(idx: FtqPtr) = shouldFlushBy(s3, idx)
19609c6f1ddSLingrui98  }
19709c6f1ddSLingrui98}
19809c6f1ddSLingrui98
199c5c5edaeSJeniusclass FtqToICacheIO(implicit p: Parameters) extends XSBundle with HasCircularQueuePtrHelper {
200c5c5edaeSJenius  //NOTE: req.bits must be prepare in T cycle
201c5c5edaeSJenius  // while req.valid is set true in T + 1 cycle
202c5c5edaeSJenius  val req = Decoupled(new FtqToICacheRequestBundle)
203c5c5edaeSJenius}
204c5c5edaeSJenius
20509c6f1ddSLingrui98trait HasBackendRedirectInfo extends HasXSParameter {
2062e1be6e1SSteve Gou  def numRedirectPcRead = exuParameters.JmpCnt + exuParameters.AluCnt + 1
20709c6f1ddSLingrui98  def isLoadReplay(r: Valid[Redirect]) = r.bits.flushItself()
20809c6f1ddSLingrui98}
20909c6f1ddSLingrui98
21009c6f1ddSLingrui98class FtqToCtrlIO(implicit p: Parameters) extends XSBundle with HasBackendRedirectInfo {
211b56f947eSYinan Xu  // write to backend pc mem
212b56f947eSYinan Xu  val pc_mem_wen = Output(Bool())
213b56f947eSYinan Xu  val pc_mem_waddr = Output(UInt(log2Ceil(FtqSize).W))
214b56f947eSYinan Xu  val pc_mem_wdata = Output(new Ftq_RF_Components)
215873dc383SLingrui98  // newest target
216873dc383SLingrui98  val newest_entry_target = Output(UInt(VAddrBits.W))
217873dc383SLingrui98  val newest_entry_ptr = Output(new FtqPtr)
21809c6f1ddSLingrui98}
21909c6f1ddSLingrui98
22009c6f1ddSLingrui98
22109c6f1ddSLingrui98class FTBEntryGen(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo with HasBPUParameter {
22209c6f1ddSLingrui98  val io = IO(new Bundle {
22309c6f1ddSLingrui98    val start_addr = Input(UInt(VAddrBits.W))
22409c6f1ddSLingrui98    val old_entry = Input(new FTBEntry)
22509c6f1ddSLingrui98    val pd = Input(new Ftq_pd_Entry)
22609c6f1ddSLingrui98    val cfiIndex = Flipped(Valid(UInt(log2Ceil(PredictWidth).W)))
22709c6f1ddSLingrui98    val target = Input(UInt(VAddrBits.W))
22809c6f1ddSLingrui98    val hit = Input(Bool())
22909c6f1ddSLingrui98    val mispredict_vec = Input(Vec(PredictWidth, Bool()))
23009c6f1ddSLingrui98
23109c6f1ddSLingrui98    val new_entry = Output(new FTBEntry)
23209c6f1ddSLingrui98    val new_br_insert_pos = Output(Vec(numBr, Bool()))
23309c6f1ddSLingrui98    val taken_mask = Output(Vec(numBr, Bool()))
234803124a6SLingrui98    val jmp_taken = Output(Bool())
23509c6f1ddSLingrui98    val mispred_mask = Output(Vec(numBr+1, Bool()))
23609c6f1ddSLingrui98
23709c6f1ddSLingrui98    // for perf counters
23809c6f1ddSLingrui98    val is_init_entry = Output(Bool())
23909c6f1ddSLingrui98    val is_old_entry = Output(Bool())
24009c6f1ddSLingrui98    val is_new_br = Output(Bool())
24109c6f1ddSLingrui98    val is_jalr_target_modified = Output(Bool())
24209c6f1ddSLingrui98    val is_always_taken_modified = Output(Bool())
24309c6f1ddSLingrui98    val is_br_full = Output(Bool())
24409c6f1ddSLingrui98  })
24509c6f1ddSLingrui98
24609c6f1ddSLingrui98  // no mispredictions detected at predecode
24709c6f1ddSLingrui98  val hit = io.hit
24809c6f1ddSLingrui98  val pd = io.pd
24909c6f1ddSLingrui98
25009c6f1ddSLingrui98  val init_entry = WireInit(0.U.asTypeOf(new FTBEntry))
25109c6f1ddSLingrui98
25209c6f1ddSLingrui98
25309c6f1ddSLingrui98  val cfi_is_br = pd.brMask(io.cfiIndex.bits) && io.cfiIndex.valid
25409c6f1ddSLingrui98  val entry_has_jmp = pd.jmpInfo.valid
25509c6f1ddSLingrui98  val new_jmp_is_jal  = entry_has_jmp && !pd.jmpInfo.bits(0) && io.cfiIndex.valid
25609c6f1ddSLingrui98  val new_jmp_is_jalr = entry_has_jmp &&  pd.jmpInfo.bits(0) && io.cfiIndex.valid
25709c6f1ddSLingrui98  val new_jmp_is_call = entry_has_jmp &&  pd.jmpInfo.bits(1) && io.cfiIndex.valid
25809c6f1ddSLingrui98  val new_jmp_is_ret  = entry_has_jmp &&  pd.jmpInfo.bits(2) && io.cfiIndex.valid
25909c6f1ddSLingrui98  val last_jmp_rvi = entry_has_jmp && pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask.last
260a60a2901SLingrui98  // val last_br_rvi = cfi_is_br && io.cfiIndex.bits === (PredictWidth-1).U && !pd.rvcMask.last
26109c6f1ddSLingrui98
26209c6f1ddSLingrui98  val cfi_is_jal = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jal
26309c6f1ddSLingrui98  val cfi_is_jalr = io.cfiIndex.bits === pd.jmpOffset && new_jmp_is_jalr
26409c6f1ddSLingrui98
265a60a2901SLingrui98  def carryPos = log2Ceil(PredictWidth)+instOffsetBits
26609c6f1ddSLingrui98  def getLower(pc: UInt) = pc(carryPos-1, instOffsetBits)
26709c6f1ddSLingrui98  // if not hit, establish a new entry
26809c6f1ddSLingrui98  init_entry.valid := true.B
26909c6f1ddSLingrui98  // tag is left for ftb to assign
270eeb5ff92SLingrui98
271eeb5ff92SLingrui98  // case br
272eeb5ff92SLingrui98  val init_br_slot = init_entry.getSlotForBr(0)
273eeb5ff92SLingrui98  when (cfi_is_br) {
274eeb5ff92SLingrui98    init_br_slot.valid := true.B
275eeb5ff92SLingrui98    init_br_slot.offset := io.cfiIndex.bits
276b37e4b45SLingrui98    init_br_slot.setLowerStatByTarget(io.start_addr, io.target, numBr == 1)
277eeb5ff92SLingrui98    init_entry.always_taken(0) := true.B // set to always taken on init
278eeb5ff92SLingrui98  }
279eeb5ff92SLingrui98
280eeb5ff92SLingrui98  // case jmp
281eeb5ff92SLingrui98  when (entry_has_jmp) {
282eeb5ff92SLingrui98    init_entry.tailSlot.offset := pd.jmpOffset
283eeb5ff92SLingrui98    init_entry.tailSlot.valid := new_jmp_is_jal || new_jmp_is_jalr
284eeb5ff92SLingrui98    init_entry.tailSlot.setLowerStatByTarget(io.start_addr, Mux(cfi_is_jalr, io.target, pd.jalTarget), isShare=false)
285eeb5ff92SLingrui98  }
286eeb5ff92SLingrui98
28709c6f1ddSLingrui98  val jmpPft = getLower(io.start_addr) +& pd.jmpOffset +& Mux(pd.rvcMask(pd.jmpOffset), 1.U, 2.U)
288a60a2901SLingrui98  init_entry.pftAddr := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft, getLower(io.start_addr))
289a60a2901SLingrui98  init_entry.carry   := Mux(entry_has_jmp && !last_jmp_rvi, jmpPft(carryPos-instOffsetBits), true.B)
29009c6f1ddSLingrui98  init_entry.isJalr := new_jmp_is_jalr
29109c6f1ddSLingrui98  init_entry.isCall := new_jmp_is_call
29209c6f1ddSLingrui98  init_entry.isRet  := new_jmp_is_ret
293f4ebc4b2SLingrui98  // that means fall thru points to the middle of an inst
294ae409b75SSteve Gou  init_entry.last_may_be_rvi_call := pd.jmpOffset === (PredictWidth-1).U && !pd.rvcMask(pd.jmpOffset)
29509c6f1ddSLingrui98
29609c6f1ddSLingrui98  // if hit, check whether a new cfi(only br is possible) is detected
29709c6f1ddSLingrui98  val oe = io.old_entry
298eeb5ff92SLingrui98  val br_recorded_vec = oe.getBrRecordedVec(io.cfiIndex.bits)
29909c6f1ddSLingrui98  val br_recorded = br_recorded_vec.asUInt.orR
30009c6f1ddSLingrui98  val is_new_br = cfi_is_br && !br_recorded
30109c6f1ddSLingrui98  val new_br_offset = io.cfiIndex.bits
30209c6f1ddSLingrui98  // vec(i) means new br will be inserted BEFORE old br(i)
303eeb5ff92SLingrui98  val allBrSlotsVec = oe.allSlotsForBr
30409c6f1ddSLingrui98  val new_br_insert_onehot = VecInit((0 until numBr).map{
30509c6f1ddSLingrui98    i => i match {
306eeb5ff92SLingrui98      case 0 =>
307eeb5ff92SLingrui98        !allBrSlotsVec(0).valid || new_br_offset < allBrSlotsVec(0).offset
308eeb5ff92SLingrui98      case idx =>
309eeb5ff92SLingrui98        allBrSlotsVec(idx-1).valid && new_br_offset > allBrSlotsVec(idx-1).offset &&
310eeb5ff92SLingrui98        (!allBrSlotsVec(idx).valid || new_br_offset < allBrSlotsVec(idx).offset)
31109c6f1ddSLingrui98    }
31209c6f1ddSLingrui98  })
31309c6f1ddSLingrui98
31409c6f1ddSLingrui98  val old_entry_modified = WireInit(io.old_entry)
31509c6f1ddSLingrui98  for (i <- 0 until numBr) {
316eeb5ff92SLingrui98    val slot = old_entry_modified.allSlotsForBr(i)
317eeb5ff92SLingrui98    when (new_br_insert_onehot(i)) {
318eeb5ff92SLingrui98      slot.valid := true.B
319eeb5ff92SLingrui98      slot.offset := new_br_offset
320b37e4b45SLingrui98      slot.setLowerStatByTarget(io.start_addr, io.target, i == numBr-1)
321eeb5ff92SLingrui98      old_entry_modified.always_taken(i) := true.B
322eeb5ff92SLingrui98    }.elsewhen (new_br_offset > oe.allSlotsForBr(i).offset) {
323eeb5ff92SLingrui98      old_entry_modified.always_taken(i) := false.B
324eeb5ff92SLingrui98      // all other fields remain unchanged
325eeb5ff92SLingrui98    }.otherwise {
326eeb5ff92SLingrui98      // case i == 0, remain unchanged
327eeb5ff92SLingrui98      if (i != 0) {
328b37e4b45SLingrui98        val noNeedToMoveFromFormerSlot = (i == numBr-1).B && !oe.brSlots.last.valid
329eeb5ff92SLingrui98        when (!noNeedToMoveFromFormerSlot) {
330eeb5ff92SLingrui98          slot.fromAnotherSlot(oe.allSlotsForBr(i-1))
331eeb5ff92SLingrui98          old_entry_modified.always_taken(i) := oe.always_taken(i)
33209c6f1ddSLingrui98        }
333eeb5ff92SLingrui98      }
334eeb5ff92SLingrui98    }
335eeb5ff92SLingrui98  }
33609c6f1ddSLingrui98
337eeb5ff92SLingrui98  // two circumstances:
338eeb5ff92SLingrui98  // 1. oe: | br | j  |, new br should be in front of j, thus addr of j should be new pft
339eeb5ff92SLingrui98  // 2. oe: | br | br |, new br could be anywhere between, thus new pft is the addr of either
340eeb5ff92SLingrui98  //        the previous last br or the new br
341eeb5ff92SLingrui98  val may_have_to_replace = oe.noEmptySlotForNewBr
342eeb5ff92SLingrui98  val pft_need_to_change = is_new_br && may_have_to_replace
34309c6f1ddSLingrui98  // it should either be the given last br or the new br
34409c6f1ddSLingrui98  when (pft_need_to_change) {
345eeb5ff92SLingrui98    val new_pft_offset =
346710a8720SLingrui98      Mux(!new_br_insert_onehot.asUInt.orR,
347710a8720SLingrui98        new_br_offset, oe.allSlotsForBr.last.offset)
348eeb5ff92SLingrui98
349710a8720SLingrui98    // set jmp to invalid
35009c6f1ddSLingrui98    old_entry_modified.pftAddr := getLower(io.start_addr) + new_pft_offset
35109c6f1ddSLingrui98    old_entry_modified.carry := (getLower(io.start_addr) +& new_pft_offset).head(1).asBool
352f4ebc4b2SLingrui98    old_entry_modified.last_may_be_rvi_call := false.B
35309c6f1ddSLingrui98    old_entry_modified.isCall := false.B
35409c6f1ddSLingrui98    old_entry_modified.isRet := false.B
355eeb5ff92SLingrui98    old_entry_modified.isJalr := false.B
35609c6f1ddSLingrui98  }
35709c6f1ddSLingrui98
35809c6f1ddSLingrui98  val old_entry_jmp_target_modified = WireInit(oe)
359710a8720SLingrui98  val old_target = oe.tailSlot.getTarget(io.start_addr) // may be wrong because we store only 20 lowest bits
360b37e4b45SLingrui98  val old_tail_is_jmp = !oe.tailSlot.sharing
361eeb5ff92SLingrui98  val jalr_target_modified = cfi_is_jalr && (old_target =/= io.target) && old_tail_is_jmp // TODO: pass full jalr target
3623bcae573SLingrui98  when (jalr_target_modified) {
36309c6f1ddSLingrui98    old_entry_jmp_target_modified.setByJmpTarget(io.start_addr, io.target)
36409c6f1ddSLingrui98    old_entry_jmp_target_modified.always_taken := 0.U.asTypeOf(Vec(numBr, Bool()))
36509c6f1ddSLingrui98  }
36609c6f1ddSLingrui98
36709c6f1ddSLingrui98  val old_entry_always_taken = WireInit(oe)
36809c6f1ddSLingrui98  val always_taken_modified_vec = Wire(Vec(numBr, Bool())) // whether modified or not
36909c6f1ddSLingrui98  for (i <- 0 until numBr) {
37009c6f1ddSLingrui98    old_entry_always_taken.always_taken(i) :=
37109c6f1ddSLingrui98      oe.always_taken(i) && io.cfiIndex.valid && oe.brValids(i) && io.cfiIndex.bits === oe.brOffset(i)
372710a8720SLingrui98    always_taken_modified_vec(i) := oe.always_taken(i) && !old_entry_always_taken.always_taken(i)
37309c6f1ddSLingrui98  }
37409c6f1ddSLingrui98  val always_taken_modified = always_taken_modified_vec.reduce(_||_)
37509c6f1ddSLingrui98
37609c6f1ddSLingrui98
37709c6f1ddSLingrui98
37809c6f1ddSLingrui98  val derived_from_old_entry =
37909c6f1ddSLingrui98    Mux(is_new_br, old_entry_modified,
3803bcae573SLingrui98      Mux(jalr_target_modified, old_entry_jmp_target_modified, old_entry_always_taken))
38109c6f1ddSLingrui98
38209c6f1ddSLingrui98
38309c6f1ddSLingrui98  io.new_entry := Mux(!hit, init_entry, derived_from_old_entry)
38409c6f1ddSLingrui98
38509c6f1ddSLingrui98  io.new_br_insert_pos := new_br_insert_onehot
38609c6f1ddSLingrui98  io.taken_mask := VecInit((io.new_entry.brOffset zip io.new_entry.brValids).map{
38709c6f1ddSLingrui98    case (off, v) => io.cfiIndex.bits === off && io.cfiIndex.valid && v
38809c6f1ddSLingrui98  })
389803124a6SLingrui98  io.jmp_taken := io.new_entry.jmpValid && io.new_entry.tailSlot.offset === io.cfiIndex.bits
39009c6f1ddSLingrui98  for (i <- 0 until numBr) {
39109c6f1ddSLingrui98    io.mispred_mask(i) := io.new_entry.brValids(i) && io.mispredict_vec(io.new_entry.brOffset(i))
39209c6f1ddSLingrui98  }
39309c6f1ddSLingrui98  io.mispred_mask.last := io.new_entry.jmpValid && io.mispredict_vec(pd.jmpOffset)
39409c6f1ddSLingrui98
39509c6f1ddSLingrui98  // for perf counters
39609c6f1ddSLingrui98  io.is_init_entry := !hit
3973bcae573SLingrui98  io.is_old_entry := hit && !is_new_br && !jalr_target_modified && !always_taken_modified
39809c6f1ddSLingrui98  io.is_new_br := hit && is_new_br
3993bcae573SLingrui98  io.is_jalr_target_modified := hit && jalr_target_modified
40009c6f1ddSLingrui98  io.is_always_taken_modified := hit && always_taken_modified
401eeb5ff92SLingrui98  io.is_br_full := hit && is_new_br && may_have_to_replace
40209c6f1ddSLingrui98}
40309c6f1ddSLingrui98
404c5c5edaeSJeniusclass FtqPcMemWrapper(numOtherReads: Int)(implicit p: Parameters) extends XSModule with HasBackendRedirectInfo {
405c5c5edaeSJenius  val io = IO(new Bundle {
406c5c5edaeSJenius    val ifuPtr_w       = Input(new FtqPtr)
407c5c5edaeSJenius    val ifuPtrPlus1_w  = Input(new FtqPtr)
4086bf9b30dSLingrui98    val ifuPtrPlus2_w  = Input(new FtqPtr)
409c5c5edaeSJenius    val commPtr_w      = Input(new FtqPtr)
4106bf9b30dSLingrui98    val commPtrPlus1_w = Input(new FtqPtr)
411c5c5edaeSJenius    val ifuPtr_rdata       = Output(new Ftq_RF_Components)
412c5c5edaeSJenius    val ifuPtrPlus1_rdata  = Output(new Ftq_RF_Components)
4136bf9b30dSLingrui98    val ifuPtrPlus2_rdata  = Output(new Ftq_RF_Components)
414c5c5edaeSJenius    val commPtr_rdata      = Output(new Ftq_RF_Components)
4156bf9b30dSLingrui98    val commPtrPlus1_rdata = Output(new Ftq_RF_Components)
416c5c5edaeSJenius
417c5c5edaeSJenius    val other_raddrs = Input(Vec(numOtherReads, UInt(log2Ceil(FtqSize).W)))
418c5c5edaeSJenius    val other_rdatas = Output(Vec(numOtherReads, new Ftq_RF_Components))
419c5c5edaeSJenius
420c5c5edaeSJenius    val wen = Input(Bool())
421c5c5edaeSJenius    val waddr = Input(UInt(log2Ceil(FtqSize).W))
422c5c5edaeSJenius    val wdata = Input(new Ftq_RF_Components)
423c5c5edaeSJenius  })
424c5c5edaeSJenius
4256bf9b30dSLingrui98  val num_pc_read = numOtherReads + 5
426c5c5edaeSJenius  val mem = Module(new SyncDataModuleTemplate(new Ftq_RF_Components, FtqSize,
42728f2cf58SLingrui98    num_pc_read, 1, "FtqPC"))
428c5c5edaeSJenius  mem.io.wen(0)   := io.wen
429c5c5edaeSJenius  mem.io.waddr(0) := io.waddr
430c5c5edaeSJenius  mem.io.wdata(0) := io.wdata
431c5c5edaeSJenius
4326bf9b30dSLingrui98  // read one cycle ahead for ftq local reads
433c5c5edaeSJenius  val raddr_vec = VecInit(io.other_raddrs ++
43488bc4f90SLingrui98    Seq(io.ifuPtr_w.value, io.ifuPtrPlus1_w.value, io.ifuPtrPlus2_w.value, io.commPtrPlus1_w.value, io.commPtr_w.value))
435c5c5edaeSJenius
436c5c5edaeSJenius  mem.io.raddr := raddr_vec
437c5c5edaeSJenius
4386bf9b30dSLingrui98  io.other_rdatas       := mem.io.rdata.dropRight(5)
4396bf9b30dSLingrui98  io.ifuPtr_rdata       := mem.io.rdata.dropRight(4).last
4406bf9b30dSLingrui98  io.ifuPtrPlus1_rdata  := mem.io.rdata.dropRight(3).last
4416bf9b30dSLingrui98  io.ifuPtrPlus2_rdata  := mem.io.rdata.dropRight(2).last
4426bf9b30dSLingrui98  io.commPtrPlus1_rdata := mem.io.rdata.dropRight(1).last
443c5c5edaeSJenius  io.commPtr_rdata      := mem.io.rdata.last
444c5c5edaeSJenius}
445c5c5edaeSJenius
44609c6f1ddSLingrui98class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper
447e30430c2SJay  with HasBackendRedirectInfo with BPUUtils with HasBPUConst with HasPerfEvents
448e30430c2SJay  with HasICacheParameters{
44909c6f1ddSLingrui98  val io = IO(new Bundle {
45009c6f1ddSLingrui98    val fromBpu = Flipped(new BpuToFtqIO)
45109c6f1ddSLingrui98    val fromIfu = Flipped(new IfuToFtqIO)
45209c6f1ddSLingrui98    val fromBackend = Flipped(new CtrlToFtqIO)
45309c6f1ddSLingrui98
45409c6f1ddSLingrui98    val toBpu = new FtqToBpuIO
45509c6f1ddSLingrui98    val toIfu = new FtqToIfuIO
456c5c5edaeSJenius    val toICache = new FtqToICacheIO
45709c6f1ddSLingrui98    val toBackend = new FtqToCtrlIO
45809c6f1ddSLingrui98
4597052722fSJay    val toPrefetch = new FtqPrefechBundle
4607052722fSJay
46109c6f1ddSLingrui98    val bpuInfo = new Bundle {
46209c6f1ddSLingrui98      val bpRight = Output(UInt(XLEN.W))
46309c6f1ddSLingrui98      val bpWrong = Output(UInt(XLEN.W))
46409c6f1ddSLingrui98    }
4651d1e6d4dSJenius
4661d1e6d4dSJenius    val mmioCommitRead = Flipped(new mmioCommitRead)
467d2b20d1aSTang Haojin
468d2b20d1aSTang Haojin    // for perf
469d2b20d1aSTang Haojin    val ControlBTBMissBubble = Output(Bool())
470d2b20d1aSTang Haojin    val TAGEMissBubble = Output(Bool())
471d2b20d1aSTang Haojin    val SCMissBubble = Output(Bool())
472d2b20d1aSTang Haojin    val ITTAGEMissBubble = Output(Bool())
473d2b20d1aSTang Haojin    val RASMissBubble = Output(Bool())
47409c6f1ddSLingrui98  })
47509c6f1ddSLingrui98  io.bpuInfo := DontCare
47609c6f1ddSLingrui98
477d2b20d1aSTang Haojin  val topdown_stage = RegInit(0.U.asTypeOf(new FrontendTopDownBundle))
478d2b20d1aSTang Haojin  // only driven by clock, not valid-ready
479d2b20d1aSTang Haojin  topdown_stage := io.fromBpu.resp.bits.topdown_info
480d2b20d1aSTang Haojin  io.toIfu.req.bits.topdown_info := topdown_stage
481d2b20d1aSTang Haojin
482d2b20d1aSTang Haojin  val ifuRedirected = RegInit(VecInit(Seq.fill(FtqSize)(false.B)))
483d2b20d1aSTang Haojin
484*bace178aSGao-Zeyu
485*bace178aSGao-Zeyu  // io.fromBackend.ftqIdxAhead: jmp + alu(aluCnt) + ldReplay + exception
486*bace178aSGao-Zeyu  val aluAheadStart = 1
487*bace178aSGao-Zeyu  val ftqIdxAhead = VecInit(Seq.tabulate(FtqRedirectAheadNum)(i => io.fromBackend.ftqIdxAhead(i + aluAheadStart))) // only alu
488*bace178aSGao-Zeyu  val ftqIdxSelOH = io.fromBackend.ftqIdxSelOH.bits(FtqRedirectAheadNum, 1)
489*bace178aSGao-Zeyu
490*bace178aSGao-Zeyu  val aheadValid   = ftqIdxAhead.map(_.valid).reduce(_|_) && !io.fromBackend.redirect.valid
491*bace178aSGao-Zeyu  val realAhdValid = io.fromBackend.redirect.valid && (ftqIdxSelOH > 0.U) && RegNext(aheadValid)
492d2b20d1aSTang Haojin  val backendRedirect = Wire(Valid(new BranchPredictionRedirect))
493*bace178aSGao-Zeyu  val backendRedirectReg = RegNext(backendRedirect)
494*bace178aSGao-Zeyu  backendRedirectReg.valid := Mux(realAhdValid, 0.B, backendRedirect.valid)
495*bace178aSGao-Zeyu  val fromBackendRedirect = Wire(Valid(new BranchPredictionRedirect))
496*bace178aSGao-Zeyu  fromBackendRedirect := Mux(realAhdValid, backendRedirect, backendRedirectReg)
49709c6f1ddSLingrui98
498df5b4b8eSYinan Xu  val stage2Flush = backendRedirect.valid
49909c6f1ddSLingrui98  val backendFlush = stage2Flush || RegNext(stage2Flush)
50009c6f1ddSLingrui98  val ifuFlush = Wire(Bool())
50109c6f1ddSLingrui98
50209c6f1ddSLingrui98  val flush = stage2Flush || RegNext(stage2Flush)
50309c6f1ddSLingrui98
50409c6f1ddSLingrui98  val allowBpuIn, allowToIfu = WireInit(false.B)
50509c6f1ddSLingrui98  val flushToIfu = !allowToIfu
506*bace178aSGao-Zeyu  allowBpuIn := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
507*bace178aSGao-Zeyu  allowToIfu := !ifuFlush && !backendRedirect.valid && !backendRedirectReg.valid
50809c6f1ddSLingrui98
509f56177cbSJenius  def copyNum = 5
510e30430c2SJay  val bpuPtr, ifuPtr, ifuWbPtr, commPtr = RegInit(FtqPtr(false.B, 0.U))
511c9bc5480SLingrui98  val ifuPtrPlus1 = RegInit(FtqPtr(false.B, 1.U))
5126bf9b30dSLingrui98  val ifuPtrPlus2 = RegInit(FtqPtr(false.B, 2.U))
5136bf9b30dSLingrui98  val commPtrPlus1 = RegInit(FtqPtr(false.B, 1.U))
514f56177cbSJenius  val copied_ifu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
515dc270d3bSJenius  val copied_bpu_ptr = Seq.fill(copyNum)(RegInit(FtqPtr(false.B, 0.U)))
5166bf9b30dSLingrui98  require(FtqSize >= 4)
517c5c5edaeSJenius  val ifuPtr_write       = WireInit(ifuPtr)
518c5c5edaeSJenius  val ifuPtrPlus1_write  = WireInit(ifuPtrPlus1)
5196bf9b30dSLingrui98  val ifuPtrPlus2_write  = WireInit(ifuPtrPlus2)
520c5c5edaeSJenius  val ifuWbPtr_write     = WireInit(ifuWbPtr)
521c5c5edaeSJenius  val commPtr_write      = WireInit(commPtr)
5226bf9b30dSLingrui98  val commPtrPlus1_write = WireInit(commPtrPlus1)
523c5c5edaeSJenius  ifuPtr       := ifuPtr_write
524c5c5edaeSJenius  ifuPtrPlus1  := ifuPtrPlus1_write
5256bf9b30dSLingrui98  ifuPtrPlus2  := ifuPtrPlus2_write
526c5c5edaeSJenius  ifuWbPtr     := ifuWbPtr_write
527c5c5edaeSJenius  commPtr      := commPtr_write
528f83ef67eSLingrui98  commPtrPlus1 := commPtrPlus1_write
529f56177cbSJenius  copied_ifu_ptr.map{ptr =>
530f56177cbSJenius    ptr := ifuPtr_write
531f56177cbSJenius    dontTouch(ptr)
532f56177cbSJenius  }
53309c6f1ddSLingrui98  val validEntries = distanceBetween(bpuPtr, commPtr)
53443aca6c2SGuokai Chen  val canCommit = Wire(Bool())
53509c6f1ddSLingrui98
53609c6f1ddSLingrui98  // **********************************************************************
53709c6f1ddSLingrui98  // **************************** enq from bpu ****************************
53809c6f1ddSLingrui98  // **********************************************************************
53943aca6c2SGuokai Chen  val new_entry_ready = validEntries < FtqSize.U || canCommit
54009c6f1ddSLingrui98  io.fromBpu.resp.ready := new_entry_ready
54109c6f1ddSLingrui98
54209c6f1ddSLingrui98  val bpu_s2_resp = io.fromBpu.resp.bits.s2
543cb4f77ceSLingrui98  val bpu_s3_resp = io.fromBpu.resp.bits.s3
544adc0b8dfSGuokai Chen  val bpu_s2_redirect = bpu_s2_resp.valid(3) && bpu_s2_resp.hasRedirect(3)
545adc0b8dfSGuokai Chen  val bpu_s3_redirect = bpu_s3_resp.valid(3) && bpu_s3_resp.hasRedirect(3)
54609c6f1ddSLingrui98
54709c6f1ddSLingrui98  io.toBpu.enq_ptr := bpuPtr
548935edac4STang Haojin  val enq_fire = io.fromBpu.resp.fire && allowBpuIn // from bpu s1
549935edac4STang Haojin  val bpu_in_fire = (io.fromBpu.resp.fire || bpu_s2_redirect || bpu_s3_redirect) && allowBpuIn
55009c6f1ddSLingrui98
551b37e4b45SLingrui98  val bpu_in_resp = io.fromBpu.resp.bits.selectedResp
552adc0b8dfSGuokai Chen  val bpu_in_stage = io.fromBpu.resp.bits.selectedRespIdxForFtq
55309c6f1ddSLingrui98  val bpu_in_resp_ptr = Mux(bpu_in_stage === BP_S1, bpuPtr, bpu_in_resp.ftq_idx)
55409c6f1ddSLingrui98  val bpu_in_resp_idx = bpu_in_resp_ptr.value
55509c6f1ddSLingrui98
556378f00d9SJenius  // read ports:      prefetchReq ++  ifuReq1 + ifuReq2 + ifuReq3 + commitUpdate2 + commitUpdate
557378f00d9SJenius  val ftq_pc_mem = Module(new FtqPcMemWrapper(1))
5586bf9b30dSLingrui98  // resp from uBTB
559c5c5edaeSJenius  ftq_pc_mem.io.wen := bpu_in_fire
560c5c5edaeSJenius  ftq_pc_mem.io.waddr := bpu_in_resp_idx
561c5c5edaeSJenius  ftq_pc_mem.io.wdata.fromBranchPrediction(bpu_in_resp)
56209c6f1ddSLingrui98
56309c6f1ddSLingrui98  //                                                            ifuRedirect + backendRedirect + commit
564*bace178aSGao-Zeyu  val ftq_redirect_sram = Module(new FtqNRSRAM(new Ftq_Redirect_SRAMEntry, 1+FtqRedirectAheadNum+1))
56509c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
566adc0b8dfSGuokai Chen  ftq_redirect_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3)
56709c6f1ddSLingrui98  ftq_redirect_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
568c2d1ec7dSLingrui98  ftq_redirect_sram.io.wdata := io.fromBpu.resp.bits.last_stage_spec_info
56949cbc998SLingrui98  println(f"ftq redirect SRAM: entry ${ftq_redirect_sram.io.wdata.getWidth} * ${FtqSize} * 3")
57049cbc998SLingrui98  println(f"ftq redirect SRAM: ahead fh ${ftq_redirect_sram.io.wdata.afhob.getWidth} * ${FtqSize} * 3")
57109c6f1ddSLingrui98
57209c6f1ddSLingrui98  val ftq_meta_1r_sram = Module(new FtqNRSRAM(new Ftq_1R_SRAMEntry, 1))
57309c6f1ddSLingrui98  // these info is intended to enq at the last stage of bpu
574adc0b8dfSGuokai Chen  ftq_meta_1r_sram.io.wen := io.fromBpu.resp.bits.lastStage.valid(3)
57509c6f1ddSLingrui98  ftq_meta_1r_sram.io.waddr := io.fromBpu.resp.bits.lastStage.ftq_idx.value
576c2d1ec7dSLingrui98  ftq_meta_1r_sram.io.wdata.meta := io.fromBpu.resp.bits.last_stage_meta
57709c6f1ddSLingrui98  //                                                            ifuRedirect + backendRedirect + commit
578*bace178aSGao-Zeyu  val ftb_entry_mem = Module(new SyncDataModuleTemplate(new FTBEntry, FtqSize, 1+FtqRedirectAheadNum+1, 1))
579adc0b8dfSGuokai Chen  ftb_entry_mem.io.wen(0) := io.fromBpu.resp.bits.lastStage.valid(3)
58009c6f1ddSLingrui98  ftb_entry_mem.io.waddr(0) := io.fromBpu.resp.bits.lastStage.ftq_idx.value
581c2d1ec7dSLingrui98  ftb_entry_mem.io.wdata(0) := io.fromBpu.resp.bits.last_stage_ftb_entry
58209c6f1ddSLingrui98
58309c6f1ddSLingrui98
58409c6f1ddSLingrui98  // multi-write
585b0ed7239SLingrui98  val update_target = Reg(Vec(FtqSize, UInt(VAddrBits.W))) // could be taken target or fallThrough //TODO: remove this
5866bf9b30dSLingrui98  val newest_entry_target = Reg(UInt(VAddrBits.W))
5876bf9b30dSLingrui98  val newest_entry_ptr = Reg(new FtqPtr)
58809c6f1ddSLingrui98  val cfiIndex_vec = Reg(Vec(FtqSize, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))))
58909c6f1ddSLingrui98  val mispredict_vec = Reg(Vec(FtqSize, Vec(PredictWidth, Bool())))
59009c6f1ddSLingrui98  val pred_stage = Reg(Vec(FtqSize, UInt(2.W)))
591209a4cafSSteve Gou  val pred_s1_cycle = if (!env.FPGAPlatform) Some(Reg(Vec(FtqSize, UInt(64.W)))) else None
59209c6f1ddSLingrui98
593b5808fc2Ssfencevma  val c_invalid :: c_valid :: c_commited :: Nil = Enum(3)
59409c6f1ddSLingrui98  val commitStateQueue = RegInit(VecInit(Seq.fill(FtqSize) {
59509c6f1ddSLingrui98    VecInit(Seq.fill(PredictWidth)(c_invalid))
59609c6f1ddSLingrui98  }))
59709c6f1ddSLingrui98
59809c6f1ddSLingrui98  val f_to_send :: f_sent :: Nil = Enum(2)
59909c6f1ddSLingrui98  val entry_fetch_status = RegInit(VecInit(Seq.fill(FtqSize)(f_sent)))
60009c6f1ddSLingrui98
60109c6f1ddSLingrui98  val h_not_hit :: h_false_hit :: h_hit :: Nil = Enum(3)
60209c6f1ddSLingrui98  val entry_hit_status = RegInit(VecInit(Seq.fill(FtqSize)(h_not_hit)))
60309c6f1ddSLingrui98
604f63797a4SLingrui98  // modify registers one cycle later to cut critical path
605f63797a4SLingrui98  val last_cycle_bpu_in = RegNext(bpu_in_fire)
6066bf9b30dSLingrui98  val last_cycle_bpu_in_ptr = RegNext(bpu_in_resp_ptr)
6076bf9b30dSLingrui98  val last_cycle_bpu_in_idx = last_cycle_bpu_in_ptr.value
608adc0b8dfSGuokai Chen  val last_cycle_bpu_target = RegNext(bpu_in_resp.getTarget(3))
609adc0b8dfSGuokai Chen  val last_cycle_cfiIndex = RegNext(bpu_in_resp.cfiIndex(3))
610f63797a4SLingrui98  val last_cycle_bpu_in_stage = RegNext(bpu_in_stage)
611f56177cbSJenius
6127be982afSLingrui98  def extra_copyNum_for_commitStateQueue = 2
6137be982afSLingrui98  val copied_last_cycle_bpu_in = VecInit(Seq.fill(copyNum+extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_fire)))
6147be982afSLingrui98  val copied_last_cycle_bpu_in_ptr_for_ftq = VecInit(Seq.fill(extra_copyNum_for_commitStateQueue)(RegNext(bpu_in_resp_ptr)))
615f56177cbSJenius
616f63797a4SLingrui98  when (last_cycle_bpu_in) {
617f63797a4SLingrui98    entry_fetch_status(last_cycle_bpu_in_idx) := f_to_send
618f63797a4SLingrui98    cfiIndex_vec(last_cycle_bpu_in_idx) := last_cycle_cfiIndex
619f63797a4SLingrui98    pred_stage(last_cycle_bpu_in_idx) := last_cycle_bpu_in_stage
6206bf9b30dSLingrui98
621b0ed7239SLingrui98    update_target(last_cycle_bpu_in_idx) := last_cycle_bpu_target // TODO: remove this
6226bf9b30dSLingrui98    newest_entry_target := last_cycle_bpu_target
6236bf9b30dSLingrui98    newest_entry_ptr := last_cycle_bpu_in_ptr
62409c6f1ddSLingrui98  }
62509c6f1ddSLingrui98
6267be982afSLingrui98  // reduce fanout by delay write for a cycle
6277be982afSLingrui98  when (RegNext(last_cycle_bpu_in)) {
6287be982afSLingrui98    mispredict_vec(RegNext(last_cycle_bpu_in_idx)) := WireInit(VecInit(Seq.fill(PredictWidth)(false.B)))
6297be982afSLingrui98  }
6307be982afSLingrui98
631209a4cafSSteve Gou  // record s1 pred cycles
632209a4cafSSteve Gou  pred_s1_cycle.map(vec => {
633209a4cafSSteve Gou    when (bpu_in_fire && (bpu_in_stage === BP_S1)) {
634209a4cafSSteve Gou      vec(bpu_in_resp_ptr.value) := bpu_in_resp.full_pred(0).predCycle.getOrElse(0.U)
635209a4cafSSteve Gou    }
636209a4cafSSteve Gou  })
637209a4cafSSteve Gou
6387be982afSLingrui98  // reduce fanout using copied last_cycle_bpu_in and copied last_cycle_bpu_in_ptr
6397be982afSLingrui98  val copied_last_cycle_bpu_in_for_ftq = copied_last_cycle_bpu_in.takeRight(extra_copyNum_for_commitStateQueue)
6407be982afSLingrui98  copied_last_cycle_bpu_in_for_ftq.zip(copied_last_cycle_bpu_in_ptr_for_ftq).zipWithIndex.map {
6417be982afSLingrui98    case ((in, ptr), i) =>
6427be982afSLingrui98      when (in) {
6437be982afSLingrui98        val perSetEntries = FtqSize / extra_copyNum_for_commitStateQueue // 32
6447be982afSLingrui98        require(FtqSize % extra_copyNum_for_commitStateQueue == 0)
6457be982afSLingrui98        for (j <- 0 until perSetEntries) {
6469361b0c5SLingrui98          when (ptr.value === (i*perSetEntries+j).U) {
6477be982afSLingrui98            commitStateQueue(i*perSetEntries+j) := VecInit(Seq.fill(PredictWidth)(c_invalid))
6487be982afSLingrui98          }
6497be982afSLingrui98        }
6507be982afSLingrui98      }
6519361b0c5SLingrui98  }
6527be982afSLingrui98
653873dc383SLingrui98  // num cycle is fixed
654873dc383SLingrui98  io.toBackend.newest_entry_ptr := RegNext(newest_entry_ptr)
655873dc383SLingrui98  io.toBackend.newest_entry_target := RegNext(newest_entry_target)
656873dc383SLingrui98
657f63797a4SLingrui98
65809c6f1ddSLingrui98  bpuPtr := bpuPtr + enq_fire
659dc270d3bSJenius  copied_bpu_ptr.map(_ := bpuPtr + enq_fire)
660c9bc5480SLingrui98  when (io.toIfu.req.fire && allowToIfu) {
661c5c5edaeSJenius    ifuPtr_write := ifuPtrPlus1
6626bf9b30dSLingrui98    ifuPtrPlus1_write := ifuPtrPlus2
6636bf9b30dSLingrui98    ifuPtrPlus2_write := ifuPtrPlus2 + 1.U
664c9bc5480SLingrui98  }
66509c6f1ddSLingrui98
66609c6f1ddSLingrui98  // only use ftb result to assign hit status
667adc0b8dfSGuokai Chen  when (bpu_s2_resp.valid(3)) {
668adc0b8dfSGuokai Chen    entry_hit_status(bpu_s2_resp.ftq_idx.value) := Mux(bpu_s2_resp.full_pred(3).hit, h_hit, h_not_hit)
66909c6f1ddSLingrui98  }
67009c6f1ddSLingrui98
67109c6f1ddSLingrui98
6722f4a3aa4SLingrui98  io.toIfu.flushFromBpu.s2.valid := bpu_s2_redirect
67309c6f1ddSLingrui98  io.toIfu.flushFromBpu.s2.bits := bpu_s2_resp.ftq_idx
674adc0b8dfSGuokai Chen  when (bpu_s2_redirect) {
67509c6f1ddSLingrui98    bpuPtr := bpu_s2_resp.ftq_idx + 1.U
676dc270d3bSJenius    copied_bpu_ptr.map(_ := bpu_s2_resp.ftq_idx + 1.U)
67709c6f1ddSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
67809c6f1ddSLingrui98    when (!isBefore(ifuPtr, bpu_s2_resp.ftq_idx)) {
679c5c5edaeSJenius      ifuPtr_write := bpu_s2_resp.ftq_idx
680c5c5edaeSJenius      ifuPtrPlus1_write := bpu_s2_resp.ftq_idx + 1.U
6816bf9b30dSLingrui98      ifuPtrPlus2_write := bpu_s2_resp.ftq_idx + 2.U
68209c6f1ddSLingrui98    }
68309c6f1ddSLingrui98  }
68409c6f1ddSLingrui98
685cb4f77ceSLingrui98  io.toIfu.flushFromBpu.s3.valid := bpu_s3_redirect
686cb4f77ceSLingrui98  io.toIfu.flushFromBpu.s3.bits := bpu_s3_resp.ftq_idx
687adc0b8dfSGuokai Chen  when (bpu_s3_redirect) {
688cb4f77ceSLingrui98    bpuPtr := bpu_s3_resp.ftq_idx + 1.U
689dc270d3bSJenius    copied_bpu_ptr.map(_ := bpu_s3_resp.ftq_idx + 1.U)
690cb4f77ceSLingrui98    // only when ifuPtr runs ahead of bpu s2 resp should we recover it
691cb4f77ceSLingrui98    when (!isBefore(ifuPtr, bpu_s3_resp.ftq_idx)) {
692c5c5edaeSJenius      ifuPtr_write := bpu_s3_resp.ftq_idx
693c5c5edaeSJenius      ifuPtrPlus1_write := bpu_s3_resp.ftq_idx + 1.U
6946bf9b30dSLingrui98      ifuPtrPlus2_write := bpu_s3_resp.ftq_idx + 2.U
695cb4f77ceSLingrui98    }
696cb4f77ceSLingrui98  }
697cb4f77ceSLingrui98
69809c6f1ddSLingrui98  XSError(isBefore(bpuPtr, ifuPtr) && !isFull(bpuPtr, ifuPtr), "\nifuPtr is before bpuPtr!\n")
6992448f137SGuokai Chen  XSError(isBefore(ifuWbPtr, commPtr) && !isFull(ifuWbPtr, commPtr), "\ncommPtr is before ifuWbPtr!\n")
70009c6f1ddSLingrui98
701dc270d3bSJenius  (0 until copyNum).map{i =>
702dc270d3bSJenius    XSError(copied_bpu_ptr(i) =/= bpuPtr, "\ncopiedBpuPtr is different from bpuPtr!\n")
703dc270d3bSJenius  }
704dc270d3bSJenius
70509c6f1ddSLingrui98  // ****************************************************************
70609c6f1ddSLingrui98  // **************************** to ifu ****************************
70709c6f1ddSLingrui98  // ****************************************************************
708f22cf846SJenius  // 0  for ifu, and 1-4 for ICache
709935edac4STang Haojin  val bpu_in_bypass_buf = RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)
710935edac4STang Haojin  val copied_bpu_in_bypass_buf = VecInit(Seq.fill(copyNum)(RegEnable(ftq_pc_mem.io.wdata, bpu_in_fire)))
711f56177cbSJenius  val bpu_in_bypass_buf_for_ifu = bpu_in_bypass_buf
71209c6f1ddSLingrui98  val bpu_in_bypass_ptr = RegNext(bpu_in_resp_ptr)
71309c6f1ddSLingrui98  val last_cycle_to_ifu_fire = RegNext(io.toIfu.req.fire)
71409c6f1ddSLingrui98
715f56177cbSJenius  val copied_bpu_in_bypass_ptr = VecInit(Seq.fill(copyNum)(RegNext(bpu_in_resp_ptr)))
716f56177cbSJenius  val copied_last_cycle_to_ifu_fire = VecInit(Seq.fill(copyNum)(RegNext(io.toIfu.req.fire)))
71788bc4f90SLingrui98
71809c6f1ddSLingrui98  // read pc and target
7196bf9b30dSLingrui98  ftq_pc_mem.io.ifuPtr_w       := ifuPtr_write
7206bf9b30dSLingrui98  ftq_pc_mem.io.ifuPtrPlus1_w  := ifuPtrPlus1_write
7216bf9b30dSLingrui98  ftq_pc_mem.io.ifuPtrPlus2_w  := ifuPtrPlus2_write
7226bf9b30dSLingrui98  ftq_pc_mem.io.commPtr_w      := commPtr_write
7236bf9b30dSLingrui98  ftq_pc_mem.io.commPtrPlus1_w := commPtrPlus1_write
724c5c5edaeSJenius
72509c6f1ddSLingrui98
7265ff19bd8SLingrui98  io.toIfu.req.bits.ftqIdx := ifuPtr
727f63797a4SLingrui98
728f56177cbSJenius  val toICachePcBundle = Wire(Vec(copyNum,new Ftq_RF_Components))
729dc270d3bSJenius  val toICacheEntryToSend = Wire(Vec(copyNum,Bool()))
730b37e4b45SLingrui98  val toIfuPcBundle = Wire(new Ftq_RF_Components)
731f63797a4SLingrui98  val entry_is_to_send = WireInit(entry_fetch_status(ifuPtr.value) === f_to_send)
732f63797a4SLingrui98  val entry_ftq_offset = WireInit(cfiIndex_vec(ifuPtr.value))
7336bf9b30dSLingrui98  val entry_next_addr  = Wire(UInt(VAddrBits.W))
734b004fa13SJenius
735f56177cbSJenius  val pc_mem_ifu_ptr_rdata   = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtr_rdata)))
736f56177cbSJenius  val pc_mem_ifu_plus1_rdata = VecInit(Seq.fill(copyNum)(RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)))
737b0ed7239SLingrui98  val diff_entry_next_addr = WireInit(update_target(ifuPtr.value)) //TODO: remove this
738f63797a4SLingrui98
739dc270d3bSJenius  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))))
740dc270d3bSJenius  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)))
741dc270d3bSJenius
742f56177cbSJenius  for(i <- 0 until copyNum){
743f56177cbSJenius    when(copied_last_cycle_bpu_in(i) && copied_bpu_in_bypass_ptr(i) === copied_ifu_ptr(i)){
744f56177cbSJenius      toICachePcBundle(i) := copied_bpu_in_bypass_buf(i)
745dc270d3bSJenius      toICacheEntryToSend(i)   := true.B
746f56177cbSJenius    }.elsewhen(copied_last_cycle_to_ifu_fire(i)){
747f56177cbSJenius      toICachePcBundle(i) := pc_mem_ifu_plus1_rdata(i)
748dc270d3bSJenius      toICacheEntryToSend(i)   := copied_ifu_plus1_to_send(i)
749f56177cbSJenius    }.otherwise{
750f56177cbSJenius      toICachePcBundle(i) := pc_mem_ifu_ptr_rdata(i)
751dc270d3bSJenius      toICacheEntryToSend(i)   := copied_ifu_ptr_to_send(i)
752f56177cbSJenius    }
753f56177cbSJenius  }
754f56177cbSJenius
755873dc383SLingrui98  // TODO: reconsider target address bypass logic
75609c6f1ddSLingrui98  when (last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) {
75788bc4f90SLingrui98    toIfuPcBundle := bpu_in_bypass_buf_for_ifu
758f678dd91SSteve Gou    entry_is_to_send := true.B
7596bf9b30dSLingrui98    entry_next_addr := last_cycle_bpu_target
760f63797a4SLingrui98    entry_ftq_offset := last_cycle_cfiIndex
761b0ed7239SLingrui98    diff_entry_next_addr := last_cycle_bpu_target // TODO: remove this
76209c6f1ddSLingrui98  }.elsewhen (last_cycle_to_ifu_fire) {
763c5c5edaeSJenius    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata)
764c5c5edaeSJenius    entry_is_to_send := RegNext(entry_fetch_status(ifuPtrPlus1.value) === f_to_send) ||
765c5c5edaeSJenius                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1)) // reduce potential bubbles
766ed434d67SLingrui98    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
76788bc4f90SLingrui98                          bpu_in_bypass_buf_for_ifu.startAddr,
768fef810c0SLingrui98                          Mux(ifuPtr === newest_entry_ptr,
7696bf9b30dSLingrui98                            newest_entry_target,
770f83ef67eSLingrui98                            RegNext(ftq_pc_mem.io.ifuPtrPlus2_rdata.startAddr))) // ifuPtr+2
771c5c5edaeSJenius  }.otherwise {
772c5c5edaeSJenius    toIfuPcBundle := RegNext(ftq_pc_mem.io.ifuPtr_rdata)
77328f2cf58SLingrui98    entry_is_to_send := RegNext(entry_fetch_status(ifuPtr.value) === f_to_send) ||
77428f2cf58SLingrui98                        RegNext(last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr) // reduce potential bubbles
7756bf9b30dSLingrui98    entry_next_addr := Mux(last_cycle_bpu_in && bpu_in_bypass_ptr === (ifuPtrPlus1),
77688bc4f90SLingrui98                          bpu_in_bypass_buf_for_ifu.startAddr,
777fef810c0SLingrui98                          Mux(ifuPtr === newest_entry_ptr,
7786bf9b30dSLingrui98                            newest_entry_target,
779f83ef67eSLingrui98                            RegNext(ftq_pc_mem.io.ifuPtrPlus1_rdata.startAddr))) // ifuPtr+1
78009c6f1ddSLingrui98  }
78109c6f1ddSLingrui98
782f678dd91SSteve Gou  io.toIfu.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
783f63797a4SLingrui98  io.toIfu.req.bits.nextStartAddr := entry_next_addr
784f63797a4SLingrui98  io.toIfu.req.bits.ftqOffset := entry_ftq_offset
785b37e4b45SLingrui98  io.toIfu.req.bits.fromFtqPcBundle(toIfuPcBundle)
786c5c5edaeSJenius
787c5c5edaeSJenius  io.toICache.req.valid := entry_is_to_send && ifuPtr =/= bpuPtr
788dc270d3bSJenius  io.toICache.req.bits.readValid.zipWithIndex.map{case(copy, i) => copy := toICacheEntryToSend(i) && copied_ifu_ptr(i) =/= copied_bpu_ptr(i)}
789b004fa13SJenius  io.toICache.req.bits.pcMemRead.zipWithIndex.map{case(copy,i) => copy.fromFtqPcBundle(toICachePcBundle(i))}
790b004fa13SJenius  // io.toICache.req.bits.bypassSelect := last_cycle_bpu_in && bpu_in_bypass_ptr === ifuPtr
791b004fa13SJenius  // io.toICache.req.bits.bpuBypassWrite.zipWithIndex.map{case(bypassWrtie, i) =>
792b004fa13SJenius  //   bypassWrtie.startAddr := bpu_in_bypass_buf.tail(i).startAddr
793b004fa13SJenius  //   bypassWrtie.nextlineStart := bpu_in_bypass_buf.tail(i).nextLineAddr
794b004fa13SJenius  // }
795f22cf846SJenius
796b0ed7239SLingrui98  // TODO: remove this
797b0ed7239SLingrui98  XSError(io.toIfu.req.valid && diff_entry_next_addr =/= entry_next_addr,
7985a674179SLingrui98          p"\nifu_req_target wrong! ifuPtr: ${ifuPtr}, entry_next_addr: ${Hexadecimal(entry_next_addr)} diff_entry_next_addr: ${Hexadecimal(diff_entry_next_addr)}\n")
799b0ed7239SLingrui98
80009c6f1ddSLingrui98  // when fall through is smaller in value than start address, there must be a false hit
801b37e4b45SLingrui98  when (toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit) {
80209c6f1ddSLingrui98    when (io.toIfu.req.fire &&
803cb4f77ceSLingrui98      !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) &&
804cb4f77ceSLingrui98      !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr)
80509c6f1ddSLingrui98    ) {
80609c6f1ddSLingrui98      entry_hit_status(ifuPtr.value) := h_false_hit
807352db50aSLingrui98      // XSError(true.B, "FTB false hit by fallThroughError, startAddr: %x, fallTHru: %x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
80809c6f1ddSLingrui98    }
809b37e4b45SLingrui98    XSDebug(true.B, "fallThruError! start:%x, fallThru:%x\n", io.toIfu.req.bits.startAddr, io.toIfu.req.bits.nextStartAddr)
81009c6f1ddSLingrui98  }
81109c6f1ddSLingrui98
812a60a2901SLingrui98  XSPerfAccumulate(f"fall_through_error_to_ifu", toIfuPcBundle.fallThruError && entry_hit_status(ifuPtr.value) === h_hit &&
813a60a2901SLingrui98    io.toIfu.req.fire && !(bpu_s2_redirect && bpu_s2_resp.ftq_idx === ifuPtr) && !(bpu_s3_redirect && bpu_s3_resp.ftq_idx === ifuPtr))
814a60a2901SLingrui98
81509c6f1ddSLingrui98  val ifu_req_should_be_flushed =
816cb4f77ceSLingrui98    io.toIfu.flushFromBpu.shouldFlushByStage2(io.toIfu.req.bits.ftqIdx) ||
817cb4f77ceSLingrui98    io.toIfu.flushFromBpu.shouldFlushByStage3(io.toIfu.req.bits.ftqIdx)
81809c6f1ddSLingrui98
81909c6f1ddSLingrui98    when (io.toIfu.req.fire && !ifu_req_should_be_flushed) {
82009c6f1ddSLingrui98      entry_fetch_status(ifuPtr.value) := f_sent
82109c6f1ddSLingrui98    }
82209c6f1ddSLingrui98
82309c6f1ddSLingrui98  // *********************************************************************
82409c6f1ddSLingrui98  // **************************** wb from ifu ****************************
82509c6f1ddSLingrui98  // *********************************************************************
82609c6f1ddSLingrui98  val pdWb = io.fromIfu.pdWb
82709c6f1ddSLingrui98  val pds = pdWb.bits.pd
82809c6f1ddSLingrui98  val ifu_wb_valid = pdWb.valid
82909c6f1ddSLingrui98  val ifu_wb_idx = pdWb.bits.ftqIdx.value
83009c6f1ddSLingrui98  // read ports:                                                         commit update
83109c6f1ddSLingrui98  val ftq_pd_mem = Module(new SyncDataModuleTemplate(new Ftq_pd_Entry, FtqSize, 1, 1))
83209c6f1ddSLingrui98  ftq_pd_mem.io.wen(0) := ifu_wb_valid
83309c6f1ddSLingrui98  ftq_pd_mem.io.waddr(0) := pdWb.bits.ftqIdx.value
83409c6f1ddSLingrui98  ftq_pd_mem.io.wdata(0).fromPdWb(pdWb.bits)
83509c6f1ddSLingrui98
83609c6f1ddSLingrui98  val hit_pd_valid = entry_hit_status(ifu_wb_idx) === h_hit && ifu_wb_valid
83709c6f1ddSLingrui98  val hit_pd_mispred = hit_pd_valid && pdWb.bits.misOffset.valid
83809c6f1ddSLingrui98  val hit_pd_mispred_reg = RegNext(hit_pd_mispred, init=false.B)
839005e809bSJiuyang Liu  val pd_reg       = RegEnable(pds,             pdWb.valid)
840005e809bSJiuyang Liu  val start_pc_reg = RegEnable(pdWb.bits.pc(0), pdWb.valid)
841005e809bSJiuyang Liu  val wb_idx_reg   = RegEnable(ifu_wb_idx,      pdWb.valid)
84209c6f1ddSLingrui98
84309c6f1ddSLingrui98  when (ifu_wb_valid) {
84409c6f1ddSLingrui98    val comm_stq_wen = VecInit(pds.map(_.valid).zip(pdWb.bits.instrRange).map{
84509c6f1ddSLingrui98      case (v, inRange) => v && inRange
84609c6f1ddSLingrui98    })
84709c6f1ddSLingrui98    (commitStateQueue(ifu_wb_idx) zip comm_stq_wen).map{
84809c6f1ddSLingrui98      case (qe, v) => when (v) { qe := c_valid }
84909c6f1ddSLingrui98    }
85009c6f1ddSLingrui98  }
85109c6f1ddSLingrui98
852c5c5edaeSJenius  when (ifu_wb_valid) {
853c5c5edaeSJenius    ifuWbPtr_write := ifuWbPtr + 1.U
854c5c5edaeSJenius  }
85509c6f1ddSLingrui98
856f21bbcb2SGuokai Chen  XSError(ifu_wb_valid && isAfter(pdWb.bits.ftqIdx, ifuPtr), "IFU returned a predecode before its req, check IFU")
857f21bbcb2SGuokai Chen
85809c6f1ddSLingrui98  ftb_entry_mem.io.raddr.head := ifu_wb_idx
85909c6f1ddSLingrui98  val has_false_hit = WireInit(false.B)
86009c6f1ddSLingrui98  when (RegNext(hit_pd_valid)) {
86109c6f1ddSLingrui98    // check for false hit
86209c6f1ddSLingrui98    val pred_ftb_entry = ftb_entry_mem.io.rdata.head
863eeb5ff92SLingrui98    val brSlots = pred_ftb_entry.brSlots
864eeb5ff92SLingrui98    val tailSlot = pred_ftb_entry.tailSlot
86509c6f1ddSLingrui98    // we check cfis that bpu predicted
86609c6f1ddSLingrui98
867eeb5ff92SLingrui98    // bpu predicted branches but denied by predecode
868eeb5ff92SLingrui98    val br_false_hit =
869eeb5ff92SLingrui98      brSlots.map{
870eeb5ff92SLingrui98        s => s.valid && !(pd_reg(s.offset).valid && pd_reg(s.offset).isBr)
871eeb5ff92SLingrui98      }.reduce(_||_) ||
872b37e4b45SLingrui98      (tailSlot.valid && pred_ftb_entry.tailSlot.sharing &&
873eeb5ff92SLingrui98        !(pd_reg(tailSlot.offset).valid && pd_reg(tailSlot.offset).isBr))
874eeb5ff92SLingrui98
875eeb5ff92SLingrui98    val jmpOffset = tailSlot.offset
87609c6f1ddSLingrui98    val jmp_pd = pd_reg(jmpOffset)
87709c6f1ddSLingrui98    val jal_false_hit = pred_ftb_entry.jmpValid &&
87809c6f1ddSLingrui98      ((pred_ftb_entry.isJal  && !(jmp_pd.valid && jmp_pd.isJal)) ||
87909c6f1ddSLingrui98       (pred_ftb_entry.isJalr && !(jmp_pd.valid && jmp_pd.isJalr)) ||
88009c6f1ddSLingrui98       (pred_ftb_entry.isCall && !(jmp_pd.valid && jmp_pd.isCall)) ||
88109c6f1ddSLingrui98       (pred_ftb_entry.isRet  && !(jmp_pd.valid && jmp_pd.isRet))
88209c6f1ddSLingrui98      )
88309c6f1ddSLingrui98
88409c6f1ddSLingrui98    has_false_hit := br_false_hit || jal_false_hit || hit_pd_mispred_reg
88565fddcf0Szoujr    XSDebug(has_false_hit, "FTB false hit by br or jal or hit_pd, startAddr: %x\n", pdWb.bits.pc(0))
88665fddcf0Szoujr
887352db50aSLingrui98    // assert(!has_false_hit)
88809c6f1ddSLingrui98  }
88909c6f1ddSLingrui98
89009c6f1ddSLingrui98  when (has_false_hit) {
89109c6f1ddSLingrui98    entry_hit_status(wb_idx_reg) := h_false_hit
89209c6f1ddSLingrui98  }
89309c6f1ddSLingrui98
89409c6f1ddSLingrui98
89509c6f1ddSLingrui98  // **********************************************************************
896b56f947eSYinan Xu  // ***************************** to backend *****************************
89709c6f1ddSLingrui98  // **********************************************************************
898b56f947eSYinan Xu  // to backend pc mem / target
899b56f947eSYinan Xu  io.toBackend.pc_mem_wen   := RegNext(last_cycle_bpu_in)
900b56f947eSYinan Xu  io.toBackend.pc_mem_waddr := RegNext(last_cycle_bpu_in_idx)
90188bc4f90SLingrui98  io.toBackend.pc_mem_wdata := RegNext(bpu_in_bypass_buf_for_ifu)
90209c6f1ddSLingrui98
90309c6f1ddSLingrui98  // *******************************************************************************
90409c6f1ddSLingrui98  // **************************** redirect from backend ****************************
90509c6f1ddSLingrui98  // *******************************************************************************
90609c6f1ddSLingrui98
90709c6f1ddSLingrui98  // redirect read cfiInfo, couples to redirectGen s2
908*bace178aSGao-Zeyu  val redirectReadStart = 1 // 0 for ifuRedirect
909*bace178aSGao-Zeyu  val ftq_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new Ftq_Redirect_SRAMEntry))
910*bace178aSGao-Zeyu  val ftb_redirect_rdata = Wire(Vec(FtqRedirectAheadNum, new FTBEntry))
911*bace178aSGao-Zeyu  for (i <- redirectReadStart until FtqRedirectAheadNum) {
912*bace178aSGao-Zeyu    ftq_redirect_sram.io.ren(i + redirectReadStart)   := ftqIdxAhead(i).valid
913*bace178aSGao-Zeyu    ftq_redirect_sram.io.raddr(i + redirectReadStart) := ftqIdxAhead(i).bits.value
914*bace178aSGao-Zeyu    ftb_entry_mem.io.raddr(i + redirectReadStart)     := ftqIdxAhead(i).bits.value
9159342624fSGao-Zeyu  }
916*bace178aSGao-Zeyu  ftq_redirect_sram.io.ren(redirectReadStart)   := Mux(aheadValid, ftqIdxAhead(0).valid,      backendRedirect.valid)
917*bace178aSGao-Zeyu  ftq_redirect_sram.io.raddr(redirectReadStart) := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
918*bace178aSGao-Zeyu  ftb_entry_mem.io.raddr(redirectReadStart)     := Mux(aheadValid, ftqIdxAhead(0).bits.value, backendRedirect.bits.ftqIdx.value)
919*bace178aSGao-Zeyu
920*bace178aSGao-Zeyu  for (i <- 0 until FtqRedirectAheadNum) {
921*bace178aSGao-Zeyu    ftq_redirect_rdata(i) := ftq_redirect_sram.io.rdata(i + redirectReadStart)
922*bace178aSGao-Zeyu    ftb_redirect_rdata(i) := ftb_entry_mem.io.rdata(i + redirectReadStart)
923*bace178aSGao-Zeyu  }
924*bace178aSGao-Zeyu  val stage3CfiInfo = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftq_redirect_rdata), ftq_redirect_sram.io.rdata(redirectReadStart))
92509c6f1ddSLingrui98  val backendRedirectCfi = fromBackendRedirect.bits.cfiUpdate
92609c6f1ddSLingrui98  backendRedirectCfi.fromFtqRedirectSram(stage3CfiInfo)
92709c6f1ddSLingrui98
928d2b20d1aSTang Haojin
929*bace178aSGao-Zeyu  val r_ftb_entry = Mux(realAhdValid, Mux1H(ftqIdxSelOH, ftb_redirect_rdata), ftb_entry_mem.io.rdata(redirectReadStart))
93009c6f1ddSLingrui98  val r_ftqOffset = fromBackendRedirect.bits.ftqOffset
93109c6f1ddSLingrui98
932d2b20d1aSTang Haojin  backendRedirectCfi.br_hit := r_ftb_entry.brIsSaved(r_ftqOffset)
933d2b20d1aSTang Haojin  backendRedirectCfi.jr_hit := r_ftb_entry.isJalr && r_ftb_entry.tailSlot.offset === r_ftqOffset
9343711cf36S小造xu_zh  // FIXME: not portable
935abdc3a32Sxu_zh  val sc_disagree = stage3CfiInfo.sc_disagree.getOrElse(VecInit(Seq.fill(numBr)(false.B)))
936d2b20d1aSTang Haojin  backendRedirectCfi.sc_hit := backendRedirectCfi.br_hit && Mux(r_ftb_entry.brSlots(0).offset === r_ftqOffset,
937abdc3a32Sxu_zh    sc_disagree(0), sc_disagree(1))
938d2b20d1aSTang Haojin
93909c6f1ddSLingrui98  when (entry_hit_status(fromBackendRedirect.bits.ftqIdx.value) === h_hit) {
94009c6f1ddSLingrui98    backendRedirectCfi.shift := PopCount(r_ftb_entry.getBrMaskByOffset(r_ftqOffset)) +&
94109c6f1ddSLingrui98      (backendRedirectCfi.pd.isBr && !r_ftb_entry.brIsSaved(r_ftqOffset) &&
942eeb5ff92SLingrui98      !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
94309c6f1ddSLingrui98
94409c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr && (r_ftb_entry.brIsSaved(r_ftqOffset) ||
945eeb5ff92SLingrui98        !r_ftb_entry.newBrCanNotInsert(r_ftqOffset))
94609c6f1ddSLingrui98  }.otherwise {
94709c6f1ddSLingrui98    backendRedirectCfi.shift := (backendRedirectCfi.pd.isBr && backendRedirectCfi.taken).asUInt
94809c6f1ddSLingrui98    backendRedirectCfi.addIntoHist := backendRedirectCfi.pd.isBr.asUInt
94909c6f1ddSLingrui98  }
95009c6f1ddSLingrui98
95109c6f1ddSLingrui98
95209c6f1ddSLingrui98  // ***************************************************************************
95309c6f1ddSLingrui98  // **************************** redirect from ifu ****************************
95409c6f1ddSLingrui98  // ***************************************************************************
955d2b20d1aSTang Haojin  val fromIfuRedirect = WireInit(0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
95609c6f1ddSLingrui98  fromIfuRedirect.valid := pdWb.valid && pdWb.bits.misOffset.valid && !backendFlush
95709c6f1ddSLingrui98  fromIfuRedirect.bits.ftqIdx := pdWb.bits.ftqIdx
95809c6f1ddSLingrui98  fromIfuRedirect.bits.ftqOffset := pdWb.bits.misOffset.bits
95909c6f1ddSLingrui98  fromIfuRedirect.bits.level := RedirectLevel.flushAfter
960d2b20d1aSTang Haojin  fromIfuRedirect.bits.BTBMissBubble := true.B
961d2b20d1aSTang Haojin  fromIfuRedirect.bits.debugIsMemVio := false.B
962d2b20d1aSTang Haojin  fromIfuRedirect.bits.debugIsCtrl := false.B
96309c6f1ddSLingrui98
96409c6f1ddSLingrui98  val ifuRedirectCfiUpdate = fromIfuRedirect.bits.cfiUpdate
96509c6f1ddSLingrui98  ifuRedirectCfiUpdate.pc := pdWb.bits.pc(pdWb.bits.misOffset.bits)
96609c6f1ddSLingrui98  ifuRedirectCfiUpdate.pd := pdWb.bits.pd(pdWb.bits.misOffset.bits)
96709c6f1ddSLingrui98  ifuRedirectCfiUpdate.predTaken := cfiIndex_vec(pdWb.bits.ftqIdx.value).valid
96809c6f1ddSLingrui98  ifuRedirectCfiUpdate.target := pdWb.bits.target
96909c6f1ddSLingrui98  ifuRedirectCfiUpdate.taken := pdWb.bits.cfiOffset.valid
97009c6f1ddSLingrui98  ifuRedirectCfiUpdate.isMisPred := pdWb.bits.misOffset.valid
97109c6f1ddSLingrui98
972d2b20d1aSTang Haojin  val ifuRedirectReg = RegNext(fromIfuRedirect, init=0.U.asTypeOf(Valid(new BranchPredictionRedirect)))
97309c6f1ddSLingrui98  val ifuRedirectToBpu = WireInit(ifuRedirectReg)
97409c6f1ddSLingrui98  ifuFlush := fromIfuRedirect.valid || ifuRedirectToBpu.valid
97509c6f1ddSLingrui98
97609c6f1ddSLingrui98  ftq_redirect_sram.io.ren.head := fromIfuRedirect.valid
97709c6f1ddSLingrui98  ftq_redirect_sram.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
97809c6f1ddSLingrui98
97909c6f1ddSLingrui98  ftb_entry_mem.io.raddr.head := fromIfuRedirect.bits.ftqIdx.value
98009c6f1ddSLingrui98
98109c6f1ddSLingrui98  val toBpuCfi = ifuRedirectToBpu.bits.cfiUpdate
98209c6f1ddSLingrui98  toBpuCfi.fromFtqRedirectSram(ftq_redirect_sram.io.rdata.head)
983f1267a13SEaston Man  when (ifuRedirectReg.bits.cfiUpdate.pd.isRet && ifuRedirectReg.bits.cfiUpdate.pd.valid) {
984c89b4642SGuokai Chen    toBpuCfi.target := toBpuCfi.topAddr
98509c6f1ddSLingrui98  }
98609c6f1ddSLingrui98
987d2b20d1aSTang Haojin  when (ifuRedirectReg.valid) {
988d2b20d1aSTang Haojin    ifuRedirected(ifuRedirectReg.bits.ftqIdx.value) := true.B
989d2b20d1aSTang Haojin  } .elsewhen(RegNext(pdWb.valid)) {
990d2b20d1aSTang Haojin    // if pdWb and no redirect, set to false
991d2b20d1aSTang Haojin    ifuRedirected(last_cycle_bpu_in_ptr.value) := false.B
992d2b20d1aSTang Haojin  }
993d2b20d1aSTang Haojin
99409c6f1ddSLingrui98  // *********************************************************************
99509c6f1ddSLingrui98  // **************************** wb from exu ****************************
99609c6f1ddSLingrui98  // *********************************************************************
99709c6f1ddSLingrui98
998d2b20d1aSTang Haojin  backendRedirect.valid := io.fromBackend.redirect.valid
999d2b20d1aSTang Haojin  backendRedirect.bits.connectRedirect(io.fromBackend.redirect.bits)
1000d2b20d1aSTang Haojin  backendRedirect.bits.BTBMissBubble := false.B
1001d2b20d1aSTang Haojin
10022e1be6e1SSteve Gou
100309c6f1ddSLingrui98  def extractRedirectInfo(wb: Valid[Redirect]) = {
10046bf9b30dSLingrui98    val ftqPtr = wb.bits.ftqIdx
100509c6f1ddSLingrui98    val ftqOffset = wb.bits.ftqOffset
100609c6f1ddSLingrui98    val taken = wb.bits.cfiUpdate.taken
100709c6f1ddSLingrui98    val mispred = wb.bits.cfiUpdate.isMisPred
10086bf9b30dSLingrui98    (wb.valid, ftqPtr, ftqOffset, taken, mispred)
100909c6f1ddSLingrui98  }
101009c6f1ddSLingrui98
101109c6f1ddSLingrui98  // fix mispredict entry
101209c6f1ddSLingrui98  val lastIsMispredict = RegNext(
1013df5b4b8eSYinan Xu    backendRedirect.valid && backendRedirect.bits.level === RedirectLevel.flushAfter, init = false.B
101409c6f1ddSLingrui98  )
101509c6f1ddSLingrui98
101609c6f1ddSLingrui98  def updateCfiInfo(redirect: Valid[Redirect], isBackend: Boolean = true) = {
10176bf9b30dSLingrui98    val (r_valid, r_ptr, r_offset, r_taken, r_mispred) = extractRedirectInfo(redirect)
10186bf9b30dSLingrui98    val r_idx = r_ptr.value
101909c6f1ddSLingrui98    val cfiIndex_bits_wen = r_valid && r_taken && r_offset < cfiIndex_vec(r_idx).bits
102009c6f1ddSLingrui98    val cfiIndex_valid_wen = r_valid && r_offset === cfiIndex_vec(r_idx).bits
102109c6f1ddSLingrui98    when (cfiIndex_bits_wen || cfiIndex_valid_wen) {
102209c6f1ddSLingrui98      cfiIndex_vec(r_idx).valid := cfiIndex_bits_wen || cfiIndex_valid_wen && r_taken
10233f88c020SGuokai Chen    } .elsewhen (r_valid && !r_taken && r_offset =/= cfiIndex_vec(r_idx).bits) {
10243f88c020SGuokai Chen      cfiIndex_vec(r_idx).valid :=false.B
102509c6f1ddSLingrui98    }
102609c6f1ddSLingrui98    when (cfiIndex_bits_wen) {
102709c6f1ddSLingrui98      cfiIndex_vec(r_idx).bits := r_offset
102809c6f1ddSLingrui98    }
10296bf9b30dSLingrui98    newest_entry_target := redirect.bits.cfiUpdate.target
1030873dc383SLingrui98    newest_entry_ptr := r_ptr
1031b0ed7239SLingrui98    update_target(r_idx) := redirect.bits.cfiUpdate.target // TODO: remove this
103209c6f1ddSLingrui98    if (isBackend) {
103309c6f1ddSLingrui98      mispredict_vec(r_idx)(r_offset) := r_mispred
103409c6f1ddSLingrui98    }
103509c6f1ddSLingrui98  }
103609c6f1ddSLingrui98
1037*bace178aSGao-Zeyu  when(fromBackendRedirect.valid) {
1038*bace178aSGao-Zeyu    updateCfiInfo(fromBackendRedirect)
103909c6f1ddSLingrui98  }.elsewhen (ifuRedirectToBpu.valid) {
104009c6f1ddSLingrui98    updateCfiInfo(ifuRedirectToBpu, isBackend=false)
104109c6f1ddSLingrui98  }
104209c6f1ddSLingrui98
1043*bace178aSGao-Zeyu  when (fromBackendRedirect.valid) {
1044*bace178aSGao-Zeyu    when (fromBackendRedirect.bits.ControlRedirectBubble) {
1045d2b20d1aSTang Haojin      when (fromBackendRedirect.bits.ControlBTBMissBubble) {
1046d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1047d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1048d2b20d1aSTang Haojin      } .elsewhen (fromBackendRedirect.bits.TAGEMissBubble) {
1049d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
1050d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.TAGEMissBubble.id) := true.B
1051d2b20d1aSTang Haojin      } .elsewhen (fromBackendRedirect.bits.SCMissBubble) {
1052d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.SCMissBubble.id) := true.B
1053d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.SCMissBubble.id) := true.B
1054d2b20d1aSTang Haojin      } .elsewhen (fromBackendRedirect.bits.ITTAGEMissBubble) {
1055d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
1056d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.ITTAGEMissBubble.id) := true.B
1057d2b20d1aSTang Haojin      } .elsewhen (fromBackendRedirect.bits.RASMissBubble) {
1058d2b20d1aSTang Haojin        topdown_stage.reasons(TopDownCounters.RASMissBubble.id) := true.B
1059d2b20d1aSTang Haojin        io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.RASMissBubble.id) := true.B
1060d2b20d1aSTang Haojin      }
1061d2b20d1aSTang Haojin
1062d2b20d1aSTang Haojin
10639342624fSGao-Zeyu    } .elsewhen (backendRedirect.bits.MemVioRedirectBubble) {
1064d2b20d1aSTang Haojin      topdown_stage.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
1065d2b20d1aSTang Haojin      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.MemVioRedirectBubble.id) := true.B
1066d2b20d1aSTang Haojin    } .otherwise {
1067d2b20d1aSTang Haojin      topdown_stage.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
1068d2b20d1aSTang Haojin      io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.OtherRedirectBubble.id) := true.B
1069d2b20d1aSTang Haojin    }
1070d2b20d1aSTang Haojin  } .elsewhen (ifuRedirectReg.valid) {
1071d2b20d1aSTang Haojin    topdown_stage.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1072d2b20d1aSTang Haojin    io.toIfu.req.bits.topdown_info.reasons(TopDownCounters.BTBMissBubble.id) := true.B
1073d2b20d1aSTang Haojin  }
1074d2b20d1aSTang Haojin
1075d2b20d1aSTang Haojin  io.ControlBTBMissBubble := fromBackendRedirect.bits.ControlBTBMissBubble
1076d2b20d1aSTang Haojin  io.TAGEMissBubble := fromBackendRedirect.bits.TAGEMissBubble
1077d2b20d1aSTang Haojin  io.SCMissBubble := fromBackendRedirect.bits.SCMissBubble
1078d2b20d1aSTang Haojin  io.ITTAGEMissBubble := fromBackendRedirect.bits.ITTAGEMissBubble
1079d2b20d1aSTang Haojin  io.RASMissBubble := fromBackendRedirect.bits.RASMissBubble
1080d2b20d1aSTang Haojin
108109c6f1ddSLingrui98  // ***********************************************************************************
108209c6f1ddSLingrui98  // **************************** flush ptr and state queue ****************************
108309c6f1ddSLingrui98  // ***********************************************************************************
108409c6f1ddSLingrui98
1085df5b4b8eSYinan Xu  val redirectVec = VecInit(backendRedirect, fromIfuRedirect)
108609c6f1ddSLingrui98
108709c6f1ddSLingrui98  // when redirect, we should reset ptrs and status queues
108809c6f1ddSLingrui98  when(redirectVec.map(r => r.valid).reduce(_||_)){
10892f4a3aa4SLingrui98    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
109009c6f1ddSLingrui98    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
10912f4a3aa4SLingrui98    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
109209c6f1ddSLingrui98    val next = idx + 1.U
109309c6f1ddSLingrui98    bpuPtr := next
1094dc270d3bSJenius    copied_bpu_ptr.map(_ := next)
1095c5c5edaeSJenius    ifuPtr_write := next
1096c5c5edaeSJenius    ifuWbPtr_write := next
1097c5c5edaeSJenius    ifuPtrPlus1_write := idx + 2.U
10986bf9b30dSLingrui98    ifuPtrPlus2_write := idx + 3.U
10993f88c020SGuokai Chen
11003f88c020SGuokai Chen  }
11013f88c020SGuokai Chen  when(RegNext(redirectVec.map(r => r.valid).reduce(_||_))){
11023f88c020SGuokai Chen    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
11033f88c020SGuokai Chen    val notIfu = redirectVec.dropRight(1).map(r => r.valid).reduce(_||_)
11043f88c020SGuokai Chen    val (idx, offset, flushItSelf) = (r.ftqIdx, r.ftqOffset, RedirectLevel.flushItself(r.level))
11053f88c020SGuokai Chen    when (RegNext(notIfu)) {
11063f88c020SGuokai Chen      commitStateQueue(RegNext(idx.value)).zipWithIndex.foreach({ case (s, i) =>
11073f88c020SGuokai Chen        when(i.U > RegNext(offset) || i.U === RegNext(offset) && RegNext(flushItSelf)){
1108b5808fc2Ssfencevma          s := c_invalid
110909c6f1ddSLingrui98        }
111009c6f1ddSLingrui98      })
111109c6f1ddSLingrui98    }
111209c6f1ddSLingrui98  }
111309c6f1ddSLingrui98
11143f88c020SGuokai Chen
111509c6f1ddSLingrui98  // only the valid bit is actually needed
1116df5b4b8eSYinan Xu  io.toIfu.redirect.bits    := backendRedirect.bits
111709c6f1ddSLingrui98  io.toIfu.redirect.valid   := stage2Flush
1118d2b20d1aSTang Haojin  io.toIfu.topdown_redirect := fromBackendRedirect
111909c6f1ddSLingrui98
112009c6f1ddSLingrui98  // commit
11219aca92b9SYinan Xu  for (c <- io.fromBackend.rob_commits) {
112209c6f1ddSLingrui98    when(c.valid) {
112309c6f1ddSLingrui98      commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset) := c_commited
112488825c5cSYinan Xu      // TODO: remove this
112588825c5cSYinan Xu      // For instruction fusions, we also update the next instruction
1126c3abb8b6SYinan Xu      when (c.bits.commitType === 4.U) {
112788825c5cSYinan Xu        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 1.U) := c_commited
1128c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 5.U) {
112988825c5cSYinan Xu        commitStateQueue(c.bits.ftqIdx.value)(c.bits.ftqOffset + 2.U) := c_commited
1130c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 6.U) {
113188825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
113288825c5cSYinan Xu        commitStateQueue(index)(0) := c_commited
1133c3abb8b6SYinan Xu      }.elsewhen(c.bits.commitType === 7.U) {
113488825c5cSYinan Xu        val index = (c.bits.ftqIdx + 1.U).value
113588825c5cSYinan Xu        commitStateQueue(index)(1) := c_commited
113688825c5cSYinan Xu      }
113709c6f1ddSLingrui98    }
113809c6f1ddSLingrui98  }
113909c6f1ddSLingrui98
114009c6f1ddSLingrui98  // ****************************************************************
114109c6f1ddSLingrui98  // **************************** to bpu ****************************
114209c6f1ddSLingrui98  // ****************************************************************
114309c6f1ddSLingrui98
114451981c77SbugGenerator  io.toBpu.redirect := Mux(fromBackendRedirect.valid, fromBackendRedirect, ifuRedirectToBpu)
1145209a4cafSSteve Gou  val dummy_s1_pred_cycle_vec = VecInit(List.tabulate(FtqSize)(_=>0.U(64.W)))
1146209a4cafSSteve Gou  val redirect_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(io.toBpu.redirect.bits.ftqIdx.value) + 1.U
1147209a4cafSSteve Gou  XSPerfHistogram("backend_redirect_latency", redirect_latency, fromBackendRedirect.valid, 0, 60, 1)
1148209a4cafSSteve Gou  XSPerfHistogram("ifu_redirect_latency", redirect_latency, !fromBackendRedirect.valid && ifuRedirectToBpu.valid, 0, 60, 1)
114909c6f1ddSLingrui98
1150f21bbcb2SGuokai Chen  XSError(io.toBpu.redirect.valid && isBefore(io.toBpu.redirect.bits.ftqIdx, commPtr), "Ftq received a redirect after its commit, check backend or replay")
1151f21bbcb2SGuokai Chen
115202f21c16SLingrui98  val may_have_stall_from_bpu = Wire(Bool())
115302f21c16SLingrui98  val bpu_ftb_update_stall = RegInit(0.U(2.W)) // 2-cycle stall, so we need 3 states
115402f21c16SLingrui98  may_have_stall_from_bpu := bpu_ftb_update_stall =/= 0.U
115543aca6c2SGuokai Chen  canCommit := commPtr =/= ifuWbPtr && !may_have_stall_from_bpu &&
115609c6f1ddSLingrui98    Cat(commitStateQueue(commPtr.value).map(s => {
1157b5808fc2Ssfencevma      s === c_invalid || s === c_commited
1158935edac4STang Haojin    })).andR
115909c6f1ddSLingrui98
11601d1e6d4dSJenius  val mmioReadPtr = io.mmioCommitRead.mmioFtqPtr
11611d1e6d4dSJenius  val mmioLastCommit = isBefore(commPtr, mmioReadPtr) && (isAfter(ifuPtr,mmioReadPtr)  ||  mmioReadPtr ===   ifuPtr) &&
1162935edac4STang Haojin                       Cat(commitStateQueue(mmioReadPtr.value).map(s => { s === c_invalid || s === c_commited})).andR
11631d1e6d4dSJenius  io.mmioCommitRead.mmioLastCommit := RegNext(mmioLastCommit)
11641d1e6d4dSJenius
116509c6f1ddSLingrui98  // commit reads
1166c5c5edaeSJenius  val commit_pc_bundle = RegNext(ftq_pc_mem.io.commPtr_rdata)
116781101dc4SLingrui98  val commit_target =
116834cf890eSLingrui98    Mux(RegNext(commPtr === newest_entry_ptr),
116934cf890eSLingrui98      RegNext(newest_entry_target),
117081101dc4SLingrui98      RegNext(ftq_pc_mem.io.commPtrPlus1_rdata.startAddr))
117109c6f1ddSLingrui98  ftq_pd_mem.io.raddr.last := commPtr.value
117209c6f1ddSLingrui98  val commit_pd = ftq_pd_mem.io.rdata.last
117309c6f1ddSLingrui98  ftq_redirect_sram.io.ren.last := canCommit
117409c6f1ddSLingrui98  ftq_redirect_sram.io.raddr.last := commPtr.value
117509c6f1ddSLingrui98  val commit_spec_meta = ftq_redirect_sram.io.rdata.last
117609c6f1ddSLingrui98  ftq_meta_1r_sram.io.ren(0) := canCommit
117709c6f1ddSLingrui98  ftq_meta_1r_sram.io.raddr(0) := commPtr.value
117809c6f1ddSLingrui98  val commit_meta = ftq_meta_1r_sram.io.rdata(0)
117909c6f1ddSLingrui98  ftb_entry_mem.io.raddr.last := commPtr.value
118009c6f1ddSLingrui98  val commit_ftb_entry = ftb_entry_mem.io.rdata.last
118109c6f1ddSLingrui98
118209c6f1ddSLingrui98  // need one cycle to read mem and srams
118309c6f1ddSLingrui98  val do_commit_ptr = RegNext(commPtr)
11845371700eSzoujr  val do_commit = RegNext(canCommit, init=false.B)
11856bf9b30dSLingrui98  when (canCommit) {
11866bf9b30dSLingrui98    commPtr_write := commPtrPlus1
11876bf9b30dSLingrui98    commPtrPlus1_write := commPtrPlus1 + 1.U
11886bf9b30dSLingrui98  }
118909c6f1ddSLingrui98  val commit_state = RegNext(commitStateQueue(commPtr.value))
11905371700eSzoujr  val can_commit_cfi = WireInit(cfiIndex_vec(commPtr.value))
1191d4fcfc3eSGuokai Chen  val do_commit_cfi = WireInit(cfiIndex_vec(do_commit_ptr.value))
11923f88c020SGuokai Chen  //
11933f88c020SGuokai Chen  //when (commitStateQueue(commPtr.value)(can_commit_cfi.bits) =/= c_commited) {
11943f88c020SGuokai Chen  //  can_commit_cfi.valid := false.B
11953f88c020SGuokai Chen  //}
11965371700eSzoujr  val commit_cfi = RegNext(can_commit_cfi)
1197d4fcfc3eSGuokai Chen  val debug_cfi = commitStateQueue(do_commit_ptr.value)(do_commit_cfi.bits) =/= c_commited && do_commit_cfi.valid
119809c6f1ddSLingrui98
1199cc2d1573SEaston Man  val commit_mispredict  : Vec[Bool] = VecInit((RegNext(mispredict_vec(commPtr.value)) zip commit_state).map {
120009c6f1ddSLingrui98    case (mis, state) => mis && state === c_commited
120109c6f1ddSLingrui98  })
1202cc2d1573SEaston Man  val commit_instCommited: Vec[Bool] = VecInit(commit_state.map(_ === c_commited)) // [PredictWidth]
12035371700eSzoujr  val can_commit_hit                 = entry_hit_status(commPtr.value)
12045371700eSzoujr  val commit_hit                     = RegNext(can_commit_hit)
12055fa3df0dSLingrui98  val diff_commit_target             = RegNext(update_target(commPtr.value)) // TODO: remove this
1206edc18578SLingrui98  val commit_stage                   = RegNext(pred_stage(commPtr.value))
120709c6f1ddSLingrui98  val commit_valid                   = commit_hit === h_hit || commit_cfi.valid // hit or taken
120809c6f1ddSLingrui98
12095371700eSzoujr  val to_bpu_hit = can_commit_hit === h_hit || can_commit_hit === h_false_hit
121002f21c16SLingrui98  switch (bpu_ftb_update_stall) {
121102f21c16SLingrui98    is (0.U) {
121202f21c16SLingrui98      when (can_commit_cfi.valid && !to_bpu_hit && canCommit) {
121302f21c16SLingrui98        bpu_ftb_update_stall := 2.U // 2-cycle stall
121402f21c16SLingrui98      }
121502f21c16SLingrui98    }
121602f21c16SLingrui98    is (2.U) {
121702f21c16SLingrui98      bpu_ftb_update_stall := 1.U
121802f21c16SLingrui98    }
121902f21c16SLingrui98    is (1.U) {
122002f21c16SLingrui98      bpu_ftb_update_stall := 0.U
122102f21c16SLingrui98    }
122202f21c16SLingrui98    is (3.U) {
122302f21c16SLingrui98      XSError(true.B, "bpu_ftb_update_stall should be 0, 1 or 2")
122402f21c16SLingrui98    }
122502f21c16SLingrui98  }
122609c6f1ddSLingrui98
1227b0ed7239SLingrui98  // TODO: remove this
1228b0ed7239SLingrui98  XSError(do_commit && diff_commit_target =/= commit_target, "\ncommit target should be the same as update target\n")
1229b0ed7239SLingrui98
1230b2f6ed0aSSteve Gou  // update latency stats
1231b2f6ed0aSSteve Gou  val update_latency = GTimer() - pred_s1_cycle.getOrElse(dummy_s1_pred_cycle_vec)(do_commit_ptr.value) + 1.U
1232b2f6ed0aSSteve Gou  XSPerfHistogram("bpu_update_latency", update_latency, io.toBpu.update.valid, 0, 64, 2)
1233b2f6ed0aSSteve Gou
123409c6f1ddSLingrui98  io.toBpu.update := DontCare
123509c6f1ddSLingrui98  io.toBpu.update.valid := commit_valid && do_commit
123609c6f1ddSLingrui98  val update = io.toBpu.update.bits
123709c6f1ddSLingrui98  update.false_hit   := commit_hit === h_false_hit
123809c6f1ddSLingrui98  update.pc          := commit_pc_bundle.startAddr
123909c6f1ddSLingrui98  update.meta        := commit_meta.meta
1240803124a6SLingrui98  update.cfi_idx     := commit_cfi
12418ffcd86aSLingrui98  update.full_target := commit_target
1242edc18578SLingrui98  update.from_stage  := commit_stage
1243c2d1ec7dSLingrui98  update.spec_info   := commit_spec_meta
12443f88c020SGuokai Chen  XSError(commit_valid && do_commit && debug_cfi, "\ncommit cfi can be non c_commited\n")
124509c6f1ddSLingrui98
124609c6f1ddSLingrui98  val commit_real_hit = commit_hit === h_hit
124709c6f1ddSLingrui98  val update_ftb_entry = update.ftb_entry
124809c6f1ddSLingrui98
124909c6f1ddSLingrui98  val ftbEntryGen = Module(new FTBEntryGen).io
125009c6f1ddSLingrui98  ftbEntryGen.start_addr     := commit_pc_bundle.startAddr
125109c6f1ddSLingrui98  ftbEntryGen.old_entry      := commit_ftb_entry
125209c6f1ddSLingrui98  ftbEntryGen.pd             := commit_pd
125309c6f1ddSLingrui98  ftbEntryGen.cfiIndex       := commit_cfi
125409c6f1ddSLingrui98  ftbEntryGen.target         := commit_target
125509c6f1ddSLingrui98  ftbEntryGen.hit            := commit_real_hit
125609c6f1ddSLingrui98  ftbEntryGen.mispredict_vec := commit_mispredict
125709c6f1ddSLingrui98
125809c6f1ddSLingrui98  update_ftb_entry         := ftbEntryGen.new_entry
125909c6f1ddSLingrui98  update.new_br_insert_pos := ftbEntryGen.new_br_insert_pos
126009c6f1ddSLingrui98  update.mispred_mask      := ftbEntryGen.mispred_mask
126109c6f1ddSLingrui98  update.old_entry         := ftbEntryGen.is_old_entry
1262edc18578SLingrui98  update.pred_hit          := commit_hit === h_hit || commit_hit === h_false_hit
1263803124a6SLingrui98  update.br_taken_mask     := ftbEntryGen.taken_mask
1264cc2d1573SEaston Man  update.br_committed      := (ftbEntryGen.new_entry.brValids zip ftbEntryGen.new_entry.brOffset) map {
1265cc2d1573SEaston Man    case (valid, offset) => valid && commit_instCommited(offset)
1266cc2d1573SEaston Man  }
1267803124a6SLingrui98  update.jmp_taken         := ftbEntryGen.jmp_taken
1268b37e4b45SLingrui98
1269803124a6SLingrui98  // update.full_pred.fromFtbEntry(ftbEntryGen.new_entry, update.pc)
1270803124a6SLingrui98  // update.full_pred.jalr_target := commit_target
1271803124a6SLingrui98  // update.full_pred.hit := true.B
1272803124a6SLingrui98  // when (update.full_pred.is_jalr) {
1273803124a6SLingrui98  //   update.full_pred.targets.last := commit_target
1274803124a6SLingrui98  // }
127509c6f1ddSLingrui98
1276e30430c2SJay  // ****************************************************************
1277e30430c2SJay  // *********************** to prefetch ****************************
1278e30430c2SJay  // ****************************************************************
1279f9c51548Sssszwic  /**
1280f9c51548Sssszwic    ******************************************************************************
1281f9c51548Sssszwic    * prefetchPtr control
1282f9c51548Sssszwic    * - 1. prefetchPtr plus 1 when toPrefetch fire and keep distance from bpuPtr more than 2
1283f9c51548Sssszwic    * - 2. limit range of prefetchPtr is in [ifuPtr + minRange, ifuPtr + maxRange]
1284f9c51548Sssszwic    * - 3. flush prefetchPtr when receive redirect from ifu or backend
1285f9c51548Sssszwic    ******************************************************************************
1286f9c51548Sssszwic    */
1287e30430c2SJay  val prefetchPtr = RegInit(FtqPtr(false.B, 0.U))
1288f9c51548Sssszwic  val nextPrefetchPtr = WireInit(prefetchPtr)
1289e30430c2SJay
1290f9c51548Sssszwic  prefetchPtr := nextPrefetchPtr
1291f9c51548Sssszwic
1292f9c51548Sssszwic  // TODO: consider req which cross cacheline
1293f9c51548Sssszwic  when(io.toPrefetch.req.fire) {
1294f9c51548Sssszwic    when(prefetchPtr < bpuPtr - 2.U) {
1295f9c51548Sssszwic      nextPrefetchPtr := prefetchPtr + 1.U
1296a677d2cbSguohongyu    }
1297a677d2cbSguohongyu  }
1298a677d2cbSguohongyu
1299f9c51548Sssszwic  when(prefetchPtr < ifuPtr + minRangeFromIFUptr.U) {
1300f9c51548Sssszwic    nextPrefetchPtr := ifuPtr + minRangeFromIFUptr.U
1301f9c51548Sssszwic  }.elsewhen(prefetchPtr > ifuPtr + maxRangeFromIFUptr.U) {
1302f9c51548Sssszwic    nextPrefetchPtr := ifuPtr + maxRangeFromIFUptr.U
1303e30430c2SJay  }
1304e30430c2SJay
1305de7689fcSJay  when(redirectVec.map(r => r.valid).reduce(_||_)){
1306de7689fcSJay    val r = PriorityMux(redirectVec.map(r => (r.valid -> r.bits)))
1307f9c51548Sssszwic    val next = r.ftqIdx + minRangeFromIFUptr.U
1308f9c51548Sssszwic    nextPrefetchPtr := next
1309de7689fcSJay  }
1310de7689fcSJay
1311f9c51548Sssszwic  // data from ftq_pc_mem has 1 cycle delay
1312f9c51548Sssszwic  io.toPrefetch.req.valid := RegNext(entry_fetch_status(nextPrefetchPtr.value) === f_to_send)
1313f9c51548Sssszwic  ftq_pc_mem.io.other_raddrs(0) := nextPrefetchPtr.value
1314f9c51548Sssszwic  io.toPrefetch.req.bits.target := RegNext(ftq_pc_mem.io.other_rdatas(0).startAddr)
1315378f00d9SJenius
1316f9c51548Sssszwic  // record position relationship between ifuPtr, pfPtr and bpuPtr
1317f9c51548Sssszwic  val isWritePrefetchPtrTable = WireInit(Constantin.createRecord("isWritePrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString))
1318f9c51548Sssszwic  val prefetchPtrTable = ChiselDB.createTable("PrefetchPtrTable" + p(XSCoreParamsKey).HartId.toString, new PrefetchPtrDB)
1319f9c51548Sssszwic  val prefetchPtrDumpData = Wire(new PrefetchPtrDB)
1320f9c51548Sssszwic  prefetchPtrDumpData.fromFtqPtr  := distanceBetween(bpuPtr, prefetchPtr)
1321f9c51548Sssszwic  prefetchPtrDumpData.fromIfuPtr  := distanceBetween(prefetchPtr, ifuPtr)
1322378f00d9SJenius
1323f9c51548Sssszwic  prefetchPtrTable.log(
1324f9c51548Sssszwic    data = prefetchPtrDumpData,
1325f9c51548Sssszwic    en = isWritePrefetchPtrTable.orR && io.toPrefetch.req.fire,
1326f9c51548Sssszwic    site = "FTQ" + p(XSCoreParamsKey).HartId.toString,
1327f9c51548Sssszwic    clock = clock,
1328f9c51548Sssszwic    reset = reset
1329f9c51548Sssszwic  )
1330f9c51548Sssszwic
1331de7689fcSJay
133209c6f1ddSLingrui98  // ******************************************************************************
133309c6f1ddSLingrui98  // **************************** commit perf counters ****************************
133409c6f1ddSLingrui98  // ******************************************************************************
133509c6f1ddSLingrui98
133609c6f1ddSLingrui98  val commit_inst_mask    = VecInit(commit_state.map(c => c === c_commited && do_commit)).asUInt
133709c6f1ddSLingrui98  val commit_mispred_mask = commit_mispredict.asUInt
133809c6f1ddSLingrui98  val commit_not_mispred_mask = ~commit_mispred_mask
133909c6f1ddSLingrui98
134009c6f1ddSLingrui98  val commit_br_mask = commit_pd.brMask.asUInt
134109c6f1ddSLingrui98  val commit_jmp_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.jmpInfo.valid.asTypeOf(UInt(1.W)))
134209c6f1ddSLingrui98  val commit_cfi_mask = (commit_br_mask | commit_jmp_mask)
134309c6f1ddSLingrui98
134409c6f1ddSLingrui98  val mbpInstrs = commit_inst_mask & commit_cfi_mask
134509c6f1ddSLingrui98
134609c6f1ddSLingrui98  val mbpRights = mbpInstrs & commit_not_mispred_mask
134709c6f1ddSLingrui98  val mbpWrongs = mbpInstrs & commit_mispred_mask
134809c6f1ddSLingrui98
134909c6f1ddSLingrui98  io.bpuInfo.bpRight := PopCount(mbpRights)
135009c6f1ddSLingrui98  io.bpuInfo.bpWrong := PopCount(mbpWrongs)
135109c6f1ddSLingrui98
1352da3bf434SMaxpicca-Li  val isWriteFTQTable = WireInit(Constantin.createRecord("isWriteFTQTable" + p(XSCoreParamsKey).HartId.toString))
135351532d8bSGuokai Chen  val ftqBranchTraceDB = ChiselDB.createTable("FTQTable" + p(XSCoreParamsKey).HartId.toString, new FtqDebugBundle)
135409c6f1ddSLingrui98  // Cfi Info
135509c6f1ddSLingrui98  for (i <- 0 until PredictWidth) {
135609c6f1ddSLingrui98    val pc = commit_pc_bundle.startAddr + (i * instBytes).U
135709c6f1ddSLingrui98    val v = commit_state(i) === c_commited
135809c6f1ddSLingrui98    val isBr = commit_pd.brMask(i)
135909c6f1ddSLingrui98    val isJmp = commit_pd.jmpInfo.valid && commit_pd.jmpOffset === i.U
136009c6f1ddSLingrui98    val isCfi = isBr || isJmp
136109c6f1ddSLingrui98    val isTaken = commit_cfi.valid && commit_cfi.bits === i.U
136209c6f1ddSLingrui98    val misPred = commit_mispredict(i)
1363c2ad24ebSLingrui98    // val ghist = commit_spec_meta.ghist.predHist
1364c2ad24ebSLingrui98    val histPtr = commit_spec_meta.histPtr
136509c6f1ddSLingrui98    val predCycle = commit_meta.meta(63, 0)
136609c6f1ddSLingrui98    val target = commit_target
136709c6f1ddSLingrui98
136809c6f1ddSLingrui98    val brIdx = OHToUInt(Reverse(Cat(update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U})))
136909c6f1ddSLingrui98    val inFtbEntry = update_ftb_entry.brValids.zip(update_ftb_entry.brOffset).map{case(v, offset) => v && offset === i.U}.reduce(_||_)
137009c6f1ddSLingrui98    val addIntoHist = ((commit_hit === h_hit) && inFtbEntry) || ((!(commit_hit === h_hit) && i.U === commit_cfi.bits && isBr && commit_cfi.valid))
137109c6f1ddSLingrui98    XSDebug(v && do_commit && isCfi, p"cfi_update: isBr(${isBr}) pc(${Hexadecimal(pc)}) " +
1372c2ad24ebSLingrui98    p"taken(${isTaken}) mispred(${misPred}) cycle($predCycle) hist(${histPtr.value}) " +
137309c6f1ddSLingrui98    p"startAddr(${Hexadecimal(commit_pc_bundle.startAddr)}) AddIntoHist(${addIntoHist}) " +
137409c6f1ddSLingrui98    p"brInEntry(${inFtbEntry}) brIdx(${brIdx}) target(${Hexadecimal(target)})\n")
137551532d8bSGuokai Chen
137651532d8bSGuokai Chen    val logbundle = Wire(new FtqDebugBundle)
137751532d8bSGuokai Chen    logbundle.pc := pc
137851532d8bSGuokai Chen    logbundle.target := target
137951532d8bSGuokai Chen    logbundle.isBr := isBr
138051532d8bSGuokai Chen    logbundle.isJmp := isJmp
138151532d8bSGuokai Chen    logbundle.isCall := isJmp && commit_pd.hasCall
138251532d8bSGuokai Chen    logbundle.isRet := isJmp && commit_pd.hasRet
138351532d8bSGuokai Chen    logbundle.misPred := misPred
138451532d8bSGuokai Chen    logbundle.isTaken := isTaken
138551532d8bSGuokai Chen    logbundle.predStage := commit_stage
138651532d8bSGuokai Chen
138751532d8bSGuokai Chen    ftqBranchTraceDB.log(
138851532d8bSGuokai Chen      data = logbundle /* hardware of type T */,
1389da3bf434SMaxpicca-Li      en = isWriteFTQTable.orR && v && do_commit && isCfi,
139051532d8bSGuokai Chen      site = "FTQ" + p(XSCoreParamsKey).HartId.toString,
139151532d8bSGuokai Chen      clock = clock,
139251532d8bSGuokai Chen      reset = reset
139351532d8bSGuokai Chen    )
139409c6f1ddSLingrui98  }
139509c6f1ddSLingrui98
139609c6f1ddSLingrui98  val enq = io.fromBpu.resp
13972e1be6e1SSteve Gou  val perf_redirect = backendRedirect
139809c6f1ddSLingrui98
139909c6f1ddSLingrui98  XSPerfAccumulate("entry", validEntries)
140009c6f1ddSLingrui98  XSPerfAccumulate("bpu_to_ftq_stall", enq.valid && !enq.ready)
140109c6f1ddSLingrui98  XSPerfAccumulate("mispredictRedirect", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level)
140209c6f1ddSLingrui98  XSPerfAccumulate("replayRedirect", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level))
140309c6f1ddSLingrui98  XSPerfAccumulate("predecodeRedirect", fromIfuRedirect.valid)
140409c6f1ddSLingrui98
140509c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_bubble", io.toIfu.req.ready && !io.toIfu.req.valid)
140609c6f1ddSLingrui98
140709c6f1ddSLingrui98  XSPerfAccumulate("to_ifu_stall", io.toIfu.req.valid && !io.toIfu.req.ready)
140809c6f1ddSLingrui98  XSPerfAccumulate("from_bpu_real_bubble", !enq.valid && enq.ready && allowBpuIn)
140912cedb6fSLingrui98  XSPerfAccumulate("bpu_to_ifu_bubble", bpuPtr === ifuPtr)
1410b2f6ed0aSSteve Gou  XSPerfAccumulate("bpu_to_ifu_bubble_when_ftq_full", (bpuPtr === ifuPtr) && isFull(bpuPtr, commPtr) && io.toIfu.req.ready)
141109c6f1ddSLingrui98
1412*bace178aSGao-Zeyu  XSPerfAccumulate("redirectAhead_ValidNum", ftqIdxAhead.map(_.valid).reduce(_|_))
14139342624fSGao-Zeyu  XSPerfAccumulate("fromBackendRedirect_ValidNum", io.fromBackend.redirect.valid)
14149342624fSGao-Zeyu  XSPerfAccumulate("toBpuRedirect_ValidNum", io.toBpu.redirect.valid)
14159342624fSGao-Zeyu
141609c6f1ddSLingrui98  val from_bpu = io.fromBpu.resp.bits
141709c6f1ddSLingrui98  val to_ifu = io.toIfu.req.bits
141809c6f1ddSLingrui98
141909c6f1ddSLingrui98
1420209a4cafSSteve Gou  XSPerfHistogram("commit_num_inst", PopCount(commit_inst_mask), do_commit, 0, PredictWidth+1, 1)
142109c6f1ddSLingrui98
142209c6f1ddSLingrui98
142309c6f1ddSLingrui98
142409c6f1ddSLingrui98
142509c6f1ddSLingrui98  val commit_jal_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJal.asTypeOf(UInt(1.W)))
142609c6f1ddSLingrui98  val commit_jalr_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasJalr.asTypeOf(UInt(1.W)))
142709c6f1ddSLingrui98  val commit_call_mask = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasCall.asTypeOf(UInt(1.W)))
142809c6f1ddSLingrui98  val commit_ret_mask  = UIntToOH(commit_pd.jmpOffset) & Fill(PredictWidth, commit_pd.hasRet.asTypeOf(UInt(1.W)))
142909c6f1ddSLingrui98
143009c6f1ddSLingrui98
143109c6f1ddSLingrui98  val mbpBRights = mbpRights & commit_br_mask
143209c6f1ddSLingrui98  val mbpJRights = mbpRights & commit_jal_mask
143309c6f1ddSLingrui98  val mbpIRights = mbpRights & commit_jalr_mask
143409c6f1ddSLingrui98  val mbpCRights = mbpRights & commit_call_mask
143509c6f1ddSLingrui98  val mbpRRights = mbpRights & commit_ret_mask
143609c6f1ddSLingrui98
143709c6f1ddSLingrui98  val mbpBWrongs = mbpWrongs & commit_br_mask
143809c6f1ddSLingrui98  val mbpJWrongs = mbpWrongs & commit_jal_mask
143909c6f1ddSLingrui98  val mbpIWrongs = mbpWrongs & commit_jalr_mask
144009c6f1ddSLingrui98  val mbpCWrongs = mbpWrongs & commit_call_mask
144109c6f1ddSLingrui98  val mbpRWrongs = mbpWrongs & commit_ret_mask
144209c6f1ddSLingrui98
14431d7e5011SLingrui98  val commit_pred_stage = RegNext(pred_stage(commPtr.value))
14441d7e5011SLingrui98
14451d7e5011SLingrui98  def pred_stage_map(src: UInt, name: String) = {
14461d7e5011SLingrui98    (0 until numBpStages).map(i =>
14471d7e5011SLingrui98      f"${name}_stage_${i+1}" -> PopCount(src.asBools.map(_ && commit_pred_stage === BP_STAGES(i)))
14481d7e5011SLingrui98    ).foldLeft(Map[String, UInt]())(_+_)
14491d7e5011SLingrui98  }
14501d7e5011SLingrui98
14511d7e5011SLingrui98  val mispred_stage_map      = pred_stage_map(mbpWrongs,  "mispredict")
14521d7e5011SLingrui98  val br_mispred_stage_map   = pred_stage_map(mbpBWrongs, "br_mispredict")
14531d7e5011SLingrui98  val jalr_mispred_stage_map = pred_stage_map(mbpIWrongs, "jalr_mispredict")
14541d7e5011SLingrui98  val correct_stage_map      = pred_stage_map(mbpRights,  "correct")
14551d7e5011SLingrui98  val br_correct_stage_map   = pred_stage_map(mbpBRights, "br_correct")
14561d7e5011SLingrui98  val jalr_correct_stage_map = pred_stage_map(mbpIRights, "jalr_correct")
14571d7e5011SLingrui98
145809c6f1ddSLingrui98  val update_valid = io.toBpu.update.valid
145909c6f1ddSLingrui98  def u(cond: Bool) = update_valid && cond
146009c6f1ddSLingrui98  val ftb_false_hit = u(update.false_hit)
146165fddcf0Szoujr  // assert(!ftb_false_hit)
146209c6f1ddSLingrui98  val ftb_hit = u(commit_hit === h_hit)
146309c6f1ddSLingrui98
146409c6f1ddSLingrui98  val ftb_new_entry = u(ftbEntryGen.is_init_entry)
1465b37e4b45SLingrui98  val ftb_new_entry_only_br = ftb_new_entry && !update_ftb_entry.jmpValid
1466b37e4b45SLingrui98  val ftb_new_entry_only_jmp = ftb_new_entry && !update_ftb_entry.brValids(0)
1467b37e4b45SLingrui98  val ftb_new_entry_has_br_and_jmp = ftb_new_entry && update_ftb_entry.brValids(0) && update_ftb_entry.jmpValid
146809c6f1ddSLingrui98
146909c6f1ddSLingrui98  val ftb_old_entry = u(ftbEntryGen.is_old_entry)
147009c6f1ddSLingrui98
147109c6f1ddSLingrui98  val ftb_modified_entry = u(ftbEntryGen.is_new_br || ftbEntryGen.is_jalr_target_modified || ftbEntryGen.is_always_taken_modified)
147209c6f1ddSLingrui98  val ftb_modified_entry_new_br = u(ftbEntryGen.is_new_br)
1473d2b20d1aSTang Haojin  val ftb_modified_entry_ifu_redirected = u(ifuRedirected(do_commit_ptr.value))
147409c6f1ddSLingrui98  val ftb_modified_entry_jalr_target_modified = u(ftbEntryGen.is_jalr_target_modified)
147509c6f1ddSLingrui98  val ftb_modified_entry_br_full = ftb_modified_entry && ftbEntryGen.is_br_full
147609c6f1ddSLingrui98  val ftb_modified_entry_always_taken = ftb_modified_entry && ftbEntryGen.is_always_taken_modified
147709c6f1ddSLingrui98
1478209a4cafSSteve Gou  def getFtbEntryLen(pc: UInt, entry: FTBEntry) = (entry.getFallThrough(pc) - pc) >> instOffsetBits
1479209a4cafSSteve Gou  val gen_ftb_entry_len = getFtbEntryLen(update.pc, ftbEntryGen.new_entry)
1480209a4cafSSteve Gou  XSPerfHistogram("ftb_init_entry_len", gen_ftb_entry_len, ftb_new_entry, 0, PredictWidth+1, 1)
1481209a4cafSSteve Gou  XSPerfHistogram("ftb_modified_entry_len", gen_ftb_entry_len, ftb_modified_entry, 0, PredictWidth+1, 1)
1482209a4cafSSteve Gou  val s3_ftb_entry_len = getFtbEntryLen(from_bpu.s3.pc(0), from_bpu.last_stage_ftb_entry)
1483209a4cafSSteve Gou  XSPerfHistogram("s3_ftb_entry_len", s3_ftb_entry_len, from_bpu.s3.valid(0), 0, PredictWidth+1, 1)
148409c6f1ddSLingrui98
1485209a4cafSSteve Gou  XSPerfHistogram("ftq_has_entry", validEntries, true.B, 0, FtqSize+1, 1)
148609c6f1ddSLingrui98
148709c6f1ddSLingrui98  val perfCountsMap = Map(
148809c6f1ddSLingrui98    "BpInstr" -> PopCount(mbpInstrs),
148909c6f1ddSLingrui98    "BpBInstr" -> PopCount(mbpBRights | mbpBWrongs),
149009c6f1ddSLingrui98    "BpRight"  -> PopCount(mbpRights),
149109c6f1ddSLingrui98    "BpWrong"  -> PopCount(mbpWrongs),
149209c6f1ddSLingrui98    "BpBRight" -> PopCount(mbpBRights),
149309c6f1ddSLingrui98    "BpBWrong" -> PopCount(mbpBWrongs),
149409c6f1ddSLingrui98    "BpJRight" -> PopCount(mbpJRights),
149509c6f1ddSLingrui98    "BpJWrong" -> PopCount(mbpJWrongs),
149609c6f1ddSLingrui98    "BpIRight" -> PopCount(mbpIRights),
149709c6f1ddSLingrui98    "BpIWrong" -> PopCount(mbpIWrongs),
149809c6f1ddSLingrui98    "BpCRight" -> PopCount(mbpCRights),
149909c6f1ddSLingrui98    "BpCWrong" -> PopCount(mbpCWrongs),
150009c6f1ddSLingrui98    "BpRRight" -> PopCount(mbpRRights),
150109c6f1ddSLingrui98    "BpRWrong" -> PopCount(mbpRWrongs),
150209c6f1ddSLingrui98
150309c6f1ddSLingrui98    "ftb_false_hit"                -> PopCount(ftb_false_hit),
150409c6f1ddSLingrui98    "ftb_hit"                      -> PopCount(ftb_hit),
150509c6f1ddSLingrui98    "ftb_new_entry"                -> PopCount(ftb_new_entry),
150609c6f1ddSLingrui98    "ftb_new_entry_only_br"        -> PopCount(ftb_new_entry_only_br),
150709c6f1ddSLingrui98    "ftb_new_entry_only_jmp"       -> PopCount(ftb_new_entry_only_jmp),
150809c6f1ddSLingrui98    "ftb_new_entry_has_br_and_jmp" -> PopCount(ftb_new_entry_has_br_and_jmp),
150909c6f1ddSLingrui98    "ftb_old_entry"                -> PopCount(ftb_old_entry),
151009c6f1ddSLingrui98    "ftb_modified_entry"           -> PopCount(ftb_modified_entry),
151109c6f1ddSLingrui98    "ftb_modified_entry_new_br"    -> PopCount(ftb_modified_entry_new_br),
151209c6f1ddSLingrui98    "ftb_jalr_target_modified"     -> PopCount(ftb_modified_entry_jalr_target_modified),
151309c6f1ddSLingrui98    "ftb_modified_entry_br_full"   -> PopCount(ftb_modified_entry_br_full),
151409c6f1ddSLingrui98    "ftb_modified_entry_always_taken" -> PopCount(ftb_modified_entry_always_taken)
1515209a4cafSSteve Gou  ) ++ mispred_stage_map ++ br_mispred_stage_map ++ jalr_mispred_stage_map ++
15161d7e5011SLingrui98       correct_stage_map ++ br_correct_stage_map ++ jalr_correct_stage_map
151709c6f1ddSLingrui98
151809c6f1ddSLingrui98  for((key, value) <- perfCountsMap) {
151909c6f1ddSLingrui98    XSPerfAccumulate(key, value)
152009c6f1ddSLingrui98  }
152109c6f1ddSLingrui98
152209c6f1ddSLingrui98  // --------------------------- Debug --------------------------------
152309c6f1ddSLingrui98  // XSDebug(enq_fire, p"enq! " + io.fromBpu.resp.bits.toPrintable)
152409c6f1ddSLingrui98  XSDebug(io.toIfu.req.fire, p"fire to ifu " + io.toIfu.req.bits.toPrintable)
152509c6f1ddSLingrui98  XSDebug(do_commit, p"deq! [ptr] $do_commit_ptr\n")
152609c6f1ddSLingrui98  XSDebug(true.B, p"[bpuPtr] $bpuPtr, [ifuPtr] $ifuPtr, [ifuWbPtr] $ifuWbPtr [commPtr] $commPtr\n")
152709c6f1ddSLingrui98  XSDebug(true.B, p"[in] v:${io.fromBpu.resp.valid} r:${io.fromBpu.resp.ready} " +
152809c6f1ddSLingrui98    p"[out] v:${io.toIfu.req.valid} r:${io.toIfu.req.ready}\n")
152909c6f1ddSLingrui98  XSDebug(do_commit, p"[deq info] cfiIndex: $commit_cfi, $commit_pc_bundle, target: ${Hexadecimal(commit_target)}\n")
153009c6f1ddSLingrui98
153109c6f1ddSLingrui98  //   def ubtbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
153209c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
153309c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
153409c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
153509c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
153609c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
153709c6f1ddSLingrui98  //           !taken),
153809c6f1ddSLingrui98  //         !taken),
153909c6f1ddSLingrui98  //       false.B)
154009c6f1ddSLingrui98  //     }
154109c6f1ddSLingrui98  //   }
154209c6f1ddSLingrui98
154309c6f1ddSLingrui98  //   def btbCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
154409c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
154509c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
154609c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
154709c6f1ddSLingrui98  //         isWrong ^ Mux(ans.hit.asBool,
154809c6f1ddSLingrui98  //           Mux(ans.taken.asBool, taken && ans.target === commitEntry.target,
154909c6f1ddSLingrui98  //           !taken),
155009c6f1ddSLingrui98  //         !taken),
155109c6f1ddSLingrui98  //       false.B)
155209c6f1ddSLingrui98  //     }
155309c6f1ddSLingrui98  //   }
155409c6f1ddSLingrui98
155509c6f1ddSLingrui98  //   def tageCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
155609c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
155709c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
155809c6f1ddSLingrui98  //       Mux(valid && pd.isBr,
155909c6f1ddSLingrui98  //         isWrong ^ (ans.taken.asBool === taken),
156009c6f1ddSLingrui98  //       false.B)
156109c6f1ddSLingrui98  //     }
156209c6f1ddSLingrui98  //   }
156309c6f1ddSLingrui98
156409c6f1ddSLingrui98  //   def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
156509c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
156609c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
156709c6f1ddSLingrui98  //       Mux(valid && (pd.isBr) && ans.hit.asBool,
156809c6f1ddSLingrui98  //         isWrong ^ (!taken),
156909c6f1ddSLingrui98  //           false.B)
157009c6f1ddSLingrui98  //     }
157109c6f1ddSLingrui98  //   }
157209c6f1ddSLingrui98
157309c6f1ddSLingrui98  //   def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = {
157409c6f1ddSLingrui98  //     commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map {
157509c6f1ddSLingrui98  //       case (((valid, pd), ans), taken) =>
157609c6f1ddSLingrui98  //       Mux(valid && pd.isRet.asBool /*&& taken*/ && ans.hit.asBool,
157709c6f1ddSLingrui98  //         isWrong ^ (ans.target === commitEntry.target),
157809c6f1ddSLingrui98  //           false.B)
157909c6f1ddSLingrui98  //     }
158009c6f1ddSLingrui98  //   }
158109c6f1ddSLingrui98
158209c6f1ddSLingrui98  //   val ubtbRights = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), false.B)
158309c6f1ddSLingrui98  //   val ubtbWrongs = ubtbCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), true.B)
158409c6f1ddSLingrui98  //   // btb and ubtb pred jal and jalr as well
158509c6f1ddSLingrui98  //   val btbRights = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), false.B)
158609c6f1ddSLingrui98  //   val btbWrongs = btbCheck(commitEntry, commitEntry.metas.map(_.btbAns), true.B)
158709c6f1ddSLingrui98  //   val tageRights = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), false.B)
158809c6f1ddSLingrui98  //   val tageWrongs = tageCheck(commitEntry, commitEntry.metas.map(_.tageAns), true.B)
158909c6f1ddSLingrui98
159009c6f1ddSLingrui98  //   val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B)
159109c6f1ddSLingrui98  //   val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B)
159209c6f1ddSLingrui98
159309c6f1ddSLingrui98  //   val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B)
159409c6f1ddSLingrui98  //   val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B)
15951ca0e4f3SYinan Xu
1596cd365d4cSrvcoresjw  val perfEvents = Seq(
1597cd365d4cSrvcoresjw    ("bpu_s2_redirect        ", bpu_s2_redirect                                                             ),
1598cb4f77ceSLingrui98    ("bpu_s3_redirect        ", bpu_s3_redirect                                                             ),
1599cd365d4cSrvcoresjw    ("bpu_to_ftq_stall       ", enq.valid && ~enq.ready                                                     ),
1600cd365d4cSrvcoresjw    ("mispredictRedirect     ", perf_redirect.valid && RedirectLevel.flushAfter === perf_redirect.bits.level),
1601cd365d4cSrvcoresjw    ("replayRedirect         ", perf_redirect.valid && RedirectLevel.flushItself(perf_redirect.bits.level)  ),
1602cd365d4cSrvcoresjw    ("predecodeRedirect      ", fromIfuRedirect.valid                                                       ),
1603cd365d4cSrvcoresjw    ("to_ifu_bubble          ", io.toIfu.req.ready && !io.toIfu.req.valid                                   ),
1604cd365d4cSrvcoresjw    ("from_bpu_real_bubble   ", !enq.valid && enq.ready && allowBpuIn                                       ),
1605cd365d4cSrvcoresjw    ("BpInstr                ", PopCount(mbpInstrs)                                                         ),
1606cd365d4cSrvcoresjw    ("BpBInstr               ", PopCount(mbpBRights | mbpBWrongs)                                           ),
1607cd365d4cSrvcoresjw    ("BpRight                ", PopCount(mbpRights)                                                         ),
1608cd365d4cSrvcoresjw    ("BpWrong                ", PopCount(mbpWrongs)                                                         ),
1609cd365d4cSrvcoresjw    ("BpBRight               ", PopCount(mbpBRights)                                                        ),
1610cd365d4cSrvcoresjw    ("BpBWrong               ", PopCount(mbpBWrongs)                                                        ),
1611cd365d4cSrvcoresjw    ("BpJRight               ", PopCount(mbpJRights)                                                        ),
1612cd365d4cSrvcoresjw    ("BpJWrong               ", PopCount(mbpJWrongs)                                                        ),
1613cd365d4cSrvcoresjw    ("BpIRight               ", PopCount(mbpIRights)                                                        ),
1614cd365d4cSrvcoresjw    ("BpIWrong               ", PopCount(mbpIWrongs)                                                        ),
1615cd365d4cSrvcoresjw    ("BpCRight               ", PopCount(mbpCRights)                                                        ),
1616cd365d4cSrvcoresjw    ("BpCWrong               ", PopCount(mbpCWrongs)                                                        ),
1617cd365d4cSrvcoresjw    ("BpRRight               ", PopCount(mbpRRights)                                                        ),
1618cd365d4cSrvcoresjw    ("BpRWrong               ", PopCount(mbpRWrongs)                                                        ),
1619cd365d4cSrvcoresjw    ("ftb_false_hit          ", PopCount(ftb_false_hit)                                                     ),
1620cd365d4cSrvcoresjw    ("ftb_hit                ", PopCount(ftb_hit)                                                           ),
1621cd365d4cSrvcoresjw  )
16221ca0e4f3SYinan Xu  generatePerfEvent()
162309c6f1ddSLingrui98}