jit_assembler/riscv64/
instruction.rs

1/// RISC-V instruction formats and encoding
2use core::fmt;
3use crate::common::{
4    Instruction as InstructionTrait,
5    Register as RegisterTrait,
6};
7
8#[cfg(feature = "std")]
9use std::vec::Vec;
10#[cfg(not(feature = "std"))]
11use alloc::vec::Vec;
12
13/// RISC-V register representation
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub struct Register(pub u8);
16
17impl Register {
18    pub const fn new(reg: u8) -> Self {
19        Self(reg)
20    }
21
22    pub fn value(self) -> u8 {
23        self.0
24    }
25}
26
27impl RegisterTrait for Register {
28    fn id(&self) -> u32 {
29        self.0 as u32
30    }
31    
32    fn abi_class(&self) -> crate::common::AbiClass {
33        use crate::common::AbiClass;
34        
35        match self.0 {
36            // Caller-saved registers (do not need to be preserved across calls)
37            1 => AbiClass::CallerSaved,         // RA (return address) - caller-saved
38            5..=7 | 28..=31 => AbiClass::CallerSaved,  // T0-T2, T3-T6 (temporaries)
39            10..=17 => AbiClass::CallerSaved,   // A0-A7 (arguments/return values)
40            
41            // Callee-saved registers (must be preserved across calls)
42            2 => AbiClass::CalleeSaved,         // SP (stack pointer) - callee-saved
43            8..=9 | 18..=27 => AbiClass::CalleeSaved,  // S0-S1, S2-S11 (saved registers)
44            
45            // Special-purpose registers
46            0 => AbiClass::Special,  // X0 (zero register) - hardwired to zero
47            3 => AbiClass::Special,  // GP (global pointer) - special purpose
48            4 => AbiClass::Special,  // TP (thread pointer) - special purpose
49
50            // Default to Special for any unhandled registers
51            _ => AbiClass::Special,
52        }
53    }
54}
55
56/// RISC-V CSR representation
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub struct Csr(pub u16);
59
60impl Csr {
61    pub const fn new(csr: u16) -> Self {
62        Self(csr)
63    }
64
65    pub fn value(self) -> u16 {
66        self.0
67    }
68}
69
70/// RISC-V instruction representation (supports both 32-bit and 16-bit compressed instructions)
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub enum Instruction {
73    /// 32-bit standard instruction
74    Standard(u32),
75    /// 16-bit compressed instruction (C extension)
76    Compressed(u16),
77}
78
79impl Instruction {
80    /// Create a new 32-bit instruction
81    pub fn new(value: u32) -> Self {
82        Self::Standard(value)
83    }
84    
85    /// Create a new 16-bit compressed instruction
86    pub fn new_compressed(value: u16) -> Self {
87        Self::Compressed(value)
88    }
89
90    /// Get the instruction value as u64 (for compatibility)
91    pub fn value(self) -> u32 {
92        match self {
93            Self::Standard(val) => val,
94            Self::Compressed(val) => val as u32,
95        }
96    }
97
98    /// Get the instruction as bytes with proper length
99    pub fn bytes(self) -> Vec<u8> {
100        match self {
101            Self::Standard(val) => val.to_le_bytes().to_vec(),
102            Self::Compressed(val) => val.to_le_bytes().to_vec(),
103        }
104    }
105    
106    /// Get the size of this instruction in bytes
107    pub fn size(&self) -> usize {
108        match self {
109            Self::Standard(_) => 4,
110            Self::Compressed(_) => 2,
111        }
112    }
113
114    /// Check if this is a compressed instruction
115    pub fn is_compressed(&self) -> bool {
116        matches!(self, Self::Compressed(_))
117    }
118}
119
120impl InstructionTrait for Instruction {
121    fn value(&self) -> u64 {
122        match self {
123            Self::Standard(val) => *val as u64,
124            Self::Compressed(val) => *val as u64,
125        }
126    }
127
128    fn bytes(&self) -> Vec<u8> {
129        match self {
130            Self::Standard(val) => val.to_le_bytes().to_vec(),
131            Self::Compressed(val) => val.to_le_bytes().to_vec(),
132        }
133    }
134
135    fn size(&self) -> usize {
136        match self {
137            Self::Standard(_) => 4,
138            Self::Compressed(_) => 2,
139        }
140    }
141}
142
143impl fmt::Display for Instruction {
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        match self {
146            Self::Standard(val) => write!(f, "0x{:08x}", val),
147            Self::Compressed(val) => write!(f, "0x{:04x}c", val),
148        }
149    }
150}
151
152/// I-type instruction encoding
153pub fn encode_i_type(opcode: u8, rd: Register, funct3: u8, rs1: Register, imm: i16) -> Instruction {
154    let imm = imm as u32 & 0xfff;
155    let instr = (imm << 20) | ((rs1.value() as u32) << 15) | ((funct3 as u32) << 12) | ((rd.value() as u32) << 7) | (opcode as u32);
156    Instruction::Standard(instr)
157}
158
159/// CSR instruction encoding (I-type variant)
160pub fn encode_csr_type(opcode: u8, rd: Register, funct3: u8, rs1: Register, csr: Csr) -> Instruction {
161    let csr_val = csr.value() as u32;
162    let instr = (csr_val << 20) | ((rs1.value() as u32) << 15) | ((funct3 as u32) << 12) | ((rd.value() as u32) << 7) | (opcode as u32);
163    Instruction::Standard(instr)
164}
165
166/// CSR immediate instruction encoding
167pub fn encode_csr_imm_type(opcode: u8, rd: Register, funct3: u8, uimm: u8, csr: Csr) -> Instruction {
168    let csr_val = csr.value() as u32;
169    let instr = (csr_val << 20) | ((uimm as u32) << 15) | ((funct3 as u32) << 12) | ((rd.value() as u32) << 7) | (opcode as u32);
170    Instruction::Standard(instr)
171}
172
173/// Privileged instruction encoding (special SYSTEM instructions)
174pub fn encode_privileged_type(opcode: u8, funct12: u16) -> Instruction {
175    let instr = ((funct12 as u32) << 20) | (opcode as u32);
176    Instruction::Standard(instr)
177}
178
179/// R-type instruction encoding
180pub fn encode_r_type(opcode: u8, rd: Register, funct3: u8, rs1: Register, rs2: Register, funct7: u8) -> Instruction {
181    let instr = ((funct7 as u32) << 25) | ((rs2.value() as u32) << 20) | ((rs1.value() as u32) << 15) | ((funct3 as u32) << 12) | ((rd.value() as u32) << 7) | (opcode as u32);
182    Instruction::Standard(instr)
183}
184
185/// S-type instruction encoding (Store)
186pub fn encode_s_type(opcode: u8, funct3: u8, rs1: Register, rs2: Register, imm: i16) -> Instruction {
187    let imm = imm as u32 & 0xfff;
188    let imm_11_5 = (imm >> 5) & 0x7f;
189    let imm_4_0 = imm & 0x1f;
190    let instr = (imm_11_5 << 25) | ((rs2.value() as u32) << 20) | ((rs1.value() as u32) << 15) | ((funct3 as u32) << 12) | (imm_4_0 << 7) | (opcode as u32);
191    Instruction::Standard(instr)
192}
193
194/// B-type instruction encoding (Branch)
195pub fn encode_b_type(opcode: u8, funct3: u8, rs1: Register, rs2: Register, imm: i16) -> Instruction {
196    let imm = (imm as u32) & 0x1ffe; // 13-bit signed immediate
197    let imm_12 = (imm >> 12) & 0x1;
198    let imm_10_5 = (imm >> 5) & 0x3f;
199    let imm_4_1 = (imm >> 1) & 0xf;
200    let imm_11 = (imm >> 11) & 0x1;
201    let instr = (imm_12 << 31) | (imm_10_5 << 25) | ((rs2.value() as u32) << 20) | ((rs1.value() as u32) << 15) | ((funct3 as u32) << 12) | (imm_4_1 << 8) | (imm_11 << 7) | (opcode as u32);
202    Instruction::Standard(instr)
203}
204
205/// U-type instruction encoding (Upper immediate)
206pub fn encode_u_type(opcode: u8, rd: Register, imm: u32) -> Instruction {
207    let imm = (imm & 0xfffff) << 12; // 20-bit immediate shifted to upper bits
208    let instr = imm | ((rd.value() as u32) << 7) | (opcode as u32);
209    Instruction::Standard(instr)
210}
211
212/// J-type instruction encoding (Jump)
213pub fn encode_j_type(opcode: u8, rd: Register, imm: i32) -> Instruction {
214    let imm = (imm as u32) & 0x1fffff; // 21-bit signed immediate
215    let imm_20 = (imm >> 20) & 0x1;
216    let imm_10_1 = (imm >> 1) & 0x3ff;
217    let imm_11 = (imm >> 11) & 0x1;
218    let imm_19_12 = (imm >> 12) & 0xff;
219    let instr = (imm_20 << 31) | (imm_10_1 << 21) | (imm_11 << 20) | (imm_19_12 << 12) | ((rd.value() as u32) << 7) | (opcode as u32);
220    Instruction::Standard(instr)
221}
222
223/// Common RISC-V opcodes
224pub mod opcodes {
225    pub const SYSTEM: u8 = 0x73;
226    pub const OP_IMM: u8 = 0x13;
227    pub const OP: u8 = 0x33;
228    pub const LOAD: u8 = 0x03;
229    pub const STORE: u8 = 0x23;
230    pub const BRANCH: u8 = 0x63;
231    pub const JAL: u8 = 0x6f;
232    pub const JALR: u8 = 0x67;
233    pub const LUI: u8 = 0x37;
234    pub const AUIPC: u8 = 0x17;
235    pub const OP_IMM_32: u8 = 0x1b;
236    pub const OP_32: u8 = 0x3b;
237}
238
239/// SYSTEM instruction function codes
240pub mod system_funct3 {
241    pub const CSRRW: u8 = 0x1;
242    pub const CSRRS: u8 = 0x2;
243    pub const CSRRC: u8 = 0x3;
244    pub const CSRRWI: u8 = 0x5;
245    pub const CSRRSI: u8 = 0x6;
246    pub const CSRRCI: u8 = 0x7;
247}
248
249/// Privileged instruction function codes (funct12 field)
250pub mod privileged_funct12 {
251    pub const ECALL: u16 = 0x000;  // Environment call
252    pub const EBREAK: u16 = 0x001; // Environment break
253    pub const SRET: u16 = 0x102;   // Supervisor return
254    pub const MRET: u16 = 0x302;   // Machine return
255    pub const WFI: u16 = 0x105;    // Wait for interrupt
256}
257
258/// Branch instruction function codes
259pub mod branch_funct3 {
260    pub const BEQ: u8 = 0x0;
261    pub const BNE: u8 = 0x1;
262    pub const BLT: u8 = 0x4;
263    pub const BGE: u8 = 0x5;
264    pub const BLTU: u8 = 0x6;
265    pub const BGEU: u8 = 0x7;
266}
267
268/// Load instruction function codes
269pub mod load_funct3 {
270    pub const LB: u8 = 0x0;
271    pub const LH: u8 = 0x1;
272    pub const LW: u8 = 0x2;
273    pub const LD: u8 = 0x3;
274    pub const LBU: u8 = 0x4;
275    pub const LHU: u8 = 0x5;
276    pub const LWU: u8 = 0x6;
277}
278
279/// Store instruction function codes
280pub mod store_funct3 {
281    pub const SB: u8 = 0x0;
282    pub const SH: u8 = 0x1;
283    pub const SW: u8 = 0x2;
284    pub const SD: u8 = 0x3;
285}
286
287/// Arithmetic/Logic instruction function codes
288pub mod alu_funct3 {
289    pub const ADD_SUB: u8 = 0x0;
290    pub const SLL: u8 = 0x1;
291    pub const SLT: u8 = 0x2;
292    pub const SLTU: u8 = 0x3;
293    pub const XOR: u8 = 0x4;
294    pub const SRL_SRA: u8 = 0x5;
295    pub const OR: u8 = 0x6;
296    pub const AND: u8 = 0x7;
297}
298
299/// M Extension (Multiply/Divide) instruction function codes
300/// All M-extension instructions use funct7 = 0x01 and opcode = OP (0x33)
301pub mod m_funct3 {
302    pub const MUL: u8 = 0x0;      // Multiply (low 64 bits)
303    pub const MULH: u8 = 0x1;     // Multiply high (signed × signed)
304    pub const MULHSU: u8 = 0x2;   // Multiply high (signed × unsigned)
305    pub const MULHU: u8 = 0x3;    // Multiply high (unsigned × unsigned)
306    pub const DIV: u8 = 0x4;      // Divide (signed)
307    pub const DIVU: u8 = 0x5;     // Divide (unsigned)
308    pub const REM: u8 = 0x6;      // Remainder (signed)
309    pub const REMU: u8 = 0x7;     // Remainder (unsigned)
310}
311
312/// M Extension funct7 code
313pub mod m_funct7 {
314    pub const M_EXT: u8 = 0x01;
315}
316
317/// Common CSR addresses
318pub mod csr {
319    use super::Csr;
320    
321    // Machine-mode CSRs
322    pub const MSTATUS: Csr = Csr::new(0x300);
323    pub const MISA: Csr = Csr::new(0x301);
324    pub const MEDELEG: Csr = Csr::new(0x302);
325    pub const MIDELEG: Csr = Csr::new(0x303);
326    pub const MIE: Csr = Csr::new(0x304);
327    pub const MTVEC: Csr = Csr::new(0x305);
328    pub const MSCRATCH: Csr = Csr::new(0x340);
329    pub const MEPC: Csr = Csr::new(0x341);
330    pub const MCAUSE: Csr = Csr::new(0x342);
331    pub const MTVAL: Csr = Csr::new(0x343);
332    pub const MIP: Csr = Csr::new(0x344);
333    pub const MHARTID: Csr = Csr::new(0xf14);
334    
335    // Supervisor-mode CSRs
336    pub const SSTATUS: Csr = Csr::new(0x100);
337    pub const SIE: Csr = Csr::new(0x104);
338    pub const STVEC: Csr = Csr::new(0x105);
339    pub const SSCRATCH: Csr = Csr::new(0x140);
340    pub const SEPC: Csr = Csr::new(0x141);
341    pub const SCAUSE: Csr = Csr::new(0x142);
342    pub const STVAL: Csr = Csr::new(0x143);
343    pub const SIP: Csr = Csr::new(0x144);
344}
345
346/// Common registers
347pub mod reg {
348    use super::Register;
349    
350    // Standard register names (x0-x31)
351    pub const X0: Register = Register::new(0);
352    pub const X1: Register = Register::new(1);
353    pub const X2: Register = Register::new(2);
354    pub const X3: Register = Register::new(3);
355    pub const X4: Register = Register::new(4);
356    pub const X5: Register = Register::new(5);
357    pub const X6: Register = Register::new(6);
358    pub const X7: Register = Register::new(7);
359    pub const X8: Register = Register::new(8);
360    pub const X9: Register = Register::new(9);
361    pub const X10: Register = Register::new(10);
362    pub const X11: Register = Register::new(11);
363    pub const X12: Register = Register::new(12);
364    pub const X13: Register = Register::new(13);
365    pub const X14: Register = Register::new(14);
366    pub const X15: Register = Register::new(15);
367    pub const X16: Register = Register::new(16);
368    pub const X17: Register = Register::new(17);
369    pub const X18: Register = Register::new(18);
370    pub const X19: Register = Register::new(19);
371    pub const X20: Register = Register::new(20);
372    pub const X21: Register = Register::new(21);
373    pub const X22: Register = Register::new(22);
374    pub const X23: Register = Register::new(23);
375    pub const X24: Register = Register::new(24);
376    pub const X25: Register = Register::new(25);
377    pub const X26: Register = Register::new(26);
378    pub const X27: Register = Register::new(27);
379    pub const X28: Register = Register::new(28);
380    pub const X29: Register = Register::new(29);
381    pub const X30: Register = Register::new(30);
382    pub const X31: Register = Register::new(31);
383
384    // RISC-V ABI register aliases
385    pub const ZERO: Register = X0;  // Hard-wired zero
386    pub const RA: Register = X1;    // Return address
387    pub const SP: Register = X2;    // Stack pointer
388    pub const GP: Register = X3;    // Global pointer
389    pub const TP: Register = X4;    // Thread pointer
390    pub const T0: Register = X5;    // Temporary register 0
391    pub const T1: Register = X6;    // Temporary register 1
392    pub const T2: Register = X7;    // Temporary register 2
393    pub const S0: Register = X8;    // Saved register 0 / Frame pointer
394    pub const FP: Register = X8;    // Frame pointer (alias for s0)
395    pub const S1: Register = X9;    // Saved register 1
396    pub const A0: Register = X10;   // Function argument 0 / Return value 0
397    pub const A1: Register = X11;   // Function argument 1 / Return value 1
398    pub const A2: Register = X12;   // Function argument 2
399    pub const A3: Register = X13;   // Function argument 3
400    pub const A4: Register = X14;   // Function argument 4
401    pub const A5: Register = X15;   // Function argument 5
402    pub const A6: Register = X16;   // Function argument 6
403    pub const A7: Register = X17;   // Function argument 7
404    pub const S2: Register = X18;   // Saved register 2
405    pub const S3: Register = X19;   // Saved register 3
406    pub const S4: Register = X20;   // Saved register 4
407    pub const S5: Register = X21;   // Saved register 5
408    pub const S6: Register = X22;   // Saved register 6
409    pub const S7: Register = X23;   // Saved register 7
410    pub const S8: Register = X24;   // Saved register 8
411    pub const S9: Register = X25;   // Saved register 9
412    pub const S10: Register = X26;  // Saved register 10
413    pub const S11: Register = X27;  // Saved register 11
414    pub const T3: Register = X28;   // Temporary register 3
415    pub const T4: Register = X29;   // Temporary register 4
416    pub const T5: Register = X30;   // Temporary register 5
417    pub const T6: Register = X31;   // Temporary register 6
418}