xref: /XiangShan/src/main/scala/xiangshan/frontend/RAS.scala (revision 5df98e433cd3f6d01298881d7bad26b95a38989d)
109c6f1ddSLingrui98/***************************************************************************************
209c6f1ddSLingrui98* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
309c6f1ddSLingrui98* Copyright (c) 2020-2021 Peng Cheng Laboratory
409c6f1ddSLingrui98*
509c6f1ddSLingrui98* XiangShan is licensed under Mulan PSL v2.
609c6f1ddSLingrui98* You can use this software according to the terms and conditions of the Mulan PSL v2.
709c6f1ddSLingrui98* You may obtain a copy of Mulan PSL v2 at:
809c6f1ddSLingrui98*          http://license.coscl.org.cn/MulanPSL2
909c6f1ddSLingrui98*
1009c6f1ddSLingrui98* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
1109c6f1ddSLingrui98* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
1209c6f1ddSLingrui98* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
1309c6f1ddSLingrui98*
1409c6f1ddSLingrui98* See the Mulan PSL v2 for more details.
1509c6f1ddSLingrui98***************************************************************************************/
1609c6f1ddSLingrui98
1709c6f1ddSLingrui98package xiangshan.frontend
1809c6f1ddSLingrui98
1909c6f1ddSLingrui98import chipsalliance.rocketchip.config.Parameters
2009c6f1ddSLingrui98import chisel3._
2109c6f1ddSLingrui98import chisel3.experimental.chiselName
2209c6f1ddSLingrui98import chisel3.util._
2309c6f1ddSLingrui98import utils._
2409c6f1ddSLingrui98import xiangshan._
2509c6f1ddSLingrui98
2609c6f1ddSLingrui98class RASEntry()(implicit p: Parameters) extends XSBundle {
2709c6f1ddSLingrui98    val retAddr = UInt(VAddrBits.W)
2809c6f1ddSLingrui98    val ctr = UInt(8.W) // layer of nested call functions
2909c6f1ddSLingrui98}
3009c6f1ddSLingrui98
3109c6f1ddSLingrui98@chiselName
3209c6f1ddSLingrui98class RAS(implicit p: Parameters) extends BasePredictor {
3309c6f1ddSLingrui98  object RASEntry {
3409c6f1ddSLingrui98    def apply(retAddr: UInt, ctr: UInt): RASEntry = {
3509c6f1ddSLingrui98      val e = Wire(new RASEntry)
3609c6f1ddSLingrui98      e.retAddr := retAddr
3709c6f1ddSLingrui98      e.ctr := ctr
3809c6f1ddSLingrui98      e
3909c6f1ddSLingrui98    }
4009c6f1ddSLingrui98  }
4109c6f1ddSLingrui98
4209c6f1ddSLingrui98  @chiselName
4309c6f1ddSLingrui98  class RASStack(val rasSize: Int) extends XSModule {
4409c6f1ddSLingrui98    val io = IO(new Bundle {
4509c6f1ddSLingrui98      val push_valid = Input(Bool())
4609c6f1ddSLingrui98      val pop_valid = Input(Bool())
4709c6f1ddSLingrui98      val spec_new_addr = Input(UInt(VAddrBits.W))
4809c6f1ddSLingrui98
4909c6f1ddSLingrui98      val recover_sp = Input(UInt(log2Up(rasSize).W))
5009c6f1ddSLingrui98      val recover_top = Input(new RASEntry)
5109c6f1ddSLingrui98      val recover_valid = Input(Bool())
5209c6f1ddSLingrui98      val recover_push = Input(Bool())
5309c6f1ddSLingrui98      val recover_pop = Input(Bool())
5409c6f1ddSLingrui98      val recover_new_addr = Input(UInt(VAddrBits.W))
5509c6f1ddSLingrui98
5609c6f1ddSLingrui98      val sp = Output(UInt(log2Up(rasSize).W))
5709c6f1ddSLingrui98      val top = Output(new RASEntry)
5809c6f1ddSLingrui98    })
5909c6f1ddSLingrui98
6009c6f1ddSLingrui98    val debugIO = IO(new Bundle{
6109c6f1ddSLingrui98        val push_entry = Output(new RASEntry)
6209c6f1ddSLingrui98        val alloc_new = Output(Bool())
6309c6f1ddSLingrui98        val sp = Output(UInt(log2Up(rasSize).W))
6409c6f1ddSLingrui98        val topRegister = Output(new RASEntry)
6509c6f1ddSLingrui98        val out_mem = Output(Vec(RasSize, new RASEntry))
6609c6f1ddSLingrui98    })
6709c6f1ddSLingrui98
6809c6f1ddSLingrui98    val stack = Mem(RasSize, new RASEntry)
6909c6f1ddSLingrui98    val sp = RegInit(0.U(log2Up(rasSize).W))
7009c6f1ddSLingrui98    val top = RegInit(0.U.asTypeOf(new RASEntry))
7109c6f1ddSLingrui98    val topPtr = RegInit(0.U(log2Up(rasSize).W))
7209c6f1ddSLingrui98
7309c6f1ddSLingrui98    def ptrInc(ptr: UInt) = Mux(ptr === (rasSize-1).U, 0.U, ptr + 1.U)
7409c6f1ddSLingrui98    def ptrDec(ptr: UInt) = Mux(ptr === 0.U, (rasSize-1).U, ptr - 1.U)
7509c6f1ddSLingrui98
7609c6f1ddSLingrui98    val alloc_new = io.spec_new_addr =/= top.retAddr || top.ctr.andR
7709c6f1ddSLingrui98    val recover_alloc_new = io.recover_new_addr =/= io.recover_top.retAddr || io.recover_top.ctr.andR
7809c6f1ddSLingrui98
7909c6f1ddSLingrui98    // TODO: fix overflow and underflow bugs
8009c6f1ddSLingrui98    def update(recover: Bool)(do_push: Bool, do_pop: Bool, do_alloc_new: Bool,
8109c6f1ddSLingrui98                              do_sp: UInt, do_top_ptr: UInt, do_new_addr: UInt,
8209c6f1ddSLingrui98                              do_top: RASEntry) = {
8309c6f1ddSLingrui98      when (do_push) {
8409c6f1ddSLingrui98        when (do_alloc_new) {
8509c6f1ddSLingrui98          sp     := ptrInc(do_sp)
8609c6f1ddSLingrui98          topPtr := do_sp
8709c6f1ddSLingrui98          top.retAddr := do_new_addr
8809c6f1ddSLingrui98          top.ctr := 1.U
8909c6f1ddSLingrui98          stack.write(do_sp, RASEntry(do_new_addr, 1.U))
9009c6f1ddSLingrui98        }.otherwise {
9109c6f1ddSLingrui98          when (recover) {
9209c6f1ddSLingrui98            sp := do_sp
9309c6f1ddSLingrui98            topPtr := do_top_ptr
9409c6f1ddSLingrui98            top.retAddr := do_top.retAddr
9509c6f1ddSLingrui98          }
9609c6f1ddSLingrui98          top.ctr := do_top.ctr + 1.U
9709c6f1ddSLingrui98          stack.write(do_top_ptr, RASEntry(do_new_addr, do_top.ctr + 1.U))
9809c6f1ddSLingrui98        }
9909c6f1ddSLingrui98      }.elsewhen (do_pop) {
10009c6f1ddSLingrui98        when (do_top.ctr === 1.U) {
10109c6f1ddSLingrui98          sp     := ptrDec(do_sp)
10209c6f1ddSLingrui98          topPtr := ptrDec(do_top_ptr)
10309c6f1ddSLingrui98          top := stack.read(ptrDec(do_top_ptr))
10409c6f1ddSLingrui98        }.otherwise {
10509c6f1ddSLingrui98          when (recover) {
10609c6f1ddSLingrui98            sp := do_sp
10709c6f1ddSLingrui98            topPtr := do_top_ptr
10809c6f1ddSLingrui98            top.retAddr := do_top.retAddr
10909c6f1ddSLingrui98          }
11009c6f1ddSLingrui98          top.ctr := do_top.ctr - 1.U
11109c6f1ddSLingrui98          stack.write(do_top_ptr, RASEntry(do_top.retAddr, do_top.ctr - 1.U))
11209c6f1ddSLingrui98        }
11309c6f1ddSLingrui98      }.otherwise {
11409c6f1ddSLingrui98        when (recover) {
11509c6f1ddSLingrui98          sp := do_sp
11609c6f1ddSLingrui98          topPtr := do_top_ptr
11709c6f1ddSLingrui98          top := do_top
11809c6f1ddSLingrui98          stack.write(do_top_ptr, do_top)
11909c6f1ddSLingrui98        }
12009c6f1ddSLingrui98      }
12109c6f1ddSLingrui98    }
12209c6f1ddSLingrui98
123d717fd1eSLingrui98
12409c6f1ddSLingrui98    update(io.recover_valid)(
12509c6f1ddSLingrui98      Mux(io.recover_valid, io.recover_push,     io.push_valid),
12609c6f1ddSLingrui98      Mux(io.recover_valid, io.recover_pop,      io.pop_valid),
12709c6f1ddSLingrui98      Mux(io.recover_valid, recover_alloc_new,   alloc_new),
12809c6f1ddSLingrui98      Mux(io.recover_valid, io.recover_sp,       sp),
12909c6f1ddSLingrui98      Mux(io.recover_valid, io.recover_sp - 1.U, topPtr),
13009c6f1ddSLingrui98      Mux(io.recover_valid, io.recover_new_addr, io.spec_new_addr),
13109c6f1ddSLingrui98      Mux(io.recover_valid, io.recover_top,      top))
13209c6f1ddSLingrui98
13309c6f1ddSLingrui98    io.sp := sp
13409c6f1ddSLingrui98    io.top := top
13509c6f1ddSLingrui98
136d717fd1eSLingrui98    val resetIdx = RegInit(0.U(log2Ceil(RasSize).W))
137d717fd1eSLingrui98    val do_reset = RegInit(true.B)
138d717fd1eSLingrui98    when (do_reset) {
139d717fd1eSLingrui98      stack.write(resetIdx, RASEntry(0x80000000L.U, 0.U))
140d717fd1eSLingrui98    }
141d717fd1eSLingrui98    resetIdx := resetIdx + do_reset
142d717fd1eSLingrui98    when (resetIdx === (RasSize-1).U) {
143d717fd1eSLingrui98      do_reset := false.B
144d717fd1eSLingrui98    }
145d717fd1eSLingrui98
14609c6f1ddSLingrui98    debugIO.push_entry := RASEntry(io.spec_new_addr, Mux(alloc_new, 1.U, top.ctr + 1.U))
14709c6f1ddSLingrui98    debugIO.alloc_new := alloc_new
14809c6f1ddSLingrui98    debugIO.sp := sp
14909c6f1ddSLingrui98    debugIO.topRegister := top
15009c6f1ddSLingrui98    for (i <- 0 until RasSize) {
15109c6f1ddSLingrui98        debugIO.out_mem(i) := stack.read(i.U)
15209c6f1ddSLingrui98    }
15309c6f1ddSLingrui98  }
15409c6f1ddSLingrui98
15509c6f1ddSLingrui98  val spec = Module(new RASStack(RasSize))
15609c6f1ddSLingrui98  val spec_ras = spec.io
157cb4f77ceSLingrui98  val spec_top_addr = spec_ras.top.retAddr
15809c6f1ddSLingrui98
15909c6f1ddSLingrui98
160cb4f77ceSLingrui98  val s2_spec_push = WireInit(false.B)
161cb4f77ceSLingrui98  val s2_spec_pop = WireInit(false.B)
16209c6f1ddSLingrui98  // val jump_is_first = io.callIdx.bits === 0.U
16309c6f1ddSLingrui98  // val call_is_last_half = io.isLastHalfRVI && jump_is_first
16409c6f1ddSLingrui98  // 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)
165cb4f77ceSLingrui98  val s2_spec_new_addr = io.in.bits.resp_in(0).s2.full_pred.fallThroughAddr
166cb4f77ceSLingrui98  spec_ras.push_valid := s2_spec_push
167cb4f77ceSLingrui98  spec_ras.pop_valid  := s2_spec_pop
168cb4f77ceSLingrui98  spec_ras.spec_new_addr := s2_spec_new_addr
16909c6f1ddSLingrui98
17009c6f1ddSLingrui98  // confirm that the call/ret is the taken cfi
171cb4f77ceSLingrui98  s2_spec_push := io.s2_fire && io.in.bits.resp_in(0).s2.full_pred.hit_taken_on_call
172cb4f77ceSLingrui98  s2_spec_pop  := io.s2_fire && io.in.bits.resp_in(0).s2.full_pred.hit_taken_on_ret
17309c6f1ddSLingrui98
174cb4f77ceSLingrui98  val s2_jalr_target = io.out.resp.s2.full_pred.jalr_target
175cb4f77ceSLingrui98  val s2_last_target_in = io.in.bits.resp_in(0).s2.full_pred.targets.last
176cb4f77ceSLingrui98  val s2_last_target_out = io.out.resp.s2.full_pred.targets.last
177cb4f77ceSLingrui98  val s2_is_jalr = io.in.bits.resp_in(0).s2.full_pred.is_jalr
178cb4f77ceSLingrui98  val s2_is_ret = io.in.bits.resp_in(0).s2.full_pred.is_ret
179b30c10d6SLingrui98  // assert(is_jalr && is_ret || !is_ret)
180cb4f77ceSLingrui98  when(s2_is_ret) {
181cb4f77ceSLingrui98    s2_jalr_target := spec_top_addr
182b30c10d6SLingrui98    // FIXME: should use s1 globally
18309c6f1ddSLingrui98  }
184cb4f77ceSLingrui98  s2_last_target_out := Mux(s2_is_jalr, s2_jalr_target, s2_last_target_in)
18509c6f1ddSLingrui98
186cb4f77ceSLingrui98  val s3_top = RegEnable(spec_ras.top, io.s2_fire)
187cb4f77ceSLingrui98  val s3_sp = RegEnable(spec_ras.sp, io.s2_fire)
188cb4f77ceSLingrui98  val s3_spec_new_addr = RegEnable(s2_spec_new_addr, io.s2_fire)
189cb4f77ceSLingrui98
190cb4f77ceSLingrui98  val s3_jalr_target = io.out.resp.s3.full_pred.jalr_target
191cb4f77ceSLingrui98  val s3_last_target_in = io.in.bits.resp_in(0).s3.full_pred.targets.last
192cb4f77ceSLingrui98  val s3_last_target_out = io.out.resp.s3.full_pred.targets.last
193cb4f77ceSLingrui98  val s3_is_jalr = io.in.bits.resp_in(0).s3.full_pred.is_jalr
194cb4f77ceSLingrui98  val s3_is_ret = io.in.bits.resp_in(0).s3.full_pred.is_ret
195cb4f77ceSLingrui98  // assert(is_jalr && is_ret || !is_ret)
196cb4f77ceSLingrui98  when(s3_is_ret) {
197cb4f77ceSLingrui98    s3_jalr_target := s3_top.retAddr
198cb4f77ceSLingrui98    // FIXME: should use s1 globally
199cb4f77ceSLingrui98  }
200cb4f77ceSLingrui98  s3_last_target_out := Mux(s3_is_jalr, s3_jalr_target, s3_last_target_in)
201cb4f77ceSLingrui98
202cb4f77ceSLingrui98  val s3_pushed_in_s2 = RegEnable(s2_spec_push, io.s2_fire)
203cb4f77ceSLingrui98  val s3_popped_in_s2 = RegEnable(s2_spec_pop,  io.s2_fire)
204*5df98e43SLingrui98  val s3_push = io.in.bits.resp_in(0).s3.full_pred.hit_taken_on_call
205*5df98e43SLingrui98  val s3_pop  = io.in.bits.resp_in(0).s3.full_pred.hit_taken_on_ret
206cb4f77ceSLingrui98
207*5df98e43SLingrui98  val s3_recover = io.s3_fire && (s3_pushed_in_s2 =/= s3_push || s3_popped_in_s2 =/= s3_pop)
208*5df98e43SLingrui98  io.out.resp.s3.rasSp  := s3_sp
209*5df98e43SLingrui98  io.out.resp.s3.rasTop := s3_top
21009c6f1ddSLingrui98
21109c6f1ddSLingrui98
21209c6f1ddSLingrui98  val redirect = RegNext(io.redirect)
213cb4f77ceSLingrui98  val do_recover = redirect.valid || s3_recover
21409c6f1ddSLingrui98  val recover_cfi = redirect.bits.cfiUpdate
21509c6f1ddSLingrui98
21609c6f1ddSLingrui98  val retMissPred  = do_recover && redirect.bits.level === 0.U && recover_cfi.pd.isRet
21709c6f1ddSLingrui98  val callMissPred = do_recover && redirect.bits.level === 0.U && recover_cfi.pd.isCall
21809c6f1ddSLingrui98  // when we mispredict a call, we must redo a push operation
21909c6f1ddSLingrui98  // similarly, when we mispredict a return, we should redo a pop
22009c6f1ddSLingrui98  spec_ras.recover_valid := do_recover
221*5df98e43SLingrui98  spec_ras.recover_push := Mux(redirect.valid, callMissPred, s3_push)
222*5df98e43SLingrui98  spec_ras.recover_pop  := Mux(redirect.valid, retMissPred, s3_pop)
22309c6f1ddSLingrui98
224cb4f77ceSLingrui98  spec_ras.recover_sp  := Mux(redirect.valid, recover_cfi.rasSp, s3_sp)
225cb4f77ceSLingrui98  spec_ras.recover_top := Mux(redirect.valid, recover_cfi.rasEntry, s3_top)
226cb4f77ceSLingrui98  spec_ras.recover_new_addr := Mux(redirect.valid, recover_cfi.pc + Mux(recover_cfi.pd.isRVC, 2.U, 4.U), s3_spec_new_addr)
22709c6f1ddSLingrui98
228cb4f77ceSLingrui98
229cb4f77ceSLingrui98  XSPerfAccumulate("ras_s3_recover", s3_recover)
230cb4f77ceSLingrui98  XSPerfAccumulate("ras_redirect_recover", redirect.valid)
231cb4f77ceSLingrui98  XSPerfAccumulate("ras_s3_and_redirect_recover_at_the_same_time", s3_recover && redirect.valid)
23209c6f1ddSLingrui98  // TODO: back-up stack for ras
23309c6f1ddSLingrui98  // use checkpoint to recover RAS
23409c6f1ddSLingrui98
23509c6f1ddSLingrui98  val spec_debug = spec.debugIO
23609c6f1ddSLingrui98  XSDebug("----------------RAS----------------\n")
23709c6f1ddSLingrui98  XSDebug(" TopRegister: 0x%x   %d \n",spec_debug.topRegister.retAddr,spec_debug.topRegister.ctr)
23809c6f1ddSLingrui98  XSDebug("  index       addr           ctr \n")
23909c6f1ddSLingrui98  for(i <- 0 until RasSize){
24009c6f1ddSLingrui98      XSDebug("  (%d)   0x%x      %d",i.U,spec_debug.out_mem(i).retAddr,spec_debug.out_mem(i).ctr)
24109c6f1ddSLingrui98      when(i.U === spec_debug.sp){XSDebug(false,true.B,"   <----sp")}
24209c6f1ddSLingrui98      XSDebug(false,true.B,"\n")
24309c6f1ddSLingrui98  }
244cb4f77ceSLingrui98  XSDebug(s2_spec_push, "(spec_ras)push  inAddr: 0x%x  inCtr: %d |  allocNewEntry:%d |   sp:%d \n",
245cb4f77ceSLingrui98      s2_spec_new_addr,spec_debug.push_entry.ctr,spec_debug.alloc_new,spec_debug.sp.asUInt)
246cb4f77ceSLingrui98  XSDebug(s2_spec_pop, "(spec_ras)pop  outAddr: 0x%x \n",io.out.resp.s2.getTarget)
24709c6f1ddSLingrui98  val redirectUpdate = redirect.bits.cfiUpdate
24809c6f1ddSLingrui98  XSDebug("recoverValid:%d recover(SP:%d retAddr:%x ctr:%d) \n",
24909c6f1ddSLingrui98      do_recover,redirectUpdate.rasSp,redirectUpdate.rasEntry.retAddr,redirectUpdate.rasEntry.ctr)
25009c6f1ddSLingrui98}
251