riscv_isa/
instruction.rs

1// Copyright James Wainwright
2//
3// SPDX-License-Identifier: MPL-2.0
4
5/// RISC-V instruction.
6///
7/// Contains all supported canonical RISC-V instructions. Does not
8/// contain pseudo or compressed instructions.
9///
10/// Instruction arguments are all in their decoded forms, meaning correctly
11/// scaled and sign extended. Their names are as they appear in specifications
12/// (for the most part), and include:
13///
14/// * `rd`, `rs1`, `rs2`: destination and source registers.
15/// * `frd`, `frs1`, `frs2`, `frs3`: destination and source floating point registers.
16/// * `offset`, `imm`, `shamt`: numerical offsets, immediates, and shift amounts.
17#[allow(non_camel_case_types)]
18#[allow(clippy::upper_case_acronyms)]
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub enum Instruction {
21    // Unknown:
22    UNIMP,
23    // RV32I base instruction set:
24    LUI { rd: u32, imm: u32 },
25    AUIPC { rd: u32, imm: u32 },
26    JAL { rd: u32, offset: i32 },
27    JALR { rd: u32, rs1: u32, offset: i32 },
28    BEQ { rs1: u32, rs2: u32, offset: i32 },
29    BNE { rs1: u32, rs2: u32, offset: i32 },
30    BLT { rs1: u32, rs2: u32, offset: i32 },
31    BGE { rs1: u32, rs2: u32, offset: i32 },
32    BLTU { rs1: u32, rs2: u32, offset: i32 },
33    BGEU { rs1: u32, rs2: u32, offset: i32 },
34    LB { rd: u32, rs1: u32, offset: i32 },
35    LH { rd: u32, rs1: u32, offset: i32 },
36    LW { rd: u32, rs1: u32, offset: i32 },
37    LBU { rd: u32, rs1: u32, offset: i32 },
38    LHU { rd: u32, rs1: u32, offset: i32 },
39    SB { rs1: u32, rs2: u32, offset: i32 },
40    SH { rs1: u32, rs2: u32, offset: i32 },
41    SW { rs1: u32, rs2: u32, offset: i32 },
42    ADDI { rd: u32, rs1: u32, imm: i32 },
43    SLTI { rd: u32, rs1: u32, imm: i32 },
44    SLTIU { rd: u32, rs1: u32, imm: i32 },
45    XORI { rd: u32, rs1: u32, imm: i32 },
46    ORI { rd: u32, rs1: u32, imm: i32 },
47    ANDI { rd: u32, rs1: u32, imm: i32 },
48    SLLI { rd: u32, rs1: u32, shamt: u32 },
49    SRLI { rd: u32, rs1: u32, shamt: u32 },
50    SRAI { rd: u32, rs1: u32, shamt: u32 },
51    ADD { rd: u32, rs1: u32, rs2: u32 },
52    SUB { rd: u32, rs1: u32, rs2: u32 },
53    SLL { rd: u32, rs1: u32, rs2: u32 },
54    SLT { rd: u32, rs1: u32, rs2: u32 },
55    SLTU { rd: u32, rs1: u32, rs2: u32 },
56    XOR { rd: u32, rs1: u32, rs2: u32 },
57    SRL { rd: u32, rs1: u32, rs2: u32 },
58    SRA { rd: u32, rs1: u32, rs2: u32 },
59    OR { rd: u32, rs1: u32, rs2: u32 },
60    AND { rd: u32, rs1: u32, rs2: u32 },
61    FENCE { pred: Iorw, succ: Iorw },
62    ECALL,
63    EBREAK,
64    // S-mode:
65    SRET,
66    SFENCE_VMA { rs1: u32, rs2: u32 },
67    // Privileged:
68    MRET,
69    WFI,
70    // RV64I base instruction set:
71    LWU { rd: u32, rs1: u32, offset: i32 },
72    LD { rd: u32, rs1: u32, offset: i32 },
73    SD { rs1: u32, rs2: u32, offset: i32 },
74    ADDIW { rd: u32, rs1: u32, imm: i32 },
75    SLLIW { rd: u32, rs1: u32, shamt: u32 },
76    SRLIW { rd: u32, rs1: u32, shamt: u32 },
77    SRAIW { rd: u32, rs1: u32, shamt: u32 },
78    ADDW { rd: u32, rs1: u32, rs2: u32 },
79    SUBW { rd: u32, rs1: u32, rs2: u32 },
80    SLLW { rd: u32, rs1: u32, rs2: u32 },
81    SRLW { rd: u32, rs1: u32, rs2: u32 },
82    SRAW { rd: u32, rs1: u32, rs2: u32 },
83    // RV32/RV64 Zifencei:
84    FENCE_I,
85    // RV32/RV64 Zicsr extension:
86    CSRRW { rd: u32, csr: u32, rs1: u32 },
87    CSRRS { rd: u32, csr: u32, rs1: u32 },
88    CSRRC { rd: u32, csr: u32, rs1: u32 },
89    CSRRWI { rd: u32, csr: u32, uimm: u32 },
90    CSRRSI { rd: u32, csr: u32, uimm: u32 },
91    CSRRCI { rd: u32, csr: u32, uimm: u32 },
92    // RV32M extension:
93    MUL { rd: u32, rs1: u32, rs2: u32 },
94    MULH { rd: u32, rs1: u32, rs2: u32 },
95    MULHSU { rd: u32, rs1: u32, rs2: u32 },
96    MULHU { rd: u32, rs1: u32, rs2: u32 },
97    DIV { rd: u32, rs1: u32, rs2: u32 },
98    DIVU { rd: u32, rs1: u32, rs2: u32 },
99    REM { rd: u32, rs1: u32, rs2: u32 },
100    REMU { rd: u32, rs1: u32, rs2: u32 },
101    // RV64M extension:
102    MULW { rd: u32, rs1: u32, rs2: u32 },
103    DIVW { rd: u32, rs1: u32, rs2: u32 },
104    DIVUW { rd: u32, rs1: u32, rs2: u32 },
105    REMW { rd: u32, rs1: u32, rs2: u32 },
106    REMUW { rd: u32, rs1: u32, rs2: u32 },
107    // RV32A extension:
108    LR_W { rd: u32, rs1: u32, rl: u32, aq: u32 },
109    SC_W { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
110    AMOSWAP_W { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
111    AMOADD_W { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
112    AMOXOR_W { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
113    AMOAND_W { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
114    AMOOR_W { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
115    AMOMIN_W { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
116    AMOMAX_W { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
117    AMOMINU_W { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
118    AMOMAXU_W { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
119    // RV64A extension:
120    LR_D { rd: u32, rs1: u32, rl: u32, aq: u32 },
121    SC_D { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
122    AMOSWAP_D { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
123    AMOADD_D { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
124    AMOXOR_D { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
125    AMOAND_D { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
126    AMOOR_D { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
127    AMOMIN_D { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
128    AMOMAX_D { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
129    AMOMINU_D { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
130    AMOMAXU_D { rd: u32, rs1: u32, rs2: u32, rl: u32, aq: u32 },
131    // RV32F extension:
132    FLW { frd: u32, rs1: u32, offset: i32 },
133    FSW { rs1: u32, frs2: u32, offset: i32 },
134    FMADD_S { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
135    FMSUB_S { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
136    FNMSUB_S { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
137    FNMADD_S { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
138    FADD_S { frd: u32, rm: u32, frs1: u32, frs2: u32 },
139    FSUB_S { frd: u32, rm: u32, frs1: u32, frs2: u32 },
140    FMUL_S { frd: u32, rm: u32, frs1: u32, frs2: u32 },
141    FDIV_S { frd: u32, rm: u32, frs1: u32, frs2: u32 },
142    FSQRT_S { frd: u32, rm: u32, frs1: u32 },
143    FSGNJ_S { frd: u32, frs1: u32, frs2: u32 },
144    FSGNJN_S { frd: u32, frs1: u32, frs2: u32 },
145    FSGNJX_S { frd: u32, frs1: u32, frs2: u32 },
146    FMIN_S { frd: u32, frs1: u32, frs2: u32 },
147    FMAX_S { frd: u32, frs1: u32, frs2: u32 },
148    FCVT_W_S { rd: u32, rm: u32, frs1: u32 },
149    FCVT_WU_S { rd: u32, rm: u32, frs1: u32 },
150    FMV_X_W { rd: u32, frs1: u32 },
151    FEQ_S { rd: u32, frs1: u32, frs2: u32 },
152    FLT_S { rd: u32, frs1: u32, frs2: u32 },
153    FLE_S { rd: u32, frs1: u32, frs2: u32 },
154    FCLASS_S { rd: u32, frs1: u32 },
155    FCVT_S_W { frd: u32, rm: u32, rs1: u32 },
156    FCVT_S_WU { frd: u32, rm: u32, rs1: u32 },
157    FMV_W_X { frd: u32, rs1: u32 },
158    // RV64F extension:
159    FCVT_L_S { rd: u32, rm: u32, frs1: u32 },
160    FCVT_LU_S { rd: u32, rm: u32, frs1: u32 },
161    FCVT_S_L { frd: u32, rm: u32, rs1: u32 },
162    FCVT_S_LU { frd: u32, rm: u32, rs1: u32 },
163    // RV32D extension:
164    FLD { frd: u32, rs1: u32, offset: i32 },
165    FSD { rs1: u32, frs2: u32, offset: i32 },
166    FMADD_D { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
167    FMSUB_D { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
168    FNMSUB_D { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
169    FNMADD_D { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
170    FADD_D { frd: u32, rm: u32, frs1: u32, frs2: u32 },
171    FSUB_D { frd: u32, rm: u32, frs1: u32, frs2: u32 },
172    FMUL_D { frd: u32, rm: u32, frs1: u32, frs2: u32 },
173    FDIV_D { frd: u32, rm: u32, frs1: u32, frs2: u32 },
174    FSQRT_D { frd: u32, rm: u32, frs1: u32 },
175    FSGNJ_D { frd: u32, frs1: u32, frs2: u32 },
176    FSGNJN_D { frd: u32, frs1: u32, frs2: u32 },
177    FSGNJX_D { frd: u32, frs1: u32, frs2: u32 },
178    FMIN_D { frd: u32, frs1: u32, frs2: u32 },
179    FMAX_D { frd: u32, frs1: u32, frs2: u32 },
180    FCVT_S_D { frd: u32, rm: u32, frs1: u32 },
181    FCVT_D_S { frd: u32, rm: u32, frs1: u32 },
182    FEQ_D { rd: u32, frs1: u32, frs2: u32 },
183    FLT_D { rd: u32, frs1: u32, frs2: u32 },
184    FLE_D { rd: u32, frs1: u32, frs2: u32 },
185    FCLASS_D { rd: u32, frs1: u32 },
186    FCVT_W_D { rd: u32, rm: u32, frs1: u32 },
187    FCVT_WU_D { rd: u32, rm: u32, frs1: u32 },
188    FCVT_D_W { frd: u32, rm: u32, rs1: u32 },
189    FCVT_D_WU { frd: u32, rm: u32, rs1: u32 },
190    // RV64D extension:
191    FCVT_L_D { rd: u32, rm: u32, frs1: u32 },
192    FCVT_LU_D { rd: u32, rm: u32, frs1: u32 },
193    FMV_X_D { rd: u32, frs1: u32 },
194    FCVT_D_L { frd: u32, rm: u32, rs1: u32 },
195    FCVT_D_LU { frd: u32, rm: u32, rs1: u32 },
196    FMV_D_X { frd: u32, rs1: u32 },
197    // RV32Q extension:
198    FLQ { frd: u32, rs1: u32, offset: i32 },
199    FSQ { rs1: u32, frs2: u32, offset: i32 },
200    FMADD_Q { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
201    FMSUB_Q { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
202    FNMSUB_Q { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
203    FNMADD_Q { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
204    FADD_Q { frd: u32, rm: u32, frs1: u32, frs2: u32 },
205    FSUB_Q { frd: u32, rm: u32, frs1: u32, frs2: u32 },
206    FMUL_Q { frd: u32, rm: u32, frs1: u32, frs2: u32 },
207    FDIV_Q { frd: u32, rm: u32, frs1: u32, frs2: u32 },
208    FSQRT_Q { frd: u32, rm: u32, frs1: u32 },
209    FSGNJ_Q { frd: u32, frs1: u32, frs2: u32 },
210    FSGNJN_Q { frd: u32, frs1: u32, frs2: u32 },
211    FSGNJX_Q { frd: u32, frs1: u32, frs2: u32 },
212    FMIN_Q { frd: u32, frs1: u32, frs2: u32 },
213    FMAX_Q { frd: u32, frs1: u32, frs2: u32 },
214    FCVT_S_Q { frd: u32, rm: u32, frs1: u32 },
215    FCVT_Q_S { frd: u32, rm: u32, frs1: u32 },
216    FCVT_D_Q { frd: u32, rm: u32, frs1: u32 },
217    FCVT_Q_D { frd: u32, rm: u32, frs1: u32 },
218    FEQ_Q { rd: u32, frs1: u32, frs2: u32 },
219    FLT_Q { rd: u32, frs1: u32, frs2: u32 },
220    FLE_Q { rd: u32, frs1: u32, frs2: u32 },
221    FCLASS_Q { rd: u32, frs1: u32 },
222    FCVT_W_Q { rd: u32, rm: u32, frs1: u32 },
223    FCVT_WU_Q { rd: u32, rm: u32, frs1: u32 },
224    FCVT_Q_W { frd: u32, rm: u32, rs1: u32 },
225    FCVT_Q_WU { frd: u32, rm: u32, rs1: u32 },
226    // RV64Q extension:
227    FCVT_L_Q { rd: u32, rm: u32, frs1: u32 },
228    FCVT_LU_Q { rd: u32, rm: u32, frs1: u32 },
229    FCVT_Q_L { frd: u32, rm: u32, rs1: u32 },
230    FCVT_Q_LU { frd: u32, rm: u32, rs1: u32 },
231    // RV32Zfh extension:
232    FLH { frd: u32, rs1: u32, offset: i32 },
233    FSH { rs1: u32, frs2: u32, offset: i32 },
234    FMADD_H { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
235    FMSUB_H { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
236    FNMSUB_H { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
237    FNMADD_H { frd: u32, rm: u32, frs1: u32, frs2: u32, frs3: u32 },
238    FADD_H { frd: u32, rm: u32, frs1: u32, frs2: u32 },
239    FSUB_H { frd: u32, rm: u32, frs1: u32, frs2: u32 },
240    FMUL_H { frd: u32, rm: u32, frs1: u32, frs2: u32 },
241    FDIV_H { frd: u32, rm: u32, frs1: u32, frs2: u32 },
242    FSQRT_H { frd: u32, rm: u32, frs1: u32 },
243    FSGNJ_H { frd: u32, frs1: u32, frs2: u32 },
244    FSGNJN_H { frd: u32, frs1: u32, frs2: u32 },
245    FSGNJX_H { frd: u32, frs1: u32, frs2: u32 },
246    FMIN_H { frd: u32, frs1: u32, frs2: u32 },
247    FMAX_H { frd: u32, frs1: u32, frs2: u32 },
248    FCVT_S_H { frd: u32, rm: u32, frs1: u32 },
249    FCVT_H_S { frd: u32, rm: u32, frs1: u32 },
250    FCVT_D_H { frd: u32, rm: u32, frs1: u32 },
251    FCVT_H_D { frd: u32, rm: u32, frs1: u32 },
252    FCVT_Q_H { frd: u32, rm: u32, frs1: u32 },
253    FCVT_H_Q { frd: u32, rm: u32, frs1: u32 },
254    FEQ_H { rd: u32, frs1: u32, frs2: u32 },
255    FLT_H { rd: u32, frs1: u32, frs2: u32 },
256    FLE_H { rd: u32, frs1: u32, frs2: u32 },
257    FCLASS_H { rd: u32, frs1: u32 },
258    FCVT_W_H { rd: u32, rm: u32, frs1: u32 },
259    FCVT_WU_H { rd: u32, rm: u32, frs1: u32 },
260    FMV_X_H { frd: u32, rs1: u32 },
261    FCVT_H_W { frd: u32, rm: u32, rs1: u32 },
262    FCVT_H_WU { frd: u32, rm: u32, rs1: u32 },
263    FMV_H_X { frd: u32, rs1: u32 },
264    // RV64Zfh extension:
265    FCVT_L_H { rd: u32, rm: u32, frs1: u32 },
266    FCVT_LU_H { rd: u32, rm: u32, frs1: u32 },
267    FCVT_H_L { frd: u32, rm: u32, rs1: u32 },
268    FCVT_H_LU { frd: u32, rm: u32, rs1: u32 },
269    // Zawrs extension:
270    WRS_NTO,
271    WRS_STO,
272    // RV32Zba extension:
273    SH1ADD { rd: u32, rs1: u32, rs2: u32 },
274    SH2ADD { rd: u32, rs1: u32, rs2: u32 },
275    SH3ADD { rd: u32, rs1: u32, rs2: u32 },
276    // RV64Zba extension:
277    ADD_UW { rd: u32, rs1: u32, rs2: u32 },
278    SH1ADD_UW { rd: u32, rs1: u32, rs2: u32 },
279    SH2ADD_UW { rd: u32, rs1: u32, rs2: u32 },
280    SH3ADD_UW { rd: u32, rs1: u32, rs2: u32 },
281    SLLI_UW { rd: u32, rs1: u32, shamt: u32 },
282    // RV32Zbb extension:
283    ANDN { rd: u32, rs1: u32, rs2: u32 },
284    ORN { rd: u32, rs1: u32, rs2: u32 },
285    XNOR { rd: u32, rs1: u32, rs2: u32 },
286    CLZ { rd: u32, rs1: u32 },
287    CTZ { rd: u32, rs1: u32 },
288    CPOP { rd: u32, rs1: u32 },
289    MAX { rd: u32, rs1: u32, rs2: u32 },
290    MAXU { rd: u32, rs1: u32, rs2: u32 },
291    MIN { rd: u32, rs1: u32, rs2: u32 },
292    MINU { rd: u32, rs1: u32, rs2: u32 },
293    SEXT_B { rd: u32, rs1: u32 },
294    SEXT_H { rd: u32, rs1: u32 },
295    ZEXT_H { rd: u32, rs1: u32 },
296    // RV64Zbb extension:
297    CLZW { rd: u32, rs1: u32 },
298    CTZW { rd: u32, rs1: u32 },
299    CPOPW { rd: u32, rs1: u32 },
300    // Bitwise rotations (RV32Zbb AND RV32Zbkb extensions):
301    ROL { rd: u32, rs1: u32, rs2: u32 },
302    ROR { rd: u32, rs1: u32, rs2: u32 },
303    RORI { rd: u32, rs1: u32, shamt: u32 },
304    ORC_B { rd: u32, rs1: u32 },
305    REV8 { rd: u32, rs1: u32 },
306    // Bitwise rotations (RV64Zbb AND RV64Zbkb extensions):
307    ROLW { rd: u32, rs1: u32, rs2: u32 },
308    RORIW { rd: u32, rs1: u32, shamt: u32 },
309    RORW { rd: u32, rs1: u32, rs2: u32 },
310    // RV32Zbkb extension:
311    PACK { rd: u32, rs1: u32, rs2: u32 },
312    PACKH { rd: u32, rs1: u32, rs2: u32 },
313    BREV8 { rd: u32, rs1: u32 },
314    ZIP { rd: u32, rs1: u32 },
315    UNZIP { rd: u32, rs1: u32 },
316    // RV64Zbkb extension:
317    PACKW { rd: u32, rs1: u32, rs2: u32 },
318    // Zbc extension:
319    CLMUL { rd: u32, rs1: u32, rs2: u32 },
320    CLMULH { rd: u32, rs1: u32, rs2: u32 },
321    CLMULR { rd: u32, rs1: u32, rs2: u32 },
322    // Zbs extension:
323    BCLR { rd: u32, rs1: u32, rs2: u32 },
324    BCLRI { rd: u32, rs1: u32, shamt: u32 },
325    BEXT { rd: u32, rs1: u32, rs2: u32 },
326    BEXTI { rd: u32, rs1: u32, shamt: u32 },
327    BINV { rd: u32, rs1: u32, rs2: u32 },
328    BINVI { rd: u32, rs1: u32, shamt: u32 },
329    BSET { rd: u32, rs1: u32, rs2: u32 },
330    BSETI { rd: u32, rs1: u32, shamt: u32 },
331}
332
333impl Instruction {
334    /// Check whether an instruction could branch or jump.
335    pub fn branch(&self) -> bool {
336        matches!(
337            self,
338            Instruction::JAL { .. }
339                | Instruction::JALR { .. }
340                | Instruction::BEQ { .. }
341                | Instruction::BNE { .. }
342                | Instruction::BLT { .. }
343                | Instruction::BGE { .. }
344                | Instruction::BLTU { .. }
345                | Instruction::BGEU { .. }
346        )
347    }
348
349    /// Check whether an instruction could load from memory.
350    pub fn load(&self) -> bool {
351        matches!(
352            self,
353            Instruction::LB { .. }
354                | Instruction::LH { .. }
355                | Instruction::LW { .. }
356                | Instruction::LBU { .. }
357                | Instruction::LHU { .. }
358                | Instruction::LWU { .. }
359                | Instruction::LD { .. }
360                | Instruction::LR_W { .. }
361                | Instruction::LR_D { .. }
362                | Instruction::AMOSWAP_W { .. }
363                | Instruction::AMOADD_W { .. }
364                | Instruction::AMOXOR_W { .. }
365                | Instruction::AMOAND_W { .. }
366                | Instruction::AMOOR_W { .. }
367                | Instruction::AMOMIN_W { .. }
368                | Instruction::AMOMAX_W { .. }
369                | Instruction::AMOMINU_W { .. }
370                | Instruction::AMOMAXU_W { .. }
371                | Instruction::AMOSWAP_D { .. }
372                | Instruction::AMOADD_D { .. }
373                | Instruction::AMOXOR_D { .. }
374                | Instruction::AMOAND_D { .. }
375                | Instruction::AMOOR_D { .. }
376                | Instruction::AMOMIN_D { .. }
377                | Instruction::AMOMAX_D { .. }
378                | Instruction::AMOMINU_D { .. }
379                | Instruction::AMOMAXU_D { .. }
380                | Instruction::FLW { .. }
381                | Instruction::FLD { .. }
382                | Instruction::FLQ { .. }
383                | Instruction::FLH { .. }
384        )
385    }
386
387    /// Check whether an instruction could store to memory.
388    pub fn store(&self) -> bool {
389        matches!(
390            self,
391            Instruction::SB { .. }
392                | Instruction::SH { .. }
393                | Instruction::SW { .. }
394                | Instruction::SD { .. }
395                | Instruction::SC_W { .. }
396                | Instruction::SC_D { .. }
397                | Instruction::AMOSWAP_W { .. }
398                | Instruction::AMOADD_W { .. }
399                | Instruction::AMOXOR_W { .. }
400                | Instruction::AMOAND_W { .. }
401                | Instruction::AMOOR_W { .. }
402                | Instruction::AMOMIN_W { .. }
403                | Instruction::AMOMAX_W { .. }
404                | Instruction::AMOMINU_W { .. }
405                | Instruction::AMOMAXU_W { .. }
406                | Instruction::AMOSWAP_D { .. }
407                | Instruction::AMOADD_D { .. }
408                | Instruction::AMOXOR_D { .. }
409                | Instruction::AMOAND_D { .. }
410                | Instruction::AMOOR_D { .. }
411                | Instruction::AMOMIN_D { .. }
412                | Instruction::AMOMAX_D { .. }
413                | Instruction::AMOMINU_D { .. }
414                | Instruction::AMOMAXU_D { .. }
415                | Instruction::FSW { .. }
416                | Instruction::FSD { .. }
417                | Instruction::FSQ { .. }
418                | Instruction::FSH { .. }
419        )
420    }
421}
422
423/// Compressed RISC-V instruction.
424///
425/// Compressed instructions can be decompressed using [`Instruction::from`].
426///
427/// Instruction arguments are all in their decoded forms, meaning correctly
428/// scaled and sign extended. Registers are normalised. Their names are as they
429/// appear in specifications (for the most part), and include:
430///
431/// * `rd`, `rs1`, `rs2``: destination and source registers.
432/// * `frd`, `frs2`: destination and source floating point registers.
433/// * `offset`, `imm`, `shamt`: numerical offsets, immediates, and shift amounts.
434/// * `pred`, `succ`: predecessor and successor IORW (input, output, read, write) flags.
435/// * `rm`: floating point rounding mode.
436/// * `rl`, `aq`: atomic release and acquire flags.
437///
438/// Assumed and redundant flags are not repeated, i.e. `rd` is not stored for
439/// `c.swsp` as it's always `sp` (`x2`) and only `rd` is stored for `c.addi` as
440/// `rs1` is always the same.
441#[allow(non_camel_case_types)]
442#[allow(clippy::upper_case_acronyms)]
443#[derive(Clone, Copy, Debug, PartialEq, Eq)]
444pub enum Compressed {
445    // Unknown:
446    UNIMP,
447    // Stack-pointer based loads and stores:
448    C_LWSP { rd: u32, offset: i32 },
449    C_LDSP { rd: u32, offset: i32 },
450    C_LQSP { rd: u32, offset: i32 },
451    C_FLWSP { frd: u32, offset: i32 },
452    C_FLDSP { frd: u32, offset: i32 },
453    C_SWSP { rs2: u32, offset: i32 },
454    C_SDSP { rs2: u32, offset: i32 },
455    C_SQSP { rs2: u32, offset: i32 },
456    C_FSWSP { frs2: u32, offset: i32 },
457    C_FSDSP { frs2: u32, offset: i32 },
458    // Register based loads and stores:
459    C_LW { rd: u32, rs1: u32, offset: i32 },
460    C_LD { rd: u32, rs1: u32, offset: i32 },
461    C_LQ { rd: u32, rs1: u32, offset: i32 },
462    C_FLW { frd: u32, rs1: u32, offset: i32 },
463    C_FLD { frd: u32, rs1: u32, offset: i32 },
464    C_SW { rs1: u32, rs2: u32, offset: i32 },
465    C_SD { rs1: u32, rs2: u32, offset: i32 },
466    C_SQ { rs1: u32, rs2: u32, offset: i32 },
467    C_FSW { rs1: u32, frs2: u32, offset: i32 },
468    C_FSD { rs1: u32, frs2: u32, offset: i32 },
469    // Control transfer instructions:
470    C_J { offset: i32 },
471    C_JAL { offset: i32 },
472    C_JR { rs1: u32 },
473    C_JALR { rs1: u32 },
474    C_BEQZ { rs1: u32, offset: i32 },
475    C_BNEZ { rs1: u32, offset: i32 },
476    // Integer computation instructions:
477    C_LI { rd: u32, imm: i32 },
478    C_LUI { rd: u32, imm: u32 },
479    C_ADDI { rd: u32, imm: i32 },
480    C_ADDIW { rd: u32, imm: i32 },
481    C_ADDI16SP { imm: i32 },
482    C_ADDI4SPN { rd: u32, imm: i32 },
483    C_SLLI { rd: u32, shamt: u32 },
484    C_SRLI { rd: u32, shamt: u32 },
485    C_SRAI { rd: u32, shamt: u32 },
486    C_ANDI { rd: u32, imm: i32 },
487    C_MV { rd: u32, rs2: u32 },
488    C_ADD { rd: u32, rs2: u32 },
489    C_AND { rd: u32, rs2: u32 },
490    C_OR { rd: u32, rs2: u32 },
491    C_XOR { rd: u32, rs2: u32 },
492    C_SUB { rd: u32, rs2: u32 },
493    C_ADDW { rd: u32, rs2: u32 },
494    C_SUBW { rd: u32, rs2: u32 },
495    // Misc and system instructions:
496    C_NOP,
497    C_EBREAK,
498}
499
500impl From<Compressed> for Instruction {
501    fn from(compressed: Compressed) -> Self {
502        match compressed {
503            Compressed::UNIMP => Instruction::UNIMP,
504            Compressed::C_LWSP { rd, offset } => Instruction::LW { rd, rs1: 2, offset },
505            Compressed::C_LDSP { rd, offset } => Instruction::LD { rd, rs1: 2, offset },
506            Compressed::C_LQSP { .. } => unimplemented!("rv128"),
507            Compressed::C_FLWSP { frd, offset } => Instruction::FLW { frd, rs1: 2, offset },
508            Compressed::C_FLDSP { frd, offset } => Instruction::FLD { frd, rs1: 2, offset },
509            Compressed::C_SWSP { rs2, offset } => Instruction::SW { rs1: 2, rs2, offset },
510            Compressed::C_SDSP { rs2, offset } => Instruction::SD { rs1: 2, rs2, offset },
511            Compressed::C_SQSP { .. } => unimplemented!("rv128"),
512            Compressed::C_FSWSP { frs2, offset } => Instruction::FSW { rs1: 2, frs2, offset },
513            Compressed::C_FSDSP { frs2, offset } => Instruction::FSD { rs1: 2, frs2, offset },
514            Compressed::C_LW { rd, rs1, offset } => Instruction::LW { rd, rs1, offset },
515            Compressed::C_LD { rd, rs1, offset } => Instruction::LD { rd, rs1, offset },
516            Compressed::C_LQ { .. } => unimplemented!("rv128"),
517            Compressed::C_FLW { frd, rs1, offset } => Instruction::FLW { frd, rs1, offset },
518            Compressed::C_FLD { frd, rs1, offset } => Instruction::FLD { frd, rs1, offset },
519            Compressed::C_SW { rs1, rs2, offset } => Instruction::SW { rs1, rs2, offset },
520            Compressed::C_SD { rs1, rs2, offset } => Instruction::SD { rs1, rs2, offset },
521            Compressed::C_SQ { .. } => unimplemented!("rv128"),
522            Compressed::C_FSW { rs1, frs2, offset } => Instruction::FSW { rs1, frs2, offset },
523            Compressed::C_FSD { rs1, frs2, offset } => Instruction::FSD { rs1, frs2, offset },
524            Compressed::C_J { offset } => Instruction::JAL { rd: 0, offset },
525            Compressed::C_JAL { offset } => Instruction::JAL { rd: 1, offset },
526            Compressed::C_JR { rs1 } => Instruction::JALR { rd: 0, rs1, offset: 0 },
527            Compressed::C_JALR { rs1 } => Instruction::JALR { rd: 1, rs1, offset: 0 },
528            Compressed::C_BEQZ { rs1, offset } => Instruction::BEQ { rs1, rs2: 0, offset },
529            Compressed::C_BNEZ { rs1, offset } => Instruction::BNE { rs1, rs2: 0, offset },
530            Compressed::C_LI { rd, imm } => Instruction::ADDI { rd, rs1: 0, imm },
531            Compressed::C_LUI { rd, imm } => Instruction::LUI { rd, imm },
532            Compressed::C_ADDI { rd, imm } => Instruction::ADDI { rd, rs1: rd, imm },
533            Compressed::C_ADDIW { rd, imm } => Instruction::ADDIW { rd, rs1: rd, imm },
534            Compressed::C_ADDI16SP { imm } => Instruction::ADDI { rd: 2, rs1: 2, imm },
535            Compressed::C_ADDI4SPN { rd, imm } => Instruction::ADDI { rd, rs1: 2, imm },
536            Compressed::C_SLLI { rd, shamt } => Instruction::SLLI { rd, rs1: rd, shamt },
537            Compressed::C_SRLI { rd, shamt } => Instruction::SRLI { rd, rs1: rd, shamt },
538            Compressed::C_SRAI { rd, shamt } => Instruction::SRAI { rd, rs1: rd, shamt },
539            Compressed::C_ANDI { rd, imm } => Instruction::ANDI { rd, rs1: rd, imm },
540            Compressed::C_MV { rd, rs2 } => Instruction::ADD { rd, rs1: 0, rs2 },
541            Compressed::C_ADD { rd, rs2 } => Instruction::ADD { rd, rs1: rd, rs2 },
542            Compressed::C_AND { rd, rs2 } => Instruction::AND { rd, rs1: rd, rs2 },
543            Compressed::C_OR { rd, rs2 } => Instruction::OR { rd, rs1: rd, rs2 },
544            Compressed::C_XOR { rd, rs2 } => Instruction::XOR { rd, rs1: rd, rs2 },
545            Compressed::C_SUB { rd, rs2 } => Instruction::SUB { rd, rs1: rd, rs2 },
546            Compressed::C_ADDW { rd, rs2 } => Instruction::ADDW { rd, rs1: rd, rs2 },
547            Compressed::C_SUBW { rd, rs2 } => Instruction::SUBW { rd, rs1: rd, rs2 },
548            Compressed::C_NOP => Instruction::ADDI { rd: 0, rs1: 0, imm: 0 },
549            Compressed::C_EBREAK => Instruction::EBREAK,
550        }
551    }
552}
553
554impl Compressed {
555    /// Check whether an instruction could branch or jump.
556    pub fn branch(&self) -> bool {
557        matches!(
558            self,
559            Compressed::C_J { .. }
560                | Compressed::C_JAL { .. }
561                | Compressed::C_JR { .. }
562                | Compressed::C_JALR { .. }
563                | Compressed::C_BEQZ { .. }
564                | Compressed::C_BNEZ { .. }
565        )
566    }
567}
568
569/// Bitfield for input/output/read/write fields, e.g. for `FENCE`.
570#[derive(Clone, Copy, Debug, PartialEq, Eq)]
571pub struct Iorw(pub(crate) u8);