ab_riscv_primitives/instruction/
rv64.rs

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