xref: /XiangShan/src/main/scala/xiangshan/frontend/RAS.scala (revision 3fce4f48e1f4c43253ff1758dbd05b8b71627990)
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        val specEmpty = Bool()
15    }
16
17    class RASBranchInfo extends Meta
18    {
19        val rasSp = UInt(log2Up(RasSize).W)
20        val rasTopCtr = UInt(8.W)
21        val rasToqAddr = UInt(VAddrBits.W)
22    }
23
24    class RASIO extends DefaultBasePredictorIO
25    {
26        val is_ret = Input(Bool())
27        val callIdx = Flipped(ValidIO(UInt(log2Ceil(PredictWidth).W)))
28        val isRVC = Input(Bool())
29        val isLastHalfRVI = Input(Bool())
30        val recover =  Flipped(ValidIO(new BranchUpdateInfo))
31        val out = ValidIO(new RASResp)
32        val branchInfo = Output(new RASBranchInfo)
33    }
34
35    class RASEntry() extends XSBundle {
36        val retAddr = UInt(VAddrBits.W)
37        val ctr = UInt(8.W) // layer of nested call functions
38    }
39
40    def rasEntry() = new RASEntry
41
42    object RASEntry {
43        def apply(retAddr: UInt, ctr: UInt): RASEntry = {
44            val e = Wire(rasEntry())
45            e.retAddr := retAddr
46            e.ctr := ctr
47            e
48        }
49    }
50
51    override val io = IO(new RASIO)
52
53    class RASStack(val rasSize: Int) extends XSModule {
54        val io = IO(new Bundle {
55            val push_valid = Input(Bool())
56            val pop_valid = Input(Bool())
57            val new_addr = Input(UInt(VAddrBits.W))
58            val top_addr = Output(UInt(VAddrBits.W))
59            val is_empty = Output(Bool())
60            val is_full = Output(Bool())
61            val copy_valid = Input(Bool())
62            val copy_in_mem  = Input(Vec(rasSize, rasEntry()))
63            val copy_in_sp   = Input(UInt(log2Up(rasSize).W))
64            val copy_out_mem = Output(Vec(rasSize, rasEntry()))
65            val copy_out_sp  = Output(UInt(log2Up(rasSize).W))
66        })
67
68        class Stack(val size: Int) extends XSModule {
69            val io = IO(new Bundle {
70                val rIdx = Input(UInt(log2Up(size).W))
71                val rdata = Output(rasEntry())
72                val wen = Input(Bool())
73                val wIdx = Input(UInt(log2Up(size).W))
74                val wdata = Input(rasEntry())
75                val copyen = Input(Bool())
76                val copy_in = Input(Vec(size, rasEntry()))
77                val copy_out = Output(Vec(size, rasEntry()))
78            })
79            val mem = Reg(Vec(size, rasEntry()))
80            when (io.wen)  {
81                mem(io.wIdx) := io.wdata
82            }
83            io.rdata := mem(io.rIdx)
84            (0 until size).foreach { i => io.copy_out(i) := mem(i) }
85            when (io.copyen) {
86                (0 until size).foreach {i => mem(i) := io.copy_in(i) }
87            }
88        }
89        val sp = RegInit(0.U(log2Up(rasSize).W))
90        val stack = Module(new Stack(rasSize)).io
91
92        stack.rIdx := sp - 1.U
93        val top_entry = stack.rdata
94        val top_addr = top_entry.retAddr
95        val top_ctr = top_entry.ctr
96        val alloc_new = io.new_addr =/= top_addr
97        stack.wen := io.push_valid || io.pop_valid && top_ctr =/= 1.U
98        stack.wIdx := Mux(io.pop_valid && top_ctr =/= 1.U, sp - 1.U, Mux(alloc_new, sp, sp - 1.U))
99        stack.wdata := Mux(io.pop_valid && top_ctr =/= 1.U,
100                            RASEntry(top_addr, top_ctr - 1.U),
101                            Mux(alloc_new, RASEntry(io.new_addr, 1.U), RASEntry(top_addr, top_ctr + 1.U)))
102
103        when (io.push_valid && alloc_new) {
104            sp := sp + 1.U
105        }
106
107        when (io.pop_valid && top_ctr === 1.U) {
108            sp := Mux(sp === 0.U, 0.U, sp - 1.U)
109        }
110
111        io.copy_out_mem := stack.copy_out
112        io.copy_out_sp  := sp
113        stack.copyen := io.copy_valid
114        stack.copy_in := io.copy_in_mem
115        when (io.copy_valid) {
116            sp := io.copy_in_sp
117        }
118
119        io.top_addr := top_addr
120        io.is_empty := sp === 0.U
121        io.is_full  := sp === (RasSize - 1).U
122    }
123
124    // val ras_0 = Reg(Vec(RasSize, rasEntry()))  //RegInit(0.U)asTypeOf(Vec(RasSize,rasEntry)) cause comb loop
125    // val ras_1 = Reg(Vec(RasSize, rasEntry()))
126    // val sp_0 = RegInit(0.U(log2Up(RasSize).W))
127    // val sp_1 = RegInit(0.U(log2Up(RasSize).W))
128    // val choose_bit = RegInit(false.B)   //start with 0
129    // val spec_ras = Mux(choose_bit, ras_1, ras_0)
130    // val spec_sp = Mux(choose_bit,sp_1,sp_0)
131    // val commit_ras = Mux(choose_bit, ras_0, ras_1)
132    // val commit_sp = Mux(choose_bit,sp_0,sp_1)
133
134    // val spec_ras = Reg(Vec(RasSize, rasEntry()))
135    // val spec_sp = RegInit(0.U(log2Up(RasSize).W))
136    // val commit_ras = Reg(Vec(RasSize, rasEntry()))
137    // val commit_sp = RegInit(0.U(log2Up(RasSize).W))
138
139    val spec_ras   = Module(new RASStack(RasSize)).io
140
141    val spec_push = WireInit(false.B)
142    val spec_pop = WireInit(false.B)
143    val spec_new_addr = WireInit(io.pc.bits + (io.callIdx.bits << 1.U) + Mux(io.isRVC,2.U,Mux(io.isLastHalfRVI, 2.U, 4.U)))
144    spec_ras.push_valid := spec_push
145    spec_ras.pop_valid  := spec_pop
146    spec_ras.new_addr   := spec_new_addr
147    val spec_is_empty = spec_ras.is_empty
148    val spec_is_full = spec_ras.is_full
149    val spec_top_addr = spec_ras.top_addr
150
151    spec_push := !spec_is_full && io.callIdx.valid && io.pc.valid
152    spec_pop  := !spec_is_empty && io.is_ret && io.pc.valid
153
154    val commit_ras = Module(new RASStack(RasSize)).io
155
156    val commit_push = WireInit(false.B)
157    val commit_pop = WireInit(false.B)
158    val commit_new_addr = Mux(io.recover.bits.pd.isRVC,io.recover.bits.pc + 2.U,io.recover.bits.pc + 4.U)
159    commit_ras.push_valid := commit_push
160    commit_ras.pop_valid  := commit_pop
161    commit_ras.new_addr   := commit_new_addr
162    val commit_is_empty = commit_ras.is_empty
163    val commit_is_full = commit_ras.is_full
164    val commit_top_addr = commit_ras.top_addr
165
166    commit_push := !commit_is_full  && io.recover.valid && io.recover.bits.pd.isCall
167    commit_pop  := !commit_is_empty && io.recover.valid && io.recover.bits.pd.isRet
168
169
170    io.out.valid := !spec_is_empty && io.is_ret
171    io.out.bits.target := spec_top_addr
172    io.out.bits.specEmpty := spec_is_empty
173    // TODO: back-up stack for ras
174    // use checkpoint to recover RAS
175
176    val copy_valid = io.recover.valid && io.recover.bits.isMisPred
177    val copy_next = RegNext(copy_valid)
178    spec_ras.copy_valid := copy_next
179    spec_ras.copy_in_mem := commit_ras.copy_out_mem
180    spec_ras.copy_in_sp  := commit_ras.copy_out_sp
181    commit_ras.copy_valid := DontCare
182    commit_ras.copy_in_mem := DontCare
183    commit_ras.copy_in_sp  := DontCare
184
185    //no need to pass the ras branchInfo
186    io.branchInfo.rasSp := DontCare
187    io.branchInfo.rasTopCtr := DontCare
188    io.branchInfo.rasToqAddr := DontCare
189
190    if (BPUDebug && debug) {
191        // XSDebug("----------------RAS(spec)----------------\n")
192        // XSDebug("  index       addr           ctr \n")
193        // for(i <- 0 until RasSize){
194        //     XSDebug("  (%d)   0x%x      %d",i.U,spec_ras(i).retAddr,spec_ras(i).ctr)
195        //     when(i.U === spec_sp){XSDebug(false,true.B,"   <----sp")}
196        //     XSDebug(false,true.B,"\n")
197        // }
198        // XSDebug("----------------RAS(commit)----------------\n")
199        // XSDebug("  index       addr           ctr \n")
200        // for(i <- 0 until RasSize){
201        //     XSDebug("  (%d)   0x%x      %d",i.U,commit_ras(i).retAddr,commit_ras(i).ctr)
202        //     when(i.U === commit_sp){XSDebug(false,true.B,"   <----sp")}
203        //     XSDebug(false,true.B,"\n")
204        // }
205
206        // XSDebug(spec_push, "(spec_ras)push  inAddr: 0x%x  inCtr: %d |  allocNewEntry:%d |   sp:%d \n",spec_ras_write.retAddr,spec_ras_write.ctr,sepc_alloc_new,spec_sp.asUInt)
207        // XSDebug(spec_pop, "(spec_ras)pop outValid:%d  outAddr: 0x%x \n",io.out.valid,io.out.bits.target)
208        // XSDebug(commit_push, "(commit_ras)push  inAddr: 0x%x  inCtr: %d |  allocNewEntry:%d |   sp:%d \n",commit_ras_write.retAddr,commit_ras_write.ctr,sepc_alloc_new,commit_sp.asUInt)
209        // XSDebug(commit_pop, "(commit_ras)pop outValid:%d  outAddr: 0x%x \n",io.out.valid,io.out.bits.target)
210        // XSDebug("copyValid:%d copyNext:%d \n",copy_valid,copy_next)
211    }
212
213
214    // val recoverSp = io.recover.bits.brInfo.rasSp
215    // val recoverCtr = io.recover.bits.brInfo.rasTopCtr
216    // val recoverAddr = io.recover.bits.brInfo.rasToqAddr
217    // val recover_top = ras(recoverSp - 1.U)
218    // when (recover_valid) {
219    //     sp := recoverSp
220    //     recover_top.ctr := recoverCtr
221    //     recover_top.retAddr := recoverAddr
222    //     XSDebug("RAS update: SP:%d , Ctr:%d \n",recoverSp,recoverCtr)
223    // }
224    // val recover_and_push = recover_valid && push
225    // val recover_and_pop = recover_valid && pop
226    // val recover_alloc_new = new_addr =/= recoverAddr
227    // when(recover_and_push)
228    // {
229    //     when(recover_alloc_new){
230    //         sp := recoverSp + 1.U
231    //         ras(recoverSp).retAddr := new_addr
232    //         ras(recoverSp).ctr := 1.U
233    //         recover_top.retAddr := recoverAddr
234    //         recover_top.ctr := recoverCtr
235    //     } .otherwise{
236    //         sp := recoverSp
237    //         recover_top.ctr := recoverCtr + 1.U
238    //         recover_top.retAddr := recoverAddr
239    //     }
240    // } .elsewhen(recover_and_pop)
241    // {
242    //     io.out.bits.target := recoverAddr
243    //     when ( recover_top.ctr === 1.U) {
244    //         sp := recoverSp - 1.U
245    //     }.otherwise {
246    //         sp := recoverSp
247    //        recover_top.ctr := recoverCtr - 1.U
248    //     }
249    // }
250
251}
252