Skip to main content

ab_riscv_primitives/instructions/
rv64.rs

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