xref: /XiangShan/src/main/scala/xiangshan/frontend/RAS.scala (revision 09c6f1dd83448ac60a0bb7980c3e4e524df66de0)
1*09c6f1ddSLingrui98/***************************************************************************************
2*09c6f1ddSLingrui98* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3*09c6f1ddSLingrui98* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*09c6f1ddSLingrui98*
5*09c6f1ddSLingrui98* XiangShan is licensed under Mulan PSL v2.
6*09c6f1ddSLingrui98* You can use this software according to the terms and conditions of the Mulan PSL v2.
7*09c6f1ddSLingrui98* You may obtain a copy of Mulan PSL v2 at:
8*09c6f1ddSLingrui98*          http://license.coscl.org.cn/MulanPSL2
9*09c6f1ddSLingrui98*
10*09c6f1ddSLingrui98* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11*09c6f1ddSLingrui98* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12*09c6f1ddSLingrui98* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*09c6f1ddSLingrui98*
14*09c6f1ddSLingrui98* See the Mulan PSL v2 for more details.
15*09c6f1ddSLingrui98***************************************************************************************/
16*09c6f1ddSLingrui98
17*09c6f1ddSLingrui98package xiangshan.frontend
18*09c6f1ddSLingrui98
19*09c6f1ddSLingrui98import chipsalliance.rocketchip.config.Parameters
20*09c6f1ddSLingrui98import chisel3._
21*09c6f1ddSLingrui98import chisel3.experimental.chiselName
22*09c6f1ddSLingrui98import chisel3.util._
23*09c6f1ddSLingrui98import utils._
24*09c6f1ddSLingrui98import xiangshan._
25*09c6f1ddSLingrui98
26*09c6f1ddSLingrui98class RASEntry()(implicit p: Parameters) extends XSBundle {
27*09c6f1ddSLingrui98    val retAddr = UInt(VAddrBits.W)
28*09c6f1ddSLingrui98    val ctr = UInt(8.W) // layer of nested call functions
29*09c6f1ddSLingrui98}
30*09c6f1ddSLingrui98
31*09c6f1ddSLingrui98@chiselName
32*09c6f1ddSLingrui98class RAS(implicit p: Parameters) extends BasePredictor {
33*09c6f1ddSLingrui98  object RASEntry {
34*09c6f1ddSLingrui98    def apply(retAddr: UInt, ctr: UInt): RASEntry = {
35*09c6f1ddSLingrui98      val e = Wire(new RASEntry)
36*09c6f1ddSLingrui98      e.retAddr := retAddr
37*09c6f1ddSLingrui98      e.ctr := ctr
38*09c6f1ddSLingrui98      e
39*09c6f1ddSLingrui98    }
40*09c6f1ddSLingrui98  }
41*09c6f1ddSLingrui98
42*09c6f1ddSLingrui98  @chiselName
43*09c6f1ddSLingrui98  class RASStack(val rasSize: Int) extends XSModule {
44*09c6f1ddSLingrui98    val io = IO(new Bundle {
45*09c6f1ddSLingrui98      val push_valid = Input(Bool())
46*09c6f1ddSLingrui98      val pop_valid = Input(Bool())
47*09c6f1ddSLingrui98      val spec_new_addr = Input(UInt(VAddrBits.W))
48*09c6f1ddSLingrui98
49*09c6f1ddSLingrui98      val recover_sp = Input(UInt(log2Up(rasSize).W))
50*09c6f1ddSLingrui98      val recover_top = Input(new RASEntry)
51*09c6f1ddSLingrui98      val recover_valid = Input(Bool())
52*09c6f1ddSLingrui98      val recover_push = Input(Bool())
53*09c6f1ddSLingrui98      val recover_pop = Input(Bool())
54*09c6f1ddSLingrui98      val recover_new_addr = Input(UInt(VAddrBits.W))
55*09c6f1ddSLingrui98
56*09c6f1ddSLingrui98      val sp = Output(UInt(log2Up(rasSize).W))
57*09c6f1ddSLingrui98      val top = Output(new RASEntry)
58*09c6f1ddSLingrui98    })
59*09c6f1ddSLingrui98
60*09c6f1ddSLingrui98    val debugIO = IO(new Bundle{
61*09c6f1ddSLingrui98        val push_entry = Output(new RASEntry)
62*09c6f1ddSLingrui98        val alloc_new = Output(Bool())
63*09c6f1ddSLingrui98        val sp = Output(UInt(log2Up(rasSize).W))
64*09c6f1ddSLingrui98        val topRegister = Output(new RASEntry)
65*09c6f1ddSLingrui98        val out_mem = Output(Vec(RasSize, new RASEntry))
66*09c6f1ddSLingrui98    })
67*09c6f1ddSLingrui98
68*09c6f1ddSLingrui98    val stack = Mem(RasSize, new RASEntry)
69*09c6f1ddSLingrui98    val sp = RegInit(0.U(log2Up(rasSize).W))
70*09c6f1ddSLingrui98    val top = RegInit(0.U.asTypeOf(new RASEntry))
71*09c6f1ddSLingrui98    val topPtr = RegInit(0.U(log2Up(rasSize).W))
72*09c6f1ddSLingrui98
73*09c6f1ddSLingrui98    def ptrInc(ptr: UInt) = Mux(ptr === (rasSize-1).U, 0.U, ptr + 1.U)
74*09c6f1ddSLingrui98    def ptrDec(ptr: UInt) = Mux(ptr === 0.U, (rasSize-1).U, ptr - 1.U)
75*09c6f1ddSLingrui98
76*09c6f1ddSLingrui98    val alloc_new = io.spec_new_addr =/= top.retAddr || top.ctr.andR
77*09c6f1ddSLingrui98    val recover_alloc_new = io.recover_new_addr =/= io.recover_top.retAddr || io.recover_top.ctr.andR
78*09c6f1ddSLingrui98
79*09c6f1ddSLingrui98    // TODO: fix overflow and underflow bugs
80*09c6f1ddSLingrui98    def update(recover: Bool)(do_push: Bool, do_pop: Bool, do_alloc_new: Bool,
81*09c6f1ddSLingrui98                              do_sp: UInt, do_top_ptr: UInt, do_new_addr: UInt,
82*09c6f1ddSLingrui98                              do_top: RASEntry) = {
83*09c6f1ddSLingrui98      when (do_push) {
84*09c6f1ddSLingrui98        when (do_alloc_new) {
85*09c6f1ddSLingrui98          sp     := ptrInc(do_sp)
86*09c6f1ddSLingrui98          topPtr := do_sp
87*09c6f1ddSLingrui98          top.retAddr := do_new_addr
88*09c6f1ddSLingrui98          top.ctr := 1.U
89*09c6f1ddSLingrui98          stack.write(do_sp, RASEntry(do_new_addr, 1.U))
90*09c6f1ddSLingrui98        }.otherwise {
91*09c6f1ddSLingrui98          when (recover) {
92*09c6f1ddSLingrui98            sp := do_sp
93*09c6f1ddSLingrui98            topPtr := do_top_ptr
94*09c6f1ddSLingrui98            top.retAddr := do_top.retAddr
95*09c6f1ddSLingrui98          }
96*09c6f1ddSLingrui98          top.ctr := do_top.ctr + 1.U
97*09c6f1ddSLingrui98          stack.write(do_top_ptr, RASEntry(do_new_addr, do_top.ctr + 1.U))
98*09c6f1ddSLingrui98        }
99*09c6f1ddSLingrui98      }.elsewhen (do_pop) {
100*09c6f1ddSLingrui98        when (do_top.ctr === 1.U) {
101*09c6f1ddSLingrui98          sp     := ptrDec(do_sp)
102*09c6f1ddSLingrui98          topPtr := ptrDec(do_top_ptr)
103*09c6f1ddSLingrui98          top := stack.read(ptrDec(do_top_ptr))
104*09c6f1ddSLingrui98        }.otherwise {
105*09c6f1ddSLingrui98          when (recover) {
106*09c6f1ddSLingrui98            sp := do_sp
107*09c6f1ddSLingrui98            topPtr := do_top_ptr
108*09c6f1ddSLingrui98            top.retAddr := do_top.retAddr
109*09c6f1ddSLingrui98          }
110*09c6f1ddSLingrui98          top.ctr := do_top.ctr - 1.U
111*09c6f1ddSLingrui98          stack.write(do_top_ptr, RASEntry(do_top.retAddr, do_top.ctr - 1.U))
112*09c6f1ddSLingrui98        }
113*09c6f1ddSLingrui98      }.otherwise {
114*09c6f1ddSLingrui98        when (recover) {
115*09c6f1ddSLingrui98          sp := do_sp
116*09c6f1ddSLingrui98          topPtr := do_top_ptr
117*09c6f1ddSLingrui98          top := do_top
118*09c6f1ddSLingrui98          stack.write(do_top_ptr, do_top)
119*09c6f1ddSLingrui98        }
120*09c6f1ddSLingrui98      }
121*09c6f1ddSLingrui98    }
122*09c6f1ddSLingrui98
123*09c6f1ddSLingrui98    update(io.recover_valid)(
124*09c6f1ddSLingrui98      Mux(io.recover_valid, io.recover_push,     io.push_valid),
125*09c6f1ddSLingrui98      Mux(io.recover_valid, io.recover_pop,      io.pop_valid),
126*09c6f1ddSLingrui98      Mux(io.recover_valid, recover_alloc_new,   alloc_new),
127*09c6f1ddSLingrui98      Mux(io.recover_valid, io.recover_sp,       sp),
128*09c6f1ddSLingrui98      Mux(io.recover_valid, io.recover_sp - 1.U, topPtr),
129*09c6f1ddSLingrui98      Mux(io.recover_valid, io.recover_new_addr, io.spec_new_addr),
130*09c6f1ddSLingrui98      Mux(io.recover_valid, io.recover_top,      top))
131*09c6f1ddSLingrui98
132*09c6f1ddSLingrui98    io.sp := sp
133*09c6f1ddSLingrui98    io.top := top
134*09c6f1ddSLingrui98
135*09c6f1ddSLingrui98    debugIO.push_entry := RASEntry(io.spec_new_addr, Mux(alloc_new, 1.U, top.ctr + 1.U))
136*09c6f1ddSLingrui98    debugIO.alloc_new := alloc_new
137*09c6f1ddSLingrui98    debugIO.sp := sp
138*09c6f1ddSLingrui98    debugIO.topRegister := top
139*09c6f1ddSLingrui98    for (i <- 0 until RasSize) {
140*09c6f1ddSLingrui98        debugIO.out_mem(i) := stack.read(i.U)
141*09c6f1ddSLingrui98    }
142*09c6f1ddSLingrui98  }
143*09c6f1ddSLingrui98
144*09c6f1ddSLingrui98  val spec = Module(new RASStack(RasSize))
145*09c6f1ddSLingrui98  val spec_ras = spec.io
146*09c6f1ddSLingrui98
147*09c6f1ddSLingrui98
148*09c6f1ddSLingrui98  val spec_push = WireInit(false.B)
149*09c6f1ddSLingrui98  val spec_pop = WireInit(false.B)
150*09c6f1ddSLingrui98  // val jump_is_first = io.callIdx.bits === 0.U
151*09c6f1ddSLingrui98  // val call_is_last_half = io.isLastHalfRVI && jump_is_first
152*09c6f1ddSLingrui98  // val spec_new_addr = packetAligned(io.pc.bits) + (io.callIdx.bits << instOffsetBits.U) + Mux( (io.isRVC | call_is_last_half) && HasCExtension.B, 2.U, 4.U)
153*09c6f1ddSLingrui98  val spec_new_addr = io.in.bits.resp_in(0).s2.fallThroughAddr
154*09c6f1ddSLingrui98  spec_ras.push_valid := spec_push
155*09c6f1ddSLingrui98  spec_ras.pop_valid  := spec_pop
156*09c6f1ddSLingrui98  spec_ras.spec_new_addr := spec_new_addr
157*09c6f1ddSLingrui98  val spec_top_addr = spec_ras.top.retAddr
158*09c6f1ddSLingrui98
159*09c6f1ddSLingrui98  // confirm that the call/ret is the taken cfi
160*09c6f1ddSLingrui98  spec_push := io.s2_fire && io.in.bits.resp_in(0).s2.hit_taken_on_call
161*09c6f1ddSLingrui98  spec_pop  := io.s2_fire && io.in.bits.resp_in(0).s2.hit_taken_on_ret
162*09c6f1ddSLingrui98
163*09c6f1ddSLingrui98  when (spec_pop) {
164*09c6f1ddSLingrui98    io.out.resp.s2.preds.jmp_target := spec_top_addr
165*09c6f1ddSLingrui98  }
166*09c6f1ddSLingrui98
167*09c6f1ddSLingrui98  io.out.resp.s2.rasSp  := spec_ras.sp
168*09c6f1ddSLingrui98  io.out.resp.s2.rasTop := spec_ras.top
169*09c6f1ddSLingrui98
170*09c6f1ddSLingrui98  io.out.resp.s3 := RegEnable(io.out.resp.s2, io.s2_fire)
171*09c6f1ddSLingrui98
172*09c6f1ddSLingrui98  val redirect = RegNext(io.redirect)
173*09c6f1ddSLingrui98  val do_recover = redirect.valid
174*09c6f1ddSLingrui98  val recover_cfi = redirect.bits.cfiUpdate
175*09c6f1ddSLingrui98
176*09c6f1ddSLingrui98  val retMissPred  = do_recover && redirect.bits.level === 0.U && recover_cfi.pd.isRet
177*09c6f1ddSLingrui98  val callMissPred = do_recover && redirect.bits.level === 0.U && recover_cfi.pd.isCall
178*09c6f1ddSLingrui98  // when we mispredict a call, we must redo a push operation
179*09c6f1ddSLingrui98  // similarly, when we mispredict a return, we should redo a pop
180*09c6f1ddSLingrui98  spec_ras.recover_valid := do_recover
181*09c6f1ddSLingrui98  spec_ras.recover_push := callMissPred
182*09c6f1ddSLingrui98  spec_ras.recover_pop  := retMissPred
183*09c6f1ddSLingrui98
184*09c6f1ddSLingrui98  spec_ras.recover_sp  := recover_cfi.rasSp
185*09c6f1ddSLingrui98  spec_ras.recover_top := recover_cfi.rasEntry
186*09c6f1ddSLingrui98  spec_ras.recover_new_addr := recover_cfi.pc + Mux(recover_cfi.pd.isRVC, 2.U, 4.U)
187*09c6f1ddSLingrui98
188*09c6f1ddSLingrui98  // TODO: back-up stack for ras
189*09c6f1ddSLingrui98  // use checkpoint to recover RAS
190*09c6f1ddSLingrui98
191*09c6f1ddSLingrui98  val spec_debug = spec.debugIO
192*09c6f1ddSLingrui98  XSDebug("----------------RAS----------------\n")
193*09c6f1ddSLingrui98  XSDebug(" TopRegister: 0x%x   %d \n",spec_debug.topRegister.retAddr,spec_debug.topRegister.ctr)
194*09c6f1ddSLingrui98  XSDebug("  index       addr           ctr \n")
195*09c6f1ddSLingrui98  for(i <- 0 until RasSize){
196*09c6f1ddSLingrui98      XSDebug("  (%d)   0x%x      %d",i.U,spec_debug.out_mem(i).retAddr,spec_debug.out_mem(i).ctr)
197*09c6f1ddSLingrui98      when(i.U === spec_debug.sp){XSDebug(false,true.B,"   <----sp")}
198*09c6f1ddSLingrui98      XSDebug(false,true.B,"\n")
199*09c6f1ddSLingrui98  }
200*09c6f1ddSLingrui98  XSDebug(spec_push, "(spec_ras)push  inAddr: 0x%x  inCtr: %d |  allocNewEntry:%d |   sp:%d \n",
201*09c6f1ddSLingrui98      spec_new_addr,spec_debug.push_entry.ctr,spec_debug.alloc_new,spec_debug.sp.asUInt)
202*09c6f1ddSLingrui98  XSDebug(spec_pop, "(spec_ras)pop  outAddr: 0x%x \n",io.out.resp.s2.target)
203*09c6f1ddSLingrui98  val redirectUpdate = redirect.bits.cfiUpdate
204*09c6f1ddSLingrui98  XSDebug("recoverValid:%d recover(SP:%d retAddr:%x ctr:%d) \n",
205*09c6f1ddSLingrui98      do_recover,redirectUpdate.rasSp,redirectUpdate.rasEntry.retAddr,redirectUpdate.rasEntry.ctr)
206*09c6f1ddSLingrui98}
207