Skip to main content

rv_asm/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3#![deny(missing_docs)]
4
5use core::fmt::{self, Debug, Display};
6use core::ops::RangeInclusive;
7
8/// The register size of the ISA, RV32 or RV64.
9#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub enum Xlen {
11    /// 32 bit
12    Rv32,
13    /// 64 bit
14    Rv64,
15}
16
17impl Xlen {
18    /// Whether this is [`Xlen::Rv32`].
19    pub fn is_32(self) -> bool {
20        matches!(self, Self::Rv32)
21    }
22
23    /// Whether this is [`Xlen::Rv64`].
24    pub fn is_64(self) -> bool {
25        matches!(self, Self::Rv64)
26    }
27}
28
29/// A decoded RISC-V integer register.
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
31pub struct Reg(pub u8);
32
33impl Reg {
34    /// The zero register `zero` (`x0`)
35    pub const ZERO: Reg = Reg(0);
36
37    /// The return address register `ra` (`x1`)
38    pub const RA: Reg = Reg(1);
39    /// The stack pointer register `sp` (`x2`)
40    pub const SP: Reg = Reg(2);
41    /// The global pointer register `gp` (`x3`)
42    pub const GP: Reg = Reg(3);
43    /// The thread pointer register `tp` (`x4`)
44    pub const TP: Reg = Reg(4);
45
46    /// Saved register `s0` (`x8`)
47    pub const S0: Reg = Reg(8);
48    /// Saved register frame pointer `fp` (`s0`, `x8`)
49    pub const FP: Reg = Reg(8);
50    /// Saved register `s1` (`x9`)
51    pub const S1: Reg = Reg(9);
52    /// Saved register `s2` (`x18`)
53    pub const S2: Reg = Reg(18);
54    /// Saved register `s3` (`x19`)
55    pub const S3: Reg = Reg(19);
56    /// Saved register `s4` (`x20`)
57    pub const S4: Reg = Reg(20);
58    /// Saved register `s5` (`x21`)
59    pub const S5: Reg = Reg(21);
60    /// Saved register `s6` (`x22`)
61    pub const S6: Reg = Reg(22);
62    /// Saved register `s7` (`x23`)
63    pub const S7: Reg = Reg(23);
64    /// Saved register `s8` (`x24`)
65    pub const S8: Reg = Reg(24);
66    /// Saved register `s9` (`x25`)
67    pub const S9: Reg = Reg(25);
68    /// Saved register `s10` (`x26`)
69    pub const S10: Reg = Reg(26);
70    /// Saved register `s11` (`x27`)
71    pub const S11: Reg = Reg(27);
72
73    /// Argument/return value register `a0` (`x10`)
74    pub const A0: Reg = Reg(10);
75    /// Argument/return value register `a1` (`x11`)
76    pub const A1: Reg = Reg(11);
77    /// Argument register `a2` (`x12`)
78    pub const A2: Reg = Reg(12);
79    /// Argument register `a3` (`x13`)
80    pub const A3: Reg = Reg(13);
81    /// Argument register `a4` (`x14`)
82    pub const A4: Reg = Reg(14);
83    /// Argument register `a5` (`x15`)
84    pub const A5: Reg = Reg(15);
85    /// Argument register `a6` (`x16`)
86    pub const A6: Reg = Reg(16);
87    /// Argument register `a7` (`x17`)
88    pub const A7: Reg = Reg(17);
89
90    /// Temporary register `t0` (`x5`)
91    pub const T0: Reg = Reg(5);
92    /// Temporary register `t1` (`x6`)
93    pub const T1: Reg = Reg(6);
94    /// Temporary register `t2` (`x7`)
95    pub const T2: Reg = Reg(7);
96    /// Temporary register `t3` (`x28`)
97    pub const T3: Reg = Reg(28);
98    /// Temporary register `t4` (`x29`)
99    pub const T4: Reg = Reg(29);
100    /// Temporary register `t5` (`x30`)
101    pub const T5: Reg = Reg(30);
102    /// Temporary register `t6` (`x31`)
103    pub const T6: Reg = Reg(31);
104}
105
106impl Display for Reg {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        let n = self.0;
109        match n {
110            0 => write!(f, "zero"),
111            1 => write!(f, "ra"),
112            2 => write!(f, "sp"),
113            3 => write!(f, "gp"),
114            4 => write!(f, "tp"),
115            5..=7 => write!(f, "t{}", n - 5),
116            8 => write!(f, "s0"),
117            9 => write!(f, "s1"),
118            10..=17 => write!(f, "a{}", n - 10),
119            18..=27 => write!(f, "s{}", n - 18 + 2),
120            28..=31 => write!(f, "t{}", n - 28 + 3),
121            _ => unreachable!("invalid register"),
122        }
123    }
124}
125
126/// An immediate in an instruction.
127/// This represents the real value that will be put in the register,
128/// so sign extension has been performed if necessary, and for instructions
129/// like `lui` the value will have been shifted.
130///
131/// This type is XLEN-agnostic, use the XLEN-specific accessors to get the correct value.
132#[derive(Copy, Clone, PartialEq, Eq, Hash)]
133pub struct Imm(u64);
134
135impl Imm {
136    /// The immediate `0`.
137    /// Useful as a shortcut for `Imm::new_u32(0)` and for patterns.
138    pub const ZERO: Self = Self::new_u32(0);
139
140    /// Create a new immediate from the (if necessary) sign-extended value.
141    pub const fn new_i32(value: i32) -> Self {
142        Self(value as i64 as u64)
143    }
144
145    /// Create a new immediate from the (if necessary) zero-extended value.
146    pub const fn new_u32(value: u32) -> Self {
147        Self(value as u64)
148    }
149
150    /// Get the `u32` (RV32) value of the immediate.
151    pub const fn as_u32(self) -> u32 {
152        self.0 as u32
153    }
154
155    /// Get the `i32` (RV32) value of the immediate.
156    pub const fn as_i32(self) -> i32 {
157        self.0 as i32
158    }
159
160    /// Get the `u64` (RV64) value of the immediate.
161    pub const fn as_u64(self) -> u64 {
162        self.0 as u64
163    }
164
165    /// Get the `i64` (RV64) value of the immediate.
166    pub const fn as_i64(self) -> i64 {
167        self.0 as i64
168    }
169}
170
171impl From<i32> for Imm {
172    fn from(value: i32) -> Self {
173        Self::new_i32(value)
174    }
175}
176
177impl From<u32> for Imm {
178    fn from(value: u32) -> Self {
179        Self::new_u32(value)
180    }
181}
182
183impl From<Imm> for u32 {
184    fn from(value: Imm) -> Self {
185        value.as_u32()
186    }
187}
188
189impl From<Imm> for i32 {
190    fn from(value: Imm) -> Self {
191        value.as_i32()
192    }
193}
194
195/// A RISC-V instruction.
196/// 
197/// Every variant is a different instruction, with immediates as `u32`.
198/// For instructions that sign-extend immediates, the immediates will have been
199/// sign-extended already, so the value can be used as-is.
200/// For instructions that have immediates in the upper bits (`lui`, `auipc`),
201/// the shift will have been done already, so the value can also be used as-is.
202#[derive(Clone, Copy, PartialEq, Eq, Hash)]
203#[rustfmt::skip]
204#[expect(missing_docs)] // enum variant fields
205#[non_exhaustive]
206pub enum Inst {
207    /// Load Upper Immediate
208    Lui { uimm: Imm, dest: Reg },
209    /// Add Upper Immediate to PC
210    Auipc { uimm: Imm, dest: Reg },
211
212    /// Jump And Link
213    Jal { offset: Imm, dest: Reg },
214    /// Jump And Link Register (indirect)
215    Jalr { offset: Imm, base: Reg, dest: Reg },
216
217    /// Branch Equal
218    Beq { offset: Imm, src1: Reg, src2: Reg },
219    /// Branch Not Equal
220    Bne { offset: Imm, src1: Reg, src2: Reg },
221    /// Branch Less Than (signed)
222    Blt { offset: Imm, src1: Reg, src2: Reg },
223    /// Branch Greater or Equal (signed)
224    Bge { offset: Imm, src1: Reg, src2: Reg },
225    /// Branch Less Than Unsigned
226    Bltu { offset: Imm, src1: Reg, src2: Reg },
227    /// Branch Greater or Equal Unsigned
228    Bgeu { offset: Imm, src1: Reg, src2: Reg },
229
230    /// Load Byte (sign-ext)
231    Lb { offset: Imm, dest: Reg, base: Reg },
232    /// Load Unsigned Byte (zero-ext)
233    Lbu { offset: Imm, dest: Reg, base: Reg },
234    /// Load Half (sign-ext)
235    Lh { offset: Imm, dest: Reg, base: Reg },
236    /// Load Unsigned Half (zero-ext)
237    Lhu { offset: Imm, dest: Reg, base: Reg },
238    /// Load Word (on RV64: sign-ext)
239    Lw { offset: Imm, dest: Reg, base: Reg },
240    /// Load Word (zero-ext) (**RV64 only**)
241    Lwu { offset: Imm, dest: Reg, base: Reg },
242    /// Load Doubleword (**RV64 only**)
243    Ld { offset: Imm, dest: Reg, base: Reg },
244
245
246    /// Store Byte
247    Sb { offset: Imm, src: Reg, base: Reg },
248    /// Store Half
249    Sh { offset: Imm, src: Reg, base: Reg },
250    /// Store Word
251    Sw { offset: Imm, src: Reg, base: Reg },
252    /// Store Doubleword (**RV64 only**)
253    Sd { offset: Imm, src: Reg, base: Reg },
254
255    /// Add Immediate
256    Addi { imm: Imm, dest: Reg, src1: Reg },
257    /// Add Immediate 32-bit (**RV64 only**)
258    AddiW { imm: Imm, dest: Reg, src1: Reg },
259    /// Set Less Than Immediate (signed)
260    Slti { imm: Imm, dest: Reg, src1: Reg },
261    /// Set Less Than Immediate Unsigned
262    Sltiu { imm: Imm, dest: Reg, src1: Reg },
263    /// XOR Immediate
264    Xori { imm: Imm, dest: Reg, src1: Reg },
265    /// OR Immediate
266    Ori { imm: Imm, dest: Reg, src1: Reg },
267    /// AND Immediate
268    Andi { imm: Imm, dest: Reg, src1: Reg },
269    /// Shift Left Logical Immediate
270    Slli { imm: Imm, dest: Reg, src1: Reg },
271    /// Shift Left Logical Immediate 32-bit (**RV64 only**)
272    SlliW { imm: Imm, dest: Reg, src1: Reg },
273    /// Shift Right Logical Immediate (unsigned)
274    Srli { imm: Imm, dest: Reg, src1: Reg },
275    /// Shift Right Logical Immediate (unsigned) 32-bit (**RV64 only**)
276    SrliW { imm: Imm, dest: Reg, src1: Reg },
277    /// Shift Right Arithmetic Immediate (signed)
278    Srai { imm: Imm, dest: Reg, src1: Reg },
279    /// Shift Right Arithmetic Immediate (signed) 32-bit (**RV64 only**)
280    SraiW { imm: Imm, dest: Reg, src1: Reg },
281
282    /// Add
283    Add { dest: Reg, src1: Reg, src2: Reg },
284    /// Add 32-bit (**RV64 only**)
285    AddW { dest: Reg, src1: Reg, src2: Reg },
286    /// Subtract
287    Sub { dest: Reg, src1: Reg, src2: Reg },
288    /// Subtract 32-bit (**RV64 only**)
289    SubW { dest: Reg, src1: Reg, src2: Reg },
290    /// Shift Left Logical
291    Sll { dest: Reg, src1: Reg, src2: Reg },
292    /// Shift Left Logical 32-bit (**RV64 only**)
293    SllW { dest: Reg, src1: Reg, src2: Reg },
294    /// Set Less Than (signed)
295    Slt { dest: Reg, src1: Reg, src2: Reg },
296    /// Set Less Than Unsigned
297    Sltu { dest: Reg, src1: Reg, src2: Reg },
298    /// XOR
299    Xor { dest: Reg, src1: Reg, src2: Reg },
300    /// Shift Right Logical (unsigned)
301    Srl { dest: Reg, src1: Reg, src2: Reg },
302    /// Shift Right Logical (unsigned) 32-bit (**RV64 only**)
303    SrlW { dest: Reg, src1: Reg, src2: Reg },
304    /// Shift Right Arithmetic (unsigned)
305    Sra { dest: Reg, src1: Reg, src2: Reg },
306    /// Shift Right Arithmetic (unsigned) 32-bit (**RV64 only**)
307    SraW { dest: Reg, src1: Reg, src2: Reg },
308    /// OR
309    Or { dest: Reg, src1: Reg, src2: Reg },
310    /// AND
311    And { dest: Reg, src1: Reg, src2: Reg },
312    /// Memory Fence
313    Fence { fence: Fence },
314
315    /// ECALL, call into environment
316    Ecall,
317    /// EBREAK, break into debugger
318    Ebreak,
319
320    // ------------- M extension -------------
321    /// Multiply
322    Mul { dest: Reg, src1: Reg, src2: Reg },
323    /// Multiply 32-bit (**RV64 only**)
324    MulW { dest: Reg, src1: Reg, src2: Reg },
325    /// Mul Upper Half Signed-Signed
326    Mulh { dest: Reg, src1: Reg, src2: Reg },
327    /// Mul Upper Half Signed-Unsigned
328    Mulhsu { dest: Reg, src1: Reg, src2: Reg },
329    /// Mul Upper Half Unsigned-Unsigned
330    Mulhu { dest: Reg, src1: Reg, src2: Reg },
331    /// Divide (signed)
332    Div { dest: Reg, src1: Reg, src2: Reg },
333    /// Divide (signed) 32-bit (**RV64 only**)
334    DivW { dest: Reg, src1: Reg, src2: Reg },
335    /// Divide Unsigned
336    Divu { dest: Reg, src1: Reg, src2: Reg },
337    /// Divide Unsigned 32-bit (**RV64 only**)
338    DivuW { dest: Reg, src1: Reg, src2: Reg },
339    /// Remainder (signed)
340    Rem { dest: Reg, src1: Reg, src2: Reg },
341    /// Remainder (signed) 32-bit (**RV64 only**)
342    RemW { dest: Reg, src1: Reg, src2: Reg },
343    /// Remainder Unsigned
344    Remu { dest: Reg, src1: Reg, src2: Reg },
345    /// Remainder Unsigned 32-bit (**RV64 only**)
346    RemuW { dest: Reg, src1: Reg, src2: Reg },
347
348    // ------------- A extension -------------
349    /// Load-Reserved Word
350    LrW {
351        order: AmoOrdering,
352        dest: Reg,
353        addr: Reg,  
354    },
355    /// Store-Conditional Word
356    ScW {
357        order: AmoOrdering,
358        dest: Reg,
359        addr: Reg,
360        src: Reg,
361    },
362    /// Atomic Memory Operation
363    AmoW {
364        order: AmoOrdering,
365        op: AmoOp,
366        dest: Reg,
367        addr: Reg,
368        src: Reg,
369    },
370}
371
372/// The details of a RISC-V `fence` instruction.
373#[derive(Clone, Copy, PartialEq, Eq, Hash)]
374pub struct Fence {
375    /// The `fm` field of the instruction.
376    /// - `0b0000` is a normal fence
377    /// - `0b1000` with `rw,rw` implies a `fence.tso`
378    pub fm: u8,
379    /// The predecessor set.
380    pub pred: FenceSet,
381    /// The sucessor set.
382    pub succ: FenceSet,
383    /// The `rd` field of the instruction. Currently always zero.
384    pub dest: Reg,
385    /// The `rs1` field of the instruction. Currently always zero.
386    pub src: Reg,
387}
388
389/// The affected parts of a fence.
390#[derive(Clone, Copy, PartialEq, Eq, Hash)]
391#[expect(missing_docs)]
392pub struct FenceSet {
393    pub device_input: bool,
394    pub device_output: bool,
395    pub memory_read: bool,
396    pub memory_write: bool,
397}
398
399/// An atomic memory ordering for instructions from the A extension.
400#[derive(Clone, Copy, PartialEq, Eq, Hash)]
401pub enum AmoOrdering {
402    /// No bits.
403    Relaxed,
404    /// `aq`
405    Acquire,
406    /// `rl`
407    Release,
408    /// `aq`, `rl`
409    SeqCst,
410}
411
412/// An atomic memory operations from the Zaamo extension.
413#[derive(Clone, Copy, PartialEq, Eq, Hash)]
414pub enum AmoOp {
415    /// Swap
416    Swap,
417    /// ADD
418    Add,
419    /// XOR
420    Xor,
421    /// AND
422    And,
423    /// OR
424    Or,
425    /// Signed minimum
426    Min,
427    /// Signed maximum
428    Max,
429    /// Unsigned minimum
430    Minu,
431    /// Unsigned maximum
432    Maxu,
433}
434
435/// The error used for invalid instructions containing information about the instruction and error.
436///
437/// Note that this is also returned for the defined illegal instruction of all zero.
438pub struct DecodeError {
439    /// The instruction bytes that failed to decode.
440    pub instruction: u32,
441    /// Which field of the instruction contained unexpected bits.
442    pub unexpected_field: &'static str,
443}
444
445impl Fence {
446    /// Whether this is a `fence.tso`.
447    /// `fm=0b1000` and `RW,RW`
448    pub fn is_tso(&self) -> bool {
449        matches!(
450            self,
451            Self {
452                fm: 0b1000,
453                pred: FenceSet {
454                    device_input: _,
455                    device_output: _,
456                    memory_read: true,
457                    memory_write: true
458                },
459                succ: FenceSet {
460                    device_input: _,
461                    device_output: _,
462                    memory_read: true,
463                    memory_write: true
464                },
465                ..
466            }
467        )
468    }
469    /// Whether this fence indicates a `pause` assembler pseudoinstruction.
470    pub fn is_pause(&self) -> bool {
471        self.pred
472            == FenceSet {
473                device_input: false,
474                device_output: false,
475                memory_read: false,
476                memory_write: true,
477            }
478            && self.succ
479                == FenceSet {
480                    device_input: false,
481                    device_output: false,
482                    memory_read: false,
483                    memory_write: false,
484                }
485            && self.dest == Reg::ZERO
486            && self.src == Reg::ZERO
487    }
488}
489
490impl AmoOrdering {
491    /// Create a new [`AmoOrdering`] from the two ordering bits.
492    pub fn from_aq_rl(aq: bool, rl: bool) -> Self {
493        match (aq, rl) {
494            (false, false) => Self::Relaxed,
495            (true, false) => Self::Acquire,
496            (false, true) => Self::Release,
497            (true, true) => Self::SeqCst,
498        }
499    }
500    /// Undoes [`from_aq_rel`], creating two ordering bits
501    pub fn aq_rl(&self) -> (bool, bool) {
502        match self {
503            AmoOrdering::Relaxed => (false, false),
504            AmoOrdering::Acquire => (true, false),
505            AmoOrdering::Release => (false, true),
506            AmoOrdering::SeqCst => (true, true),
507        }
508    }
509}
510
511impl Debug for Inst {
512    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
513        Display::fmt(&self, f)
514    }
515}
516
517/// Prints the instruction in disassembled form.
518///
519/// Note that the precise output here is not considered stable.
520impl Display for Inst {
521    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522        match *self {
523            Inst::Lui { uimm, dest } => write!(f, "lui {dest}, {}", uimm.as_u32() >> 12),
524            Inst::Auipc { uimm, dest } => write!(f, "auipc {dest}, {}", uimm.as_u32() >> 12),
525            Inst::Jal { offset, dest } => {
526                if dest.0 == 0 {
527                    write!(f, "j {}", offset.as_i32())
528                } else {
529                    write!(f, "jal {dest}, {}", offset.as_i32())
530                }
531            }
532            Inst::Jalr { offset, base, dest } => {
533                if dest == Reg::ZERO && offset.as_u32() == 0 && base == Reg::RA {
534                    write!(f, "ret")
535                } else {
536                    write!(f, "jalr {dest}, {}({base})", offset.as_i32())
537                }
538            }
539            Inst::Beq { offset, src1, src2 } => {
540                write!(f, "beq {src1}, {src2}, {}", offset.as_i32())
541            }
542            Inst::Bne { offset, src1, src2 } => {
543                write!(f, "bne {src1}, {src2}, {}", offset.as_i32())
544            }
545            Inst::Blt { offset, src1, src2 } => {
546                write!(f, "blt {src1}, {src2}, {}", offset.as_i32())
547            }
548            Inst::Bge { offset, src1, src2 } => {
549                write!(f, "bge {src1}, {src2}, {}", offset.as_i32())
550            }
551            Inst::Bltu { offset, src1, src2 } => {
552                write!(f, "bltu {src1}, {src2}, {}", offset.as_i32())
553            }
554            Inst::Bgeu { offset, src1, src2 } => {
555                write!(f, "bgeu {src1}, {src2}, {}", offset.as_i32())
556            }
557            Inst::Lb { offset, dest, base } => write!(f, "lb {dest}, {}({base})", offset.as_i32()),
558            Inst::Lbu { offset, dest, base } => {
559                write!(f, "lbu {dest}, {}({base})", offset.as_i32())
560            }
561            Inst::Lh { offset, dest, base } => write!(f, "lh {dest}, {}({base})", offset.as_i32()),
562            Inst::Lhu { offset, dest, base } => {
563                write!(f, "lhu {dest}, {}({base})", offset.as_i32())
564            }
565            Inst::Lw { offset, dest, base } => write!(f, "lw {dest}, {}({base})", offset.as_i32()),
566            Inst::Lwu { offset, dest, base } => {
567                write!(f, "lwu {dest}, {}({base})", offset.as_i32())
568            }
569            Inst::Ld { offset, dest, base } => write!(f, "ld {dest}, {}({base})", offset.as_i32()),
570            Inst::Sb { offset, src, base } => write!(f, "sb {src}, {}({base})", offset.as_i32()),
571            Inst::Sh { offset, src, base } => write!(f, "sh {src}, {}({base})", offset.as_i32()),
572            Inst::Sw { offset, src, base } => write!(f, "sw {src}, {}({base})", offset.as_i32()),
573            Inst::Sd { offset, src, base } => write!(f, "sd {src}, {}({base})", offset.as_i32()),
574            Inst::Addi { imm, dest, src1 } => {
575                if dest.0 == 0 && src1.0 == 0 && imm.as_u32() == 0 {
576                    write!(f, "nop")
577                } else if src1.0 == 0 {
578                    write!(f, "li {dest}, {}", imm.as_i32())
579                } else if imm.as_u32() == 0 {
580                    write!(f, "mv {dest}, {src1}")
581                } else {
582                    write!(f, "addi {dest}, {src1}, {}", imm.as_i32())
583                }
584            }
585            Inst::AddiW { imm, dest, src1 } => {
586                if imm.as_u32() == 0 {
587                    write!(f, "sext.w {dest}, {src1}")
588                } else {
589                    write!(f, "addiw {dest}, {src1}, {}", imm.as_i32())
590                }
591            }
592            Inst::Slti {
593                imm,
594                dest,
595                src1: rs1,
596            } => write!(f, "slti {dest}, {rs1}, {}", imm.as_i32()),
597            Inst::Sltiu {
598                imm,
599                dest,
600                src1: rs1,
601            } => write!(f, "sltiu {dest}, {rs1}, {}", imm.as_i32()),
602            Inst::Andi {
603                imm,
604                dest,
605                src1: rs1,
606            } => write!(f, "andi {dest}, {rs1}, {}", imm.as_i32()),
607            Inst::Ori {
608                imm,
609                dest,
610                src1: rs1,
611            } => write!(f, "ori {dest}, {rs1}, {}", imm.as_i32()),
612            Inst::Xori {
613                imm,
614                dest,
615                src1: rs1,
616            } => write!(f, "xori {dest}, {rs1}, {}", imm.as_i32()),
617            Inst::Slli {
618                imm,
619                dest,
620                src1: rs1,
621            } => write!(f, "slli {dest}, {rs1}, {}", imm.as_i32()),
622            Inst::SlliW {
623                imm,
624                dest,
625                src1: rs1,
626            } => write!(f, "slliw {dest}, {rs1}, {}", imm.as_i32()),
627            Inst::Srli {
628                imm,
629                dest,
630                src1: rs1,
631            } => write!(f, "srli {dest}, {rs1}, {}", imm.as_i32()),
632            Inst::SrliW {
633                imm,
634                dest,
635                src1: rs1,
636            } => write!(f, "srliw {dest}, {rs1}, {}", imm.as_i32()),
637            Inst::Srai {
638                imm,
639                dest,
640                src1: rs1,
641            } => write!(f, "srai {dest}, {rs1}, {}", imm.as_i32()),
642            Inst::SraiW {
643                imm,
644                dest,
645                src1: rs1,
646            } => write!(f, "sraiw {dest}, {rs1}, {}", imm.as_i32()),
647            Inst::Add { dest, src1, src2 } => {
648                write!(f, "add {dest}, {src1}, {src2}")
649            }
650            Inst::AddW { dest, src1, src2 } => {
651                write!(f, "addw {dest}, {src1}, {src2}")
652            }
653            Inst::Sub { dest, src1, src2 } => write!(f, "sub {dest}, {src1}, {src2}"),
654            Inst::SubW { dest, src1, src2 } => write!(f, "subw {dest}, {src1}, {src2}"),
655            Inst::Sll { dest, src1, src2 } => write!(f, "sll {dest}, {src1}, {src2}"),
656            Inst::SllW { dest, src1, src2 } => write!(f, "sllw {dest}, {src1}, {src2}"),
657            Inst::Slt { dest, src1, src2 } => write!(f, "slt {dest}, {src1}, {src2}"),
658            Inst::Sltu { dest, src1, src2 } => write!(f, "sltu {dest}, {src1}, {src2}"),
659            Inst::Xor { dest, src1, src2 } => write!(f, "xor {dest}, {src1}, {src2}"),
660            Inst::Srl { dest, src1, src2 } => write!(f, "srl {dest}, {src1}, {src2}"),
661            Inst::SrlW { dest, src1, src2 } => write!(f, "srlw {dest}, {src1}, {src2}"),
662            Inst::Sra { dest, src1, src2 } => write!(f, "sra {dest}, {src1}, {src2}"),
663            Inst::SraW { dest, src1, src2 } => write!(f, "sraw {dest}, {src1}, {src2}"),
664            Inst::Or { dest, src1, src2 } => write!(f, "or {dest}, {src1}, {src2}"),
665            Inst::And { dest, src1, src2 } => write!(f, "and {dest}, {src1}, {src2}"),
666            Inst::Fence { fence } => match fence.fm {
667                _ if fence.is_tso() => write!(f, "fence.tso"),
668                0b0000 if fence.is_pause() => {
669                    write!(f, "pause")
670                }
671                _ => write!(f, "fence {},{}", fence.pred, fence.succ),
672            },
673            Inst::Ecall => write!(f, "ecall"),
674            Inst::Ebreak => write!(f, "ebreak"),
675            Inst::Mul { dest, src1, src2 } => write!(f, "mul {dest}, {src1}, {src2}"),
676            Inst::MulW { dest, src1, src2 } => write!(f, "mulw {dest}, {src1}, {src2}"),
677            Inst::Mulh { dest, src1, src2 } => write!(f, "mulh {dest}, {src1}, {src2}"),
678            Inst::Mulhsu { dest, src1, src2 } => write!(f, "mulhsu {dest}, {src1}, {src2}"),
679            Inst::Mulhu { dest, src1, src2 } => write!(f, "mulhu {dest}, {src1}, {src2}"),
680            Inst::Div { dest, src1, src2 } => write!(f, "div {dest}, {src1}, {src2}"),
681            Inst::DivW { dest, src1, src2 } => write!(f, "divw {dest}, {src1}, {src2}"),
682            Inst::Divu { dest, src1, src2 } => write!(f, "divu {dest}, {src1}, {src2}"),
683            Inst::DivuW { dest, src1, src2 } => write!(f, "divuw {dest}, {src1}, {src2}"),
684            Inst::Rem { dest, src1, src2 } => write!(f, "rem {dest}, {src1}, {src2}"),
685            Inst::RemW { dest, src1, src2 } => write!(f, "remw {dest}, {src1}, {src2}"),
686            Inst::Remu { dest, src1, src2 } => write!(f, "remu {dest}, {src1}, {src2}"),
687            Inst::RemuW { dest, src1, src2 } => write!(f, "remuw {dest}, {src1}, {src2}"),
688            Inst::LrW { order, dest, addr } => write!(f, "lr.w{order} {dest}, ({addr})",),
689            Inst::ScW {
690                order,
691                dest,
692                addr,
693                src,
694            } => write!(f, "sc.w{order} {dest}, {src}, ({addr})"),
695            Inst::AmoW {
696                order,
697                op,
698                dest,
699                addr,
700                src,
701            } => write!(f, "amo{op}.w{order} {dest}, {src}, ({addr})",),
702        }
703    }
704}
705
706impl Display for FenceSet {
707    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
708        let mut has = false;
709        if self.device_input {
710            has = true;
711            write!(f, "i")?;
712        }
713        if self.device_output {
714            has = true;
715            write!(f, "o")?;
716        }
717        if self.memory_read {
718            has = true;
719            write!(f, "r")?;
720        }
721        if self.memory_write {
722            has = true;
723            write!(f, "w")?;
724        }
725        if !has {
726            write!(f, "0")?;
727        }
728        Ok(())
729    }
730}
731
732impl Display for AmoOrdering {
733    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
734        match self {
735            AmoOrdering::Relaxed => write!(f, ""),
736            AmoOrdering::Acquire => write!(f, ".aq"),
737            AmoOrdering::Release => write!(f, ".rl"),
738            AmoOrdering::SeqCst => write!(f, ".aqrl"),
739        }
740    }
741}
742
743impl Display for AmoOp {
744    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
745        match self {
746            AmoOp::Swap => write!(f, "swap"),
747            AmoOp::Add => write!(f, "add"),
748            AmoOp::Xor => write!(f, "xor"),
749            AmoOp::And => write!(f, "and"),
750            AmoOp::Or => write!(f, "or"),
751            AmoOp::Min => write!(f, "min"),
752            AmoOp::Max => write!(f, "max"),
753            AmoOp::Minu => write!(f, "minu"),
754            AmoOp::Maxu => write!(f, "maxu"),
755        }
756    }
757}
758
759impl Debug for DecodeError {
760    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
761        f.debug_struct("DecodeError")
762            .field("instruction", &format_args!("{:0>32b}", self.instruction))
763            .field("unexpected_field", &self.unexpected_field)
764            .finish()
765    }
766}
767
768impl Display for DecodeError {
769    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
770        write!(
771            f,
772            "failed to decode instruction '{:0>32b}' because of field '{}'",
773            self.instruction, self.unexpected_field
774        )
775    }
776}
777
778impl core::error::Error for DecodeError {}
779
780fn sign_extend(value: u32, size: u32) -> u32 {
781    let right = u32::BITS - size;
782    (((value << right) as i32) >> right) as u32
783}
784
785#[derive(Clone, Copy)]
786struct InstCode(u32);
787
788impl InstCode {
789    fn extract(self, range: RangeInclusive<u32>) -> u32 {
790        let end_span = 32 - (range.end() + 1);
791        (self.0 << (end_span)) >> (end_span + range.start())
792    }
793    fn insert(self, range: RangeInclusive<u32>, data: u32) -> Self {
794        let (start,end) = (*range.start(),*range.end());
795        // let start = ;
796        let span_item = (1 << (end - start + 1)) - 1;
797        Self(self.0 & !(span_item << start) | ((data & span_item) << start))
798    }
799    fn immediate_s(self, mappings: &[(RangeInclusive<u32>, u32)]) -> Imm {
800        let mut imm = 0;
801        let mut size = 0;
802        for (from, to) in mappings {
803            let value = self.extract(from.clone());
804            imm |= value << to;
805            let this_size = from.end() - from.start() + 1;
806            size = size.max(*to + this_size);
807        }
808        Imm::new_i32(sign_extend(imm, size) as i32)
809    }
810    fn with_immediate_s(self, mappings: &[(RangeInclusive<u32>, u32)], data: Imm) -> Self {
811        let mut size = 0;
812        for (from, to) in mappings {
813            let this_size = from.end() - from.start() + 1;
814            size = size.max(*to + this_size);
815        }
816        mappings.iter().fold(self, |this, (from, to)| {
817            this.insert(
818                from.clone(),
819                data.as_u32() >> *to,
820            )
821        })
822    }
823
824    fn opcode(self) -> u32 {
825        self.0 & 0b1111111
826    }
827    fn with_opcode(self, opcode: u32) -> Self {
828        let mask = 0b1111111;
829        Self(self.0 & !mask | (opcode & mask))
830    }
831    fn funct3(self) -> u32 {
832        self.extract(12..=14)
833    }
834    fn funct7(self) -> u32 {
835        self.extract(25..=31)
836    }
837    fn with_funct3(self, data: u32) -> Self {
838        self.insert(12..=14, data)
839    }
840    fn with_funct7(self, data: u32) -> Self {
841        self.insert(25..=31, data)
842    }
843    fn rs1(self) -> Reg {
844        Reg(self.extract(15..=19) as u8)
845    }
846    fn rs2(self) -> Reg {
847        Reg(self.extract(20..=24) as u8)
848    }
849    fn with_rs1(self, data: Reg) -> Self {
850        self.insert(15..=19, data.0 as u32)
851    }
852    fn with_rs2(self, data: Reg) -> Self {
853        self.insert(20..=24, data.0 as u32)
854    }
855    fn rs2_imm(self) -> u32 {
856        self.extract(20..=24)
857    }
858    // shifts on RV64 have one extra bit
859    fn rs2_imm_plus(self) -> u32 {
860        self.extract(20..=25)
861    }
862    fn with_rs2_imm(self, data: u32) -> Self {
863        self.insert(20..=24, data)
864    }
865    // shifts on RV64 have one extra bit
866    fn with_rs2_imm_plus(self, data: u32) -> Self {
867        self.insert(20..=25, data)
868    }
869    fn rd(self) -> Reg {
870        Reg(self.extract(7..=11) as u8)
871    }
872    fn with_rd(self, data: Reg) -> Self {
873        self.insert(7..=11, data.0 as u32)
874    }
875    fn imm_i(self) -> Imm {
876        self.immediate_s(&[(20..=31, 0)])
877    }
878    fn imm_s(self) -> Imm {
879        self.immediate_s(&[(25..=31, 5), (7..=11, 0)])
880    }
881    fn imm_b(self) -> Imm {
882        self.immediate_s(&[(31..=31, 12), (7..=7, 11), (25..=30, 5), (8..=11, 1)])
883    }
884    fn imm_u(self) -> Imm {
885        // Don't be fooled by the "u", LUI/AUIPC immediates are sign-extended on RV64.
886        self.immediate_s(&[(12..=31, 12)])
887    }
888    fn imm_j(self) -> Imm {
889        self.immediate_s(&[(31..=31, 20), (21..=30, 1), (20..=20, 11), (12..=19, 12)])
890    }
891    fn with_imm_i(self, data: Imm) -> Self {
892        self.with_immediate_s(&[(20..=31, 0)], data)
893    }
894    fn with_imm_s(self, data: Imm) -> Self {
895        self.with_immediate_s(&[(25..=31, 5), (7..=11, 0)], data)
896    }
897    fn with_imm_b(self, data: Imm) -> Self {
898        self.with_immediate_s(
899            &[(31..=31, 12), (7..=7, 11), (25..=30, 5), (8..=11, 1)],
900            data,
901        )
902    }
903    fn with_imm_u(self, data: Imm) -> Self {
904        // Don't be fooled by the "u", LUI/AUIPC immediates are sign-extended on RV64.
905        self.with_immediate_s(&[(12..=31, 12)], data)
906    }
907    fn with_imm_j(self, data: Imm) -> Self {
908        self.with_immediate_s(
909            &[(31..=31, 20), (21..=30, 1), (20..=20, 11), (12..=19, 12)],
910            data,
911        )
912    }
913}
914
915#[derive(Clone, Copy)]
916struct InstCodeC(u16);
917
918impl InstCodeC {
919    fn extract(self, range: RangeInclusive<u32>) -> u32 {
920        let end_span = u16::BITS - (range.end() + 1);
921        ((self.0 << (end_span)) >> (end_span + range.start())) as u32
922    }
923    fn immediate_u(self, mappings: &[(RangeInclusive<u32>, u32)]) -> Imm {
924        let mut imm = 0;
925        for (from, to) in mappings {
926            let value = self.extract(from.clone());
927            imm |= value << to;
928        }
929        Imm::new_u32(imm)
930    }
931    fn immediate_s(self, mappings: &[(RangeInclusive<u32>, u32)]) -> Imm {
932        let mut imm = 0;
933        let mut size = 0;
934        for (from, to) in mappings {
935            assert!(from.start() <= from.end());
936            let value = self.extract(from.clone());
937            imm |= value << to;
938            let this_size = from.end() - from.start() + 1;
939            size = size.max(*to + this_size);
940        }
941        Imm::new_i32(sign_extend(imm, size) as i32)
942    }
943    fn quadrant(self) -> u16 {
944        self.0 & 0b11
945    }
946    fn funct3(self) -> u32 {
947        self.extract(13..=15)
948    }
949    fn funct2(self) -> u32 {
950        self.extract(10..=11)
951    }
952    /// rd/rs1 (7..=11)
953    fn rd(self) -> Reg {
954        Reg(self.extract(7..=11) as u8)
955    }
956    /// rs2 (2..=6)
957    fn rs2(self) -> Reg {
958        Reg(self.extract(2..=6) as u8)
959    }
960    /// rs1' (7..=9)
961    fn rs1_short(self) -> Reg {
962        let smol_reg = self.extract(7..=9);
963        // map to x8..=x15
964        Reg((smol_reg + 8) as u8)
965    }
966    /// rs2' (2..=4)
967    fn rs2_short(self) -> Reg {
968        let smol_reg = self.extract(2..=4);
969        // map to x8..=x15
970        Reg((smol_reg + 8) as u8)
971    }
972}
973
974impl From<InstCodeC> for InstCode {
975    fn from(value: InstCodeC) -> Self {
976        Self(value.0 as u32)
977    }
978}
979
980/// Whether the decoded instruction was a compressed instruction or not.
981/// If it was compressed, only the first two bytes were used.
982/// If it was not compressed, all four bytes are consumed.
983#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
984pub enum IsCompressed {
985    /// Normal 4-byte instruction
986    No,
987    /// Compressed 2-byte instruction
988    Yes,
989}
990
991fn decode_error(instruction: impl Into<InstCode>, unexpected_field: &'static str) -> DecodeError {
992    DecodeError {
993        instruction: instruction.into().0,
994        unexpected_field,
995    }
996}
997
998impl Inst {
999    /// Whether the first byte of an instruction indicates a compressed or uncompressed instruction.
1000    ///
1001    /// # Examples
1002    ///
1003    /// ```rust
1004    /// // addi sp, sp, -0x20 (compressed)
1005    /// let x = 0x1101_u32;
1006    /// assert!(rvdc::Inst::first_byte_is_compressed(x.to_le_bytes()[0]));
1007    /// let x = 0x1101_u16;
1008    /// assert!(rvdc::Inst::first_byte_is_compressed(x.to_le_bytes()[0]));
1009    /// ```
1010    ///
1011    /// ```rust
1012    /// // auipc t1, 0xa
1013    /// let x = 0x0000a317_u32;
1014    /// assert!(!rvdc::Inst::first_byte_is_compressed(x.to_le_bytes()[0]));
1015    /// ```
1016    pub fn first_byte_is_compressed(byte: u8) -> bool {
1017        (byte & 0b11) != 0b11
1018    }
1019
1020    /// Decode an instruction from four bytes.
1021    ///
1022    /// The instruction may be compressed, in which case only two bytes are consumed.
1023    /// Even in these cases, the full next four bytes must be passed.
1024    ///
1025    /// If the caller wants to avoid reading more bytes than necessary, [`Self::first_byte_is_compressed`]
1026    /// can be used to check, read the required bytes, and then call [`Self::decode_compressed`] or
1027    /// [`Self::decode_normal`] directly.
1028    pub fn decode(code: u32, xlen: Xlen) -> Result<(Inst, IsCompressed), DecodeError> {
1029        let is_compressed = (code & 0b11) != 0b11;
1030        if is_compressed {
1031            Ok((
1032                Self::decode_compressed(code as u16, xlen)?,
1033                IsCompressed::Yes,
1034            ))
1035        } else {
1036            Ok((Self::decode_normal(code, xlen)?, IsCompressed::No))
1037        }
1038    }
1039
1040    /// Decode a known compressed instruction from its two bytes.
1041    ///
1042    /// # Example
1043    /// ```rust
1044    /// // Compressed addi sp, sp, -0x20
1045    /// let x = 0x1101_u16;
1046    /// let expected = rvdc::Inst::Addi { imm: rvdc::Imm::new_i32(-0x20), dest: rvdc::Reg::SP, src1: rvdc::Reg::SP };
1047    ///
1048    /// let inst = rvdc::Inst::decode_compressed(x, rvdc::Xlen::Rv32).unwrap();
1049    /// assert_eq!(inst, expected);
1050    /// ```
1051    pub fn decode_compressed(code: u16, xlen: Xlen) -> Result<Inst, DecodeError> {
1052        let code = InstCodeC(code);
1053        if code.0 == 0 {
1054            return Err(decode_error(code, "null instruction"));
1055        }
1056        let inst = match code.quadrant() {
1057            // C0
1058            0b00 => match code.funct3() {
1059                // C.ADDI4SPN -> addi \rd', sp, \imm
1060                0b000 => {
1061                    let imm =
1062                        code.immediate_u(&[(5..=5, 3), (6..=6, 2), (7..=10, 6), (11..=12, 4)]);
1063                    if imm.as_u32() == 0 {
1064                        return Err(decode_error(code, "uimm=0 for C.ADDISPN is reserved"));
1065                    }
1066                    Inst::Addi {
1067                        imm,
1068                        dest: code.rs2_short(),
1069                        src1: Reg::SP,
1070                    }
1071                }
1072                // C.LW -> lw \dest \offset(\base)
1073                0b010 => Inst::Lw {
1074                    offset: code.immediate_u(&[(10..=12, 3), (5..=5, 6), (6..=6, 2)]),
1075                    dest: code.rs2_short(),
1076                    base: code.rs1_short(),
1077                },
1078                // C.SW -> sw \src, \offset(\base)
1079                0b110 => Inst::Sw {
1080                    offset: code.immediate_u(&[(10..=12, 3), (5..=5, 6), (6..=6, 2)]),
1081                    src: code.rs2_short(),
1082                    base: code.rs1_short(),
1083                },
1084                _ => return Err(decode_error(code, "C0 funct3")),
1085            },
1086            // C1
1087            0b01 => match code.funct3() {
1088                // C.ADDI -> addi \rd, \rd, \imm
1089                0b000 => Inst::Addi {
1090                    imm: code.immediate_s(&[(2..=6, 0), (12..=12, 5)]),
1091                    dest: code.rd(),
1092                    src1: code.rd(),
1093                },
1094                // C.JAL -> jal ra, \offset
1095                0b001 => Inst::Jal {
1096                    offset: code.immediate_s(&[
1097                        (2..=2, 5),
1098                        (3..=5, 1),
1099                        (6..=6, 7),
1100                        (7..=7, 6),
1101                        (8..=8, 10),
1102                        (9..=10, 8),
1103                        (11..=11, 4),
1104                        (12..=12, 11),
1105                    ]),
1106                    dest: Reg::RA,
1107                },
1108                // C.LI -> addi \rd, zero, \imm
1109                0b010 => Inst::Addi {
1110                    imm: code.immediate_s(&[(2..=6, 0), (12..=12, 5)]),
1111                    dest: code.rd(),
1112                    src1: Reg::ZERO,
1113                },
1114                // Arithmetic instructions
1115                0b100 => {
1116                    let bit12 = code.extract(12..=12);
1117                    match code.funct2() {
1118                        // C.SRLI -> srli \rd', \rd', \imm
1119                        0b00 => {
1120                            if bit12 != 0 {
1121                                return Err(decode_error(code, "C.SRLI imm"));
1122                            }
1123
1124                            Inst::Srli {
1125                                imm: code.immediate_u(&[(2..=6, 0), (12..=12, 5)]),
1126                                dest: code.rs1_short(),
1127                                src1: code.rs1_short(),
1128                            }
1129                        }
1130                        // C.SRAI -> srai \rd', \rd', \imm
1131                        0b01 => {
1132                            if bit12 != 0 {
1133                                return Err(decode_error(code, "C.SRLI imm"));
1134                            }
1135
1136                            Inst::Srai {
1137                                imm: code.immediate_u(&[(2..=6, 0), (12..=12, 5)]),
1138                                dest: code.rs1_short(),
1139                                src1: code.rs1_short(),
1140                            }
1141                        }
1142                        // C.ANDI -> andi \rd', \rd', \imm
1143                        0b10 => Inst::Andi {
1144                            imm: code.immediate_u(&[(2..=6, 0), (12..=12, 5)]),
1145                            dest: code.rs1_short(),
1146                            src1: code.rs1_short(),
1147                        },
1148                        0b11 => {
1149                            if bit12 != 0 {
1150                                return Err(decode_error(code, "C1 Arith bit 12"));
1151                            }
1152                            let funct2 = code.extract(5..=6);
1153                            match funct2 {
1154                                // C.SUB -> sub \rd', \rd', \rs2'
1155                                0b00 => Inst::Sub {
1156                                    dest: code.rs1_short(),
1157                                    src1: code.rs1_short(),
1158                                    src2: code.rs2_short(),
1159                                },
1160                                // C.XOR -> xor \rd', \rd', \rs2'
1161                                0b01 => Inst::Xor {
1162                                    dest: code.rs1_short(),
1163                                    src1: code.rs1_short(),
1164                                    src2: code.rs2_short(),
1165                                },
1166                                // C.OR -> or \rd', \rd', \rs2'
1167                                0b10 => Inst::Or {
1168                                    dest: code.rs1_short(),
1169                                    src1: code.rs1_short(),
1170                                    src2: code.rs2_short(),
1171                                },
1172                                // C.AND -> and \rd', \rd', \rs2'
1173                                0b11 => Inst::And {
1174                                    dest: code.rs1_short(),
1175                                    src1: code.rs1_short(),
1176                                    src2: code.rs2_short(),
1177                                },
1178                                _ => unreachable!("only two bits"),
1179                            }
1180                        }
1181                        _ => unreachable!("only two bits"),
1182                    }
1183                }
1184                // C.J -> jal zero, \offset
1185                0b101 => Inst::Jal {
1186                    offset: code.immediate_s(&[
1187                        (2..=2, 5),
1188                        (3..=5, 1),
1189                        (6..=6, 7),
1190                        (7..=7, 6),
1191                        (8..=8, 10),
1192                        (9..=10, 8),
1193                        (11..=11, 4),
1194                        (12..=12, 11),
1195                    ]),
1196                    dest: Reg::ZERO,
1197                },
1198                0b011 => {
1199                    match code.rd().0 {
1200                        // C.ADDI16SP -> addi sp, sp, \imm
1201                        2 => Inst::Addi {
1202                            imm: code.immediate_s(&[
1203                                (2..=2, 5),
1204                                (3..=4, 7),
1205                                (5..=5, 6),
1206                                (6..=6, 4),
1207                                (12..=12, 9),
1208                            ]),
1209                            dest: Reg::SP,
1210                            src1: Reg::SP,
1211                        },
1212                        // C.LUI -> lui \rd, \imm
1213                        _ => {
1214                            let uimm = code.immediate_s(&[(2..=6, 12), (12..=12, 17)]);
1215                            if uimm.as_u32() == 0 {
1216                                return Err(decode_error(code, "C.LUI zero immediate"));
1217                            }
1218                            Inst::Lui {
1219                                uimm,
1220                                dest: code.rd(),
1221                            }
1222                        }
1223                    }
1224                }
1225                // C.BEQZ -> beq \rs1', zero, \offset
1226                0b110 => Inst::Beq {
1227                    offset: code.immediate_s(&[
1228                        (2..=2, 5),
1229                        (3..=4, 1),
1230                        (5..=6, 6),
1231                        (10..=11, 3),
1232                        (12..=12, 8),
1233                    ]),
1234                    src1: code.rs1_short(),
1235                    src2: Reg::ZERO,
1236                },
1237                // C.BEQZ -> bne \rs1', zero, \offset
1238                0b111 => Inst::Bne {
1239                    offset: code.immediate_s(&[
1240                        (2..=2, 5),
1241                        (3..=4, 1),
1242                        (5..=6, 6),
1243                        (10..=11, 3),
1244                        (12..=12, 8),
1245                    ]),
1246                    src1: code.rs1_short(),
1247                    src2: Reg::ZERO,
1248                },
1249                _ => return Err(decode_error(code, "C1 funct3")),
1250            },
1251            // C2
1252            0b10 => match code.funct3() {
1253                // C.SLLI -> slli \rd, \rd, \imm
1254                0b000 => {
1255                    if code.extract(12..=12) != 0 {
1256                        return Err(decode_error(code, "C.SLLI shift amount must be zero"));
1257                    }
1258                    Inst::Slli {
1259                        imm: code.immediate_u(&[(2..=6, 0), (12..=12, 5)]),
1260                        dest: code.rd(),
1261                        src1: code.rd(),
1262                    }
1263                }
1264                // C.LWSP -> lw \reg \offset(sp)
1265                0b010 => {
1266                    let dest = code.rd();
1267                    if dest.0 == 0 {
1268                        return Err(decode_error(code, "C.LWSP rd must not be zero"));
1269                    }
1270
1271                    Inst::Lw {
1272                        offset: code.immediate_u(&[(12..=12, 5), (4..=6, 2), (2..=3, 6)]),
1273                        dest,
1274                        base: Reg::SP,
1275                    }
1276                }
1277
1278                // C.LDSP -> ld \reg \offset(sp)
1279                0b011 => {
1280                    if xlen.is_32() {
1281                        return Err(decode_error(code, "C.LDSP is not allowed on RV32"));
1282                    }
1283                    let dest = code.rd();
1284                    if dest.0 == 0 {
1285                        return Err(decode_error(code, "C.LWSP rd must not be zero"));
1286                    }
1287
1288                    Inst::Ld {
1289                        offset: code.immediate_u(&[(12..=12, 5), (4..=6, 2), (2..=3, 6)]),
1290                        dest,
1291                        base: Reg::SP,
1292                    }
1293                }
1294                0b100 => {
1295                    let bit = code.extract(12..=12);
1296                    let rs2 = code.rs2();
1297                    let rd_rs1 = code.rd();
1298                    match (bit, rd_rs1.0, rs2.0) {
1299                        // C.JR -> jalr zero, 0(\rs1)
1300                        (0, _, 0) => {
1301                            if rd_rs1.0 == 0 {
1302                                return Err(decode_error(code, "C.JR rs1 must not be zero"));
1303                            }
1304                            Inst::Jalr {
1305                                offset: Imm::ZERO,
1306                                base: rd_rs1,
1307                                dest: Reg::ZERO,
1308                            }
1309                        }
1310                        // C.MV -> add \rd, x0, \rs2
1311                        (0, _, _) => Inst::Add {
1312                            dest: code.rd(),
1313                            src1: Reg::ZERO,
1314                            src2: code.rs2(),
1315                        },
1316                        // C.EBREAK -> ebreak
1317                        (1, 0, 0) => Inst::Ebreak,
1318                        // C.JALR -> jalr ra, 0(\rs1)
1319                        (1, _, 0) if rd_rs1.0 != 0 => Inst::Jalr {
1320                            offset: Imm::ZERO,
1321                            base: rd_rs1,
1322                            dest: Reg::RA,
1323                        },
1324                        // C.ADD -> add \rd, \rd, \rs2
1325                        (1, _, _) => Inst::Add {
1326                            dest: rd_rs1,
1327                            src1: rd_rs1,
1328                            src2: rs2,
1329                        },
1330                        _ => return Err(decode_error(code, "C2 funct=100 inst")),
1331                    }
1332                }
1333                // C.SWSP -> sw \reg \offset(sp)
1334                0b110 => Inst::Sw {
1335                    offset: code.immediate_u(&[(7..=8, 6), (9..=12, 2)]),
1336                    src: code.rs2(),
1337                    base: Reg::SP,
1338                },
1339                // C.SDSP -> sd \reg \offset(sp)
1340                0b111 => {
1341                    if xlen.is_32() {
1342                        return Err(decode_error(code, "C.SDSP is not allowed on RV32"));
1343                    }
1344                    Inst::Sd {
1345                        offset: code.immediate_u(&[(7..=9, 6), (10..=12, 3)]),
1346                        src: code.rs2(),
1347                        base: Reg::SP,
1348                    }
1349                }
1350                _ => return Err(decode_error(code, "C2 funct3")),
1351            },
1352            _ => return Err(decode_error(code, "instruction is not compressed")),
1353        };
1354        Ok(inst)
1355    }
1356
1357    /// Decode a normal (not compressed) instruction.
1358    pub fn decode_normal(code: u32, xlen: Xlen) -> Result<Inst, DecodeError> {
1359        let code = InstCode(code);
1360        let inst = match code.opcode() {
1361            // LUI
1362            0b0110111 => Inst::Lui {
1363                uimm: code.imm_u(),
1364                dest: code.rd(),
1365            },
1366            // AUIPC
1367            0b0010111 => Inst::Auipc {
1368                uimm: code.imm_u(),
1369                dest: code.rd(),
1370            },
1371            // JAL
1372            0b1101111 => Inst::Jal {
1373                offset: code.imm_j(),
1374                dest: code.rd(),
1375            },
1376            // JALR
1377            0b1100111 => match code.funct3() {
1378                0b000 => Inst::Jalr {
1379                    offset: code.imm_i(),
1380                    base: code.rs1(),
1381                    dest: code.rd(),
1382                },
1383                _ => return Err(decode_error(code, "JALR funct3")),
1384            },
1385            // BRANCH
1386            0b1100011 => match code.funct3() {
1387                0b000 => Inst::Beq {
1388                    offset: code.imm_b(),
1389                    src1: code.rs1(),
1390                    src2: code.rs2(),
1391                },
1392                0b001 => Inst::Bne {
1393                    offset: code.imm_b(),
1394                    src1: code.rs1(),
1395                    src2: code.rs2(),
1396                },
1397                0b100 => Inst::Blt {
1398                    offset: code.imm_b(),
1399                    src1: code.rs1(),
1400                    src2: code.rs2(),
1401                },
1402                0b101 => Inst::Bge {
1403                    offset: code.imm_b(),
1404                    src1: code.rs1(),
1405                    src2: code.rs2(),
1406                },
1407                0b110 => Inst::Bltu {
1408                    offset: code.imm_b(),
1409                    src1: code.rs1(),
1410                    src2: code.rs2(),
1411                },
1412                0b111 => Inst::Bgeu {
1413                    offset: code.imm_b(),
1414                    src1: code.rs1(),
1415                    src2: code.rs2(),
1416                },
1417                _ => return Err(decode_error(code, "BRANCH funct3")),
1418            },
1419            // LOAD
1420            0b0000011 => match code.funct3() {
1421                0b000 => Inst::Lb {
1422                    offset: code.imm_i(),
1423                    dest: code.rd(),
1424                    base: code.rs1(),
1425                },
1426                0b001 => Inst::Lh {
1427                    offset: code.imm_i(),
1428                    dest: code.rd(),
1429                    base: code.rs1(),
1430                },
1431                0b010 => Inst::Lw {
1432                    offset: code.imm_i(),
1433                    dest: code.rd(),
1434                    base: code.rs1(),
1435                },
1436                0b011 => {
1437                    if xlen.is_32() {
1438                        return Err(decode_error(code, "LD is not supported on RV32"));
1439                    }
1440                    Inst::Ld {
1441                        offset: code.imm_i(),
1442                        dest: code.rd(),
1443                        base: code.rs1(),
1444                    }
1445                }
1446                0b100 => Inst::Lbu {
1447                    offset: code.imm_i(),
1448                    dest: code.rd(),
1449                    base: code.rs1(),
1450                },
1451                0b101 => Inst::Lhu {
1452                    offset: code.imm_i(),
1453                    dest: code.rd(),
1454                    base: code.rs1(),
1455                },
1456                0b110 => {
1457                    if xlen.is_32() {
1458                        return Err(decode_error(code, "LWU is not supported on RV32"));
1459                    }
1460                    Inst::Lwu {
1461                        offset: code.imm_i(),
1462                        dest: code.rd(),
1463                        base: code.rs1(),
1464                    }
1465                }
1466                _ => return Err(decode_error(code, "Invalid funct3 for LOAD instruction")),
1467            },
1468            // STORE
1469            0b0100011 => match code.funct3() {
1470                0b000 => Inst::Sb {
1471                    offset: code.imm_s(),
1472                    src: code.rs2(),
1473                    base: code.rs1(),
1474                },
1475                0b001 => Inst::Sh {
1476                    offset: code.imm_s(),
1477                    src: code.rs2(),
1478                    base: code.rs1(),
1479                },
1480                0b010 => Inst::Sw {
1481                    offset: code.imm_s(),
1482                    src: code.rs2(),
1483                    base: code.rs1(),
1484                },
1485                0b011 => {
1486                    if xlen.is_32() {
1487                        return Err(decode_error(code, "SD is not supported on RV32"));
1488                    }
1489                    Inst::Sd {
1490                        offset: code.imm_s(),
1491                        src: code.rs2(),
1492                        base: code.rs1(),
1493                    }
1494                }
1495                _ => return Err(decode_error(code, "STORE funct3")),
1496            },
1497            // OP-IMM
1498            0b0010011 => match code.funct3() {
1499                0b000 => Inst::Addi {
1500                    imm: code.imm_i(),
1501                    dest: code.rd(),
1502                    src1: code.rs1(),
1503                },
1504                0b010 => Inst::Slti {
1505                    imm: code.imm_i(),
1506                    dest: code.rd(),
1507                    src1: code.rs1(),
1508                },
1509                0b011 => Inst::Sltiu {
1510                    imm: code.imm_i(),
1511                    dest: code.rd(),
1512                    src1: code.rs1(),
1513                },
1514                0b100 => Inst::Xori {
1515                    imm: code.imm_i(),
1516                    dest: code.rd(),
1517                    src1: code.rs1(),
1518                },
1519                0b110 => Inst::Ori {
1520                    imm: code.imm_i(),
1521                    dest: code.rd(),
1522                    src1: code.rs1(),
1523                },
1524                0b111 => Inst::Andi {
1525                    imm: code.imm_i(),
1526                    dest: code.rd(),
1527                    src1: code.rs1(),
1528                },
1529                0b001 => {
1530                    // For RV32, bit 25 must be zero as well.
1531                    let left_zeroes = code.funct7()
1532                        >> match xlen {
1533                            Xlen::Rv32 => 0,
1534                            Xlen::Rv64 => 1,
1535                        };
1536                    if left_zeroes != 0 {
1537                        return Err(decode_error(code, "slli shift overflow"));
1538                    }
1539                    Inst::Slli {
1540                        imm: code.imm_i(),
1541                        dest: code.rd(),
1542                        src1: code.rs1(),
1543                    }
1544                }
1545                0b101 => match xlen {
1546                    Xlen::Rv32 => match code.funct7() {
1547                        0b0000000 => Inst::Srli {
1548                            imm: Imm::new_u32(code.rs2_imm()),
1549                            dest: code.rd(),
1550                            src1: code.rs1(),
1551                        },
1552                        0b0100000 => Inst::Srai {
1553                            imm: Imm::new_u32(code.rs2_imm()),
1554                            dest: code.rd(),
1555                            src1: code.rs1(),
1556                        },
1557                        _ => return Err(decode_error(code, "srli shift overflow")),
1558                    },
1559                    Xlen::Rv64 => {
1560                        let upper = code.funct7() >> 1;
1561                        match upper {
1562                            0b010000 => Inst::Srai {
1563                                imm: Imm::new_u32(code.rs2_imm_plus()),
1564                                dest: code.rd(),
1565                                src1: code.rs1(),
1566                            },
1567                            0b000000 => Inst::Srli {
1568                                imm: Imm::new_u32(code.rs2_imm_plus()),
1569                                dest: code.rd(),
1570                                src1: code.rs1(),
1571                            },
1572                            _ => return Err(decode_error(code, "srai/srli upper bits")),
1573                        }
1574                    }
1575                },
1576                _ => return Err(decode_error(code, "OP-IMM funct3")),
1577            },
1578            // OP-IMM-32
1579            0b0011011 => {
1580                if xlen.is_32() {
1581                    return Err(decode_error(code, "OP-IMM-32 only on RV64"));
1582                }
1583
1584                match code.funct3() {
1585                    0b000 => Inst::AddiW {
1586                        imm: code.imm_i(),
1587                        dest: code.rd(),
1588                        src1: code.rs1(),
1589                    },
1590                    // SLLIW
1591                    0b001 => {
1592                        if code.funct7() != 0 {
1593                            return Err(decode_error(code, "SLLIW funct7"));
1594                        }
1595
1596                        Inst::SlliW {
1597                            imm: Imm::new_u32(code.rs2_imm()),
1598                            dest: code.rd(),
1599                            src1: code.rs1(),
1600                        }
1601                    }
1602
1603                    0b101 => match code.funct7() {
1604                        0b0000000 => Inst::SrliW {
1605                            imm: Imm::new_u32(code.rs2_imm()),
1606                            dest: code.rd(),
1607                            src1: code.rs1(),
1608                        },
1609                        0b0100000 => Inst::SraiW {
1610                            imm: Imm::new_u32(code.rs2_imm()),
1611                            dest: code.rd(),
1612                            src1: code.rs1(),
1613                        },
1614                        _ => return Err(decode_error(code, "OP-IMM-32 funct7")),
1615                    },
1616                    _ => return Err(decode_error(code, "OP-IMM-32 funct3")),
1617                }
1618            }
1619            // OP
1620            0b0110011 => {
1621                let (dest, src1, src2) = (code.rd(), code.rs1(), code.rs2());
1622                match (code.funct3(), code.funct7()) {
1623                    (0b000, 0b0000000) => Inst::Add { dest, src1, src2 },
1624                    (0b000, 0b0100000) => Inst::Sub { dest, src1, src2 },
1625                    (0b001, 0b0000000) => Inst::Sll { dest, src1, src2 },
1626                    (0b010, 0b0000000) => Inst::Slt { dest, src1, src2 },
1627                    (0b011, 0b0000000) => Inst::Sltu { dest, src1, src2 },
1628                    (0b100, 0b0000000) => Inst::Xor { dest, src1, src2 },
1629                    (0b101, 0b0000000) => Inst::Srl { dest, src1, src2 },
1630                    (0b101, 0b0100000) => Inst::Sra { dest, src1, src2 },
1631                    (0b110, 0b0000000) => Inst::Or { dest, src1, src2 },
1632                    (0b111, 0b0000000) => Inst::And { dest, src1, src2 },
1633
1634                    (0b000, 0b0000001) => Inst::Mul { dest, src1, src2 },
1635                    (0b001, 0b0000001) => Inst::Mulh { dest, src1, src2 },
1636                    (0b010, 0b0000001) => Inst::Mulhsu { dest, src1, src2 },
1637                    (0b011, 0b0000001) => Inst::Mulhu { dest, src1, src2 },
1638                    (0b100, 0b0000001) => Inst::Div { dest, src1, src2 },
1639                    (0b101, 0b0000001) => Inst::Divu { dest, src1, src2 },
1640                    (0b110, 0b0000001) => Inst::Rem { dest, src1, src2 },
1641                    (0b111, 0b0000001) => Inst::Remu { dest, src1, src2 },
1642                    _ => return Err(decode_error(code, "OP funct3/funct7")),
1643                }
1644            }
1645            // OP-32
1646            0b0111011 => {
1647                if xlen.is_32() {
1648                    return Err(decode_error(code, "OP-IMM-32 only on RV64"));
1649                }
1650
1651                let (dest, src1, src2) = (code.rd(), code.rs1(), code.rs2());
1652                match (code.funct3(), code.funct7()) {
1653                    (0b000, 0b0000000) => Inst::AddW { dest, src1, src2 },
1654                    (0b000, 0b0100000) => Inst::SubW { dest, src1, src2 },
1655                    (0b001, 0b0000000) => Inst::SllW { dest, src1, src2 },
1656                    (0b101, 0b0000000) => Inst::SrlW { dest, src1, src2 },
1657                    (0b101, 0b0100000) => Inst::SraW { dest, src1, src2 },
1658
1659                    (0b000, 0b0000001) => Inst::MulW { dest, src1, src2 },
1660                    (0b100, 0b0000001) => Inst::DivW { dest, src1, src2 },
1661                    (0b101, 0b0000001) => Inst::DivuW { dest, src1, src2 },
1662                    (0b110, 0b0000001) => Inst::RemW { dest, src1, src2 },
1663                    (0b111, 0b0000001) => Inst::RemuW { dest, src1, src2 },
1664                    _ => return Err(decode_error(code, "OP-32 funct3/funct7")),
1665                }
1666            }
1667            // MISC-MEM
1668            0b0001111 => {
1669                let fm = code.extract(28..=31);
1670                let pred = FenceSet {
1671                    device_input: code.extract(27..=27) == 1,
1672                    device_output: code.extract(26..=26) == 1,
1673                    memory_read: code.extract(25..=25) == 1,
1674                    memory_write: code.extract(24..=24) == 1,
1675                };
1676                let succ = FenceSet {
1677                    device_input: code.extract(23..=23) == 1,
1678                    device_output: code.extract(22..=22) == 1,
1679                    memory_read: code.extract(21..=21) == 1,
1680                    memory_write: code.extract(20..=20) == 1,
1681                };
1682
1683                match code.funct3() {
1684                    0b000 => Inst::Fence {
1685                        fence: Fence {
1686                            fm: fm as u8,
1687                            pred,
1688                            succ,
1689                            dest: code.rd(),
1690                            src: code.rs1(),
1691                        },
1692                    },
1693                    _ => return Err(decode_error(code, "MISC-MEM funct3")),
1694                }
1695            }
1696            // SYSTEM
1697            0b1110011 => {
1698                if code.0 == 0b11000000000000000001000001110011 {
1699                    return Err(decode_error(code, "unimp instruction"));
1700                }
1701                if code.rd().0 != 0 {
1702                    return Err(decode_error(code, "SYSTEM rd"));
1703                }
1704                if code.funct3() != 0 {
1705                    return Err(decode_error(code, "SYSTEM funct3"));
1706                }
1707                if code.rs1().0 != 0 {
1708                    return Err(decode_error(code, "SYSTEM rs1"));
1709                }
1710                match code.imm_i().as_u32() {
1711                    0b000000000000 => Inst::Ecall,
1712                    0b000000000001 => Inst::Ebreak,
1713                    _ => return Err(decode_error(code, "SYSTEM imm")),
1714                }
1715            }
1716            // AMO
1717            0b00101111 => {
1718                // width must be W
1719                if code.funct3() != 0b010 {
1720                    return Err(decode_error(code, "AMO width funct3"));
1721                }
1722
1723                let kind = code.extract(27..=31);
1724                let aq = code.extract(26..=26) == 1;
1725                let rl = code.extract(25..=25) == 1;
1726
1727                let order = AmoOrdering::from_aq_rl(aq, rl);
1728
1729                match kind {
1730                    // LR
1731                    0b00010 => {
1732                        if code.rs2().0 != 0 {
1733                            return Err(decode_error(code, "AMO.LR rs2"));
1734                        }
1735
1736                        Inst::LrW {
1737                            order,
1738                            dest: code.rd(),
1739                            addr: code.rs1(),
1740                        }
1741                    }
1742                    // SC
1743                    0b00011 => Inst::ScW {
1744                        order,
1745                        dest: code.rd(),
1746                        addr: code.rs1(),
1747                        src: code.rs2(),
1748                    },
1749                    _ => {
1750                        let op = match kind {
1751                            0b00001 => AmoOp::Swap,
1752                            0b00000 => AmoOp::Add,
1753                            0b00100 => AmoOp::Xor,
1754                            0b01100 => AmoOp::And,
1755                            0b01000 => AmoOp::Or,
1756                            0b10000 => AmoOp::Min,
1757                            0b10100 => AmoOp::Max,
1758                            0b11000 => AmoOp::Minu,
1759                            0b11100 => AmoOp::Maxu,
1760                            _ => return Err(decode_error(code, "AMO op funct7")),
1761                        };
1762                        Inst::AmoW {
1763                            order,
1764                            op,
1765                            dest: code.rd(),
1766                            addr: code.rs1(),
1767                            src: code.rs2(),
1768                        }
1769                    }
1770                }
1771            }
1772            _ => return Err(decode_error(code, "opcode")),
1773        };
1774        Ok(inst)
1775    }
1776    /// Encode a normal (not compressed) instruction
1777    pub fn encode_normal(&self, xlen: Xlen) -> u32 {
1778        let code = InstCode(0);
1779        macro_rules! BRANCH {
1780            ($offset:ident, $src1:ident, $src2:ident => $a:expr) => {
1781                $a.with_opcode(0b1100011)
1782                    .with_imm_b(*$offset)
1783                    .with_rs1(*$src1)
1784                    .with_rs2(*$src2)
1785            };
1786        }
1787        macro_rules! LOAD {
1788            ($offset:ident, $src1:ident, $dest:ident => $a:expr) => {
1789                $a.with_opcode(0b0000011)
1790                    .with_imm_i(*$offset)
1791                    .with_rs1(*$src1)
1792                    .with_rd(*$dest)
1793            };
1794        }
1795        macro_rules! STORE {
1796            ($offset:ident, $src1:ident, $src2:ident => $a:expr) => {
1797                $a.with_opcode(0b0100011)
1798                    .with_imm_s(*$offset)
1799                    .with_rs1(*$src1)
1800                    .with_rs2(*$src2)
1801            };
1802        }
1803        macro_rules! OP_IMM {
1804            ($offset:ident, $src1:ident, $dest:ident => $a:expr) => {
1805                $a.with_opcode(0b0010011)
1806                    .with_imm_i(*$offset)
1807                    .with_rs1(*$src1)
1808                    .with_rd(*$dest)
1809            };
1810        }
1811        macro_rules! OP_IMM_32 {
1812            ($offset:ident, $src1:ident, $dest:ident => $a:expr) => {
1813                $a.with_opcode(0b0011011)
1814                    .with_imm_i(*$offset)
1815                    .with_rs1(*$src1)
1816                    .with_rd(*$dest)
1817            };
1818        }
1819        macro_rules! OP {
1820            ($src1:ident, $src2:ident, $dest:ident => $a:expr) => {
1821                $a.with_opcode(0b0110011)
1822                    .with_rs2(*$src2)
1823                    .with_rs1(*$src1)
1824                    .with_rd(*$dest)
1825            };
1826        }
1827        macro_rules! OP_32 {
1828            ($src1:ident, $src2:ident, $dest:ident => $a:expr) => {
1829                $a.with_opcode(0b0111011)
1830                    .with_rs2(*$src2)
1831                    .with_rs1(*$src1)
1832                    .with_rd(*$dest)
1833            };
1834        }
1835        let code: InstCode = match self {
1836            Inst::Lui { uimm, dest } => {
1837                code.with_opcode(0b0110111).with_rd(*dest).with_imm_u(*uimm)
1838            }
1839            Inst::Auipc { uimm, dest } => {
1840                code.with_opcode(0b0010111).with_rd(*dest).with_imm_u(*uimm)
1841            }
1842            Inst::Jal { offset, dest } => code
1843                .with_opcode(0b1101111)
1844                .with_imm_j(*offset)
1845                .with_rd(*dest),
1846            Inst::Jalr { offset, base, dest } => code
1847                .with_opcode(0b1100111)
1848                .with_funct3(0b000)
1849                .with_imm_i(*offset)
1850                .with_rs1(*base)
1851                .with_rd(*dest),
1852            Inst::Beq { offset, src1, src2 } => {
1853                BRANCH!(offset,src1,src2 => code).with_funct3(0b000)
1854            }
1855            Inst::Bne { offset, src1, src2 } => {
1856                BRANCH!(offset,src1,src2 => code).with_funct3(0b001)
1857            }
1858            Inst::Blt { offset, src1, src2 } => {
1859                BRANCH!(offset,src1,src2 => code).with_funct3(0b100)
1860            }
1861            Inst::Bge { offset, src1, src2 } => {
1862                BRANCH!(offset,src1,src2 => code).with_funct3(0b101)
1863            }
1864            Inst::Bltu { offset, src1, src2 } => {
1865                BRANCH!(offset,src1,src2 => code).with_funct3(0b110)
1866            }
1867            Inst::Bgeu { offset, src1, src2 } => {
1868                BRANCH!(offset,src1,src2 => code).with_funct3(0b111)
1869            }
1870            Inst::Lb { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b000),
1871            Inst::Lbu { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b100),
1872            Inst::Lh { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b001),
1873            Inst::Lhu { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b101),
1874            Inst::Lw { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b010),
1875            Inst::Lwu { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b110),
1876            Inst::Ld { offset, dest, base } => LOAD!(offset,base,dest => code).with_funct3(0b011),
1877            Inst::Sb { offset, src, base } => STORE!(offset,base,src => code).with_funct3(0b000),
1878            Inst::Sh { offset, src, base } => STORE!(offset,base,src => code).with_funct3(0b001),
1879            Inst::Sw { offset, src, base } => STORE!(offset,base,src => code).with_funct3(0b010),
1880            Inst::Sd { offset, src, base } => STORE!(offset,base,src => code).with_funct3(0b011),
1881            Inst::Addi { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b000),
1882            Inst::AddiW { imm, dest, src1 } => OP_IMM_32!(imm,src1,dest => code).with_funct3(0b000),
1883            Inst::Slti { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b010),
1884            Inst::Sltiu { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b011),
1885            Inst::Xori { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b100),
1886            Inst::Ori { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b110),
1887            Inst::Andi { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b111),
1888            Inst::Slli { imm, dest, src1 } => OP_IMM!(imm,src1,dest => code).with_funct3(0b001),
1889            Inst::SlliW { imm, dest, src1 } => OP_IMM_32!(imm,src1,dest => code).with_funct3(0b001),
1890            Inst::Srli { imm, dest, src1 } => {
1891                match OP_IMM!(imm,src1,dest => code).with_funct3(0b101) {
1892                    x => match xlen {
1893                        Xlen::Rv32 => x.with_funct7(0b0000000).with_rs2_imm(imm.as_u32()),
1894                        Xlen::Rv64 => x.with_funct7(0b0000000).with_rs2_imm_plus(imm.as_u32()),
1895                    },
1896                }
1897            }
1898            Inst::SrliW { imm, dest, src1 } => OP_IMM_32!(imm,src1,dest => code)
1899                .with_funct3(0b101)
1900                .with_funct7(0b0000000)
1901                .with_rs2_imm(imm.as_u32()),
1902            Inst::Srai { imm, dest, src1 } => {
1903                match OP_IMM!(imm,src1,dest => code).with_funct3(0b101) {
1904                    x => match xlen {
1905                        Xlen::Rv32 => x.with_funct7(0b0100000).with_rs2_imm(imm.as_u32()),
1906                        Xlen::Rv64 => x.with_funct7(0b0100000).with_rs2_imm_plus(imm.as_u32()),
1907                    },
1908                }
1909            }
1910            Inst::SraiW { imm, dest, src1 } => OP_IMM_32!(imm,src1,dest => code)
1911                .with_funct3(0b101)
1912                .with_funct7(0b0100000)
1913                .with_rs2_imm(imm.as_u32()),
1914            Inst::Add { dest, src1, src2 } => OP!(src1,src2,dest => code)
1915                .with_funct3(0b000)
1916                .with_funct7(0b0000000),
1917            Inst::AddW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
1918                .with_funct3(0b000)
1919                .with_funct7(0b0000000),
1920            Inst::Sub { dest, src1, src2 } => OP!(src1,src2,dest => code)
1921                .with_funct3(0b000)
1922                .with_funct7(0b0100000),
1923            Inst::SubW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
1924                .with_funct3(0b000)
1925                .with_funct7(0b0100000),
1926            Inst::Sll { dest, src1, src2 } => OP!(src1,src2,dest => code)
1927                .with_funct3(0b001)
1928                .with_funct7(0b0000000),
1929            Inst::SllW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
1930                .with_funct3(0b001)
1931                .with_funct7(0b0000000),
1932            Inst::Slt { dest, src1, src2 } => OP!(src1,src2,dest => code)
1933                .with_funct3(0b010)
1934                .with_funct7(0b0000000),
1935            Inst::Sltu { dest, src1, src2 } => OP!(src1,src2,dest => code)
1936                .with_funct3(0b011)
1937                .with_funct7(0b0000000),
1938            Inst::Xor { dest, src1, src2 } => OP!(src1,src2,dest => code)
1939                .with_funct3(0b100)
1940                .with_funct7(0b0000000),
1941            Inst::Srl { dest, src1, src2 } => OP!(src1,src2,dest => code)
1942                .with_funct3(0b101)
1943                .with_funct7(0b0000000),
1944            Inst::SrlW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
1945                .with_funct3(0b101)
1946                .with_funct7(0b0000000),
1947            Inst::Sra { dest, src1, src2 } => OP!(src1,src2,dest => code)
1948                .with_funct3(0b101)
1949                .with_funct7(0b0100000),
1950            Inst::SraW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
1951                .with_funct3(0b101)
1952                .with_funct7(0b0100000),
1953            Inst::Or { dest, src1, src2 } => OP!(src1,src2,dest => code)
1954                .with_funct3(0b110)
1955                .with_funct7(0b0000000),
1956            Inst::And { dest, src1, src2 } => OP!(src1,src2,dest => code)
1957                .with_funct3(0b111)
1958                .with_funct7(0b0000000),
1959            Inst::Fence { fence } => match code
1960                .with_opcode(0b0001111)
1961                .insert(28..=31, fence.fm as u32)
1962                .with_rd(fence.dest)
1963                .with_rs1(fence.src)
1964            {
1965                mut v => {
1966                    let mut i = |x, b| v = v.insert(x..=x, if b { 1 } else { 0 });
1967                    i(27, fence.pred.device_input);
1968                    i(26, fence.pred.device_output);
1969                    i(25, fence.pred.memory_read);
1970                    i(24, fence.pred.memory_write);
1971                    i(23, fence.succ.device_input);
1972                    i(22, fence.succ.device_output);
1973                    i(21, fence.succ.memory_read);
1974                    i(20, fence.succ.memory_write);
1975                    v
1976                }
1977            },
1978            Inst::Ecall => code
1979                .with_opcode(0b1110011)
1980                .with_imm_i(Imm::new_u32(0b000000000000)),
1981            Inst::Ebreak => code
1982                .with_opcode(0b1110011)
1983                .with_imm_i(Imm::new_u32(0b000000000001)),
1984            Inst::Mul { dest, src1, src2 } => OP!(src1,src2,dest => code)
1985                .with_funct3(0b000)
1986                .with_funct7(0b0000001),
1987            Inst::MulW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
1988                .with_funct3(0b000)
1989                .with_funct7(0b0000001),
1990            Inst::Mulh { dest, src1, src2 } => OP!(src1,src2,dest => code)
1991                .with_funct3(0b001)
1992                .with_funct7(0b0000001),
1993            Inst::Mulhsu { dest, src1, src2 } => OP!(src1,src2,dest => code)
1994                .with_funct3(0b010)
1995                .with_funct7(0b0000001),
1996            Inst::Mulhu { dest, src1, src2 } => OP!(src1,src2,dest => code)
1997                .with_funct3(0b011)
1998                .with_funct7(0b0000001),
1999            Inst::Div { dest, src1, src2 } => OP!(src1,src2,dest => code)
2000                .with_funct3(0b100)
2001                .with_funct7(0b0000001),
2002            Inst::DivW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
2003                .with_funct3(0b100)
2004                .with_funct7(0b0000001),
2005            Inst::Divu { dest, src1, src2 } => OP!(src1,src2,dest => code)
2006                .with_funct3(0b101)
2007                .with_funct7(0b0000001),
2008            Inst::DivuW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
2009                .with_funct3(0b101)
2010                .with_funct7(0b0000001),
2011            Inst::Rem { dest, src1, src2 } => OP!(src1,src2,dest => code)
2012                .with_funct3(0b110)
2013                .with_funct7(0b0000001),
2014            Inst::RemW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
2015                .with_funct3(0b110)
2016                .with_funct7(0b0000001),
2017            Inst::Remu { dest, src1, src2 } => OP!(src1,src2,dest => code)
2018                .with_funct3(0b111)
2019                .with_funct7(0b0000001),
2020            Inst::RemuW { dest, src1, src2 } => OP_32!(src1,src2,dest => code)
2021                .with_funct3(0b111)
2022                .with_funct7(0b0000001),
2023            Inst::LrW { order, dest, addr } => match code
2024                .with_opcode(0b00101111)
2025                .with_funct3(0b010)
2026                .insert(26..=26, if order.aq_rl().0 { 1 } else { 0 })
2027                .insert(25..=25, if order.aq_rl().1 { 1 } else { 0 })
2028            {
2029                code => code.insert(27..=31, 0b00010).with_rd(*dest).with_rs1(*addr),
2030            },
2031            Inst::ScW {
2032                order,
2033                dest,
2034                addr,
2035                src,
2036            } => match code
2037                .with_opcode(0b00101111)
2038                .with_funct3(0b010)
2039                .insert(26..=26, if order.aq_rl().0 { 1 } else { 0 })
2040                .insert(25..=25, if order.aq_rl().1 { 1 } else { 0 })
2041            {
2042                code => code
2043                    .insert(27..=31, 0b00011)
2044                    .with_rd(*dest)
2045                    .with_rs1(*addr)
2046                    .with_rs2(*src),
2047            },
2048            Inst::AmoW {
2049                order,
2050                op,
2051                dest,
2052                addr,
2053                src,
2054            } => match code
2055                .with_opcode(0b00101111)
2056                .with_funct3(0b010)
2057                .insert(26..=26, if order.aq_rl().0 { 1 } else { 0 })
2058                .insert(25..=25, if order.aq_rl().1 { 1 } else { 0 })
2059            {
2060                code => code.with_rd(*dest).with_rs1(*addr).with_rs2(*src).insert(
2061                    27..=31,
2062                    match op {
2063                        AmoOp::Swap => 0b00001,
2064                        AmoOp::Add => 0b00000,
2065                        AmoOp::Xor => 0b00100,
2066                        AmoOp::And => 0b01100,
2067                        AmoOp::Or => 0b01000,
2068                        AmoOp::Min => 0b10000,
2069                        AmoOp::Max => 0b10100,
2070                        AmoOp::Minu => 0b11000,
2071                        AmoOp::Maxu => 0b11100,
2072                    },
2073                ),
2074            },
2075        };
2076        code.0
2077    }
2078}
2079
2080#[cfg(test)]
2081mod tests {
2082    extern crate std;
2083    use core::sync::atomic::AtomicU32;
2084    use core::sync::atomic::Ordering;
2085    use core::u32;
2086    use std::prelude::rust_2024::*;
2087
2088    use std::fmt::Write as _;
2089    use std::io::Write as _;
2090
2091    use object::Object;
2092    use object::ObjectSection;
2093    use rayon::iter::IntoParallelRefIterator;
2094    use rayon::iter::ParallelIterator;
2095
2096    use crate::Fence;
2097    use crate::FenceSet;
2098    use crate::Imm;
2099    use crate::Inst;
2100    use crate::Reg;
2101    use crate::Xlen;
2102
2103    #[test]
2104    #[cfg_attr(not(slow_tests), ignore = "cfg(slow_tests) not enabled")]
2105    fn exhaustive_decode_no_panic_32() {
2106        exhaustive_decode_no_panic(Xlen::Rv32);
2107    }
2108
2109    #[test]
2110    #[cfg_attr(not(slow_tests), ignore = "cfg(slow_tests) not enabled")]
2111    fn exhaustive_decode_no_panic_64() {
2112        exhaustive_decode_no_panic(Xlen::Rv64);
2113    }
2114
2115    fn exhaustive_decode_no_panic(xlen: Xlen) {
2116        for i in 0..u32::MAX {
2117            if (i % (2 << 25)) == 0 {
2118                let percent = i as f32 / (u32::MAX as f32);
2119                let done = (100.0 * percent) as usize;
2120                std::print!("\r{}{}", "#".repeat(done), "-".repeat(100 - done));
2121                std::io::stdout().flush().unwrap();
2122            }
2123            let i2 = Inst::decode(i, xlen);
2124            if let Ok((i2, crate::IsCompressed::No)) = i2 {
2125                if is_inst_supposed_to_roundtrip(&i2) {
2126                    assert_eq!(
2127                        i2,
2128                        Inst::decode(i2.encode_normal(xlen), xlen)
2129                            .expect("to succeed")
2130                            .0,
2131                        "encoded inst different: {i2} from {i} encodes differently"
2132                    );
2133                }
2134            }
2135        }
2136        let i2 = Inst::decode(u32::MAX, xlen);
2137        let i = u32::MAX;
2138        if let Ok((i2, crate::IsCompressed::No)) = i2 {
2139            if is_inst_supposed_to_roundtrip(&i2) {
2140                assert_eq!(
2141                    i2,
2142                    Inst::decode(i2.encode_normal(xlen), xlen)
2143                        .expect("to succeed")
2144                        .0,
2145                    "encoded inst different: {i2} from {i} encodes differently"
2146                );
2147            }
2148        }
2149    }
2150
2151    #[test]
2152    fn size_of_instruction() {
2153        assert!(
2154            size_of::<Inst>() <= 16,
2155            "size of instruction is too large: {}",
2156            size_of::<Inst>()
2157        );
2158    }
2159
2160    const TEST_SECTION_NAME: &str = ".text.rvdctest";
2161
2162    /// Some instruction fields are reserved and not printed in the assembly,
2163    /// but should be ignored instead of rejected by the decoder.
2164    /// We filter out non-canonical forms of these instructions as they do not roundtrip.
2165    fn is_inst_supposed_to_roundtrip(inst: &Inst) -> bool {
2166        match inst {
2167            // Canonical fence.tso
2168            Inst::Fence {
2169                fence:
2170                    Fence {
2171                        fm: 0b1000,
2172                        pred:
2173                            FenceSet {
2174                                device_input: false,
2175                                device_output: false,
2176                                memory_read: true,
2177                                memory_write: true,
2178                            },
2179                        succ:
2180                            FenceSet {
2181                                device_input: false,
2182                                device_output: false,
2183                                memory_read: true,
2184                                memory_write: true,
2185                            },
2186                        src: Reg::ZERO,
2187                        dest: Reg::ZERO,
2188                    },
2189            } => true,
2190            // Only canonical normal fence with x0 and x0
2191            Inst::Fence {
2192                fence:
2193                    Fence {
2194                        fm: 0b0000,
2195                        pred: _,
2196                        succ: _,
2197                        src: Reg::ZERO,
2198                        dest: Reg::ZERO,
2199                    },
2200            } => true,
2201            // All other fences are reserved
2202            Inst::Fence { .. } => false,
2203            _ => true,
2204        }
2205    }
2206
2207    fn is_compressed_inst_supposed_to_roundtrip(inst: &Inst) -> bool {
2208        match inst {
2209            // HINT
2210            Inst::Addi {
2211                dest: Reg::ZERO, ..
2212            } => false,
2213            // This does roundtrip, but only through C.MV, not C.ADDI
2214            Inst::Addi { imm: Imm::ZERO, .. } => false,
2215            // This does rountrip, but not through C.ADDI
2216            Inst::Addi {
2217                dest: Reg::SP,
2218                src1: Reg::SP,
2219                ..
2220            } => false,
2221            // HINT
2222            Inst::Slli {
2223                dest: Reg::ZERO, ..
2224            }
2225            | Inst::Slli { imm: Imm::ZERO, .. }
2226            | Inst::Srli {
2227                dest: Reg::ZERO, ..
2228            }
2229            | Inst::Srli { imm: Imm::ZERO, .. }
2230            | Inst::Srai {
2231                dest: Reg::ZERO, ..
2232            }
2233            | Inst::Srai { imm: Imm::ZERO, .. } => false,
2234            // HINT
2235            Inst::Lui {
2236                dest: Reg::ZERO, ..
2237            } => false,
2238            _ => true,
2239        }
2240    }
2241
2242    // turn this up for debugging, only run the test directly in these cases
2243    const SKIP_CHUNKS: u32 = 0;
2244
2245    #[test]
2246    fn ensure_no_chunks_are_skipped() {
2247        assert_eq!(SKIP_CHUNKS, 0);
2248    }
2249
2250    #[test]
2251    #[cfg_attr(not(slow_tests), ignore = "cfg(slow_tests) not enabled")]
2252    fn normal_clang_roundtrip() {
2253        const CHUNKS: u32 = 128;
2254        const CHUNK_SIZE: u32 = u32::MAX / CHUNKS;
2255
2256        let chunks = ((SKIP_CHUNKS * CHUNK_SIZE)..u32::MAX)
2257            .step_by(CHUNK_SIZE as usize)
2258            .collect::<Vec<_>>();
2259
2260        let start_time = std::time::Instant::now();
2261        let completed = AtomicU32::new(0);
2262
2263        chunks.par_iter().for_each(|&start| {
2264            let insts = (start..=start.saturating_add(CHUNK_SIZE))
2265                .filter_map(|code| Some((code, Inst::decode_normal(code, Xlen::Rv32).ok()?)))
2266                .filter(|(_, inst)| is_inst_supposed_to_roundtrip(inst))
2267                .collect::<Vec<_>>();
2268
2269            let mut text = std::format!(".section {TEST_SECTION_NAME}\n.globl _start\n_start:\n");
2270            for (_, inst) in &insts {
2271                writeln!(text, "  {inst}").unwrap();
2272            }
2273
2274            let data = clang_assemble(&text, "-march=rv32ima_zihintpause");
2275
2276            for (i, result_code) in data.chunks(4).enumerate() {
2277                let result_code = u32::from_le_bytes(result_code.try_into().unwrap());
2278
2279                assert_eq!(
2280                    insts[i].0, result_code,
2281                    "failed to rountrip!\n\
2282                     instruction `{:0>32b}` failed to rountrip\n\
2283                     resulted in `{:0>32b}` instead.\n\
2284                     disassembly of original instruction: `{}`",
2285                    insts[i].0, result_code, insts[i].1
2286                );
2287            }
2288
2289            let already_completed = completed.fetch_add(1, Ordering::Relaxed);
2290            let already_elapsed = start_time.elapsed();
2291
2292            let remaining_chunks = CHUNKS.saturating_sub(already_completed);
2293            let remaining =
2294                already_elapsed / std::cmp::max(already_completed, 1) * remaining_chunks;
2295
2296            writeln!(
2297                std::io::stdout(),
2298                "Completed chunk {already_completed}/{CHUNKS} (estimated {remaining:?} remaining)",
2299            )
2300            .unwrap();
2301        });
2302    }
2303
2304    #[test]
2305    #[ignore = "this doesn't quite work yet because there is often a non-canonical encoding"]
2306    fn compressed_clang_roundtrip() {
2307        let insts = (0..=u16::MAX)
2308            .filter_map(|code| Some((code, Inst::decode_compressed(code, Xlen::Rv32).ok()?)))
2309            .filter(|(_, inst)| is_compressed_inst_supposed_to_roundtrip(inst))
2310            .collect::<Vec<_>>();
2311
2312        let mut text = std::format!(".section {TEST_SECTION_NAME}\n.globl _start\n_start:\n");
2313        for (_, inst) in &insts {
2314            writeln!(text, "  {inst}").unwrap();
2315        }
2316
2317        let data = clang_assemble(&text, "-march=rv32imac");
2318
2319        for (i, result_code) in data.chunks(2).enumerate() {
2320            assert!(
2321                Inst::first_byte_is_compressed(result_code[0]),
2322                "failed to roundtrip {i}th instruction!\n\
2323                instruction `{:0>16b}` resulted in an uncompressed instruction from clang\n\
2324                disassembly of original instruction: `{}`",
2325                insts[i].0,
2326                insts[i].1
2327            );
2328
2329            let result_code = u16::from_le_bytes(result_code.try_into().unwrap());
2330
2331            assert_eq!(
2332                insts[i].0, result_code,
2333                "failed to rountrip {i}th instruction!\n\
2334                 instruction `{:0>16b}` failed to rountrip\n\
2335                 resulted in `{:0>16b}` instead.\n\
2336                 disassembly of original instruction: `{}`",
2337                insts[i].0, result_code, insts[i].1
2338            );
2339        }
2340    }
2341
2342    fn clang_assemble(text: &str, march_flag: &str) -> Vec<u8> {
2343        let tmp = tempfile::tempdir().unwrap();
2344
2345        let path = tmp.path().join("16.s");
2346        let bin_path = tmp.path().join("16.o");
2347        std::fs::write(&path, text).unwrap();
2348
2349        let mut clang = std::process::Command::new("clang");
2350        clang.args(["-target", "riscv32-unknown-none-elf", march_flag, "-c"]);
2351        clang.arg(path);
2352        clang.arg("-o");
2353        clang.arg(&bin_path);
2354        let out = clang.output().unwrap();
2355        if !out.status.success() {
2356            panic!(
2357                "failed to run clang:\n{}",
2358                String::from_utf8_lossy(&out.stderr)
2359            );
2360        }
2361
2362        let obj = std::fs::read(bin_path).unwrap();
2363        let obj = object::File::parse(&*obj).unwrap();
2364        let section = obj.section_by_name(TEST_SECTION_NAME).unwrap();
2365        let data = section.data().unwrap();
2366        data.to_owned()
2367    }
2368}