Skip to main content

ab_riscv_primitives/instructions/
rv64.rs

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