1package xiangshan.frontend 2 3import chisel3._ 4import chisel3.util._ 5import xiangshan._ 6import xiangshan.backend.ALUOpType 7import utils._ 8import chisel3.experimental.chiselName 9import scala.tools.nsc.doc.base.comment.Bold 10 11class RASEntry() extends XSBundle { 12 val retAddr = UInt(VAddrBits.W) 13 val ctr = UInt(8.W) // layer of nested call functions 14} 15 16@chiselName 17class RAS extends BasePredictor 18{ 19 class RASResp extends Resp 20 { 21 val target =UInt(VAddrBits.W) 22 } 23 24 class RASBranchInfo extends Meta 25 { 26 val rasSp = UInt(log2Up(RasSize).W) 27 val rasTop = new RASEntry 28 } 29 30 class RASIO extends DefaultBasePredictorIO 31 { 32 val is_ret = Input(Bool()) 33 val callIdx = Flipped(ValidIO(UInt(log2Ceil(PredictWidth).W))) 34 val isRVC = Input(Bool()) 35 val isLastHalfRVI = Input(Bool()) 36 val redirect = Flipped(ValidIO(new Redirect)) 37 val out = ValidIO(new RASResp) 38 val meta = Output(new RASBranchInfo) 39 } 40 41 42 def rasEntry() = new RASEntry 43 44 object RASEntry { 45 def apply(retAddr: UInt, ctr: UInt): RASEntry = { 46 val e = Wire(rasEntry()) 47 e.retAddr := retAddr 48 e.ctr := ctr 49 e 50 } 51 } 52 53 override val io = IO(new RASIO) 54 override val debug = true 55 56 @chiselName 57 class RASStack(val rasSize: Int) extends XSModule { 58 val io = IO(new Bundle { 59 val push_valid = Input(Bool()) 60 val pop_valid = Input(Bool()) 61 val spec_new_addr = Input(UInt(VAddrBits.W)) 62 63 val recover_sp = Input(UInt(log2Up(rasSize).W)) 64 val recover_top = Input(rasEntry()) 65 val recover_valid = Input(Bool()) 66 val recover_push = Input(Bool()) 67 val recover_pop = Input(Bool()) 68 val recover_new_addr = Input(UInt(VAddrBits.W)) 69 70 val sp = Output(UInt(log2Up(rasSize).W)) 71 val top = Output(rasEntry()) 72 val is_empty = Output(Bool()) 73 val is_full = Output(Bool()) 74 }) 75 val debugIO = IO(new Bundle{ 76 val push_entry = Output(rasEntry()) 77 val alloc_new = Output(Bool()) 78 val sp = Output(UInt(log2Up(rasSize).W)) 79 val topRegister = Output(rasEntry()) 80 val out_mem = Output(Vec(RasSize, rasEntry())) 81 }) 82 83 val stack = Mem(RasSize, new RASEntry) 84 val sp = RegInit(0.U(log2Up(rasSize).W)) 85 val top = RegInit(0.U.asTypeOf(new RASEntry)) 86 val topPtr = RegInit(0.U(log2Up(rasSize).W)) 87 88 def full(sp: UInt = sp) = sp === (RasSize - 1).U 89 def empty(sp: UInt = sp) = sp === 0.U 90 val is_full = full() 91 val is_empty = empty() 92 val alloc_new = io.spec_new_addr =/= top.retAddr 93 val recover_alloc_new = io.recover_new_addr =/= io.recover_top.retAddr 94 95 // TODO: fix overflow and underflow bugs 96 def update(recover: Bool)(do_push: Bool, do_pop: Bool, do_alloc_new: Bool, 97 do_sp: UInt, do_top_ptr: UInt, do_new_addr: UInt, 98 do_top: RASEntry) = { 99 when (do_push) { 100 when (do_alloc_new) { 101 sp := Mux(full(do_sp), do_sp, do_sp + 1.U) 102 topPtr := Mux(full(do_sp), do_sp - 1.U, do_sp) 103 top.retAddr := do_new_addr 104 top.ctr := 1.U 105 stack.write(do_sp, RASEntry(do_new_addr, 1.U)) 106 }.otherwise { 107 when (recover) { 108 sp := do_sp 109 topPtr := do_top_ptr 110 top.retAddr := do_top.retAddr 111 } 112 top.ctr := do_top.ctr + 1.U 113 stack.write(do_top_ptr, RASEntry(do_new_addr, do_top.ctr + 1.U)) 114 } 115 }.elsewhen (do_pop) { 116 when (do_top.ctr === 1.U) { 117 sp := Mux(empty(do_sp), 0.U, do_sp - 1.U) 118 topPtr := Mux(empty(do_sp), 0.U, do_top_ptr - 1.U) 119 top := stack.read(do_top_ptr - 1.U) 120 }.otherwise { 121 when (recover) { 122 sp := do_sp 123 topPtr := do_top_ptr 124 top.retAddr := do_top.retAddr 125 } 126 top.ctr := do_top.ctr - 1.U 127 stack.write(do_top_ptr, RASEntry(do_top.retAddr, do_top.ctr - 1.U)) 128 } 129 }.otherwise { 130 when (recover) { 131 sp := do_sp 132 topPtr := do_top_ptr 133 top := do_top 134 stack.write(do_top_ptr, do_top) 135 } 136 } 137 } 138 139 update(io.recover_valid)( 140 Mux(io.recover_valid, io.recover_push, io.push_valid), 141 Mux(io.recover_valid, io.recover_pop, io.pop_valid), 142 Mux(io.recover_valid, recover_alloc_new, alloc_new), 143 Mux(io.recover_valid, io.recover_sp, sp), 144 Mux(io.recover_valid, io.recover_sp - 1.U, topPtr), 145 Mux(io.recover_valid, io.recover_new_addr, io.spec_new_addr), 146 Mux(io.recover_valid, io.recover_top, top)) 147 148 io.sp := sp 149 io.top := top 150 io.is_empty := is_empty 151 io.is_full := is_full 152 153 debugIO.push_entry := RASEntry(io.spec_new_addr, Mux(alloc_new, 1.U, top.ctr + 1.U)) 154 debugIO.alloc_new := alloc_new 155 debugIO.sp := sp 156 debugIO.topRegister := top 157 for (i <- 0 until RasSize) { 158 debugIO.out_mem(i) := stack.read(i.U) 159 } 160 161 } 162 163 val spec = Module(new RASStack(RasSize)) 164 val spec_ras = spec.io 165 166 167 val spec_push = WireInit(false.B) 168 val spec_pop = WireInit(false.B) 169 val jump_is_first = io.callIdx.bits === 0.U 170 val call_is_last_half = io.isLastHalfRVI && jump_is_first 171 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) 172 spec_ras.push_valid := spec_push 173 spec_ras.pop_valid := spec_pop 174 spec_ras.spec_new_addr := spec_new_addr 175 val spec_is_empty = spec_ras.is_empty 176 val spec_is_full = spec_ras.is_full 177 val spec_top_addr = spec_ras.top.retAddr 178 179 spec_push := !spec_is_full && io.callIdx.valid && io.pc.valid 180 spec_pop := !spec_is_empty && io.is_ret && io.pc.valid 181 182 val copy_valid = io.redirect.valid 183 val recover_cfi = io.redirect.bits.cfiUpdate 184 185 val retMissPred = copy_valid && io.redirect.bits.level === 0.U && recover_cfi.pd.isRet 186 val callMissPred = copy_valid && io.redirect.bits.level === 0.U && recover_cfi.pd.isCall 187 // when we mispredict a call, we must redo a push operation 188 // similarly, when we mispredict a return, we should redo a pop 189 spec_ras.recover_valid := copy_valid 190 spec_ras.recover_push := callMissPred 191 spec_ras.recover_pop := retMissPred 192 193 spec_ras.recover_sp := recover_cfi.rasSp 194 spec_ras.recover_top := recover_cfi.rasEntry 195 spec_ras.recover_new_addr := recover_cfi.pc + Mux(recover_cfi.pd.isRVC, 2.U, 4.U) 196 197 io.meta.rasSp := spec_ras.sp 198 io.meta.rasTop := spec_ras.top 199 200 io.out.valid := !spec_is_empty 201 io.out.bits.target := spec_top_addr 202 // TODO: back-up stack for ras 203 // use checkpoint to recover RAS 204 205 if (BPUDebug && debug) { 206 val spec_debug = spec.debugIO 207 XSDebug("----------------RAS----------------\n") 208 XSDebug(" TopRegister: 0x%x %d \n",spec_debug.topRegister.retAddr,spec_debug.topRegister.ctr) 209 XSDebug(" index addr ctr \n") 210 for(i <- 0 until RasSize){ 211 XSDebug(" (%d) 0x%x %d",i.U,spec_debug.out_mem(i).retAddr,spec_debug.out_mem(i).ctr) 212 when(i.U === spec_debug.sp){XSDebug(false,true.B," <----sp")} 213 XSDebug(false,true.B,"\n") 214 } 215 XSDebug(spec_push, "(spec_ras)push inAddr: 0x%x inCtr: %d | allocNewEntry:%d | sp:%d \n", 216 spec_new_addr,spec_debug.push_entry.ctr,spec_debug.alloc_new,spec_debug.sp.asUInt) 217 XSDebug(spec_pop, "(spec_ras)pop outValid:%d outAddr: 0x%x \n",io.out.valid,io.out.bits.target) 218 val redirectUpdate = io.redirect.bits.cfiUpdate 219 XSDebug("copyValid:%d recover(SP:%d retAddr:%x ctr:%d) \n", 220 copy_valid,redirectUpdate.rasSp,redirectUpdate.rasEntry.retAddr,redirectUpdate.rasEntry.ctr) 221 } 222 223} 224