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