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