xref: /XiangShan/src/main/scala/xiangshan/frontend/newRAS.scala (revision 9928cec7a67130f853d7dc18e380b564782f2954)
1c89b4642SGuokai Chen/***************************************************************************************
2e3da8badSTang Haojin* Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC)
3e3da8badSTang Haojin* Copyright (c) 2020-2024 Institute of Computing Technology, Chinese Academy of Sciences
4c89b4642SGuokai Chen* Copyright (c) 2020-2021 Peng Cheng Laboratory
5c89b4642SGuokai Chen*
6c89b4642SGuokai Chen* XiangShan is licensed under Mulan PSL v2.
7c89b4642SGuokai Chen* You can use this software according to the terms and conditions of the Mulan PSL v2.
8c89b4642SGuokai Chen* You may obtain a copy of Mulan PSL v2 at:
9c89b4642SGuokai Chen*          http://license.coscl.org.cn/MulanPSL2
10c89b4642SGuokai Chen*
11c89b4642SGuokai Chen* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
12c89b4642SGuokai Chen* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
13c89b4642SGuokai Chen* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
14c89b4642SGuokai Chen*
15c89b4642SGuokai Chen* See the Mulan PSL v2 for more details.
16c49ebec8SHaoyuan Feng*
17c49ebec8SHaoyuan Feng*
18c49ebec8SHaoyuan Feng* Acknowledgement
19c49ebec8SHaoyuan Feng*
20c49ebec8SHaoyuan Feng* This implementation is inspired by several key papers:
21c49ebec8SHaoyuan Feng* [1] Kevin Skadron, Pritpal S. Ahuja, Margaret Martonosi, and Douglas W. Clark. "[Improving prediction for procedure
22c49ebec8SHaoyuan Feng* returns with return-address-stack repair mechanisms.](https://doi.org/10.1109/MICRO.1998.742787)" 31st Annual
23c49ebec8SHaoyuan Feng* ACM/IEEE International Symposium on Microarchitecture (MICRO). 1998.
24c49ebec8SHaoyuan Feng* [2] Tan Hongze, and Wang Jian. "[A Return Address Predictor Based on Persistent Stack.]
25c49ebec8SHaoyuan Feng* (https://crad.ict.ac.cn/en/article/doi/10.7544/issn1000-1239.202111274)" Journal of Computer Research and Development
26c49ebec8SHaoyuan Feng* (CRAD) 60.6: 1337-1345. 2023.
27c89b4642SGuokai Chen***************************************************************************************/
28c89b4642SGuokai Chenpackage xiangshan.frontend
29c89b4642SGuokai Chen
30c89b4642SGuokai Chenimport chisel3._
31c89b4642SGuokai Chenimport chisel3.util._
32cf7d6b7aSMuziimport org.chipsalliance.cde.config.Parameters
33c89b4642SGuokai Chenimport utility._
34cf7d6b7aSMuziimport utils._
35c89b4642SGuokai Chenimport xiangshan._
36c89b4642SGuokai Chenimport xiangshan.frontend._
37c89b4642SGuokai Chen
38c89b4642SGuokai Chenclass RASEntry()(implicit p: Parameters) extends XSBundle {
39c89b4642SGuokai Chen  val retAddr = UInt(VAddrBits.W)
40e3704ae5Smy-mayfly  val ctr     = UInt(RasCtrSize.W) // layer of nested call functions
41c89b4642SGuokai Chen  def =/=(that: RASEntry) = this.retAddr =/= that.retAddr || this.ctr =/= that.ctr
42c89b4642SGuokai Chen}
43c89b4642SGuokai Chen
44cf7d6b7aSMuziclass RASPtr(implicit p: Parameters) extends CircularQueuePtr[RASPtr](p => p(XSCoreParamsKey).RasSpecSize) {}
45c89b4642SGuokai Chen
46c89b4642SGuokai Chenobject RASPtr {
47c89b4642SGuokai Chen  def apply(f: Bool, v: UInt)(implicit p: Parameters): RASPtr = {
48c89b4642SGuokai Chen    val ptr = Wire(new RASPtr)
49c89b4642SGuokai Chen    ptr.flag  := f
50c89b4642SGuokai Chen    ptr.value := v
51c89b4642SGuokai Chen    ptr
52c89b4642SGuokai Chen  }
53cf7d6b7aSMuzi  def inverse(ptr: RASPtr)(implicit p: Parameters): RASPtr =
54c89b4642SGuokai Chen    apply(!ptr.flag, ptr.value)
55c89b4642SGuokai Chen}
56c89b4642SGuokai Chen
57deb3a97eSGao-Zeyuclass RASInternalMeta(implicit p: Parameters) extends XSBundle {
58c89b4642SGuokai Chen  val ssp  = UInt(log2Up(RasSize).W)
5977bef50aSGuokai Chen  val sctr = UInt(RasCtrSize.W)
60c89b4642SGuokai Chen  val TOSW = new RASPtr
61c89b4642SGuokai Chen  val TOSR = new RASPtr
62c89b4642SGuokai Chen  val NOS  = new RASPtr
63c89b4642SGuokai Chen}
64c89b4642SGuokai Chen
65deb3a97eSGao-Zeyuobject RASInternalMeta {
66deb3a97eSGao-Zeyu  def apply(ssp: UInt, sctr: UInt, TOSW: RASPtr, TOSR: RASPtr, NOS: RASPtr)(implicit p: Parameters): RASInternalMeta = {
67deb3a97eSGao-Zeyu    val e = Wire(new RASInternalMeta)
68deb3a97eSGao-Zeyu    e.ssp  := ssp
69deb3a97eSGao-Zeyu    e.TOSW := TOSW
70deb3a97eSGao-Zeyu    e.TOSR := TOSR
71deb3a97eSGao-Zeyu    e.NOS  := NOS
72deb3a97eSGao-Zeyu    e
73deb3a97eSGao-Zeyu  }
74deb3a97eSGao-Zeyu}
75deb3a97eSGao-Zeyu
76deb3a97eSGao-Zeyuclass RASMeta(implicit p: Parameters) extends XSBundle {
77deb3a97eSGao-Zeyu  val ssp  = UInt(log2Up(RasSize).W)
78deb3a97eSGao-Zeyu  val TOSW = new RASPtr
79deb3a97eSGao-Zeyu}
80deb3a97eSGao-Zeyu
81c89b4642SGuokai Chenobject RASMeta {
82c89b4642SGuokai Chen  def apply(ssp: UInt, sctr: UInt, TOSW: RASPtr, TOSR: RASPtr, NOS: RASPtr)(implicit p: Parameters): RASMeta = {
83c89b4642SGuokai Chen    val e = Wire(new RASMeta)
84c89b4642SGuokai Chen    e.ssp  := ssp
85c89b4642SGuokai Chen    e.TOSW := TOSW
86c89b4642SGuokai Chen    e
87c89b4642SGuokai Chen  }
88c89b4642SGuokai Chen}
89c89b4642SGuokai Chen
90c89b4642SGuokai Chenclass RASDebug(implicit p: Parameters) extends XSBundle {
91c89b4642SGuokai Chen  val spec_queue   = Output(Vec(RasSpecSize, new RASEntry))
92c89b4642SGuokai Chen  val spec_nos     = Output(Vec(RasSpecSize, new RASPtr))
93c89b4642SGuokai Chen  val commit_stack = Output(Vec(RasSize, new RASEntry))
94c89b4642SGuokai Chen}
95c89b4642SGuokai Chen
96*9928cec7Szhou taoclass RAS(implicit p: Parameters) extends BasePredictor with HasCircularQueuePtrHelper {
97c89b4642SGuokai Chen  override val meta_size = WireInit(0.U.asTypeOf(new RASMeta)).getWidth
98c89b4642SGuokai Chen
99c89b4642SGuokai Chen  object RASEntry {
100c89b4642SGuokai Chen    def apply(retAddr: UInt, ctr: UInt): RASEntry = {
101c89b4642SGuokai Chen      val e = Wire(new RASEntry)
102c89b4642SGuokai Chen      e.retAddr := retAddr
103c89b4642SGuokai Chen      e.ctr     := ctr
104c89b4642SGuokai Chen      e
105c89b4642SGuokai Chen    }
106c89b4642SGuokai Chen  }
107c89b4642SGuokai Chen
108c89b4642SGuokai Chen  class RASStack(rasSize: Int, rasSpecSize: Int) extends XSModule with HasCircularQueuePtrHelper {
109c89b4642SGuokai Chen    val io = IO(new Bundle {
110c89b4642SGuokai Chen      val spec_push_valid = Input(Bool())
111c89b4642SGuokai Chen      val spec_pop_valid  = Input(Bool())
112c89b4642SGuokai Chen      val spec_push_addr  = Input(UInt(VAddrBits.W))
113c89b4642SGuokai Chen      // for write bypass between s2 and s3
114c89b4642SGuokai Chen
115c89b4642SGuokai Chen      val s2_fire        = Input(Bool())
116c89b4642SGuokai Chen      val s3_fire        = Input(Bool())
117c89b4642SGuokai Chen      val s3_cancel      = Input(Bool())
118deb3a97eSGao-Zeyu      val s3_meta        = Input(new RASInternalMeta)
119c89b4642SGuokai Chen      val s3_missed_pop  = Input(Bool())
120c89b4642SGuokai Chen      val s3_missed_push = Input(Bool())
121c89b4642SGuokai Chen      val s3_pushAddr    = Input(UInt(VAddrBits.W))
122c89b4642SGuokai Chen      val spec_pop_addr  = Output(UInt(VAddrBits.W))
123c89b4642SGuokai Chen
124c776f0d5Smy-mayfly      val commit_valid      = Input(Bool())
125c89b4642SGuokai Chen      val commit_push_valid = Input(Bool())
126c89b4642SGuokai Chen      val commit_pop_valid  = Input(Bool())
127c89b4642SGuokai Chen      val commit_push_addr  = Input(UInt(VAddrBits.W))
128c89b4642SGuokai Chen      val commit_meta_TOSW  = Input(new RASPtr)
129c89b4642SGuokai Chen      // for debug purpose only
130c89b4642SGuokai Chen      val commit_meta_ssp = Input(UInt(log2Up(RasSize).W))
131c89b4642SGuokai Chen
132c89b4642SGuokai Chen      val redirect_valid     = Input(Bool())
133c89b4642SGuokai Chen      val redirect_isCall    = Input(Bool())
134c89b4642SGuokai Chen      val redirect_isRet     = Input(Bool())
135c89b4642SGuokai Chen      val redirect_meta_ssp  = Input(UInt(log2Up(RasSize).W))
13677bef50aSGuokai Chen      val redirect_meta_sctr = Input(UInt(RasCtrSize.W))
137c89b4642SGuokai Chen      val redirect_meta_TOSW = Input(new RASPtr)
138c89b4642SGuokai Chen      val redirect_meta_TOSR = Input(new RASPtr)
139c89b4642SGuokai Chen      val redirect_meta_NOS  = Input(new RASPtr)
140c89b4642SGuokai Chen      val redirect_callAddr  = Input(UInt(VAddrBits.W))
141c89b4642SGuokai Chen
142c89b4642SGuokai Chen      val ssp  = Output(UInt(log2Up(RasSize).W))
14377bef50aSGuokai Chen      val sctr = Output(UInt(RasCtrSize.W))
144c89b4642SGuokai Chen      val nsp  = Output(UInt(log2Up(RasSize).W))
145c89b4642SGuokai Chen      val TOSR = Output(new RASPtr)
146c89b4642SGuokai Chen      val TOSW = Output(new RASPtr)
147c89b4642SGuokai Chen      val NOS  = Output(new RASPtr)
148c89b4642SGuokai Chen      val BOS  = Output(new RASPtr)
149c89b4642SGuokai Chen
150a8810fc6Smy-mayfly      val spec_near_overflow = Output(Bool())
151a8810fc6Smy-mayfly
152c89b4642SGuokai Chen      val debug = new RASDebug
153c89b4642SGuokai Chen    })
154c89b4642SGuokai Chen
155c89b4642SGuokai Chen    val commit_stack = RegInit(VecInit(Seq.fill(RasSize)(RASEntry(0.U, 0.U))))
156c89b4642SGuokai Chen    val spec_queue   = RegInit(VecInit(Seq.fill(rasSpecSize)(RASEntry(0.U, 0.U))))
157c89b4642SGuokai Chen    val spec_nos     = RegInit(VecInit(Seq.fill(rasSpecSize)(RASPtr(false.B, 0.U))))
158c89b4642SGuokai Chen
159c89b4642SGuokai Chen    val nsp = RegInit(0.U(log2Up(rasSize).W))
160c89b4642SGuokai Chen    val ssp = RegInit(0.U(log2Up(rasSize).W))
161c89b4642SGuokai Chen
162c89b4642SGuokai Chen    val sctr = RegInit(0.U(RasCtrSize.W))
163c89b4642SGuokai Chen    val TOSR = RegInit(RASPtr(true.B, (RasSpecSize - 1).U))
164c89b4642SGuokai Chen    val TOSW = RegInit(RASPtr(false.B, 0.U))
165c89b4642SGuokai Chen    val BOS  = RegInit(RASPtr(false.B, 0.U))
166c89b4642SGuokai Chen
167a8810fc6Smy-mayfly    val spec_near_overflowed = RegInit(false.B)
168c89b4642SGuokai Chen
169c89b4642SGuokai Chen    val writeBypassEntry = Reg(new RASEntry)
170c89b4642SGuokai Chen    val writeBypassNos   = Reg(new RASPtr)
171c89b4642SGuokai Chen
172c89b4642SGuokai Chen    val writeBypassValid     = RegInit(0.B)
173c89b4642SGuokai Chen    val writeBypassValidWire = Wire(Bool())
174c89b4642SGuokai Chen
175c89b4642SGuokai Chen    def TOSRinRange(currentTOSR: RASPtr, currentTOSW: RASPtr) = {
176c89b4642SGuokai Chen      val inflightValid = WireInit(false.B)
177c89b4642SGuokai Chen      // if in range, TOSR should be no younger than BOS and strictly younger than TOSW
178c89b4642SGuokai Chen      when(!isBefore(currentTOSR, BOS) && isBefore(currentTOSR, currentTOSW)) {
179c89b4642SGuokai Chen        inflightValid := true.B
180c89b4642SGuokai Chen      }
181c89b4642SGuokai Chen      inflightValid
182c89b4642SGuokai Chen    }
183c89b4642SGuokai Chen
184cf7d6b7aSMuzi    def getCommitTop(currentSsp: UInt) =
185c89b4642SGuokai Chen      commit_stack(currentSsp)
186c89b4642SGuokai Chen
187c89b4642SGuokai Chen    def getTopNos(currentTOSR: RASPtr, allowBypass: Boolean): RASPtr = {
188c89b4642SGuokai Chen      val ret = Wire(new RASPtr)
189c89b4642SGuokai Chen      if (allowBypass) {
190c89b4642SGuokai Chen        when(writeBypassValid) {
191c89b4642SGuokai Chen          ret := writeBypassNos
192c89b4642SGuokai Chen        }.otherwise {
193c89b4642SGuokai Chen          ret := spec_nos(TOSR.value)
194c89b4642SGuokai Chen        }
195c89b4642SGuokai Chen      } else {
196c89b4642SGuokai Chen        ret := spec_nos(TOSR.value) // invalid when TOSR is not in range
197c89b4642SGuokai Chen      }
198c89b4642SGuokai Chen      ret
199c89b4642SGuokai Chen    }
200c89b4642SGuokai Chen
201cf7d6b7aSMuzi    def getTop(
202cf7d6b7aSMuzi        currentSsp:  UInt,
203cf7d6b7aSMuzi        currentSctr: UInt,
204cf7d6b7aSMuzi        currentTOSR: RASPtr,
205cf7d6b7aSMuzi        currentTOSW: RASPtr,
206cf7d6b7aSMuzi        allowBypass: Boolean
207cf7d6b7aSMuzi    ): RASEntry = {
208c89b4642SGuokai Chen      val ret = Wire(new RASEntry)
209c89b4642SGuokai Chen      if (allowBypass) {
210c89b4642SGuokai Chen        when(writeBypassValid) {
211c89b4642SGuokai Chen          ret := writeBypassEntry
212c89b4642SGuokai Chen        }.elsewhen(TOSRinRange(currentTOSR, currentTOSW)) {
213c89b4642SGuokai Chen          ret := spec_queue(currentTOSR.value)
214c89b4642SGuokai Chen        }.otherwise {
215c89b4642SGuokai Chen          ret := getCommitTop(currentSsp)
216c89b4642SGuokai Chen        }
217c89b4642SGuokai Chen      } else {
218c89b4642SGuokai Chen        when(TOSRinRange(currentTOSR, currentTOSW)) {
219c89b4642SGuokai Chen          ret := spec_queue(currentTOSR.value)
220c89b4642SGuokai Chen        }.otherwise {
221c89b4642SGuokai Chen          ret := getCommitTop(currentSsp)
222c89b4642SGuokai Chen        }
223c89b4642SGuokai Chen      }
224c89b4642SGuokai Chen
225c89b4642SGuokai Chen      ret
226c89b4642SGuokai Chen    }
227c89b4642SGuokai Chen
228c89b4642SGuokai Chen    // it would be unsafe for specPtr manipulation if specSize is not power of 2
229c89b4642SGuokai Chen    assert(log2Up(RasSpecSize) == log2Floor(RasSpecSize))
230e3da8badSTang Haojin    def ctrMax = ((1L << RasCtrSize) - 1).U
231c89b4642SGuokai Chen    def ptrInc(ptr: UInt) = ptr + 1.U
232c89b4642SGuokai Chen    def ptrDec(ptr: UInt) = ptr - 1.U
233c89b4642SGuokai Chen
234c89b4642SGuokai Chen    def specPtrInc(ptr: RASPtr) = ptr + 1.U
235c89b4642SGuokai Chen    def specPtrDec(ptr: RASPtr) = ptr - 1.U
236c89b4642SGuokai Chen
237c89b4642SGuokai Chen    when(io.redirect_valid && io.redirect_isCall) {
238c89b4642SGuokai Chen      writeBypassValidWire := true.B
239c89b4642SGuokai Chen      writeBypassValid     := true.B
240c89b4642SGuokai Chen    }.elsewhen(io.redirect_valid) {
241c89b4642SGuokai Chen      // clear current top writeBypass if doing redirect
242c89b4642SGuokai Chen      writeBypassValidWire := false.B
243c89b4642SGuokai Chen      writeBypassValid     := false.B
244c89b4642SGuokai Chen    }.elsewhen(io.s2_fire) {
245c89b4642SGuokai Chen      writeBypassValidWire := io.spec_push_valid
246c89b4642SGuokai Chen      writeBypassValid     := io.spec_push_valid
247c89b4642SGuokai Chen    }.elsewhen(io.s3_fire) {
248c89b4642SGuokai Chen      writeBypassValidWire := false.B
249c89b4642SGuokai Chen      writeBypassValid     := false.B
250c89b4642SGuokai Chen    }.otherwise {
251c89b4642SGuokai Chen      writeBypassValidWire := writeBypassValid
252c89b4642SGuokai Chen    }
253c89b4642SGuokai Chen
254c89b4642SGuokai Chen    val topEntry = getTop(ssp, sctr, TOSR, TOSW, true)
255c89b4642SGuokai Chen    val topNos   = getTopNos(TOSR, true)
256cf7d6b7aSMuzi    val redirectTopEntry =
257cf7d6b7aSMuzi      getTop(io.redirect_meta_ssp, io.redirect_meta_sctr, io.redirect_meta_TOSR, io.redirect_meta_TOSW, false)
258c89b4642SGuokai Chen    val redirectTopNos = io.redirect_meta_NOS
259c89b4642SGuokai Chen    val s3TopEntry     = getTop(io.s3_meta.ssp, io.s3_meta.sctr, io.s3_meta.TOSR, io.s3_meta.TOSW, false)
260c89b4642SGuokai Chen    val s3TopNos       = io.s3_meta.NOS
261c89b4642SGuokai Chen
262c89b4642SGuokai Chen    val writeEntry = Wire(new RASEntry)
263c89b4642SGuokai Chen    val writeNos   = Wire(new RASPtr)
264c89b4642SGuokai Chen    writeEntry.retAddr := Mux(io.redirect_valid && io.redirect_isCall, io.redirect_callAddr, io.spec_push_addr)
265cf7d6b7aSMuzi    writeEntry.ctr := Mux(
266cf7d6b7aSMuzi      io.redirect_valid && io.redirect_isCall,
267cf7d6b7aSMuzi      Mux(
268cf7d6b7aSMuzi        redirectTopEntry.retAddr === io.redirect_callAddr && redirectTopEntry.ctr < ctrMax,
269cf7d6b7aSMuzi        io.redirect_meta_sctr + 1.U,
270cf7d6b7aSMuzi        0.U
271cf7d6b7aSMuzi      ),
272cf7d6b7aSMuzi      Mux(topEntry.retAddr === io.spec_push_addr && topEntry.ctr < ctrMax, sctr + 1.U, 0.U)
273cf7d6b7aSMuzi    )
274c89b4642SGuokai Chen
275cf7d6b7aSMuzi    writeNos := Mux(io.redirect_valid && io.redirect_isCall, io.redirect_meta_TOSR, TOSR)
276c89b4642SGuokai Chen
277c89b4642SGuokai Chen    when(io.spec_push_valid || (io.redirect_valid && io.redirect_isCall)) {
278c89b4642SGuokai Chen      writeBypassEntry := writeEntry
279c89b4642SGuokai Chen      writeBypassNos   := writeNos
280c89b4642SGuokai Chen    }
281c89b4642SGuokai Chen
282c89b4642SGuokai Chen    val realPush       = Wire(Bool())
283c89b4642SGuokai Chen    val realWriteEntry = Wire(new RASEntry)
284c89b4642SGuokai Chen    val timingTop      = RegInit(0.U.asTypeOf(new RASEntry))
285c89b4642SGuokai Chen    val timingNos      = RegInit(0.U.asTypeOf(new RASPtr))
286c89b4642SGuokai Chen
287c89b4642SGuokai Chen    when(writeBypassValidWire) {
288c89b4642SGuokai Chen      when((io.redirect_valid && io.redirect_isCall) || io.spec_push_valid) {
289c89b4642SGuokai Chen        timingTop := writeEntry
290c89b4642SGuokai Chen        timingNos := writeNos
291c89b4642SGuokai Chen      }.otherwise {
292c89b4642SGuokai Chen        timingTop := writeBypassEntry
293c89b4642SGuokai Chen        timingNos := writeBypassNos
294c89b4642SGuokai Chen      }
295c89b4642SGuokai Chen
296c89b4642SGuokai Chen    }.elsewhen(io.redirect_valid && io.redirect_isRet) {
297c89b4642SGuokai Chen      // getTop using redirect Nos as TOSR
298c89b4642SGuokai Chen      val popRedSsp  = Wire(UInt(log2Up(rasSize).W))
29977bef50aSGuokai Chen      val popRedSctr = Wire(UInt(RasCtrSize.W))
300c89b4642SGuokai Chen      val popRedTOSR = io.redirect_meta_NOS
301c89b4642SGuokai Chen      val popRedTOSW = io.redirect_meta_TOSW
302c89b4642SGuokai Chen
303c89b4642SGuokai Chen      when(io.redirect_meta_sctr > 0.U) {
304c89b4642SGuokai Chen        popRedSctr := io.redirect_meta_sctr - 1.U
305c89b4642SGuokai Chen        popRedSsp  := io.redirect_meta_ssp
306c89b4642SGuokai Chen      }.elsewhen(TOSRinRange(popRedTOSR, TOSW)) {
307c89b4642SGuokai Chen        popRedSsp  := ptrDec(io.redirect_meta_ssp)
308c89b4642SGuokai Chen        popRedSctr := spec_queue(popRedTOSR.value).ctr
309c89b4642SGuokai Chen      }.otherwise {
310c89b4642SGuokai Chen        popRedSsp  := ptrDec(io.redirect_meta_ssp)
311c89b4642SGuokai Chen        popRedSctr := getCommitTop(ptrDec(io.redirect_meta_ssp)).ctr
312c89b4642SGuokai Chen      }
313c89b4642SGuokai Chen      // We are deciding top for the next cycle, no need to use bypass here
314c89b4642SGuokai Chen      timingTop := getTop(popRedSsp, popRedSctr, popRedTOSR, popRedTOSW, false)
315c89b4642SGuokai Chen    }.elsewhen(io.redirect_valid) {
316c89b4642SGuokai Chen      // Neither call nor ret
317c89b4642SGuokai Chen      val popSsp  = io.redirect_meta_ssp
318c89b4642SGuokai Chen      val popSctr = io.redirect_meta_sctr
319c89b4642SGuokai Chen      val popTOSR = io.redirect_meta_TOSR
320c89b4642SGuokai Chen      val popTOSW = io.redirect_meta_TOSW
321c89b4642SGuokai Chen
322c89b4642SGuokai Chen      timingTop := getTop(popSsp, popSctr, popTOSR, popTOSW, false)
323c89b4642SGuokai Chen
324c89b4642SGuokai Chen    }.elsewhen(io.spec_pop_valid) {
325c89b4642SGuokai Chen      // getTop using current Nos as TOSR
326c89b4642SGuokai Chen      val popSsp  = Wire(UInt(log2Up(rasSize).W))
32777bef50aSGuokai Chen      val popSctr = Wire(UInt(RasCtrSize.W))
328c89b4642SGuokai Chen      val popTOSR = topNos
329c89b4642SGuokai Chen      val popTOSW = TOSW
330c89b4642SGuokai Chen
331c89b4642SGuokai Chen      when(sctr > 0.U) {
332c89b4642SGuokai Chen        popSctr := sctr - 1.U
333c89b4642SGuokai Chen        popSsp  := ssp
334c89b4642SGuokai Chen      }.elsewhen(TOSRinRange(popTOSR, TOSW)) {
335c89b4642SGuokai Chen        popSsp  := ptrDec(ssp)
336c89b4642SGuokai Chen        popSctr := spec_queue(popTOSR.value).ctr
337c89b4642SGuokai Chen      }.otherwise {
338c89b4642SGuokai Chen        popSsp  := ptrDec(ssp)
339c89b4642SGuokai Chen        popSctr := getCommitTop(ptrDec(ssp)).ctr
340c89b4642SGuokai Chen      }
341c89b4642SGuokai Chen      // We are deciding top for the next cycle, no need to use bypass here
342c89b4642SGuokai Chen      timingTop := getTop(popSsp, popSctr, popTOSR, popTOSW, false)
343c89b4642SGuokai Chen    }.elsewhen(realPush) {
344c89b4642SGuokai Chen      // just updating spec queue, cannot read from there
345c89b4642SGuokai Chen      timingTop := realWriteEntry
346c89b4642SGuokai Chen    }.elsewhen(io.s3_cancel) {
347c89b4642SGuokai Chen      // s3 is different with s2
348c89b4642SGuokai Chen      timingTop := getTop(io.s3_meta.ssp, io.s3_meta.sctr, io.s3_meta.TOSR, io.s3_meta.TOSW, false)
349c89b4642SGuokai Chen      when(io.s3_missed_push) {
350c89b4642SGuokai Chen        val writeEntry_s3 = Wire(new RASEntry)
351c89b4642SGuokai Chen        timingTop             := writeEntry_s3
352c89b4642SGuokai Chen        writeEntry_s3.retAddr := io.s3_pushAddr
353cf7d6b7aSMuzi        writeEntry_s3.ctr := Mux(
354cf7d6b7aSMuzi          timingTop.retAddr === io.s3_pushAddr && io.s3_meta.sctr < ctrMax,
355cf7d6b7aSMuzi          io.s3_meta.sctr + 1.U,
356cf7d6b7aSMuzi          0.U
357cf7d6b7aSMuzi        )
358c89b4642SGuokai Chen      }.elsewhen(io.s3_missed_pop) {
359c89b4642SGuokai Chen        val popRedSsp_s3  = Wire(UInt(log2Up(rasSize).W))
36077bef50aSGuokai Chen        val popRedSctr_s3 = Wire(UInt(RasCtrSize.W))
361c89b4642SGuokai Chen        val popRedTOSR_s3 = io.s3_meta.NOS
362c89b4642SGuokai Chen        val popRedTOSW_s3 = io.s3_meta.TOSW
363c89b4642SGuokai Chen
364c89b4642SGuokai Chen        when(io.s3_meta.sctr > 0.U) {
365c89b4642SGuokai Chen          popRedSctr_s3 := io.s3_meta.sctr - 1.U
366c89b4642SGuokai Chen          popRedSsp_s3  := io.s3_meta.ssp
367c89b4642SGuokai Chen        }.elsewhen(TOSRinRange(popRedTOSR_s3, popRedTOSW_s3)) {
368c89b4642SGuokai Chen          popRedSsp_s3  := ptrDec(io.s3_meta.ssp)
369c89b4642SGuokai Chen          popRedSctr_s3 := spec_queue(popRedTOSR_s3.value).ctr
370c89b4642SGuokai Chen        }.otherwise {
371c89b4642SGuokai Chen          popRedSsp_s3  := ptrDec(io.s3_meta.ssp)
372c89b4642SGuokai Chen          popRedSctr_s3 := getCommitTop(ptrDec(io.s3_meta.ssp)).ctr
373c89b4642SGuokai Chen        }
374c89b4642SGuokai Chen        // We are deciding top for the next cycle, no need to use bypass here
375c89b4642SGuokai Chen        timingTop := getTop(popRedSsp_s3, popRedSctr_s3, popRedTOSR_s3, popRedTOSW_s3, false)
376c89b4642SGuokai Chen      }
377c89b4642SGuokai Chen    }.otherwise {
378c89b4642SGuokai Chen      // easy case
379c89b4642SGuokai Chen      val popSsp  = ssp
380c89b4642SGuokai Chen      val popSctr = sctr
381c89b4642SGuokai Chen      val popTOSR = TOSR
382c89b4642SGuokai Chen      val popTOSW = TOSW
383c89b4642SGuokai Chen      timingTop := getTop(popSsp, popSctr, popTOSR, popTOSW, false)
384c89b4642SGuokai Chen    }
385c89b4642SGuokai Chen    val diffTop = Mux(writeBypassValid, writeBypassEntry.retAddr, topEntry.retAddr)
386c89b4642SGuokai Chen
387c89b4642SGuokai Chen    XSPerfAccumulate("ras_top_mismatch", diffTop =/= timingTop.retAddr);
388c89b4642SGuokai Chen    // could diff when more pop than push and a commit stack is updated with inflight info
389c89b4642SGuokai Chen
390c89b4642SGuokai Chen    val realWriteEntry_next = RegEnable(writeEntry, io.s2_fire || io.redirect_isCall)
391c89b4642SGuokai Chen    val s3_missPushEntry    = Wire(new RASEntry)
392c89b4642SGuokai Chen    val s3_missPushAddr     = Wire(new RASPtr)
393c89b4642SGuokai Chen    val s3_missPushNos      = Wire(new RASPtr)
394c89b4642SGuokai Chen
395c89b4642SGuokai Chen    s3_missPushEntry.retAddr := io.s3_pushAddr
396cf7d6b7aSMuzi    s3_missPushEntry.ctr := Mux(
397cf7d6b7aSMuzi      s3TopEntry.retAddr === io.s3_pushAddr && s3TopEntry.ctr < ctrMax,
398cf7d6b7aSMuzi      io.s3_meta.sctr + 1.U,
399cf7d6b7aSMuzi      0.U
400cf7d6b7aSMuzi    )
401c89b4642SGuokai Chen    s3_missPushAddr := io.s3_meta.TOSW
402c89b4642SGuokai Chen    s3_missPushNos  := io.s3_meta.TOSR
403c89b4642SGuokai Chen
404cf7d6b7aSMuzi    realWriteEntry := Mux(
405cf7d6b7aSMuzi      io.redirect_isCall,
406cf7d6b7aSMuzi      realWriteEntry_next,
407cf7d6b7aSMuzi      Mux(io.s3_missed_push, s3_missPushEntry, realWriteEntry_next)
408cf7d6b7aSMuzi    )
409c89b4642SGuokai Chen
410cf7d6b7aSMuzi    val realWriteAddr_next = RegEnable(
411cf7d6b7aSMuzi      Mux(io.redirect_valid && io.redirect_isCall, io.redirect_meta_TOSW, TOSW),
412cf7d6b7aSMuzi      io.s2_fire || (io.redirect_valid && io.redirect_isCall)
413cf7d6b7aSMuzi    )
414cf7d6b7aSMuzi    val realWriteAddr =
415cf7d6b7aSMuzi      Mux(io.redirect_isCall, realWriteAddr_next, Mux(io.s3_missed_push, s3_missPushAddr, realWriteAddr_next))
416cf7d6b7aSMuzi    val realNos_next = RegEnable(
417cf7d6b7aSMuzi      Mux(io.redirect_valid && io.redirect_isCall, io.redirect_meta_TOSR, TOSR),
418cf7d6b7aSMuzi      io.s2_fire || (io.redirect_valid && io.redirect_isCall)
419cf7d6b7aSMuzi    )
420cf7d6b7aSMuzi    val realNos = Mux(io.redirect_isCall, realNos_next, Mux(io.s3_missed_push, s3_missPushNos, realNos_next))
421c89b4642SGuokai Chen
422cf7d6b7aSMuzi    realPush := (io.s3_fire && (!io.s3_cancel && RegEnable(
423cf7d6b7aSMuzi      io.spec_push_valid,
424cf7d6b7aSMuzi      io.s2_fire
425cf7d6b7aSMuzi    ) || io.s3_missed_push)) || RegNext(io.redirect_valid && io.redirect_isCall)
426c89b4642SGuokai Chen
427c89b4642SGuokai Chen    when(realPush) {
428c89b4642SGuokai Chen      spec_queue(realWriteAddr.value) := realWriteEntry
429c89b4642SGuokai Chen      spec_nos(realWriteAddr.value)   := realNos
430c89b4642SGuokai Chen    }
431c89b4642SGuokai Chen
432cf7d6b7aSMuzi    def specPush(
433cf7d6b7aSMuzi        retAddr:     UInt,
434cf7d6b7aSMuzi        currentSsp:  UInt,
435cf7d6b7aSMuzi        currentSctr: UInt,
436cf7d6b7aSMuzi        currentTOSR: RASPtr,
437cf7d6b7aSMuzi        currentTOSW: RASPtr,
438cf7d6b7aSMuzi        topEntry:    RASEntry
439cf7d6b7aSMuzi    ) = {
440c89b4642SGuokai Chen      TOSR := currentTOSW
441c89b4642SGuokai Chen      TOSW := specPtrInc(currentTOSW)
442c89b4642SGuokai Chen      // spec sp and ctr should always be maintained
443c89b4642SGuokai Chen      when(topEntry.retAddr === retAddr && currentSctr < ctrMax) {
444c89b4642SGuokai Chen        sctr := currentSctr + 1.U
445c89b4642SGuokai Chen      }.otherwise {
446c89b4642SGuokai Chen        ssp  := ptrInc(currentSsp)
447c89b4642SGuokai Chen        sctr := 0.U
448c89b4642SGuokai Chen      }
449c89b4642SGuokai Chen    }
450c89b4642SGuokai Chen
451c89b4642SGuokai Chen    when(io.spec_push_valid) {
452c89b4642SGuokai Chen      specPush(io.spec_push_addr, ssp, sctr, TOSR, TOSW, topEntry)
453c89b4642SGuokai Chen    }
454cf7d6b7aSMuzi    def specPop(
455cf7d6b7aSMuzi        currentSsp:    UInt,
456cf7d6b7aSMuzi        currentSctr:   UInt,
457cf7d6b7aSMuzi        currentTOSR:   RASPtr,
458cf7d6b7aSMuzi        currentTOSW:   RASPtr,
459cf7d6b7aSMuzi        currentTopNos: RASPtr
460cf7d6b7aSMuzi    ) = {
461c89b4642SGuokai Chen      // TOSR is only maintained when spec queue is not empty
462c89b4642SGuokai Chen      when(TOSRinRange(currentTOSR, currentTOSW)) {
463c89b4642SGuokai Chen        TOSR := currentTopNos
464c89b4642SGuokai Chen      }
465c89b4642SGuokai Chen      // spec sp and ctr should always be maintained
466c89b4642SGuokai Chen      when(currentSctr > 0.U) {
467c89b4642SGuokai Chen        sctr := currentSctr - 1.U
468c89b4642SGuokai Chen      }.elsewhen(TOSRinRange(currentTopNos, currentTOSW)) {
469c89b4642SGuokai Chen        // in range, use inflight data
470c89b4642SGuokai Chen        ssp  := ptrDec(currentSsp)
471c89b4642SGuokai Chen        sctr := spec_queue(currentTopNos.value).ctr
472c89b4642SGuokai Chen      }.otherwise {
473c89b4642SGuokai Chen        // NOS not in range, use commit data
474c89b4642SGuokai Chen        ssp  := ptrDec(currentSsp)
475c89b4642SGuokai Chen        sctr := getCommitTop(ptrDec(currentSsp)).ctr
476c89b4642SGuokai Chen        // in overflow state, we cannot determine the next sctr, sctr here is not accurate
477c89b4642SGuokai Chen      }
478c89b4642SGuokai Chen    }
479c89b4642SGuokai Chen    when(io.spec_pop_valid) {
480c89b4642SGuokai Chen      specPop(ssp, sctr, TOSR, TOSW, topNos)
481c89b4642SGuokai Chen    }
482c89b4642SGuokai Chen
483c89b4642SGuokai Chen    // io.spec_pop_addr := Mux(writeBypassValid, writeBypassEntry.retAddr, topEntry.retAddr)
484c89b4642SGuokai Chen
485c89b4642SGuokai Chen    io.spec_pop_addr := timingTop.retAddr
486c89b4642SGuokai Chen    io.BOS           := BOS
487c89b4642SGuokai Chen    io.TOSW          := TOSW
488c89b4642SGuokai Chen    io.TOSR          := TOSR
489c89b4642SGuokai Chen    io.NOS           := topNos
490c89b4642SGuokai Chen    io.ssp           := ssp
491c89b4642SGuokai Chen    io.sctr          := sctr
492c89b4642SGuokai Chen    io.nsp           := nsp
493c89b4642SGuokai Chen
494c89b4642SGuokai Chen    when(io.s3_cancel) {
495c89b4642SGuokai Chen      // recovery of all related pointers
496c89b4642SGuokai Chen      TOSR := io.s3_meta.TOSR
497c89b4642SGuokai Chen      TOSW := io.s3_meta.TOSW
498c89b4642SGuokai Chen      ssp  := io.s3_meta.ssp
499c89b4642SGuokai Chen      sctr := io.s3_meta.sctr
500c89b4642SGuokai Chen
501c89b4642SGuokai Chen      // for missing pop, we also need to do a pop here
502c89b4642SGuokai Chen      when(io.s3_missed_pop) {
503c89b4642SGuokai Chen        specPop(io.s3_meta.ssp, io.s3_meta.sctr, io.s3_meta.TOSR, io.s3_meta.TOSW, io.s3_meta.NOS)
504c89b4642SGuokai Chen      }
505c89b4642SGuokai Chen      when(io.s3_missed_push) {
506c89b4642SGuokai Chen        // do not use any bypass from f2
507c89b4642SGuokai Chen        specPush(io.s3_pushAddr, io.s3_meta.ssp, io.s3_meta.sctr, io.s3_meta.TOSR, io.s3_meta.TOSW, s3TopEntry)
508c89b4642SGuokai Chen      }
509c89b4642SGuokai Chen    }
510c89b4642SGuokai Chen
511c89b4642SGuokai Chen    val commitTop = commit_stack(nsp)
512c89b4642SGuokai Chen
513c89b4642SGuokai Chen    when(io.commit_pop_valid) {
514c89b4642SGuokai Chen
515c89b4642SGuokai Chen      val nsp_update = Wire(UInt(log2Up(rasSize).W))
516c89b4642SGuokai Chen      when(io.commit_meta_ssp =/= nsp) {
517c89b4642SGuokai Chen        // force set nsp to commit ssp to avoid permanent errors
518c89b4642SGuokai Chen        nsp_update := io.commit_meta_ssp
519c89b4642SGuokai Chen      }.otherwise {
520c89b4642SGuokai Chen        nsp_update := nsp
521c89b4642SGuokai Chen      }
522c89b4642SGuokai Chen
523c89b4642SGuokai Chen      // if ctr > 0, --ctr in stack, otherwise --nsp
524c89b4642SGuokai Chen      when(commitTop.ctr > 0.U) {
525c89b4642SGuokai Chen        commit_stack(nsp_update).ctr := commitTop.ctr - 1.U
526c89b4642SGuokai Chen        nsp                          := nsp_update
527c89b4642SGuokai Chen      }.otherwise {
528c89b4642SGuokai Chen        nsp := ptrDec(nsp_update);
529c89b4642SGuokai Chen      }
530c89b4642SGuokai Chen      // XSError(io.commit_meta_ssp =/= nsp, "nsp mismatch with expected ssp")
531c89b4642SGuokai Chen    }
532c89b4642SGuokai Chen
533c89b4642SGuokai Chen    val commit_push_addr = spec_queue(io.commit_meta_TOSW.value).retAddr
534c89b4642SGuokai Chen
535c89b4642SGuokai Chen    when(io.commit_push_valid) {
536c89b4642SGuokai Chen      val nsp_update = Wire(UInt(log2Up(rasSize).W))
537c89b4642SGuokai Chen      when(io.commit_meta_ssp =/= nsp) {
538c89b4642SGuokai Chen        // force set nsp to commit ssp to avoid permanent errors
539c89b4642SGuokai Chen        nsp_update := io.commit_meta_ssp
540c89b4642SGuokai Chen      }.otherwise {
541c89b4642SGuokai Chen        nsp_update := nsp
542c89b4642SGuokai Chen      }
543c89b4642SGuokai Chen      // if ctr < max && topAddr == push addr, ++ctr, otherwise ++nsp
544c89b4642SGuokai Chen      when(commitTop.ctr < ctrMax && commitTop.retAddr === commit_push_addr) {
545c89b4642SGuokai Chen        commit_stack(nsp_update).ctr := commitTop.ctr + 1.U
546c89b4642SGuokai Chen        nsp                          := nsp_update
547c89b4642SGuokai Chen      }.otherwise {
548c89b4642SGuokai Chen        nsp                                      := ptrInc(nsp_update)
549c89b4642SGuokai Chen        commit_stack(ptrInc(nsp_update)).retAddr := commit_push_addr
550c89b4642SGuokai Chen        commit_stack(ptrInc(nsp_update)).ctr     := 0.U
551c89b4642SGuokai Chen      }
552a8810fc6Smy-mayfly
553c89b4642SGuokai Chen      // XSError(io.commit_meta_ssp =/= nsp, "nsp mismatch with expected ssp")
554c89b4642SGuokai Chen      // XSError(io.commit_push_addr =/= commit_push_addr, "addr from commit mismatch with addr from spec")
555c89b4642SGuokai Chen    }
556c89b4642SGuokai Chen
557c776f0d5Smy-mayfly    when(io.commit_push_valid) {
558c776f0d5Smy-mayfly      BOS := io.commit_meta_TOSW
559c776f0d5Smy-mayfly    }.elsewhen(io.commit_valid && (distanceBetween(io.commit_meta_TOSW, BOS) > 2.U)) {
560c776f0d5Smy-mayfly      BOS := specPtrDec(io.commit_meta_TOSW)
561c776f0d5Smy-mayfly    }
562c3d62b63SEaston Man    XSError(
563c3d62b63SEaston Man      io.commit_valid && (distanceBetween(io.commit_meta_TOSW, BOS) > 2.U),
564c3d62b63SEaston Man      "The use of inference queue of the RAS module has unexpected situations"
565c3d62b63SEaston Man    )
566c776f0d5Smy-mayfly
567c89b4642SGuokai Chen    when(io.redirect_valid) {
568c89b4642SGuokai Chen      TOSR := io.redirect_meta_TOSR
569c89b4642SGuokai Chen      TOSW := io.redirect_meta_TOSW
570c89b4642SGuokai Chen      ssp  := io.redirect_meta_ssp
571c89b4642SGuokai Chen      sctr := io.redirect_meta_sctr
572c89b4642SGuokai Chen
573c89b4642SGuokai Chen      when(io.redirect_isCall) {
574cf7d6b7aSMuzi        specPush(
575cf7d6b7aSMuzi          io.redirect_callAddr,
576cf7d6b7aSMuzi          io.redirect_meta_ssp,
577cf7d6b7aSMuzi          io.redirect_meta_sctr,
578cf7d6b7aSMuzi          io.redirect_meta_TOSR,
579cf7d6b7aSMuzi          io.redirect_meta_TOSW,
580cf7d6b7aSMuzi          redirectTopEntry
581cf7d6b7aSMuzi        )
582c89b4642SGuokai Chen      }
583c89b4642SGuokai Chen      when(io.redirect_isRet) {
584cf7d6b7aSMuzi        specPop(
585cf7d6b7aSMuzi          io.redirect_meta_ssp,
586cf7d6b7aSMuzi          io.redirect_meta_sctr,
587cf7d6b7aSMuzi          io.redirect_meta_TOSR,
588cf7d6b7aSMuzi          io.redirect_meta_TOSW,
589cf7d6b7aSMuzi          redirectTopNos
590cf7d6b7aSMuzi        )
591c89b4642SGuokai Chen      }
592c89b4642SGuokai Chen    }
593c89b4642SGuokai Chen
594*9928cec7Szhou tao    when(distanceBetween(TOSW, BOS) > (rasSpecSize - 2).U) {
595a8810fc6Smy-mayfly      spec_near_overflowed := true.B
596a8810fc6Smy-mayfly    }.otherwise {
597a8810fc6Smy-mayfly      spec_near_overflowed := false.B
598a8810fc6Smy-mayfly    }
599a8810fc6Smy-mayfly
600a8810fc6Smy-mayfly    io.spec_near_overflow := spec_near_overflowed
601a8810fc6Smy-mayfly    XSPerfAccumulate("spec_near_overflow", spec_near_overflowed)
602c89b4642SGuokai Chen    io.debug.commit_stack.zipWithIndex.foreach { case (a, i) => a := commit_stack(i) }
603c89b4642SGuokai Chen    io.debug.spec_nos.zipWithIndex.foreach { case (a, i) => a := spec_nos(i) }
604c89b4642SGuokai Chen    io.debug.spec_queue.zipWithIndex.foreach { case (a, i) => a := spec_queue(i) }
605c89b4642SGuokai Chen  }
606c89b4642SGuokai Chen
607c89b4642SGuokai Chen  val stack = Module(new RASStack(RasSize, RasSpecSize)).io
608c89b4642SGuokai Chen
609*9928cec7Szhou tao  val stack_near_overflow = stack.spec_near_overflow
610c89b4642SGuokai Chen  val s2_spec_push        = WireInit(false.B)
611c89b4642SGuokai Chen  val s2_spec_pop         = WireInit(false.B)
612c89b4642SGuokai Chen  val s2_full_pred        = io.in.bits.resp_in(0).s2.full_pred(2)
613c89b4642SGuokai Chen  // when last inst is an rvi call, fall through address would be set to the middle of it, so an addition is needed
614c89b4642SGuokai Chen  val s2_spec_new_addr = s2_full_pred.fallThroughAddr + Mux(s2_full_pred.last_may_be_rvi_call, 2.U, 0.U)
615*9928cec7Szhou tao  stack.spec_push_valid := s2_spec_push && !stack_near_overflow
616*9928cec7Szhou tao  stack.spec_pop_valid  := s2_spec_pop && !stack_near_overflow
617c89b4642SGuokai Chen  stack.spec_push_addr  := s2_spec_new_addr
618c89b4642SGuokai Chen
619c89b4642SGuokai Chen  // confirm that the call/ret is the taken cfi
620c89b4642SGuokai Chen  s2_spec_push := io.s2_fire(2) && s2_full_pred.hit_taken_on_call && !io.s3_redirect(2)
621c89b4642SGuokai Chen  s2_spec_pop  := io.s2_fire(2) && s2_full_pred.hit_taken_on_ret && !io.s3_redirect(2)
622c89b4642SGuokai Chen
623c89b4642SGuokai Chen  // val s2_jalr_target = io.out.s2.full_pred.jalr_target
624c89b4642SGuokai Chen  // val s2_last_target_in = s2_full_pred.targets.last
625c89b4642SGuokai Chen  // val s2_last_target_out = io.out.s2.full_pred(2).targets.last
626c89b4642SGuokai Chen  val s2_is_jalr = s2_full_pred.is_jalr
627c89b4642SGuokai Chen  val s2_is_ret  = s2_full_pred.is_ret
628c89b4642SGuokai Chen  val s2_top     = stack.spec_pop_addr
629c89b4642SGuokai Chen  // assert(is_jalr && is_ret || !is_ret)
630c89b4642SGuokai Chen  when(s2_is_ret && io.ctrl.ras_enable) {
631c89b4642SGuokai Chen    io.out.s2.full_pred.map(_.jalr_target).foreach(_ := s2_top)
632c89b4642SGuokai Chen    // FIXME: should use s1 globally
633c89b4642SGuokai Chen  }
634c89b4642SGuokai Chen  // s2_last_target_out := Mux(s2_is_jalr, s2_jalr_target, s2_last_target_in)
635c89b4642SGuokai Chen  io.out.s2.full_pred.zipWithIndex.foreach { case (a, i) =>
636cf7d6b7aSMuzi    a.targets.last := Mux(
637cf7d6b7aSMuzi      s2_is_jalr,
638cf7d6b7aSMuzi      io.out.s2.full_pred(i).jalr_target,
639cf7d6b7aSMuzi      io.in.bits.resp_in(0).s2.full_pred(i).targets.last
640cf7d6b7aSMuzi    )
641c89b4642SGuokai Chen  }
642c89b4642SGuokai Chen
643deb3a97eSGao-Zeyu  val s2_meta = Wire(new RASInternalMeta)
644c89b4642SGuokai Chen  s2_meta.ssp  := stack.ssp
645c89b4642SGuokai Chen  s2_meta.sctr := stack.sctr
646c89b4642SGuokai Chen  s2_meta.TOSR := stack.TOSR
647c89b4642SGuokai Chen  s2_meta.TOSW := stack.TOSW
648c89b4642SGuokai Chen  s2_meta.NOS  := stack.NOS
649c89b4642SGuokai Chen
650c89b4642SGuokai Chen  val s3_top           = RegEnable(stack.spec_pop_addr, io.s2_fire(2))
651c89b4642SGuokai Chen  val s3_spec_new_addr = RegEnable(s2_spec_new_addr, io.s2_fire(2))
652c89b4642SGuokai Chen
653c6a44c35Smy-mayfly  // val s3_jalr_target = io.out.s3.full_pred.jalr_target
654c6a44c35Smy-mayfly  // val s3_last_target_in = io.in.bits.resp_in(0).s3.full_pred(2).targets.last
655c6a44c35Smy-mayfly  // val s3_last_target_out = io.out.s3.full_pred(2).targets.last
656cf7d6b7aSMuzi  val s3_is_jalr =
657cf7d6b7aSMuzi    io.in.bits.resp_in(0).s3.full_pred(2).is_jalr && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr
658a1c30bb9Smy-mayfly  val s3_is_ret = io.in.bits.resp_in(0).s3.full_pred(2).is_ret && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr
659c89b4642SGuokai Chen  // assert(is_jalr && is_ret || !is_ret)
660c89b4642SGuokai Chen  when(s3_is_ret && io.ctrl.ras_enable) {
661c89b4642SGuokai Chen    io.out.s3.full_pred.map(_.jalr_target).foreach(_ := s3_top)
662c89b4642SGuokai Chen    // FIXME: should use s1 globally
663c89b4642SGuokai Chen  }
664c89b4642SGuokai Chen  // s3_last_target_out := Mux(s3_is_jalr, s3_jalr_target, s3_last_target_in)
665c89b4642SGuokai Chen  io.out.s3.full_pred.zipWithIndex.foreach { case (a, i) =>
666cf7d6b7aSMuzi    a.targets.last := Mux(
667cf7d6b7aSMuzi      s3_is_jalr,
668cf7d6b7aSMuzi      io.out.s3.full_pred(i).jalr_target,
669cf7d6b7aSMuzi      io.in.bits.resp_in(0).s3.full_pred(i).targets.last
670cf7d6b7aSMuzi    )
671c89b4642SGuokai Chen  }
672c89b4642SGuokai Chen
673c89b4642SGuokai Chen  val s3_pushed_in_s2 = RegEnable(s2_spec_push, io.s2_fire(2))
674c89b4642SGuokai Chen  val s3_popped_in_s2 = RegEnable(s2_spec_pop, io.s2_fire(2))
675cf7d6b7aSMuzi  val s3_push =
676cf7d6b7aSMuzi    io.in.bits.resp_in(0).s3.full_pred(2).hit_taken_on_call && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr
677cf7d6b7aSMuzi  val s3_pop =
678cf7d6b7aSMuzi    io.in.bits.resp_in(0).s3.full_pred(2).hit_taken_on_ret && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr
679c89b4642SGuokai Chen
680c89b4642SGuokai Chen  val s3_cancel = io.s3_fire(2) && (s3_pushed_in_s2 =/= s3_push || s3_popped_in_s2 =/= s3_pop)
681c89b4642SGuokai Chen  stack.s2_fire := io.s2_fire(2)
682c89b4642SGuokai Chen  stack.s3_fire := io.s3_fire(2)
683c89b4642SGuokai Chen
684*9928cec7Szhou tao  stack.s3_cancel := s3_cancel && !stack_near_overflow
685c89b4642SGuokai Chen
686c89b4642SGuokai Chen  val s3_meta = RegEnable(s2_meta, io.s2_fire(2))
687c89b4642SGuokai Chen
688c89b4642SGuokai Chen  stack.s3_meta        := s3_meta
689c89b4642SGuokai Chen  stack.s3_missed_pop  := s3_pop && !s3_popped_in_s2
690c89b4642SGuokai Chen  stack.s3_missed_push := s3_push && !s3_pushed_in_s2
691c89b4642SGuokai Chen  stack.s3_pushAddr    := s3_spec_new_addr
692c89b4642SGuokai Chen
693c89b4642SGuokai Chen  // no longer need the top Entry, but TOSR, TOSW, ssp sctr
694c89b4642SGuokai Chen  // TODO: remove related signals
695deb3a97eSGao-Zeyu
696deb3a97eSGao-Zeyu  val last_stage_meta = Wire(new RASMeta)
697deb3a97eSGao-Zeyu  last_stage_meta.ssp  := s3_meta.ssp
698deb3a97eSGao-Zeyu  last_stage_meta.TOSW := s3_meta.TOSW
699deb3a97eSGao-Zeyu
700c89b4642SGuokai Chen  io.out.last_stage_spec_info.sctr    := s3_meta.sctr
701c89b4642SGuokai Chen  io.out.last_stage_spec_info.ssp     := s3_meta.ssp
702c89b4642SGuokai Chen  io.out.last_stage_spec_info.TOSW    := s3_meta.TOSW
703c89b4642SGuokai Chen  io.out.last_stage_spec_info.TOSR    := s3_meta.TOSR
704c89b4642SGuokai Chen  io.out.last_stage_spec_info.NOS     := s3_meta.NOS
705c89b4642SGuokai Chen  io.out.last_stage_spec_info.topAddr := s3_top
706deb3a97eSGao-Zeyu  io.out.last_stage_meta              := last_stage_meta.asUInt
707c89b4642SGuokai Chen
7087af6acb0SEaston Man  val redirect    = RegNextWithEnable(io.redirect)
709c89b4642SGuokai Chen  val do_recover  = redirect.valid
710c89b4642SGuokai Chen  val recover_cfi = redirect.bits.cfiUpdate
711c89b4642SGuokai Chen
712d1394225Szhou tao  val retMissPred  = do_recover && redirect.bits.level === 0.U && recover_cfi.pd.isRet && recover_cfi.pd.valid
713d1394225Szhou tao  val callMissPred = do_recover && redirect.bits.level === 0.U && recover_cfi.pd.isCall && recover_cfi.pd.valid
714c89b4642SGuokai Chen  // when we mispredict a call, we must redo a push operation
715c89b4642SGuokai Chen  // similarly, when we mispredict a return, we should redo a pop
716*9928cec7Szhou tao  val stack_TOSW    = stack.TOSW
717*9928cec7Szhou tao  val redirect_TOSW = recover_cfi.TOSW
718*9928cec7Szhou tao  stack.redirect_valid     := do_recover && (isBefore(redirect_TOSW, stack_TOSW) || !stack_near_overflow)
719c89b4642SGuokai Chen  stack.redirect_isCall    := callMissPred
720c89b4642SGuokai Chen  stack.redirect_isRet     := retMissPred
721c89b4642SGuokai Chen  stack.redirect_meta_ssp  := recover_cfi.ssp
722c89b4642SGuokai Chen  stack.redirect_meta_sctr := recover_cfi.sctr
723c89b4642SGuokai Chen  stack.redirect_meta_TOSW := recover_cfi.TOSW
724c89b4642SGuokai Chen  stack.redirect_meta_TOSR := recover_cfi.TOSR
725c89b4642SGuokai Chen  stack.redirect_meta_NOS  := recover_cfi.NOS
726c89b4642SGuokai Chen  stack.redirect_callAddr  := recover_cfi.pc + Mux(recover_cfi.pd.isRVC, 2.U, 4.U)
727c89b4642SGuokai Chen
72803426fe2Spengxiao  val updateValid = RegNext(io.update.valid, init = false.B)
72903426fe2Spengxiao  val update      = Wire(new BranchPredictionUpdate)
73003426fe2Spengxiao  update := RegEnable(io.update.bits, io.update.valid)
73103426fe2Spengxiao
73203426fe2Spengxiao  // The pc register has been moved outside of predictor, pc field of update bundle and other update data are not in the same stage
73303426fe2Spengxiao  // so io.update.bits.pc is used directly here
73403426fe2Spengxiao  val update_pc = io.update.bits.pc
73503426fe2Spengxiao
736a6696f06Szhou tao  // full core power down sequence need 'val updateMeta = RegEnable(io.update.bits.meta.asTypeOf(new RASMeta), io.update.valid)' to be
737a6696f06Szhou tao  // 'val updateMeta = RegEnable(io.update.bits.meta.asTypeOf(new RASMeta), io.update.valid && (io.update.bits.is_call || io.update.bits.is_ret))',
738a6696f06Szhou tao  // but the fault-tolerance mechanism of the return stack needs to be updated in time. Using an unexpected old value on reset will cause errors.
739a6696f06Szhou tao  // Only 9 registers have clock gate efficiency affected, so we relaxed the control signals.
740a6696f06Szhou tao  val updateMeta = RegEnable(io.update.bits.meta.asTypeOf(new RASMeta), io.update.valid)
741c89b4642SGuokai Chen
742c776f0d5Smy-mayfly  stack.commit_valid      := updateValid
743c89b4642SGuokai Chen  stack.commit_push_valid := updateValid && update.is_call_taken
744c89b4642SGuokai Chen  stack.commit_pop_valid  := updateValid && update.is_ret_taken
74503426fe2Spengxiao  stack.commit_push_addr := update.ftb_entry.getFallThrough(update_pc) + Mux(
746cf7d6b7aSMuzi    update.ftb_entry.last_may_be_rvi_call,
747cf7d6b7aSMuzi    2.U,
748cf7d6b7aSMuzi    0.U
749cf7d6b7aSMuzi  )
750c89b4642SGuokai Chen  stack.commit_meta_TOSW := updateMeta.TOSW
751c89b4642SGuokai Chen  stack.commit_meta_ssp  := updateMeta.ssp
752c89b4642SGuokai Chen
753c89b4642SGuokai Chen  XSPerfAccumulate("ras_s3_cancel", s3_cancel)
754c89b4642SGuokai Chen  XSPerfAccumulate("ras_redirect_recover", redirect.valid)
755c89b4642SGuokai Chen  XSPerfAccumulate("ras_s3_and_redirect_recover_at_the_same_time", s3_cancel && redirect.valid)
756c89b4642SGuokai Chen
757c89b4642SGuokai Chen  val spec_debug = stack.debug
758c89b4642SGuokai Chen  XSDebug(io.s2_fire(2), "----------------RAS----------------\n")
759c89b4642SGuokai Chen  XSDebug(io.s2_fire(2), " TopRegister: 0x%x\n", stack.spec_pop_addr)
760c89b4642SGuokai Chen  XSDebug(io.s2_fire(2), "  index       addr           ctr           nos (spec part)\n")
761c89b4642SGuokai Chen  for (i <- 0 until RasSpecSize) {
762cf7d6b7aSMuzi    XSDebug(
763cf7d6b7aSMuzi      io.s2_fire(2),
764cf7d6b7aSMuzi      "  (%d)   0x%x      %d       %d",
765cf7d6b7aSMuzi      i.U,
766cf7d6b7aSMuzi      spec_debug.spec_queue(i).retAddr,
767cf7d6b7aSMuzi      spec_debug.spec_queue(i).ctr,
768cf7d6b7aSMuzi      spec_debug.spec_nos(i).value
769cf7d6b7aSMuzi    )
7708b33cd30Sklin02    XSDebug(io.s2_fire(2) && i.U === stack.TOSW.value, "   <----TOSW")
7718b33cd30Sklin02    XSDebug(io.s2_fire(2) && i.U === stack.TOSR.value, "   <----TOSR")
7728b33cd30Sklin02    XSDebug(io.s2_fire(2) && i.U === stack.BOS.value, "   <----BOS")
773c89b4642SGuokai Chen    XSDebug(io.s2_fire(2), "\n")
774c89b4642SGuokai Chen  }
775c89b4642SGuokai Chen  XSDebug(io.s2_fire(2), "  index       addr           ctr   (committed part)\n")
776c89b4642SGuokai Chen  for (i <- 0 until RasSize) {
777cf7d6b7aSMuzi    XSDebug(
778cf7d6b7aSMuzi      io.s2_fire(2),
779cf7d6b7aSMuzi      "  (%d)   0x%x      %d",
780cf7d6b7aSMuzi      i.U,
781cf7d6b7aSMuzi      spec_debug.commit_stack(i).retAddr,
782cf7d6b7aSMuzi      spec_debug.commit_stack(i).ctr
783cf7d6b7aSMuzi    )
7848b33cd30Sklin02    XSDebug(io.s2_fire(2) && i.U === stack.ssp, "   <----ssp")
7858b33cd30Sklin02    XSDebug(io.s2_fire(2) && i.U === stack.nsp, "   <----nsp")
786c89b4642SGuokai Chen    XSDebug(io.s2_fire(2), "\n")
787c89b4642SGuokai Chen  }
788c89b4642SGuokai Chen  /*
789c89b4642SGuokai Chen  XSDebug(s2_spec_push, "s2_spec_push  inAddr: 0x%x  inCtr: %d |  allocNewEntry:%d |   sp:%d \n",
790c89b4642SGuokai Chen  s2_spec_new_addr,spec_debug.spec_push_entry.ctr,spec_debug.spec_alloc_new,spec_debug.sp.asUInt)
791c89b4642SGuokai Chen  XSDebug(s2_spec_pop, "s2_spec_pop  outAddr: 0x%x \n",io.out.s2.getTarget)
792c89b4642SGuokai Chen  val s3_recover_entry = spec_debug.recover_push_entry
793c89b4642SGuokai Chen  XSDebug(s3_recover && s3_push, "s3_recover_push  inAddr: 0x%x  inCtr: %d |  allocNewEntry:%d |   sp:%d \n",
794c89b4642SGuokai Chen    s3_recover_entry.retAddr, s3_recover_entry.ctr, spec_debug.recover_alloc_new, s3_sp.asUInt)
795c89b4642SGuokai Chen  XSDebug(s3_recover && s3_pop, "s3_recover_pop  outAddr: 0x%x \n",io.out.s3.getTarget)
796c89b4642SGuokai Chen  val redirectUpdate = redirect.bits.cfiUpdate
797c89b4642SGuokai Chen  XSDebug(do_recover && callMissPred, "redirect_recover_push\n")
798c89b4642SGuokai Chen  XSDebug(do_recover && retMissPred, "redirect_recover_pop\n")
799c89b4642SGuokai Chen  XSDebug(do_recover, "redirect_recover(SP:%d retAddr:%x ctr:%d) \n",
800c89b4642SGuokai Chen      redirectUpdate.rasSp,redirectUpdate.rasEntry.retAddr,redirectUpdate.rasEntry.ctr)
801c89b4642SGuokai Chen   */
802c89b4642SGuokai Chen
803c89b4642SGuokai Chen  generatePerfEvent()
804c89b4642SGuokai Chen}
805