xref: /XiangShan/src/main/scala/xiangshan/frontend/RAS.scala (revision e9922c965748d383abc0d6abbc21b262800d719a)
1package xiangshan.frontend
2
3import chisel3._
4import chisel3.util._
5import xiangshan._
6import xiangshan.backend.ALUOpType
7import utils._
8
9class RAS extends BasePredictor
10{
11    class RASResp extends Resp
12    {
13        val target =UInt(VAddrBits.W)
14    }
15
16    class RASBranchInfo extends Meta
17    {
18        val rasSp = UInt(log2Up(RasSize).W)
19        val rasTopCtr = UInt(8.W)
20    }
21
22    class RASIO extends DefaultBasePredictorIO
23    {
24        val is_ret = Input(Bool())
25        val callIdx = Flipped(ValidIO(UInt(log2Ceil(PredictWidth).W)))
26        val isRVC = Input(Bool())
27        val redirect = Flipped(ValidIO(new Redirect))
28        val recover =  Flipped(ValidIO(new BranchUpdateInfo))
29        val out = ValidIO(new RASResp)
30        val branchInfo = Output(new RASBranchInfo)
31    }
32
33    def rasEntry() = new Bundle {
34        val retAddr = UInt(VAddrBits.W)
35        val ctr = UInt(8.W) // layer of nested call functions
36    }
37    override val io = IO(new RASIO)
38
39    val ras = Reg(Vec(RasSize, rasEntry()))  //RegInit(0.U)asTypeOf(Vec(RasSize,rasEntry)) cause comb loop
40    val sp = RegInit(0.U(log2Up(RasSize).W))
41
42    val is_empty = sp === 0.U
43    val is_full = sp === (RasSize - 1).U
44
45    val ras_top_entry = ras(sp-1.U)
46    val ras_top_addr = ras_top_entry.retAddr
47    val ras_top_ctr = ras_top_entry.ctr
48    // save ras checkpoint info
49    io.branchInfo.rasSp := sp
50    io.branchInfo.rasTopCtr := ras(sp).ctr
51
52    io.out.valid := !is_empty && io.is_ret
53    XDebug("  index       addr           ctr \n")
54    for(i <- 0 until RasSize){
55        XSDebug("  (%d)   0x%x      %d",i.U,ras(i).retAddr,ras(i).ctr)
56        when(i.U === sp){XSDebug(false,"   <----sp")}
57        XSDebug(false,"\n")
58    }
59    // update RAS
60    // speculative update RAS
61    io.out.bits.target := 0.U
62    when (!is_full && io.callIdx.valid && io.pc.valid) {
63        //push
64        //XDebug("d")
65        val new_addr = io.pc.bits + (io.callIdx.bits << 1.U) + 4.U   //TODO: consider RVC
66        val rasWrite = WireInit(0.U.asTypeOf(rasEntry()))
67        val allocNewEntry = new_addr =/= ras_top_addr
68        rasWrite.ctr := 1.U
69        rasWrite.retAddr := new_addr
70        when(allocNewEntry){
71            sp := sp + 1.U
72            ras(sp) := rasWrite
73        }.otherwise{
74            ras_top_ctr := ras_top_ctr + 1.U
75        }
76        XSDebug("push  inAddr: 0x%x  inCtr: %d |  allocNewEntry:%d |   sp:%d \n",rasWrite.retAddr,rasWrite.ctr,allocNewEntry,sp.asUInt)
77    }.elsewhen (!is_empty && io.is_ret) {
78        //pop
79        io.out.bits.target := ras_top_addr
80        when (ras_top_ctr === 1.U) {
81            sp := Mux(sp === 0.U, 0.U, sp - 1.U)
82        }.otherwise {
83           ras_top_ctr := ras_top_ctr - 1.U
84        }
85        XSDebug("pop outValid:%d  outAddr: 0x%x \n",io.out.valid,io.out.bits.target)
86    }
87    // TODO: back-up stack for ras
88    // use checkpoint to recover RAS
89    val recoverSp = io.recover.bits.brInfo.rasSp
90    val recoverCtr = io.recover.bits.brInfo.rasTopCtr
91    when (io.redirect.valid && io.redirect.bits.isMisPred) {
92        sp := recoverSp
93        ras(recoverSp).ctr := recoverCtr
94    }
95
96}