Skip to main content

ab_riscv_primitives/instruction/
rv64.rs

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