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