Skip to main content

ab_riscv_primitives/instructions/
rv32.rs

1//! Base RISC-V RV32 instruction set
2
3use crate::instructions::Instruction;
4use crate::registers::general_purpose::Register;
5use ab_riscv_macros::instruction;
6use core::fmt;
7
8pub mod b;
9pub mod m;
10#[cfg(test)]
11mod tests;
12pub mod zk;
13
14/// RISC-V RV32 instruction
15#[instruction]
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum Rv32Instruction<Reg> {
18    // R-type
19    Add { rd: Reg, rs1: Reg, rs2: Reg },
20    Sub { rd: Reg, rs1: Reg, rs2: Reg },
21    Sll { rd: Reg, rs1: Reg, rs2: Reg },
22    Slt { rd: Reg, rs1: Reg, rs2: Reg },
23    Sltu { rd: Reg, rs1: Reg, rs2: Reg },
24    Xor { rd: Reg, rs1: Reg, rs2: Reg },
25    Srl { rd: Reg, rs1: Reg, rs2: Reg },
26    Sra { rd: Reg, rs1: Reg, rs2: Reg },
27    Or { rd: Reg, rs1: Reg, rs2: Reg },
28    And { rd: Reg, rs1: Reg, rs2: Reg },
29
30    // I-type
31    Addi { rd: Reg, rs1: Reg, imm: i16 },
32    Slti { rd: Reg, rs1: Reg, imm: i16 },
33    Sltiu { rd: Reg, rs1: Reg, imm: i16 },
34    Xori { rd: Reg, rs1: Reg, imm: i16 },
35    Ori { rd: Reg, rs1: Reg, imm: i16 },
36    Andi { rd: Reg, rs1: Reg, imm: i16 },
37    Slli { rd: Reg, rs1: Reg, shamt: u8 },
38    Srli { rd: Reg, rs1: Reg, shamt: u8 },
39    Srai { rd: Reg, rs1: Reg, shamt: u8 },
40
41    // Loads (I-type)
42    Lb { rd: Reg, rs1: Reg, imm: i16 },
43    Lh { rd: Reg, rs1: Reg, imm: i16 },
44    Lw { rd: Reg, rs1: Reg, imm: i16 },
45    Lbu { rd: Reg, rs1: Reg, imm: i16 },
46    Lhu { rd: Reg, rs1: Reg, imm: i16 },
47
48    // Jalr (I-type)
49    Jalr { rd: Reg, rs1: Reg, imm: i16 },
50
51    // S-type
52    Sb { rs2: Reg, rs1: Reg, imm: i16 },
53    Sh { rs2: Reg, rs1: Reg, imm: i16 },
54    Sw { rs2: Reg, rs1: Reg, imm: i16 },
55
56    // B-type
57    Beq { rs1: Reg, rs2: Reg, imm: i32 },
58    Bne { rs1: Reg, rs2: Reg, imm: i32 },
59    Blt { rs1: Reg, rs2: Reg, imm: i32 },
60    Bge { rs1: Reg, rs2: Reg, imm: i32 },
61    Bltu { rs1: Reg, rs2: Reg, imm: i32 },
62    Bgeu { rs1: Reg, rs2: Reg, imm: i32 },
63
64    // Lui (U-type)
65    Lui { rd: Reg, imm: i32 },
66
67    // Auipc (U-type)
68    Auipc { rd: Reg, imm: i32 },
69
70    // Jal (J-type)
71    Jal { rd: Reg, imm: i32 },
72
73    // Fence
74    Fence { pred: u8, succ: u8 },
75    FenceTso,
76
77    // System instructions
78    Ecall,
79    Ebreak,
80
81    // Unimplemented/illegal
82    Unimp,
83}
84
85#[instruction]
86impl<Reg> const Instruction for Rv32Instruction<Reg>
87where
88    Reg: [const] Register<Type = u32>,
89{
90    type Reg = Reg;
91
92    #[inline(always)]
93    fn try_decode(instruction: u32) -> Option<Self> {
94        let opcode = (instruction & 0b111_1111) as u8;
95        let rd_bits = ((instruction >> 7) & 0x1f) as u8;
96        let funct3 = ((instruction >> 12) & 0b111) as u8;
97        let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
98        let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
99        let funct7 = ((instruction >> 25) & 0b111_1111) as u8;
100
101        match opcode {
102            // R-type
103            0b0110011 => {
104                let rd = Reg::from_bits(rd_bits)?;
105                let rs1 = Reg::from_bits(rs1_bits)?;
106                let rs2 = Reg::from_bits(rs2_bits)?;
107                match (funct3, funct7) {
108                    (0b000, 0b0000000) => Some(Self::Add { rd, rs1, rs2 }),
109                    (0b000, 0b0100000) => Some(Self::Sub { rd, rs1, rs2 }),
110                    (0b001, 0b0000000) => Some(Self::Sll { rd, rs1, rs2 }),
111                    (0b010, 0b0000000) => Some(Self::Slt { rd, rs1, rs2 }),
112                    (0b011, 0b0000000) => Some(Self::Sltu { rd, rs1, rs2 }),
113                    (0b100, 0b0000000) => Some(Self::Xor { rd, rs1, rs2 }),
114                    (0b101, 0b0000000) => Some(Self::Srl { rd, rs1, rs2 }),
115                    (0b101, 0b0100000) => Some(Self::Sra { rd, rs1, rs2 }),
116                    (0b110, 0b0000000) => Some(Self::Or { rd, rs1, rs2 }),
117                    (0b111, 0b0000000) => Some(Self::And { rd, rs1, rs2 }),
118                    _ => None,
119                }
120            }
121            // I-type
122            0b0010011 => {
123                let rd = Reg::from_bits(rd_bits)?;
124                let rs1 = Reg::from_bits(rs1_bits)?;
125                let imm = (instruction.cast_signed() >> 20) as i16;
126                match funct3 {
127                    0b000 => Some(Self::Addi { rd, rs1, imm }),
128                    0b010 => Some(Self::Slti { rd, rs1, imm }),
129                    0b011 => Some(Self::Sltiu { rd, rs1, imm }),
130                    0b100 => Some(Self::Xori { rd, rs1, imm }),
131                    0b110 => Some(Self::Ori { rd, rs1, imm }),
132                    0b111 => Some(Self::Andi { rd, rs1, imm }),
133                    0b001 => {
134                        // RV32: 5-bit shamt, funct7 must be 0b0000000
135                        let shamt = (instruction >> 20) as u8 & 0b1_1111;
136                        if funct7 == 0b0000000 {
137                            Some(Self::Slli { rd, rs1, shamt })
138                        } else {
139                            None
140                        }
141                    }
142                    0b101 => {
143                        // RV32: 5-bit shamt, funct7 distinguishes SRLI/SRAI
144                        let shamt = (instruction >> 20) as u8 & 0b1_1111;
145                        match funct7 {
146                            0b0000000 => Some(Self::Srli { rd, rs1, shamt }),
147                            0b0100000 => Some(Self::Srai { rd, rs1, shamt }),
148                            _ => None,
149                        }
150                    }
151                    _ => None,
152                }
153            }
154            // Loads (I-type)
155            0b0000011 => {
156                let rd = Reg::from_bits(rd_bits)?;
157                let rs1 = Reg::from_bits(rs1_bits)?;
158                let imm = (instruction.cast_signed() >> 20) as i16;
159                match funct3 {
160                    0b000 => Some(Self::Lb { rd, rs1, imm }),
161                    0b001 => Some(Self::Lh { rd, rs1, imm }),
162                    0b010 => Some(Self::Lw { rd, rs1, imm }),
163                    0b100 => Some(Self::Lbu { rd, rs1, imm }),
164                    0b101 => Some(Self::Lhu { rd, rs1, imm }),
165                    _ => None,
166                }
167            }
168            // Jalr (I-type)
169            0b1100111 => {
170                let rd = Reg::from_bits(rd_bits)?;
171                let rs1 = Reg::from_bits(rs1_bits)?;
172                if funct3 == 0b000 {
173                    let imm = (instruction.cast_signed() >> 20) as i16;
174                    Some(Self::Jalr { rd, rs1, imm })
175                } else {
176                    None
177                }
178            }
179            // S-type
180            0b0100011 => {
181                let rs1 = Reg::from_bits(rs1_bits)?;
182                let rs2 = Reg::from_bits(rs2_bits)?;
183                let imm11_5 = ((instruction >> 25) & 0b111_1111).cast_signed();
184                let imm4_0 = ((instruction >> 7) & 0b1_1111).cast_signed();
185                let imm = (imm11_5 << 5) | imm4_0;
186                // Sign extend
187                let imm = ((imm << 20) >> 20) as i16;
188                match funct3 {
189                    0b000 => Some(Self::Sb { rs2, rs1, imm }),
190                    0b001 => Some(Self::Sh { rs2, rs1, imm }),
191                    0b010 => Some(Self::Sw { rs2, rs1, imm }),
192                    _ => None,
193                }
194            }
195            // B-type
196            0b1100011 => {
197                let rs1 = Reg::from_bits(rs1_bits)?;
198                let rs2 = Reg::from_bits(rs2_bits)?;
199                let imm12 = ((instruction >> 31) & 1).cast_signed();
200                let imm10_5 = ((instruction >> 25) & 0b11_1111).cast_signed();
201                let imm4_1 = ((instruction >> 8) & 0b1111).cast_signed();
202                let imm11 = ((instruction >> 7) & 1).cast_signed();
203                let imm = (imm12 << 12) | (imm11 << 11) | (imm10_5 << 5) | (imm4_1 << 1);
204                // Sign extend
205                let imm = (imm << 19) >> 19;
206                match funct3 {
207                    0b000 => Some(Self::Beq { rs1, rs2, imm }),
208                    0b001 => Some(Self::Bne { rs1, rs2, imm }),
209                    0b100 => Some(Self::Blt { rs1, rs2, imm }),
210                    0b101 => Some(Self::Bge { rs1, rs2, imm }),
211                    0b110 => Some(Self::Bltu { rs1, rs2, imm }),
212                    0b111 => Some(Self::Bgeu { rs1, rs2, imm }),
213                    _ => None,
214                }
215            }
216            // Lui (U-type)
217            0b0110111 => {
218                let rd = Reg::from_bits(rd_bits)?;
219                let imm = (instruction & 0xffff_f000).cast_signed();
220                Some(Self::Lui { rd, imm })
221            }
222            // Auipc (U-type)
223            0b0010111 => {
224                let rd = Reg::from_bits(rd_bits)?;
225                let imm = (instruction & 0xffff_f000).cast_signed();
226                Some(Self::Auipc { rd, imm })
227            }
228            // Jal (J-type)
229            0b1101111 => {
230                let rd = Reg::from_bits(rd_bits)?;
231                let imm20 = ((instruction >> 31) & 1).cast_signed();
232                let imm10_1 = ((instruction >> 21) & 0b11_1111_1111).cast_signed();
233                let imm11 = ((instruction >> 20) & 1).cast_signed();
234                let imm19_12 = ((instruction >> 12) & 0b1111_1111).cast_signed();
235                let imm = (imm20 << 20) | (imm19_12 << 12) | (imm11 << 11) | (imm10_1 << 1);
236                // Sign extend
237                let imm = (imm << 11) >> 11;
238                Some(Self::Jal { rd, imm })
239            }
240            // Fence (I-type like, simplified for EM)
241            0b0001111 => {
242                if funct3 == 0b000 && rd_bits == 0 && rs1_bits == 0 {
243                    let fm = (instruction >> 28) & 0b1111;
244                    let pred = ((instruction >> 24) & 0xf) as u8;
245                    let succ = ((instruction >> 20) & 0xf) as u8;
246                    match fm {
247                        0b0000 => Some(Self::Fence { pred, succ }),
248                        0b1000 => {
249                            // FENCE.TSO: fm=8, pred=RW(0b0011), succ=RW(0b0011) - fixed by spec
250                            if pred == 0b0011 && succ == 0b0011 {
251                                Some(Self::FenceTso)
252                            } else {
253                                None
254                            }
255                        }
256                        _ => None,
257                    }
258                } else {
259                    None
260                }
261            }
262            // System instructions
263            0b1110011 => {
264                let imm = (instruction >> 20) & 0xfff;
265                if funct3 == 0 && rd_bits == 0 && rs1_bits == 0 {
266                    match imm {
267                        0 => Some(Self::Ecall),
268                        1 => Some(Self::Ebreak),
269                        _ => None,
270                    }
271                } else if funct3 == 0b001 && rd_bits == 0 && rs1_bits == 0 && imm == 0xc00 {
272                    // `0xc0001073` is emitted as `unimp`/illegal instruction by various compilers,
273                    // including Rust when it hits a panic
274                    Some(Self::Unimp)
275                } else {
276                    None
277                }
278            }
279            _ => None,
280        }
281    }
282
283    #[inline(always)]
284    fn alignment() -> u8 {
285        size_of::<u32>() as u8
286    }
287
288    #[inline(always)]
289    fn size(&self) -> u8 {
290        size_of::<u32>() as u8
291    }
292}
293
294impl<Reg> fmt::Display for Rv32Instruction<Reg>
295where
296    Reg: fmt::Display,
297{
298    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299        match self {
300            Self::Add { rd, rs1, rs2 } => write!(f, "add {}, {}, {}", rd, rs1, rs2),
301            Self::Sub { rd, rs1, rs2 } => write!(f, "sub {}, {}, {}", rd, rs1, rs2),
302            Self::Sll { rd, rs1, rs2 } => write!(f, "sll {}, {}, {}", rd, rs1, rs2),
303            Self::Slt { rd, rs1, rs2 } => write!(f, "slt {}, {}, {}", rd, rs1, rs2),
304            Self::Sltu { rd, rs1, rs2 } => write!(f, "sltu {}, {}, {}", rd, rs1, rs2),
305            Self::Xor { rd, rs1, rs2 } => write!(f, "xor {}, {}, {}", rd, rs1, rs2),
306            Self::Srl { rd, rs1, rs2 } => write!(f, "srl {}, {}, {}", rd, rs1, rs2),
307            Self::Sra { rd, rs1, rs2 } => write!(f, "sra {}, {}, {}", rd, rs1, rs2),
308            Self::Or { rd, rs1, rs2 } => write!(f, "or {}, {}, {}", rd, rs1, rs2),
309            Self::And { rd, rs1, rs2 } => write!(f, "and {}, {}, {}", rd, rs1, rs2),
310
311            Self::Addi { rd, rs1, imm } => write!(f, "addi {}, {}, {}", rd, rs1, imm),
312            Self::Slti { rd, rs1, imm } => write!(f, "slti {}, {}, {}", rd, rs1, imm),
313            Self::Sltiu { rd, rs1, imm } => write!(f, "sltiu {}, {}, {}", rd, rs1, imm),
314            Self::Xori { rd, rs1, imm } => write!(f, "xori {}, {}, {}", rd, rs1, imm),
315            Self::Ori { rd, rs1, imm } => write!(f, "ori {}, {}, {}", rd, rs1, imm),
316            Self::Andi { rd, rs1, imm } => write!(f, "andi {}, {}, {}", rd, rs1, imm),
317            Self::Slli { rd, rs1, shamt } => write!(f, "slli {}, {}, {}", rd, rs1, shamt),
318            Self::Srli { rd, rs1, shamt } => write!(f, "srli {}, {}, {}", rd, rs1, shamt),
319            Self::Srai { rd, rs1, shamt } => write!(f, "srai {}, {}, {}", rd, rs1, shamt),
320
321            Self::Lb { rd, rs1, imm } => write!(f, "lb {}, {}({})", rd, imm, rs1),
322            Self::Lh { rd, rs1, imm } => write!(f, "lh {}, {}({})", rd, imm, rs1),
323            Self::Lw { rd, rs1, imm } => write!(f, "lw {}, {}({})", rd, imm, rs1),
324            Self::Lbu { rd, rs1, imm } => write!(f, "lbu {}, {}({})", rd, imm, rs1),
325            Self::Lhu { rd, rs1, imm } => write!(f, "lhu {}, {}({})", rd, imm, rs1),
326
327            Self::Jalr { rd, rs1, imm } => write!(f, "jalr {}, {}({})", rd, imm, rs1),
328
329            Self::Sb { rs2, rs1, imm } => write!(f, "sb {}, {}({})", rs2, imm, rs1),
330            Self::Sh { rs2, rs1, imm } => write!(f, "sh {}, {}({})", rs2, imm, rs1),
331            Self::Sw { rs2, rs1, imm } => write!(f, "sw {}, {}({})", rs2, imm, rs1),
332
333            Self::Beq { rs1, rs2, imm } => write!(f, "beq {}, {}, {}", rs1, rs2, imm),
334            Self::Bne { rs1, rs2, imm } => write!(f, "bne {}, {}, {}", rs1, rs2, imm),
335            Self::Blt { rs1, rs2, imm } => write!(f, "blt {}, {}, {}", rs1, rs2, imm),
336            Self::Bge { rs1, rs2, imm } => write!(f, "bge {}, {}, {}", rs1, rs2, imm),
337            Self::Bltu { rs1, rs2, imm } => write!(f, "bltu {}, {}, {}", rs1, rs2, imm),
338            Self::Bgeu { rs1, rs2, imm } => write!(f, "bgeu {}, {}, {}", rs1, rs2, imm),
339
340            Self::Lui { rd, imm } => write!(f, "lui {}, 0x{:x}", rd, imm >> 12),
341
342            Self::Auipc { rd, imm } => write!(f, "auipc {}, 0x{:x}", rd, imm >> 12),
343
344            Self::Jal { rd, imm } => write!(f, "jal {}, {}", rd, imm),
345
346            Self::Fence { pred, succ } => write!(f, "fence {}, {}", pred, succ),
347            Self::FenceTso => write!(f, "fence.tso"),
348
349            Self::Ecall => write!(f, "ecall"),
350            Self::Ebreak => write!(f, "ebreak"),
351
352            Self::Unimp => write!(f, "unimp"),
353        }
354    }
355}