sp1_jit/instructions.rs
1use crate::{RiscOperand, RiscRegister};
2
3/// An ALU instruction backend for a specific target architecture.
4///
5/// This trait is implemented for each target architecture supported by the JIT transpiler.
6pub trait ComputeInstructions: Sized {
7 /// Add the values of two registers together, using 64bit arithmetic.
8 ///
9 /// add: rd = rs1 + rs2
10 fn add(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
11
12 /// Subtract the values of two registers from each other, using 64bit arithmetic.
13 ///
14 /// sub: rd = rs1 - rs2
15 fn sub(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
16
17 /// Bitwise XOR the values of two registers together.
18 ///
19 /// xor: rd = rs1 ^ rs2
20 fn xor(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
21
22 /// Bitwise OR the values of two registers together.
23 ///
24 /// or: rd = rs1 | rs2
25 fn or(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
26
27 /// Bitwise AND the values of two registers together.
28 ///
29 /// and: rd = rs1 & rs2
30 fn and(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
31
32 /// Shift the values of two registers left by the amount specified by the second register.
33 ///
34 /// sll: rd = rs1 << rs2
35 fn sll(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
36
37 /// Shift the values of two registers right by the amount specified by the second register.
38 ///
39 /// srl: rd = rs1 >> rs2
40 fn srl(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
41
42 /// Shift the values of two registers right by the amount specified by the second register,
43 /// using arithmetic right shift.
44 ///
45 /// sra: rd = rs1 >> rs2
46 fn sra(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
47
48 /// Set if less than (signed comparison).
49 ///
50 /// slt: rd = (rs1 < rs2) ? 1 : 0
51 fn slt(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
52
53 /// Set if less than (unsigned comparison).
54 ///
55 /// sltu: rd = (rs1 < rs2) ? 1 : 0
56 fn sltu(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
57
58 /// Multiply the values of two registers together, using 64bit arithmetic.
59 ///
60 /// mul: rd = rs1 * rs2
61 fn mul(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
62
63 /// Multiply the values of two registers together and return the high 64 bits (signed).
64 ///
65 /// mulh: rd = (rs1 * rs2) >> 64 (signed)
66 fn mulh(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
67
68 /// Multiply the values of two registers together and return the high 64 bits (unsigned).
69 ///
70 /// mulhu: rd = (rs1 * rs2) >> 64 (unsigned)
71 fn mulhu(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
72
73 /// Multiply signed rs1 by unsigned rs2 and return the high 64 bits.
74 ///
75 /// mulhsu: rd = (rs1 * rs2) >> 64 (signed * unsigned)
76 fn mulhsu(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
77
78 /// Divide the values of two registers (signed).
79 ///
80 /// div: rd = rs2 == 0 ? 0 : rs1 / rs2
81 fn div(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
82
83 /// Divide the values of two registers (unsigned).
84 ///
85 /// divu: rd = rs2 == 0 ? 0 : rs1 / rs2
86 fn divu(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
87
88 /// Remainder of two registers (signed).
89 ///
90 /// rem: rd = rs2 == 0 ? 0 : rs1 % rs2
91 fn rem(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
92
93 /// Remainder of two registers (unsigned).
94 ///
95 /// remu: rd = rs2 == 0 ? 0 : rs1 % rs2
96 fn remu(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
97
98 /// Add the values of two registers together, using 64bit arithmetic, but only keeping lower 32
99 /// bits.
100 ///
101 /// addw: rd = (rs1 + rs2) & 0xFFFFFFFF (sign-extended to 64-bit)
102 fn addw(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
103
104 /// Subtract the values of two registers, using 64bit arithmetic, but only keeping lower 32
105 /// bits.
106 ///
107 /// subw: rd = (rs1 - rs2) & 0xFFFFFFFF (sign-extended to 64-bit)
108 fn subw(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
109
110 /// Shift the values of two registers left by the amount specified by the second register
111 /// (32-bit).
112 ///
113 /// sllw: rd = (rs1 << (rs2 & 0x1F)) & 0xFFFFFFFF (sign-extended to 64-bit)
114 fn sllw(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
115
116 /// Shift the values of two registers right by the amount specified by the second register
117 /// (32-bit logical).
118 ///
119 /// srlw: rd = ((rs1 & 0xFFFFFFFF) >> (rs2 & 0x1F)) (sign-extended to 64-bit)
120 fn srlw(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
121
122 /// Shift the values of two registers right by the amount specified by the second register
123 /// (32-bit arithmetic).
124 ///
125 /// sraw: rd = ((rs1 as i32) >> (rs2 & 0x1F)) (sign-extended to 64-bit)
126 fn sraw(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
127
128 /// Multiply the values of two registers together, using 32bit arithmetic (sign-extended to
129 /// 64-bit).
130 ///
131 /// mulw: rd = (rs1 * rs2) & 0xFFFFFFFF (sign-extended to 64-bit)
132 fn mulw(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
133
134 /// Divide the values of two registers together, using 32bit arithmetic (sign-extended to
135 /// 64-bit).
136 ///
137 /// divw: rd = rs2 == 0 ? 0xFFFFFFFF : (rs1 as i32) / (rs2 as i32) (sign-extended to 64-bit)
138 fn divw(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
139
140 /// Divide the values of two registers, unsigned 32bit (sign-extended to 64-bit).
141 ///
142 /// divuw: rd = rs2 == 0 ? 0xFFFFFFFF : (rs1 as u32) / (rs2 as u32) (sign-extended to 64-bit)
143 fn divuw(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
144
145 /// Remainder the values of two registers together, using 32bit arithmetic (sign-extended to
146 /// 64-bit).
147 ///
148 /// remw: rd = rs2 == 0 ? rs1 : (rs1 as i32) % (rs2 as i32) (sign-extended to 64-bit)
149 fn remw(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
150
151 /// Remainder the values of two registers, unsigned 32bit (sign-extended to 64-bit).
152 ///
153 /// remuw: rd = rs2 == 0 ? rs1 : (rs1 as u32) % (rs2 as u32) (sign-extended to 64-bit)
154 fn remuw(&mut self, rd: RiscRegister, rs1: RiscOperand, rs2: RiscOperand);
155
156 /// Advance to the next pc, storing the current (pc + imm) in a register.
157 ///
158 /// auipc: rd = pc + imm, pc = pc + 4
159 fn auipc(&mut self, rd: RiscRegister, imm: u64);
160
161 /// Load upper immediate into a register.
162 ///
163 /// lui: rd = imm << 12
164 fn lui(&mut self, rd: RiscRegister, imm: u64);
165}
166
167pub trait ControlFlowInstructions: Sized {
168 /// Compare the values of two registers, and jump to an address if they are equal.
169 ///
170 /// beq: pc = pc + ((rs1 == rs2) ? imm : 4)
171 ///
172 /// NOTE: During transpilatiom, this method will emit the PC bumps for you,
173 /// typically however, you will want to explicty call [`SP1RiscvTranspiler::set_pc`] at the end
174 /// of each instruction.
175 fn beq(&mut self, rs1: RiscRegister, rs2: RiscRegister, imm: u64);
176
177 /// Compare the values of two registers, and jump to an address if they are not equal.
178 ///
179 /// bne: pc = pc + ((rs1 != rs2) ? imm : 4)
180 ///
181 /// NOTE: During transpilatiom, this method will emit the PC bumps for you,
182 /// typically however, you will want to explicty call [`SP1RiscvTranspiler::set_pc`] at the end
183 /// of each instruction.
184 fn bne(&mut self, rs1: RiscRegister, rs2: RiscRegister, imm: u64);
185
186 /// Compare the values of two registers, and jump to an address if the first is less than the
187 /// second.
188 ///
189 /// blt: pc = pc + ((rs1 < rs2) ? imm : 4)
190 ///
191 /// NOTE: During transpilatiom, this method will emit the PC bumps for you,
192 /// typically however, you will want to explicty call [`SP1RiscvTranspiler::set_pc`] at the end
193 /// of each instruction.
194 fn blt(&mut self, rs1: RiscRegister, rs2: RiscRegister, imm: u64);
195
196 /// Compare the values of two registers, and jump to an address if the first is greater than or
197 /// equal to the second.
198 ///
199 /// bge: pc = pc + ((rs1 >= rs2) ? imm : 4)
200 ///
201 /// NOTE: During transpilatiom, this method will emit the PC bumps for you,
202 /// typically however, you will want to explicty call [`SP1RiscvTranspiler::set_pc`] at the end
203 /// of each instruction.
204 fn bge(&mut self, rs1: RiscRegister, rs2: RiscRegister, imm: u64);
205
206 /// Compare the values of two registers, and jump to an address if the first is less than the
207 /// second, unsigned.
208 ///
209 /// bltu: pc = pc + ((rs1 < rs2) ? imm : 4)
210 ///
211 /// NOTE: During transpilatiom, this method will emit the PC bumps for you,
212 /// typically however, you will want to explicty call [`SP1RiscvTranspiler::set_pc`] at the end
213 /// of each instruction.
214 fn bltu(&mut self, rs1: RiscRegister, rs2: RiscRegister, imm: u64);
215
216 /// Compare the values of two registers, and jump to an address if the first is greater than or
217 /// equal to the second, unsigned.
218 ///
219 /// bgeu: pc = pc + ((rs1 >= rs2) ? imm : 4)
220 ///
221 /// NOTE: During transpilatiom, this method will emit the PC bumps for you,
222 /// typically however, you will want to explicty call [`SP1RiscvTranspiler::set_pc`] at the end
223 /// of each instruction.
224 fn bgeu(&mut self, rs1: RiscRegister, rs2: RiscRegister, imm: u64);
225
226 /// Jump to an address.
227 ///
228 /// jal: rd = pc + 4, pc = pc + imm
229 ///
230 /// NOTE: During transpilatiom, this method will emit the PC bumps for you,
231 /// typically however, you will want to explicty call [`SP1RiscvTranspiler::set_pc`] at the end
232 /// of each instruction.
233 fn jal(&mut self, rd: RiscRegister, imm: u64);
234
235 /// Jump to an address, and return to the previous address.
236 ///
237 /// jalr: rd = pc + 4, pc = rs1 + imm
238 ///
239 /// NOTE: During transpilatiom, this method will emit the PC bumps for you,
240 /// typically however, you will want to explicty call [`SP1RiscvTranspiler::set_pc`] at the end
241 /// of each instruction.
242 fn jalr(&mut self, rd: RiscRegister, rs1: RiscRegister, imm: u64);
243}
244
245pub trait MemoryInstructions: Sized {
246 /// Load a byte from memory into a register.
247 ///
248 /// lb: rd = m8(rs1 + imm)
249 fn lb(&mut self, rd: RiscRegister, rs1: RiscRegister, imm: u64);
250
251 /// Load a half word from memory into a register.
252 ///
253 /// lh: rd = m16(rs1 + imm)
254 fn lh(&mut self, rd: RiscRegister, rs1: RiscRegister, imm: u64);
255
256 /// Load a word from memory into a register.
257 ///
258 /// lw: rd = m32(rs1 + imm)
259 fn lw(&mut self, rd: RiscRegister, rs1: RiscRegister, imm: u64);
260
261 /// Load a byte from memory into a register, zero extended.
262 ///
263 /// lbu: rd = zx(m8(rs1 + imm))
264 fn lbu(&mut self, rd: RiscRegister, rs1: RiscRegister, imm: u64);
265
266 /// Load a half word from memory into a register, zero extended.
267 ///
268 /// lhu: rd = zx(m16(rs1 + imm))
269 fn lhu(&mut self, rd: RiscRegister, rs1: RiscRegister, imm: u64);
270
271 /// Load a double word from memory into a register.
272 ///
273 /// ldu: rd = m64(rs1 + imm)
274 fn ld(&mut self, rd: RiscRegister, rs1: RiscRegister, imm: u64);
275
276 /// Load a word from memory into a register, zero extended.
277 ///
278 /// lwu: rd = zx(m32(rs1 + imm))
279 fn lwu(&mut self, rd: RiscRegister, rs1: RiscRegister, imm: u64);
280
281 /// Store a byte into memory.
282 ///
283 /// sb: m8(rs1 + imm) = rs2[7:0]
284 fn sb(&mut self, rs1: RiscRegister, rs2: RiscRegister, imm: u64);
285
286 /// Store a half word into memory.
287 ///
288 /// sh: m16(rs1 + imm) = rs2[15:0]
289 fn sh(&mut self, rs1: RiscRegister, rs2: RiscRegister, imm: u64);
290
291 /// Store a word into memory.
292 ///
293 /// sw: m32(rs1 + imm) = rs2[31:0]
294 fn sw(&mut self, rs1: RiscRegister, rs2: RiscRegister, imm: u64);
295
296 /// Store a double word into memory.
297 ///
298 /// sd: m64(rs1 + imm) = rs2[63:0]
299 fn sd(&mut self, rs1: RiscRegister, rs2: RiscRegister, imm: u64);
300}
301
302pub trait SystemInstructions: Sized {
303 /// Transfer control to the operating system.
304 fn ecall(&mut self);
305
306 fn unimp(&mut self);
307}