1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright (c) 2018, Joyent, Inc.
14 */
15
16 /*
17 * RISC-V Instruction set decoder
18 */
19
20 #include <libdisasm.h>
21 #include <sys/byteorder.h>
22 #include <sys/debug.h>
23
24 #include "libdisasm_impl.h"
25
26 #include <stdio.h>
27
28 extern size_t strcmp(const char *, const char *);
29
30 /*
31 * Register names based on their ABI name.
32 */
33 static const char *dis_riscv_regs[32] = {
34 "x0", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
35 "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
36 "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
37 "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
38 };
39
40 static const char *dis_riscv_fpregs[32] = {
41 "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
42 "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
43 "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
44 "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11",
45 };
46
47 static const char *dis_riscv_c_regs[8] = {
48 "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5"
49 };
50
51 static const char *dis_riscv_c_fpregs[8] = {
52 "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5"
53 };
54
55 /*
56 * RM names have the leading comma in them because the 7th value represents that
57 * the hardware register decides the rounding mode.
58 */
59 static const char *dis_riscv_rm[8] = {
60 ",rne", ",rtz", ",rdn", ",rup", ",rmm", ",???", ",???", ""
61 };
62
63 typedef struct dis_riscv_csr {
64 uint_t drc_val;
65 const char *drc_name;
66 } dis_riscv_csr_t;
67
68 /*
69 * The current set of CSR names as per Table 2.2-2.5 from RISC-V Privileged
70 * Architectures V1.10. These include all of the ones in the User-Level ISA.
71 * These are ordered per the doc.
72 */
73 static dis_riscv_csr_t dis_riscv_csr_map[] = {
74 /* User Trap */
75 { 0x000, "ustatus" }, { 0x004, "uie" }, { 0x005, "utvec" },
76 /* User Trap Handling */
77 { 0x040, "uscratch" }, { 0x041, "uepc" }, { 0x042, "ucause" },
78 { 0x043, "utval" }, { 0x044, "uip" },
79 /* User Floating-Point CSRs */
80 { 0x001, "fflags" }, { 0x002, "frm" }, { 0x003, "fcsr" },
81 /* User Counters/Timers */
82 { 0xc00, "cycle" }, { 0xc01, "time" }, { 0xc02, "instret" },
83 { 0xc03, "hpmcounter3" }, { 0xc04, "hpmcounter4" },
84 { 0xc05, "hpmcounter5" }, { 0xc06, "hpmcounter6" },
85 { 0xc07, "hpmcounter7" }, { 0xc08, "hpmcounter8" },
86 { 0xc09, "hpmcounter9" }, { 0xc0a, "hpmcounter10" },
87 { 0xc0b, "hpmcounter11" }, { 0xc0c, "hpmcounter12" },
88 { 0xc0d, "hpmcounter13" }, { 0xc0e, "hpmcounter14" },
89 { 0xc0f, "hpmcounter15" }, { 0xc10, "hpmcounter16" },
90 { 0xc11, "hpmcounter17" }, { 0xc12, "hpmcounter18" },
91 { 0xc13, "hpmcounter19" }, { 0xc14, "hpmcounter20" },
92 { 0xc15, "hpmcounter21" }, { 0xc16, "hpmcounter22" },
93 { 0xc17, "hpmcounter23" }, { 0xc18, "hpmcounter24" },
94 { 0xc19, "hpmcounter25" }, { 0xc1a, "hpmcounter26" },
95 { 0xc1b, "hpmcounter27" }, { 0xc1c, "hpmcounter28" },
96 { 0xc1d, "hpmcounter29" }, { 0xc1e, "hpmcounter30" },
97 { 0xc1f, "hpmcounter31" },
98 { 0xc80, "cycleh" }, { 0xc81, "timeh" }, { 0xc82, "instreth" },
99 { 0xc83, "hpmcounter3h" }, { 0xc84, "hpmcounter4h" },
100 { 0xc85, "hpmcounter5h" }, { 0xc86, "hpmcounter6h" },
101 { 0xc87, "hpmcounter7h" }, { 0xc88, "hpmcounter8h" },
102 { 0xc89, "hpmcounter9h" }, { 0xc8a, "hpmcounter10h" },
103 { 0xc8b, "hpmcounter11h" }, { 0xc8c, "hpmcounter12h" },
104 { 0xc8d, "hpmcounter13h" }, { 0xc8e, "hpmcounter14h" },
105 { 0xc8f, "hpmcounter15h" }, { 0xc90, "hpmcounter16h" },
106 { 0xc91, "hpmcounter17h" }, { 0xc92, "hpmcounter18h" },
107 { 0xc93, "hpmcounter19h" }, { 0xc94, "hpmcounter20h" },
108 { 0xc95, "hpmcounter21h" }, { 0xc96, "hpmcounter22h" },
109 { 0xc97, "hpmcounter23h" }, { 0xc98, "hpmcounter24h" },
110 { 0xc99, "hpmcounter25h" }, { 0xc9a, "hpmcounter26h" },
111 { 0xc9b, "hpmcounter27h" }, { 0xc9c, "hpmcounter28h" },
112 { 0xc9d, "hpmcounter29h" }, { 0xc9e, "hpmcounter30h" },
113 { 0xc9f, "hpmcounter31h" },
114 /* Supervisor Trap Status */
115 { 0x100, "sstatus" }, { 0x102, "sedeleg" }, { 0x103, "sideleg" },
116 { 0x104, "sie" }, { 0x105, "stvec" }, { 0x106, "scounteren" },
117 /* Supervisor Trap Handling */
118 { 0x140, "sscratch" }, { 0x141, "sepc" }, { 0x142, "scause" },
119 { 0x143, "stval" }, { 0x144, "sip" },
120 /* Supervisor Protection and Translation */
121 { 0x180, "satp" },
122 /* Machine Information Registers */
123 { 0xf11, "mvendorid" }, { 0xf12, "marchid" },
124 { 0xf13, "mimpid" }, { 0xf14, "mhartid" },
125 /* Machine Trap Setup */
126 { 0x300, "mstatus" }, { 0x301, "misa" }, { 0x302, "medeleg" },
127 { 0x303, "mideleg" }, { 0x304, "mie" }, { 0x305, "mtvec" },
128 { 0x306, "mcounteren" },
129 /* Machine Trap Handling */
130 { 0x340, "mscratch" }, { 0x341, "mepc" }, { 0x342, "mcause" },
131 { 0x343, "mtval" }, { 0x344, "mip" },
132 /* Machine Protection and Translation */
133 { 0x3a0, "pmpcfg0" }, { 0x3a1, "pmpcfg1" },
134 { 0x3a2, "pmpcfg2" }, { 0x3a3, "pmpcfg3" },
135 { 0x3b0, "pmpaddr0" }, { 0x3b1, "pmpaddr1" },
136 { 0x3b2, "pmpaddr2" }, { 0x3b3, "pmpaddr3" },
137 { 0x3b4, "pmpaddr4" }, { 0x3b5, "pmpaddr5" },
138 { 0x3b6, "pmpaddr6" }, { 0x3b7, "pmpaddr7" },
139 { 0x3b8, "pmpaddr8" }, { 0x3b9, "pmpaddr9" },
140 { 0x3ba, "pmpaddr10" }, { 0x3bb, "pmpaddr11" },
141 { 0x3bc, "pmpaddr12" }, { 0x3bd, "pmpaddr13" },
142 { 0x3be, "pmpaddr14" }, { 0x3bf, "pmpaddr15" }
143 };
144
145 typedef enum dis_riscv_csr_alias_type {
146 DIS_RISCV_CSR_READ,
147 DIS_RISCV_CSR_READ_GEN,
148 DIS_RISCV_CSR_SWAP,
149 DIS_RISCV_CSR_SWAP_IMM,
150 DIS_RISCV_CSR_WRITE,
151 DIS_RISCV_CSR_WRITE_GEN,
152 DIS_RISCV_CSR_WRITE_IMM,
153 DIS_RISCV_CSR_WRITE_IMM_GEN
154 } dis_riscv_csr_alias_type_t;
155
156 typedef struct dis_riscv_csr_alias {
157 const char *drca_alias;
158 dis_riscv_csr_alias_type_t drca_type;
159 const char *drca_base;
160 const char *drca_csr;
161 int drca_rd;
162 int drca_rs;
163 } dis_riscv_csr_alias_t;
164
165 /*
166 * Table of aliases. A NULL or -1 indicates a don't care.
167 */
168 static dis_riscv_csr_alias_t dis_riscv_csr_alias[] = {
169 { "rdinstret", DIS_RISCV_CSR_READ, "csrrs", "instret", -1, 0 },
170 { "rdinstreth", DIS_RISCV_CSR_READ, "csrrs", "instreth", -1, 0 },
171 { "rdcycle", DIS_RISCV_CSR_READ, "csrrs", "cycle", -1, 0 },
172 { "rdcycleh", DIS_RISCV_CSR_READ, "csrrs", "cycleh", -1, 0 },
173 { "rdtime", DIS_RISCV_CSR_READ, "csrrs", "time", -1, 0 },
174 { "rdtimeh", DIS_RISCV_CSR_READ, "csrrs", "timeh", -1, 0 },
175 { "frcsr", DIS_RISCV_CSR_READ, "csrrs", "fcsr", -1, 0 },
176 { "fscsr", DIS_RISCV_CSR_WRITE, "csrrw", "fcsr", 0, -1 },
177 { "fscsr", DIS_RISCV_CSR_SWAP, "csrrw", "fcsr", -1, -1 },
178 { "frrm", DIS_RISCV_CSR_READ, "csrrs", "frm", -1, 0 },
179 { "fsrm", DIS_RISCV_CSR_WRITE, "csrrw", "frm", 0, -1 },
180 { "fsrm", DIS_RISCV_CSR_SWAP, "csrrw", "frm", -1, -1 },
181 { "fsrmi", DIS_RISCV_CSR_WRITE_IMM, "csrrwi", "frm", 0, -1 },
182 { "fsrmi", DIS_RISCV_CSR_SWAP_IMM, "csrrwi", "frm", -1, -1 },
183 { "frflags", DIS_RISCV_CSR_READ, "csrrs", "fflags", -1, 0 },
184 { "fsflags", DIS_RISCV_CSR_WRITE, "csrrw", "fflags", 0, -1 },
185 { "fsflags", DIS_RISCV_CSR_SWAP, "csrrw", "fflags", -1, -1 },
186 { "fsflagsi", DIS_RISCV_CSR_WRITE_IMM, "csrrwi", "fflags", 0, -1 },
187 { "fsflagsi", DIS_RISCV_CSR_SWAP_IMM, "csrrwi", "fflags", -1, -1 },
188 /*
189 * These are the generic aliases that aren't based on the CSR. Keep
190 * them last.
191 */
192 { "csrr", DIS_RISCV_CSR_READ_GEN, "csrrs", NULL, -1, 0 },
193 { "csrw", DIS_RISCV_CSR_WRITE_GEN, "csrrw", NULL, 0, -1 },
194 { "csrs", DIS_RISCV_CSR_WRITE_GEN, "csrrs", NULL, 0, -1 },
195 { "csrc", DIS_RISCV_CSR_WRITE_GEN, "csrrc", NULL, 0, -1 },
196 { "csrwi", DIS_RISCV_CSR_WRITE_IMM_GEN, "csrrwi", NULL, 0, -1 },
197 { "csrsi", DIS_RISCV_CSR_WRITE_IMM_GEN, "csrrsi", NULL, 0, -1 },
198 { "csrci", DIS_RISCV_CSR_WRITE_IMM_GEN, "csrrci", NULL, 0, -1 },
199 };
200
201 /*
202 * Take an n-bit value whose sign bit is indicated by the big sign and convert
203 * to a signed type.
204 */
205 static uint_t
206 dis_riscv_sign_extend(uint_t val, uint_t sbit, const char **sign)
207 {
208 ASSERT3U(sign, <=, 31);
209
210 if (val >= 1 << sbit) {
211 *sign = "-";
212 return ((1 << (sbit + 1)) - val);
213 } else {
214 *sign = "";
215 return (val);
216 }
217 }
218
219 /*
220 * Four byte decode tables. This is derived from the RV32/64G Instruction Set
221 * Listings. We describe a table entry based on the opcode and optional opcodes
222 * based on the type of instruction that it is and its encoding format. Most
223 * sets of instructions have one of several uniform encoding types.
224 *
225 * 31 25 24 20 19 15 14 12 11 7 6 0
226 * | funct7 | r2 | rs1 | funct3 | rd | opcode | R-type
227 * | imm[11:0] | rs1 | funct3 | rd | opcode | I-type
228 * | imm[11:5] | r2 | rs1 | funct3 | imm[4:0] | opcode | S-type
229 * | imm[12|10:5] | r2 | rs1 | funct3 | imm[4:1|11] | opcode | B-type
230 * | imm[31:12] | rd | opcode | U-type
231 * | imm[10|10:1|11|19:12] | rd | opcode | J-type
232 */
233 typedef enum dis_riscv_itype {
234 DIS_RISCV_I_R_TYPE,
235 DIS_RISCV_I_I_TYPE,
236 DIS_RISCV_I_S_TYPE,
237 DIS_RISCV_I_B_TYPE,
238 DIS_RISCV_I_U_TYPE,
239 DIS_RISCV_I_J_TYPE,
240 DIS_RISCV_I_R4_TYPE,
241 /*
242 * This is a variant of the standard R type where the first bit of
243 * funct7 is actually used for this shift.
244 */
245 DIS_RISCV_I_SHIFT64_TYPE,
246 /*
247 * This type isn't explicitly defined in the ISA doc; however, it is a
248 * standard format that is for all of the Atomic class instructions.
249 * This is treated like an R-type, except the funct7 is really a funct5.
250 * The load variant is similar; however, rs2 must be zero.
251 */
252 DIS_RISCV_I_RV32A_TYPE,
253 DIS_RISCV_I_RV32A_LOAD_TYPE,
254 /*
255 * This is a custom type we've defined where the first value is the
256 * instruction mask and the second value is the value of the bits in it.
257 * This is used for a few irregular instructions ala FENCE and ECALL.
258 */
259 DIS_RISCV_I_MASK_TYPE,
260 /*
261 * This type is used for FP arguments that use rs2 as an opcode.
262 */
263 DIS_RISCV_I_FP_RS2OP_TYPE,
264 /*
265 * This type uses the opcode and funct7 and uses funct3 as a rounding
266 * mode argument.
267 */
268 DIS_RISCV_I_FP_RM_TYPE,
269 /*
270 * This fp type uses the opcode, funct7, funct3, and rs2 as an op type.
271 */
272 DIS_RISCV_I_FP_R_RS2_TYPE,
273 } dis_riscv_itype_t;
274
275 #define DIS_RISCV_OPCODE(x) ((x) & 0x7f)
276 #define DIS_RISCV_FUNCT3(x) (((x) >> 12) & 0x7)
277 #define DIS_RISCV_FUNCT7(x) (((x) >> 25) & 0x7f)
278 #define DIS_RISCV_RD(x) (((x) >> 7) & 0x1f)
279 #define DIS_RISCV_RS1(x) (((x) >> 15) & 0x1f)
280 #define DIS_RISCV_RS2(x) (((x) >> 20) & 0x1f)
281 #define DIS_RISCV_FP_RS3(x) (((x) >> 27) & 0x1f)
282 #define DIS_RISCV_FUNCT2(x) (((x) >> 25) & 0x03)
283
284 /*
285 * SHIFT funct7 variant.
286 */
287 #define DIS_RISCV_SFUNCT7(x) (((x) >> 26) & 0x3f)
288
289 #define DIS_RISCV_UIMM(x) (((x) >> 12) & 0xfffff)
290
291 #define DIS_RISCV_IIMM(x) (((x) >> 20) & 0xfff)
292
293 #define DIS_RISCV_BIMM_12(x) (((x) >> 19) & 0x1000)
294 #define DIS_RISCV_BIMM_11(x) (((x) & 0x80) << 4)
295 #define DIS_RISCV_BIMM_10_5(x) (((x) >> 20) & 0x7e0)
296 #define DIS_RISCV_BIMM_4_1(x) (((x) >> 7) & 0x1e)
297
298 #define DIS_RISCV_SIMM_UP(x) ((((x) >> 25) & 0x7f) << 5)
299 #define DIS_RISCV_SIMM_LOW(x) (((x) >> 7) & 0x1f)
300
301 #define DIS_RISCV_JIMM_20(x) (((x) & 0x80000000) >> 11)
302 #define DIS_RISCV_JIMM_19_12(x) ((x) & 0xff000)
303 #define DIS_RISCV_JIMM_11(x) (((x) & 100000) >> 9)
304 #define DIS_RISCV_JIMM_10_1(x) (((x) & 0x7fe00000) >> 20)
305
306 #define DIS_RISCV_RVA_FUNCT5(x) (((x) >> 27) & 0x1f)
307 #define DIS_RISCV_RVA_AQ(x) (((x) >> 26) & 0x1)
308 #define DIS_RISCV_RVA_RL(x) (((x) >> 25) & 0x1)
309
310 struct dis_riscv_instr;
311 typedef void (*dis_riscv_func_t)(dis_handle_t *, uint32_t,
312 struct dis_riscv_instr *, char *, size_t);
313
314 typedef struct dis_riscv_instr {
315 const char *drv_name;
316 dis_riscv_itype_t drv_type;
317 dis_riscv_func_t drv_print;
318 uint_t drv_opcode;
319 uint_t drv_funct3;
320 uint_t drv_funct7;
321 uint_t drv_funct2;
322 } dis_riscv_instr_t;
323
324 static void
325 dis_riscv_rtype_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
326 char *buf, size_t buflen)
327 {
328 (void) dis_snprintf(buf, buflen, "%s %s,%s,%s", table->drv_name,
329 dis_riscv_regs[DIS_RISCV_RD(instr)],
330 dis_riscv_regs[DIS_RISCV_RS1(instr)],
331 dis_riscv_regs[DIS_RISCV_RS2(instr)]);
332 }
333
334 static void
335 dis_riscv_itype_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
336 char *buf, size_t buflen)
337 {
338 const char *s;
339 uint_t imm = dis_riscv_sign_extend(DIS_RISCV_IIMM(instr), 11, &s);
340
341 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
342 (void) dis_snprintf(buf, buflen, "%s %s,%s,%s0%o",
343 table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
344 dis_riscv_regs[DIS_RISCV_RS1(instr)], s, imm);
345 } else {
346 (void) dis_snprintf(buf, buflen, "%s %s,%s,%s0x%x",
347 table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
348 dis_riscv_regs[DIS_RISCV_RS1(instr)], s, imm);
349 }
350 }
351
352 static void
353 dis_riscv_btype_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
354 char *buf, size_t buflen)
355 {
356 const char *s;
357 uint_t bimm = DIS_RISCV_BIMM_12(instr) | DIS_RISCV_BIMM_11(instr) |
358 DIS_RISCV_BIMM_10_5(instr) | DIS_RISCV_BIMM_4_1(instr);
359 uint_t imm = dis_riscv_sign_extend(bimm, 12, &s);
360
361 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
362 (void) dis_snprintf(buf, buflen, "%s %s,%s,%s0%o",
363 table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
364 dis_riscv_regs[DIS_RISCV_RS1(instr)], s, imm);
365 } else {
366 (void) dis_snprintf(buf, buflen, "%s %s,%s,%s0x%x",
367 table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
368 dis_riscv_regs[DIS_RISCV_RS1(instr)], s, imm);
369 }
370 }
371
372 static void
373 dis_riscv_load(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
374 char *buf, size_t buflen)
375 {
376 const char *s;
377 uint_t imm = dis_riscv_sign_extend(DIS_RISCV_IIMM(instr), 11, &s);
378
379 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
380 (void) dis_snprintf(buf, buflen, "%s %s,%s0%o(%s)",
381 table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
382 s, imm, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
383 } else {
384 (void) dis_snprintf(buf, buflen, "%s %s,%s0x%x(%s)",
385 table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
386 s, imm, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
387 }
388 }
389
390 static void
391 dis_riscv_stype_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
392 char *buf, size_t buflen)
393 {
394 const char *s;
395 uint_t simm = DIS_RISCV_SIMM_UP(instr) | DIS_RISCV_SIMM_LOW(instr);
396 uint_t val = dis_riscv_sign_extend(simm, 11, &s);
397
398 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
399 (void) dis_snprintf(buf, buflen, "%s %s,%s0%o(%s)",
400 table->drv_name, dis_riscv_regs[DIS_RISCV_RS2(instr)],
401 s, val, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
402 } else {
403 (void) dis_snprintf(buf, buflen, "%s %s,%s0x%x(%s)",
404 table->drv_name, dis_riscv_regs[DIS_RISCV_RS2(instr)],
405 s, val, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
406 }
407 }
408
409 static void
410 dis_riscv_utype_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
411 char *buf, size_t buflen)
412 {
413 (void) dis_snprintf(buf, buflen, "%s %s,0x%x", table->drv_name,
414 dis_riscv_regs[DIS_RISCV_RD(instr)], DIS_RISCV_UIMM(instr));
415 }
416
417 static void
418 dis_riscv_jtype_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
419 char *buf, size_t buflen)
420 {
421 const char *s;
422 uint_t jimm = DIS_RISCV_JIMM_20(instr) | DIS_RISCV_JIMM_19_12(instr) |
423 DIS_RISCV_JIMM_11(instr) | DIS_RISCV_JIMM_10_1(instr);
424 uint_t imm = dis_riscv_sign_extend(jimm, 20, &s);
425
426 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
427 (void) dis_snprintf(buf, buflen, "%s %s,%s0%o",
428 table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
429 s, imm);
430 } else {
431 (void) dis_snprintf(buf, buflen, "%s %s,%s0x%x",
432 table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
433 s, imm);
434 }
435 }
436
437 /*
438 * The shift instructions are a variant on the R-type instructions where RS2 is
439 * an immediate to perform the shift by as opposed to a register.
440 */
441 static void
442 dis_riscv_shift_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
443 char *buf, size_t buflen)
444 {
445 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
446 (void) dis_snprintf(buf, buflen, "%s %s,%s,0%o",
447 table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
448 dis_riscv_regs[DIS_RISCV_RS1(instr)], DIS_RISCV_RS2(instr));
449 } else {
450 (void) dis_snprintf(buf, buflen, "%s %s,%s,0x%x",
451 table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
452 dis_riscv_regs[DIS_RISCV_RS1(instr)], DIS_RISCV_RS2(instr));
453 }
454 }
455
456 /*
457 * The 64-bit version of shift instructions steals an extra bit from funct7 to
458 * construct the shift amount.
459 */
460 static void
461 dis_riscv_shift_64(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
462 char *buf, size_t buflen)
463 {
464 uint_t shift = DIS_RISCV_RS2(instr) | ((instr & (1UL << 25)) >> 20);
465 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
466 (void) dis_snprintf(buf, buflen, "%s %s,%s,0%o",
467 table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
468 dis_riscv_regs[DIS_RISCV_RS1(instr)], shift);
469 } else {
470 (void) dis_snprintf(buf, buflen, "%s %s,%s,0x%x",
471 table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
472 dis_riscv_regs[DIS_RISCV_RS1(instr)], shift);
473 }
474 }
475
476 static void
477 dis_riscv_csr(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
478 char *buf, size_t buflen)
479 {
480 uint_t rd, csr, rs, i;
481 const char *csrstr = NULL;
482 char csrval[32];
483 dis_riscv_csr_alias_t *alias = NULL;
484
485 rd = DIS_RISCV_RD(instr);
486 rs = DIS_RISCV_RS1(instr);
487 csr = DIS_RISCV_IIMM(instr);
488
489 for (i = 0; i < ARRAY_SIZE(dis_riscv_csr_map); i++) {
490 if (csr == dis_riscv_csr_map[i].drc_val) {
491 csrstr = dis_riscv_csr_map[i].drc_name;
492 break;
493 }
494 }
495
496 if (csrstr == NULL) {
497 (void) dis_snprintf(csrval, sizeof (csrval), "0x%x", csr);
498 csrstr = csrval;
499 }
500
501 for (i = 0; i < ARRAY_SIZE(dis_riscv_csr_alias); i++) {
502 dis_riscv_csr_alias_t *a = &dis_riscv_csr_alias[i];
503 if (strcmp(a->drca_base, table->drv_name) != 0)
504 continue;
505 if (a->drca_csr != NULL && strcmp(a->drca_csr, csrstr) != 0)
506 continue;
507 if (a->drca_rd != -1 && a->drca_rd != rd)
508 continue;
509 if (a->drca_rs != -1 && a->drca_rs != rs)
510 continue;
511 alias = a;
512 break;
513 }
514
515 if (alias == NULL) {
516 (void) dis_snprintf(buf, buflen, "%s %s,%s,%s", table->drv_name,
517 dis_riscv_regs[rd], csrstr, dis_riscv_regs[rs]);
518 return;
519 }
520
521 switch (alias->drca_type) {
522 case DIS_RISCV_CSR_READ:
523 (void) dis_snprintf(buf, buflen, "%s %s", alias->drca_alias,
524 dis_riscv_regs[rd]);
525 break;
526 case DIS_RISCV_CSR_READ_GEN:
527 (void) dis_snprintf(buf, buflen, "%s %s,%s", alias->drca_alias,
528 dis_riscv_regs[rd], csrstr);
529 break;
530 case DIS_RISCV_CSR_SWAP:
531 (void) dis_snprintf(buf, buflen, "%s %s,%s", alias->drca_alias,
532 dis_riscv_regs[rd], dis_riscv_regs[rs]);
533 break;
534 case DIS_RISCV_CSR_WRITE:
535 (void) dis_snprintf(buf, buflen, "%s %s", alias->drca_alias,
536 dis_riscv_regs[rs]);
537 break;
538 case DIS_RISCV_CSR_WRITE_GEN:
539 (void) dis_snprintf(buf, buflen, "%s %s,%s", alias->drca_alias,
540 csrstr, dis_riscv_regs[rs]);
541 break;
542 default:
543 (void) dis_snprintf(buf, buflen, "<unknown>");
544 break;
545 }
546 }
547
548 static void
549 dis_riscv_csri(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
550 char *buf, size_t buflen)
551 {
552 uint_t rd, csr, imm, i;
553 const char *csrstr = NULL;
554 char csrval[32];
555 dis_riscv_csr_alias_t *alias = NULL;
556
557 rd = DIS_RISCV_RD(instr);
558 imm = DIS_RISCV_RS1(instr);
559 csr = DIS_RISCV_IIMM(instr);
560
561 for (i = 0; i < ARRAY_SIZE(dis_riscv_csr_map); i++) {
562 if (csr == dis_riscv_csr_map[i].drc_val) {
563 csrstr = dis_riscv_csr_map[i].drc_name;
564 break;
565 }
566 }
567
568 if (csrstr == NULL) {
569 (void) dis_snprintf(csrval, sizeof (csrval), "0x%x", csr);
570 csrstr = csrval;
571 }
572
573 for (i = 0; i < ARRAY_SIZE(dis_riscv_csr_alias); i++) {
574 dis_riscv_csr_alias_t *a = &dis_riscv_csr_alias[i];
575 if (strcmp(a->drca_base, table->drv_name) != 0)
576 continue;
577 if (a->drca_csr != NULL && strcmp(a->drca_csr, csrstr) != 0)
578 continue;
579 if (a->drca_rd != -1 && a->drca_rd != rd)
580 continue;
581 if (a->drca_rs != -1)
582 continue;
583 alias = a;
584 break;
585 }
586
587 if (alias == NULL) {
588 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
589 (void) dis_snprintf(buf, buflen, "%s %s,%s,0%o",
590 table->drv_name, dis_riscv_regs[rd], csrstr, imm);
591 } else {
592 (void) dis_snprintf(buf, buflen, "%s %s,%s,0x%x",
593 table->drv_name, dis_riscv_regs[rd], csrstr, imm);
594 }
595 return;
596 }
597
598 switch (alias->drca_type) {
599 case DIS_RISCV_CSR_SWAP_IMM:
600 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
601 (void) dis_snprintf(buf, buflen, "%s %s,0%o",
602 alias->drca_alias, dis_riscv_regs[rd], imm);
603 } else {
604 (void) dis_snprintf(buf, buflen, "%s %s,0x%x",
605 alias->drca_alias, dis_riscv_regs[rd], imm);
606 }
607 break;
608 case DIS_RISCV_CSR_WRITE_IMM:
609 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
610 (void) dis_snprintf(buf, buflen, "%s 0%o",
611 alias->drca_alias, imm);
612 } else {
613 (void) dis_snprintf(buf, buflen, "%s 0x%x",
614 alias->drca_alias, imm);
615 }
616 break;
617 case DIS_RISCV_CSR_WRITE_IMM_GEN:
618 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
619 (void) dis_snprintf(buf, buflen, "%s %s,0%o",
620 alias->drca_alias, csrstr, imm);
621 } else {
622 (void) dis_snprintf(buf, buflen, "%s %s,0x%x",
623 alias->drca_alias, csrstr, imm);
624 }
625 break;
626 default:
627 (void) dis_snprintf(buf, buflen, "<unknown>");
628 break;
629 }
630 }
631
632 #define DIS_RISCV_FENCE_PRED(x) (((x) >> 24) & 0xf)
633 #define DIS_RISCV_FENCE_SUCC(x) (((x) >> 20) & 0xf)
634 #define DIS_RISCV_FENCE_I 0x8
635 #define DIS_RISCV_FENCE_O 0x4
636 #define DIS_RISCV_FENCE_R 0x2
637 #define DIS_RISCV_FENCE_W 0x1
638 #define DIS_RISCV_FENCE_IORW 0xf
639
640 static void
641 dis_riscv_fence(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
642 char *buf, size_t buflen)
643 {
644 uint_t pred, succ;
645
646 pred = DIS_RISCV_FENCE_PRED(instr);
647 succ = DIS_RISCV_FENCE_SUCC(instr);
648
649 /*
650 * If both halves are iorw that is aliased to just an empty fence
651 * instruction per Chapter 20 - RISC-V Assembly Programmer's Handbook in
652 * the RISC-V user spec.
653 */
654 if (pred == DIS_RISCV_FENCE_IORW && succ == DIS_RISCV_FENCE_IORW) {
655 (void) dis_snprintf(buf, buflen, "%s", table->drv_name);
656 return;
657 }
658
659 (void) dis_snprintf(buf, buflen, "%s %s%s%s%s, %s%s%s%s",
660 table->drv_name,
661 pred & DIS_RISCV_FENCE_I ? "i" : "",
662 pred & DIS_RISCV_FENCE_O ? "o" : "",
663 pred & DIS_RISCV_FENCE_R ? "r" : "",
664 pred & DIS_RISCV_FENCE_W ? "w" : "",
665 succ & DIS_RISCV_FENCE_I ? "i" : "",
666 succ & DIS_RISCV_FENCE_O ? "o" : "",
667 succ & DIS_RISCV_FENCE_R ? "r" : "",
668 succ & DIS_RISCV_FENCE_W ? "w" : "");
669 }
670
671 static void
672 dis_riscv_name(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
673 char *buf, size_t buflen)
674 {
675 (void) dis_snprintf(buf, buflen, "%s", table->drv_name);
676 }
677
678 static void
679 dis_riscv_rs1_rs2(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
680 char *buf, size_t buflen)
681 {
682 (void) dis_snprintf(buf, buflen, "%s %s,%s", table->drv_name,
683 dis_riscv_regs[DIS_RISCV_RS1(instr)],
684 dis_riscv_regs[DIS_RISCV_RS2(instr)]);
685 }
686
687 static void
688 dis_riscv_rv32a_load(dis_handle_t *dhp, uint32_t instr,
689 dis_riscv_instr_t *table, char *buf, size_t buflen)
690 {
691 const char *suffix = "";
692
693 if (DIS_RISCV_RVA_AQ(instr) && DIS_RISCV_RVA_RL(instr)) {
694 suffix = ".aqrl";
695 } else if (DIS_RISCV_RVA_AQ(instr)) {
696 suffix = ".aq";
697 } else if (DIS_RISCV_RVA_RL(instr)) {
698 suffix = ".rl";
699 }
700
701 (void) dis_snprintf(buf, buflen, "%s%s %s,(%s)", table->drv_name,
702 suffix, dis_riscv_regs[DIS_RISCV_RD(instr)],
703 dis_riscv_regs[DIS_RISCV_RS1(instr)]);
704 }
705
706 static void
707 dis_riscv_rv32a(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
708 char *buf, size_t buflen)
709 {
710 const char *suffix = "";
711
712 if (DIS_RISCV_RVA_AQ(instr) && DIS_RISCV_RVA_RL(instr)) {
713 suffix = ".aqrl";
714 } else if (DIS_RISCV_RVA_AQ(instr)) {
715 suffix = ".aq";
716 } else if (DIS_RISCV_RVA_RL(instr)) {
717 suffix = ".rl";
718 }
719
720 (void) dis_snprintf(buf, buflen, "%s%s %s,%s,(%s)", table->drv_name,
721 suffix, dis_riscv_regs[DIS_RISCV_RD(instr)],
722 dis_riscv_regs[DIS_RISCV_RS2(instr)],
723 dis_riscv_regs[DIS_RISCV_RS1(instr)]);
724 }
725
726 static void
727 dis_riscv_fp_load(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
728 char *buf, size_t buflen)
729 {
730 const char *s;
731 uint_t imm = dis_riscv_sign_extend(DIS_RISCV_IIMM(instr), 11, &s);
732
733 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
734 (void) dis_snprintf(buf, buflen, "%s %s,%s0%o(%s)",
735 table->drv_name, dis_riscv_fpregs[DIS_RISCV_RD(instr)],
736 s, imm, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
737 } else {
738 (void) dis_snprintf(buf, buflen, "%s %s,%s0x%x(%s)",
739 table->drv_name, dis_riscv_fpregs[DIS_RISCV_RD(instr)],
740 s, imm, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
741 }
742 }
743
744 static void
745 dis_riscv_fp_store(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
746 char *buf, size_t buflen)
747 {
748 const char *s;
749 uint_t simm = DIS_RISCV_SIMM_UP(instr) | DIS_RISCV_SIMM_LOW(instr);
750 uint_t val = dis_riscv_sign_extend(simm, 11, &s);
751
752 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
753 (void) dis_snprintf(buf, buflen, "%s %s,%s0%o(%s)",
754 table->drv_name, dis_riscv_fpregs[DIS_RISCV_RS2(instr)],
755 s, val, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
756 } else {
757 (void) dis_snprintf(buf, buflen, "%s %s,%s0x%x(%s)",
758 table->drv_name, dis_riscv_fpregs[DIS_RISCV_RS2(instr)],
759 s, val, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
760 }
761 }
762
763 static void
764 dis_riscv_fp_r(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
765 char *buf, size_t buflen)
766 {
767 (void) dis_snprintf(buf, buflen, "%s %s,%s,%s", table->drv_name,
768 dis_riscv_fpregs[DIS_RISCV_RD(instr)],
769 dis_riscv_fpregs[DIS_RISCV_RS1(instr)],
770 dis_riscv_fpregs[DIS_RISCV_RS2(instr)]);
771 }
772
773 /*
774 * Variant of fp_r type that goes to integer destination registers.
775 */
776 static void
777 dis_riscv_fp_r_fpi(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
778 char *buf, size_t buflen)
779 {
780 (void) dis_snprintf(buf, buflen, "%s %s,%s,%s", table->drv_name,
781 dis_riscv_regs[DIS_RISCV_RD(instr)],
782 dis_riscv_fpregs[DIS_RISCV_RS1(instr)],
783 dis_riscv_fpregs[DIS_RISCV_RS2(instr)]);
784 }
785
786
787 static void
788 dis_riscv_fp_r4(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
789 char *buf, size_t buflen)
790 {
791 (void) dis_snprintf(buf, buflen, "%s %s,%s,%s,%s%s", table->drv_name,
792 dis_riscv_fpregs[DIS_RISCV_RD(instr)],
793 dis_riscv_fpregs[DIS_RISCV_RS1(instr)],
794 dis_riscv_fpregs[DIS_RISCV_RS2(instr)],
795 dis_riscv_fpregs[DIS_RISCV_FP_RS3(instr)],
796 dis_riscv_rm[DIS_RISCV_FUNCT3(instr)]);
797 }
798
799 static void
800 dis_riscv_fp_rs2_fp(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
801 char *buf, size_t buflen)
802 {
803 (void) dis_snprintf(buf, buflen, "%s %s,%s%s", table->drv_name,
804 dis_riscv_fpregs[DIS_RISCV_RD(instr)],
805 dis_riscv_fpregs[DIS_RISCV_RS1(instr)],
806 dis_riscv_rm[DIS_RISCV_FUNCT3(instr)]);
807 }
808
809 static void
810 dis_riscv_fp_rs2_fp_nr(dis_handle_t *dhp, uint32_t instr,
811 dis_riscv_instr_t *table, char *buf, size_t buflen)
812 {
813 (void) dis_snprintf(buf, buflen, "%s %s,%s", table->drv_name,
814 dis_riscv_fpregs[DIS_RISCV_RD(instr)],
815 dis_riscv_fpregs[DIS_RISCV_RS1(instr)]);
816 }
817
818
819 static void
820 dis_riscv_fp_rs2_fpi(dis_handle_t *dhp, uint32_t instr,
821 dis_riscv_instr_t *table, char *buf, size_t buflen)
822 {
823 (void) dis_snprintf(buf, buflen, "%s %s,%s%s", table->drv_name,
824 dis_riscv_regs[DIS_RISCV_RD(instr)],
825 dis_riscv_fpregs[DIS_RISCV_RS1(instr)],
826 dis_riscv_rm[DIS_RISCV_FUNCT3(instr)]);
827 }
828
829 static void
830 dis_riscv_fp_rs2_ifp(dis_handle_t *dhp, uint32_t instr,
831 dis_riscv_instr_t *table, char *buf, size_t buflen)
832 {
833 (void) dis_snprintf(buf, buflen, "%s %s,%s%s", table->drv_name,
834 dis_riscv_fpregs[DIS_RISCV_RD(instr)],
835 dis_riscv_regs[DIS_RISCV_RS1(instr)],
836 dis_riscv_rm[DIS_RISCV_FUNCT3(instr)]);
837 }
838
839 static void
840 dis_riscv_fp_rs2_fpi_nr(dis_handle_t *dhp, uint32_t instr,
841 dis_riscv_instr_t *table, char *buf, size_t buflen)
842 {
843 (void) dis_snprintf(buf, buflen, "%s %s,%s", table->drv_name,
844 dis_riscv_regs[DIS_RISCV_RD(instr)],
845 dis_riscv_fpregs[DIS_RISCV_RS1(instr)]);
846 }
847
848 static void
849 dis_riscv_fp_rs2_ifp_nr(dis_handle_t *dhp, uint32_t instr,
850 dis_riscv_instr_t *table, char *buf, size_t buflen)
851 {
852 (void) dis_snprintf(buf, buflen, "%s %s,%s", table->drv_name,
853 dis_riscv_fpregs[DIS_RISCV_RD(instr)],
854 dis_riscv_regs[DIS_RISCV_RS1(instr)]);
855 }
856
857
858 static void
859 dis_riscv_fp_rm(dis_handle_t *dhp, uint32_t instr,
860 dis_riscv_instr_t *table, char *buf, size_t buflen)
861 {
862 (void) dis_snprintf(buf, buflen, "%s %s,%s,%s%s", table->drv_name,
863 dis_riscv_fpregs[DIS_RISCV_RD(instr)],
864 dis_riscv_fpregs[DIS_RISCV_RS1(instr)],
865 dis_riscv_fpregs[DIS_RISCV_RS2(instr)],
866 dis_riscv_rm[DIS_RISCV_FUNCT3(instr)]);
867 }
868
869 #define DIS_RISCV_R32(str, op, f3, f7) \
870 { str, DIS_RISCV_I_R_TYPE, dis_riscv_rtype_32, op, f3, f7 }
871 #define DIS_RISCV_I32(str, op, f3) \
872 { str, DIS_RISCV_I_I_TYPE, dis_riscv_itype_32, op, f3 }
873 #define DIS_RISCV_S32(str, op, f3) \
874 { str, DIS_RISCV_I_S_TYPE, dis_riscv_stype_32, op, f3 }
875 #define DIS_RISCV_B32(str, op, f3) \
876 { str, DIS_RISCV_I_B_TYPE, dis_riscv_btype_32, op, f3 }
877 #define DIS_RISCV_U32(str, op) \
878 { str, DIS_RISCV_I_U_TYPE, dis_riscv_utype_32, op }
879 #define DIS_RISCV_J32(str, op) \
880 { str, DIS_RISCV_I_J_TYPE, dis_riscv_jtype_32, op }
881
882 /*
883 * These are non-standard types that we've defined because they require
884 * different handling.
885 */
886 #define DIS_RISCV_SHIFT32(str, op, f3, f7) \
887 { str, DIS_RISCV_I_R_TYPE, dis_riscv_shift_32, op, f3, f7 }
888 #define DIS_RISCV_SHIFT64(str, op, f3, f7) \
889 { str, DIS_RISCV_I_SHIFT64_TYPE, dis_riscv_shift_64, op, f3, f7 }
890 #define DIS_RISCV_CSR(str, op, f3) \
891 { str, DIS_RISCV_I_I_TYPE, dis_riscv_csr, op, f3 }
892 #define DIS_RISCV_CSRI(str, op, f3) \
893 { str, DIS_RISCV_I_I_TYPE, dis_riscv_csri, op, f3 }
894 #define DIS_RISCV_LOAD(str, op, f3) \
895 { str, DIS_RISCV_I_I_TYPE, dis_riscv_load, op, f3 }
896
897 #define DIS_RISCV_MASK(str, mask, val, func) \
898 { str, DIS_RISCV_I_MASK_TYPE, func, mask, val }
899
900
901 /*
902 * Atomic-extension specific entries
903 */
904 #define DIS_RISCV_A32(str, op, f3, f5) \
905 { str, DIS_RISCV_I_RV32A_TYPE, dis_riscv_rv32a, op, f3, f5 }
906 #define DIS_RISCV_A32LOAD(str, op, f3, f5, f2) \
907 { str, DIS_RISCV_I_RV32A_LOAD_TYPE, dis_riscv_rv32a_load, op, f3, \
908 f5, f2 }
909
910 /*
911 * Floating-point specific entries
912 */
913 #define DIS_RISCV_FP_LOAD(str, op, f3) \
914 { str, DIS_RISCV_I_I_TYPE, dis_riscv_fp_load, op, f3 }
915 #define DIS_RISCV_FP_STORE(str, op, f3) \
916 { str, DIS_RISCV_I_S_TYPE, dis_riscv_fp_store, op, f3 }
917 #define DIS_RISCV_FP_R(str, op, f3, f7) \
918 { str, DIS_RISCV_I_R_TYPE, dis_riscv_fp_r, op, f3, f7 }
919 #define DIS_RISCV_FP_R4(str, op, f2) \
920 { str, DIS_RISCV_I_R4_TYPE, dis_riscv_fp_r4, op, 0, 0, f2 }
921 #define DIS_RISCV_FP_RS2_FP(str, op, rs2, f7) \
922 { str, DIS_RISCV_I_FP_RS2OP_TYPE, dis_riscv_fp_rs2_fp, op, rs2, f7 }
923 #define DIS_RISCV_FP_RS2_FP_NR(str, op, rs2, f7) \
924 { str, DIS_RISCV_I_FP_RS2OP_TYPE, dis_riscv_fp_rs2_fp_nr, op, rs2, f7 }
925 #define DIS_RISCV_FP_RS2_FPI(str, op, rs2, f7) \
926 { str, DIS_RISCV_I_FP_RS2OP_TYPE, dis_riscv_fp_rs2_fpi, op, rs2, f7 }
927 #define DIS_RISCV_FP_RS2_IFP(str, op, rs2, f7) \
928 { str, DIS_RISCV_I_FP_RS2OP_TYPE, dis_riscv_fp_rs2_ifp, op, rs2, f7 }
929 #define DIS_RISCV_FP_RS2_IFP_NR(str, op, rs2, f7) \
930 { str, DIS_RISCV_I_FP_RS2OP_TYPE, dis_riscv_fp_rs2_ifp_nr, op, rs2, f7 }
931 #define DIS_RISCV_FP_RM(str, op, f7) \
932 { str, DIS_RISCV_I_FP_RM_TYPE, dis_riscv_fp_rm, op, 0, f7 }
933 #define DIS_RISCV_FP_R_RS2_FPI(str, op, f3, rs2, f7) \
934 { str, DIS_RISCV_I_FP_R_RS2_TYPE, dis_riscv_fp_rs2_fpi, op, f3, f7, \
935 rs2 }
936 #define DIS_RISCV_FP_R_RS2_IFP(str, op, f3, rs2, f7) \
937 { str, DIS_RISCV_I_FP_R_RS2_TYPE, dis_riscv_fp_rs2_ifp, op, f3, f7, \
938 rs2 }
939 #define DIS_RISCV_FP_R_RS2_FPI_NR(str, op, f3, rs2, f7) \
940 { str, DIS_RISCV_I_FP_R_RS2_TYPE, dis_riscv_fp_rs2_fpi_nr, op, f3, \
941 f7, rs2 }
942 #define DIS_RISCV_FP_R_RS2_IFP_NR(str, op, f3, rs2, f7) \
943 { str, DIS_RISCV_I_FP_R_RS2_TYPE, dis_riscv_fp_rs2_ifp_nr, op, f3, \
944 f7, rs2 }
945 #define DIS_RISCV_FP_RI(str, op, f3, f7) \
946 { str, DIS_RISCV_I_R_TYPE, dis_riscv_fp_r_fpi, op, f3, f7 }
947
948 /*
949 * This table is ordered such that it follows the ordering in the RISC-V ISA
950 * Manual.
951 */
952 static dis_riscv_instr_t dis_riscv_4byte[] = {
953 /*
954 * RV32I
955 */
956 DIS_RISCV_U32("lui", 0x37),
957 DIS_RISCV_U32("auipc", 0x17),
958 DIS_RISCV_J32("jal", 0x6f),
959 /* ret is a special case of jalr */
960 DIS_RISCV_MASK("ret", 0xffffffff, 0x00008067, dis_riscv_name),
961 DIS_RISCV_I32("jalr", 0x67, 0x0),
962 DIS_RISCV_B32("beq", 0x63, 0x0),
963 DIS_RISCV_B32("bne", 0x63, 0x1),
964 DIS_RISCV_B32("blt", 0x63, 0x4),
965 DIS_RISCV_B32("bge", 0x63, 0x5),
966 DIS_RISCV_B32("bltu", 0x63, 0x6),
967 DIS_RISCV_B32("bgeu", 0x63, 0x7),
968 DIS_RISCV_LOAD("lb", 0x03, 0x0),
969 DIS_RISCV_LOAD("lh", 0x03, 0x1),
970 DIS_RISCV_LOAD("lw", 0x03, 0x2),
971 DIS_RISCV_LOAD("lbu", 0x03, 0x4),
972 DIS_RISCV_LOAD("lhu", 0x03, 0x5),
973 DIS_RISCV_S32("sb", 0x23, 0x0),
974 DIS_RISCV_S32("sh", 0x23, 0x1),
975 DIS_RISCV_S32("sw", 0x23, 0x2),
976 /* nop is addi x0, x0, 0 */
977 DIS_RISCV_MASK("nop", 0xffffffff, 0x00000013, dis_riscv_name),
978 DIS_RISCV_I32("addi", 0x13, 0x0),
979 DIS_RISCV_I32("slti", 0x13, 0x2),
980 DIS_RISCV_I32("sltiu", 0x13, 0x3),
981 DIS_RISCV_I32("xori", 0x13, 0x4),
982 DIS_RISCV_I32("ori", 0x13, 0x6),
983 DIS_RISCV_I32("andi", 0x13, 0x7),
984 DIS_RISCV_SHIFT32("slli", 0x13, 0x1, 0x00),
985 DIS_RISCV_SHIFT32("srli", 0x13, 0x5, 0x00),
986 DIS_RISCV_SHIFT32("srai", 0x13, 0x5, 0x20),
987 DIS_RISCV_R32("add", 0x33, 0x0, 0x00),
988 DIS_RISCV_R32("sub", 0x33, 0x0, 0x20),
989 DIS_RISCV_R32("sll", 0x33, 0x1, 0x00),
990 DIS_RISCV_R32("slt", 0x33, 0x2, 0x00),
991 DIS_RISCV_R32("sltu", 0x33, 0x3, 0x00),
992 DIS_RISCV_R32("xor", 0x33, 0x4, 0x00),
993 DIS_RISCV_R32("srl", 0x33, 0x5, 0x00),
994 DIS_RISCV_R32("sra", 0x33, 0x5, 0x20),
995 DIS_RISCV_R32("or", 0x33, 0x6, 0x00),
996 DIS_RISCV_R32("and", 0x33, 0x7, 0x00),
997 DIS_RISCV_MASK("fence", 0xf00fffff, 0xf, dis_riscv_fence),
998 DIS_RISCV_MASK("fence.i", 0xfffff00f, 0x100f, dis_riscv_name),
999 DIS_RISCV_MASK("ecall", 0xffffffff, 0x73, dis_riscv_name),
1000 DIS_RISCV_MASK("ebreak", 0xffffffff, 0x100073, dis_riscv_name),
1001 DIS_RISCV_CSR("csrrw", 0x73, 0x1),
1002 DIS_RISCV_CSR("csrrs", 0x73, 0x2),
1003 DIS_RISCV_CSR("csrrc", 0x73, 0x3),
1004 DIS_RISCV_CSRI("csrrwi", 0x73, 0x5),
1005 DIS_RISCV_CSRI("csrrsi", 0x73, 0x6),
1006 DIS_RISCV_CSRI("csrrci", 0x73, 0x7),
1007 /*
1008 * RV64I
1009 */
1010 DIS_RISCV_LOAD("lwu", 0x03, 0x6),
1011 DIS_RISCV_LOAD("ld", 0x03, 0x3),
1012 DIS_RISCV_S32("sd", 0x23, 0x3),
1013 DIS_RISCV_SHIFT64("slli", 0x13, 0x1, 0x0),
1014 DIS_RISCV_SHIFT64("srli", 0x13, 0x5, 0x0),
1015 DIS_RISCV_SHIFT64("srai", 0x13, 0x5, 0x10),
1016 DIS_RISCV_I32("addiw", 0x1b, 0x0),
1017 DIS_RISCV_SHIFT32("slliw", 0x1b, 0x1, 0x0),
1018 DIS_RISCV_SHIFT32("srliw", 0x1b, 0x5, 0x0),
1019 DIS_RISCV_SHIFT32("sraiw", 0x1b, 0x5, 0x20),
1020 DIS_RISCV_R32("addw", 0x3b, 0x0, 0x00),
1021 DIS_RISCV_R32("subw", 0x3b, 0x0, 0x20),
1022 DIS_RISCV_R32("sllw", 0x3b, 0x1, 0x00),
1023 DIS_RISCV_R32("srlw", 0x3b, 0x5, 0x00),
1024 DIS_RISCV_R32("sraw", 0x3b, 0x5, 0x20),
1025 /*
1026 * RV32M
1027 */
1028 DIS_RISCV_R32("mul", 0x33, 0x0, 0x01),
1029 DIS_RISCV_R32("mulh", 0x33, 0x1, 0x01),
1030 DIS_RISCV_R32("mulhsu", 0x33, 0x2, 0x01),
1031 DIS_RISCV_R32("mulhu", 0x33, 0x3, 0x01),
1032 DIS_RISCV_R32("div", 0x33, 0x4, 0x01),
1033 DIS_RISCV_R32("divu", 0x33, 0x5, 0x01),
1034 DIS_RISCV_R32("rem", 0x33, 0x6, 0x01),
1035 DIS_RISCV_R32("remu", 0x33, 0x7, 0x01),
1036 /*
1037 * RV64M
1038 */
1039 DIS_RISCV_R32("mulw", 0x3b, 0x0, 0x01),
1040 DIS_RISCV_R32("divw", 0x3b, 0x4, 0x01),
1041 DIS_RISCV_R32("divuw", 0x3b, 0x5, 0x01),
1042 DIS_RISCV_R32("remw", 0x3b, 0x6, 0x01),
1043 DIS_RISCV_R32("remuw", 0x3b, 0x7, 0x01),
1044 /*
1045 * RV32A
1046 */
1047 DIS_RISCV_A32LOAD("lr.w", 0x2f, 0x2, 0x02, 0x0),
1048 DIS_RISCV_A32("sc.w", 0x2f, 0x2, 0x03),
1049 DIS_RISCV_A32("amoswap.w", 0x2f, 0x2, 0x01),
1050 DIS_RISCV_A32("amoadd.w", 0x2f, 0x2, 0x00),
1051 DIS_RISCV_A32("amoxor.w", 0x2f, 0x2, 0x04),
1052 DIS_RISCV_A32("amoand.w", 0x2f, 0x2, 0x0c),
1053 DIS_RISCV_A32("amoor.w", 0x2f, 0x2, 0x08),
1054 DIS_RISCV_A32("amomin.w", 0x2f, 0x2, 0x10),
1055 DIS_RISCV_A32("amomax.w", 0x2f, 0x2, 0x14),
1056 DIS_RISCV_A32("amominu.w", 0x2f, 0x2, 0x18),
1057 DIS_RISCV_A32("amomaxu.w", 0x2f, 0x2, 0x1c),
1058 /*
1059 * RV64A
1060 */
1061 DIS_RISCV_A32LOAD("lr.d", 0x2f, 0x3, 0x02, 0x0),
1062 DIS_RISCV_A32("sc.d", 0x2f, 0x3, 0x03),
1063 DIS_RISCV_A32("amoswap.d", 0x2f, 0x3, 0x01),
1064 DIS_RISCV_A32("amoadd.d", 0x2f, 0x3, 0x00),
1065 DIS_RISCV_A32("amoxor.d", 0x2f, 0x3, 0x04),
1066 DIS_RISCV_A32("amoand.d", 0x2f, 0x3, 0x0c),
1067 DIS_RISCV_A32("amoor.d", 0x2f, 0x3, 0x08),
1068 DIS_RISCV_A32("amomin.d", 0x2f, 0x3, 0x10),
1069 DIS_RISCV_A32("amomax.d", 0x2f, 0x3, 0x14),
1070 DIS_RISCV_A32("amominu.d", 0x2f, 0x3, 0x18),
1071 DIS_RISCV_A32("amomaxu.d", 0x2f, 0x3, 0x1c),
1072 /*
1073 * RV32F
1074 */
1075 DIS_RISCV_FP_LOAD("flw", 0x07, 0x2),
1076 DIS_RISCV_FP_STORE("fsw", 0x27, 0x2),
1077 DIS_RISCV_FP_R4("fmadd.s", 0x43, 0x0),
1078 DIS_RISCV_FP_R4("fmsub.s", 0x47, 0x0),
1079 DIS_RISCV_FP_R4("fnmsub.s", 0x4b, 0x0),
1080 DIS_RISCV_FP_R4("fnmadd.s", 0x4f, 0x0),
1081 DIS_RISCV_FP_RM("fadd.s", 0x53, 0x00),
1082 DIS_RISCV_FP_RM("fsub.s", 0x53, 0x04),
1083 DIS_RISCV_FP_RM("fmul.s", 0x53, 0x08),
1084 DIS_RISCV_FP_RM("fdiv.s", 0x53, 0xc),
1085 DIS_RISCV_FP_RS2_FP("fsqrt.s", 0x53, 0x00, 0x2c),
1086 DIS_RISCV_FP_R("fsgnj.s", 0x53, 0x0, 0x10),
1087 DIS_RISCV_FP_R("fsgnjn.s", 0x53, 0x1, 0x10),
1088 DIS_RISCV_FP_R("fsgnjx.s", 0x53, 0x2, 0x10),
1089 DIS_RISCV_FP_R("fmin.s", 0x53, 0x0, 0x14),
1090 DIS_RISCV_FP_R("fmax.s", 0x53, 0x1, 0x14),
1091 DIS_RISCV_FP_RS2_FPI("fcvt.w.s", 0x53, 0x00, 0x60),
1092 DIS_RISCV_FP_RS2_FPI("fcvt.wu.s", 0x53, 0x01, 0x60),
1093 DIS_RISCV_FP_R_RS2_FPI_NR("fmv.x.w", 0x53, 0x00, 0x00, 0x70),
1094 DIS_RISCV_FP_RI("feq.s", 0x53, 0x2, 0x50),
1095 DIS_RISCV_FP_RI("flt.s", 0x53, 0x1, 0x50),
1096 DIS_RISCV_FP_RI("fle.s", 0x53, 0x0, 0x50),
1097 DIS_RISCV_FP_R_RS2_FPI_NR("fclass.s", 0x53, 0x1, 0x00, 0x70),
1098 DIS_RISCV_FP_RS2_IFP("fcvt.s.w", 0x53, 0x00, 0x68),
1099 DIS_RISCV_FP_RS2_IFP("fcvt.s.wu", 0x53, 0x01, 0x68),
1100 DIS_RISCV_FP_R_RS2_IFP_NR("fmv.w.x", 0x53, 0x0, 0x00, 0x78),
1101 /*
1102 * RV64F
1103 */
1104 DIS_RISCV_FP_RS2_FPI("fcvt.l.s", 0x53, 0x02, 0x60),
1105 DIS_RISCV_FP_RS2_FPI("fcvt.lu.s", 0x53, 0x03, 0x60),
1106 DIS_RISCV_FP_RS2_IFP("fcvt.s.l", 0x53, 0x02, 0x68),
1107 DIS_RISCV_FP_RS2_IFP("fcvt.s.lu", 0x53, 0x03, 0x68),
1108 /*
1109 * RV32D
1110 */
1111 DIS_RISCV_FP_LOAD("fld", 0x07, 0x3),
1112 DIS_RISCV_FP_STORE("fsd", 0x27, 0x3),
1113 DIS_RISCV_FP_R4("fmadd.d", 0x43, 0x1),
1114 DIS_RISCV_FP_R4("fmsub.d", 0x47, 0x1),
1115 DIS_RISCV_FP_R4("fnmsub.d", 0x4b, 0x1),
1116 DIS_RISCV_FP_R4("fnmadd.d", 0x4f, 0x1),
1117 DIS_RISCV_FP_RM("fadd.d", 0x53, 0x01),
1118 DIS_RISCV_FP_RM("fsub.d", 0x53, 0x05),
1119 DIS_RISCV_FP_RM("fmul.d", 0x53, 0x09),
1120 DIS_RISCV_FP_RM("fdiv.d", 0x53, 0xd),
1121 DIS_RISCV_FP_RS2_FP("fsqrt.d", 0x53, 0x00, 0x2d),
1122 DIS_RISCV_FP_R("fsgnj.d", 0x53, 0x0, 0x11),
1123 DIS_RISCV_FP_R("fsgnjn.d", 0x53, 0x1, 0x11),
1124 DIS_RISCV_FP_R("fsgnjx.d", 0x53, 0x2, 0x11),
1125 DIS_RISCV_FP_R("fmin.d", 0x53, 0x0, 0x15),
1126 DIS_RISCV_FP_R("fmax.d", 0x53, 0x1, 0x15),
1127 DIS_RISCV_FP_RS2_FP("fcvt.s.d", 0x53, 0x01, 0x20),
1128 DIS_RISCV_FP_RS2_FP_NR("fcvt.d.s", 0x53, 0x00, 0x21),
1129 DIS_RISCV_FP_RI("feq.d", 0x53, 0x2, 0x51),
1130 DIS_RISCV_FP_RI("flt.d", 0x53, 0x1, 0x51),
1131 DIS_RISCV_FP_RI("fle.d", 0x53, 0x0, 0x51),
1132 DIS_RISCV_FP_R_RS2_FPI_NR("fclass.d", 0x53, 0x1, 0x00, 0x71),
1133 DIS_RISCV_FP_RS2_FPI("fcvt.w.d", 0x53, 0x00, 0x61),
1134 DIS_RISCV_FP_RS2_FPI("fcvt.wu.d", 0x53, 0x01, 0x61),
1135 DIS_RISCV_FP_RS2_IFP_NR("fcvt.d.w", 0x53, 0x00, 0x69),
1136 DIS_RISCV_FP_RS2_IFP_NR("fcvt.d.wu", 0x53, 0x01, 0x69),
1137 /*
1138 * RV64D
1139 */
1140 DIS_RISCV_FP_RS2_FPI("fcvt.l.d", 0x53, 0x02, 0x61),
1141 DIS_RISCV_FP_RS2_FPI("fcvt.lu.d", 0x53, 0x03, 0x61),
1142 DIS_RISCV_FP_R_RS2_FPI_NR("fmv.x.d", 0x53, 0x0, 0x00, 0x71),
1143 DIS_RISCV_FP_RS2_IFP("fcvt.d.l", 0x53, 0x02, 0x69),
1144 DIS_RISCV_FP_RS2_IFP("fcvt.d.lu", 0x53, 0x03, 0x69),
1145 DIS_RISCV_FP_R_RS2_IFP_NR("fmv.d.x", 0x53, 0x0, 0x00, 0x79),
1146 /*
1147 * Privileged Instructions from RISC-V Privileged Architectures V1.10.
1148 */
1149 DIS_RISCV_MASK("uret", 0xffffffff, 0x00200073, dis_riscv_name),
1150 DIS_RISCV_MASK("sret", 0xffffffff, 0x10200073, dis_riscv_name),
1151 DIS_RISCV_MASK("mret", 0xffffffff, 0x30200073, dis_riscv_name),
1152 DIS_RISCV_MASK("wfi", 0xffffffff, 0x10500073, dis_riscv_name),
1153 DIS_RISCV_MASK("sfence.vma", 0xfe007fff, 0x12000073, dis_riscv_rs1_rs2)
1154 };
1155
1156 static void
1157 dis_riscv_decode_4byte(dis_handle_t *dhp, uint32_t instr, char *buf,
1158 size_t buflen)
1159 {
1160 uint_t i;
1161
1162 for (i = 0; i < ARRAY_SIZE(dis_riscv_4byte); i++) {
1163 dis_riscv_instr_t *t = &dis_riscv_4byte[i];
1164 switch (t->drv_type) {
1165 case DIS_RISCV_I_R_TYPE:
1166 if (DIS_RISCV_OPCODE(instr) == t->drv_opcode &&
1167 DIS_RISCV_FUNCT3(instr) == t->drv_funct3 &&
1168 DIS_RISCV_FUNCT7(instr) == t->drv_funct7) {
1169 break;
1170 }
1171 continue;
1172 case DIS_RISCV_I_I_TYPE:
1173 case DIS_RISCV_I_S_TYPE:
1174 case DIS_RISCV_I_B_TYPE:
1175 if (DIS_RISCV_OPCODE(instr) == t->drv_opcode &&
1176 DIS_RISCV_FUNCT3(instr) == t->drv_funct3) {
1177 break;
1178 }
1179 continue;
1180 case DIS_RISCV_I_U_TYPE:
1181 case DIS_RISCV_I_J_TYPE:
1182 if (DIS_RISCV_OPCODE(instr) == t->drv_opcode) {
1183 break;
1184 }
1185 continue;
1186 case DIS_RISCV_I_R4_TYPE:
1187 if (DIS_RISCV_OPCODE(instr) == t->drv_opcode &&
1188 DIS_RISCV_FUNCT2(instr) == t->drv_funct2) {
1189 break;
1190 }
1191 continue;
1192 case DIS_RISCV_I_MASK_TYPE:
1193 if ((instr & t->drv_opcode) == t->drv_funct3) {
1194 break;
1195 }
1196 continue;
1197 case DIS_RISCV_I_SHIFT64_TYPE:
1198 if (DIS_RISCV_OPCODE(instr) == t->drv_opcode &&
1199 DIS_RISCV_FUNCT3(instr) == t->drv_funct3 &&
1200 DIS_RISCV_SFUNCT7(instr) == t->drv_funct7) {
1201 break;
1202 }
1203 continue;
1204
1205 case DIS_RISCV_I_RV32A_LOAD_TYPE:
1206 if (DIS_RISCV_OPCODE(instr) == t->drv_opcode &&
1207 DIS_RISCV_FUNCT3(instr) == t->drv_funct3 &&
1208 DIS_RISCV_RVA_FUNCT5(instr) == t->drv_funct7 &&
1209 DIS_RISCV_RS2(instr) == t->drv_funct2) {
1210 break;
1211 }
1212 continue;
1213 case DIS_RISCV_I_RV32A_TYPE:
1214 if (DIS_RISCV_OPCODE(instr) == t->drv_opcode &&
1215 DIS_RISCV_FUNCT3(instr) == t->drv_funct3 &&
1216 DIS_RISCV_RVA_FUNCT5(instr) == t->drv_funct7) {
1217 break;
1218 }
1219 continue;
1220 case DIS_RISCV_I_FP_RS2OP_TYPE:
1221 if (DIS_RISCV_OPCODE(instr) == t->drv_opcode &&
1222 DIS_RISCV_RS2(instr) == t->drv_funct3 &&
1223 DIS_RISCV_FUNCT7(instr) == t->drv_funct7) {
1224 break;
1225 }
1226 continue;
1227 case DIS_RISCV_I_FP_RM_TYPE:
1228 if (DIS_RISCV_OPCODE(instr) == t->drv_opcode &&
1229 DIS_RISCV_FUNCT7(instr) == t->drv_funct7) {
1230 break;
1231 }
1232 continue;
1233 case DIS_RISCV_I_FP_R_RS2_TYPE:
1234 if (DIS_RISCV_OPCODE(instr) == t->drv_opcode &&
1235 DIS_RISCV_FUNCT3(instr) == t->drv_funct3 &&
1236 DIS_RISCV_RS2(instr) == t->drv_funct2 &&
1237 DIS_RISCV_FUNCT7(instr) == t->drv_funct7) {
1238 break;
1239 }
1240 continue;
1241 default:
1242 continue;
1243 }
1244
1245 t->drv_print(dhp, instr, t, buf, buflen);
1246 return;
1247 }
1248
1249 (void) dis_snprintf(buf, buflen, "<unknown>");
1250 }
1251
1252 /*
1253 * Two byte decode table types.
1254 */
1255 typedef enum dis_riscv_ctype {
1256 /*
1257 * Indicates that we should match based on the opcode and funct3.
1258 */
1259 DIS_RISCV_C_FUNCT3,
1260 /*
1261 * Indicates that we should match the instruction based on a mask.
1262 */
1263 DIS_RISCV_C_MATCH
1264 } dis_riscv_ctype_t;
1265
1266 /*
1267 * The compact forms are depending on the elf class. This is used to keep track
1268 * of the class and match it.
1269 */
1270 typedef enum dis_riscv_c_class {
1271 DIS_RISCV_CL_ALL,
1272 DIS_RISCV_CL_32,
1273 DIS_RISCV_CL_64,
1274 DIS_RISCV_CL_32_64,
1275 DIS_RISCV_CL_64_128
1276 } dis_riscv_c_class_t;
1277
1278 struct dis_riscv_c_instr;
1279 typedef void (*dis_riscv_c_func_t)(dis_handle_t *, uint32_t,
1280 struct dis_riscv_c_instr *, char *, size_t);
1281
1282 typedef struct dis_riscv_c_instr {
1283 const char *drv_c_name;
1284 dis_riscv_ctype_t drv_c_type;
1285 dis_riscv_c_func_t drv_c_print;
1286 dis_riscv_c_class_t drv_c_class;
1287 uint_t drv_c_opcode;
1288 uint_t drv_c_funct;
1289 uint_t drv_c_mask;
1290 uint_t drv_c_match;
1291 } dis_riscv_c_instr_t;
1292
1293 #define DIS_RISCV_C_OPCODE(x) ((x) & 0x03)
1294 #define DIS_RISCV_C_FUNCT3(x) (((x) & 0xe000) >> 13)
1295
1296 #define DIS_RISCV_C_RS1(x) (((x) & 0x0f80) >> 7)
1297 #define DIS_RISCV_C_RS2(x) (((x) & 0x007c) >> 2)
1298 #define DIS_RISCV_C_RD(x) DIS_RISCV_C_RS1(x)
1299
1300 #define DIS_RISCV_C_RS1P(x) (((x) & 0x0380) >> 7)
1301 #define DIS_RISCV_C_RS2P(x) DIS_RISCV_C_RDP(x)
1302 #define DIS_RISCV_C_RDP(x) (((x) & 0x001c) >> 2)
1303
1304 /*
1305 * CJ format immediate extractor
1306 */
1307 #define DIS_RISCV_C_J_11(x) (((x) & 0x1000) >> 1)
1308 #define DIS_RISCV_C_J_4(x) (((x) & 0x0800) >> 7)
1309 #define DIS_RISCV_C_J_9_8(x) (((x) & 0x0600) >> 1)
1310 #define DIS_RISCV_C_J_10(x) (((x) & 0x0100) << 2)
1311 #define DIS_RISCV_C_J_6(x) (((x) & 0x0080) >> 1)
1312 #define DIS_RISCV_C_J_7(x) (((x) & 0x0040) << 1)
1313 #define DIS_RISCV_C_J_3_1(x) (((x) & 0x0038) >> 3)
1314 #define DIS_RISCV_C_J_5(x) (((x) & 0x0004) << 3)
1315
1316 /*
1317 * Compact Branch extractor
1318 */
1319 #define DIS_RISCV_C_B_8(x) (((x) & 0x1000) >> 4)
1320 #define DIS_RISCV_C_B_4_3(x) (((x) & 0x0c00) >> 7)
1321 #define DIS_RISCV_C_B_7_6(x) (((x) & 0x0060) << 1)
1322 #define DIS_RISCV_C_B_2_1(x) (((x) & 0x0018) >> 2)
1323 #define DIS_RISCV_C_B_5(x) (((x) & 0x0004) << 3)
1324
1325 /*
1326 * c.addi16spn extractor
1327 */
1328 #define DIS_RISCV_C_A16_9(x) (((x) & 0x1000) >> 3)
1329 #define DIS_RISCV_C_A16_4(x) (((x) & 0x0040) >> 2)
1330 #define DIS_RISCV_C_A16_6(x) (((x) & 0x0020) << 1)
1331 #define DIS_RISCV_C_A16_8_7(x) (((x) & 0x0018) << 4)
1332 #define DIS_RISCV_C_A16_5(x) (((x) & 0x0004) << 3)
1333
1334 /*
1335 * c.addi4spn extractor
1336 */
1337 #define DIS_RISCV_C_A4_5_4(x) (((x) & 0x1800) >> 7)
1338 #define DIS_RISCV_C_A4_9_6(x) (((x) & 0x0700) >> 2)
1339 #define DIS_RISCV_C_A4_2(x) (((x) & 0x0040) >> 4)
1340 #define DIS_RISCV_C_A4_3(x) (((x) & 0x0020) >> 2)
1341
1342 static void
1343 dis_riscv_c_name(dis_handle_t *dhp, uint32_t instr,
1344 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1345 {
1346 (void) dis_snprintf(buf, buflen, "%s", table->drv_c_name);
1347 }
1348
1349 static void
1350 dis_riscv_c_loadstore(dis_handle_t *dhp, const char *name, const char *dreg,
1351 const char *sreg, uint32_t off, char *buf, size_t buflen)
1352 {
1353
1354 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
1355 (void) dis_snprintf(buf, buflen, "%s %s,0%o(%s)", name, dreg,
1356 off, sreg);
1357 } else {
1358 (void) dis_snprintf(buf, buflen, "%s %s,0x%x(%s)", name, dreg,
1359 off, sreg);
1360 }
1361 }
1362
1363 static void
1364 dis_riscv_c_lwsp(dis_handle_t *dhp, uint32_t instr,
1365 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1366 {
1367 uint32_t imm = ((instr & 0x000c) << 4) |
1368 ((instr & 0x1000) >> 7) | ((instr & 0x0070) >> 2);
1369
1370 dis_riscv_c_loadstore(dhp, table->drv_c_name,
1371 dis_riscv_regs[DIS_RISCV_C_RD(instr)], dis_riscv_regs[2], imm, buf,
1372 buflen);
1373 }
1374
1375 static void
1376 dis_riscv_c_ldsp(dis_handle_t *dhp, uint32_t instr,
1377 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1378 {
1379 uint32_t imm = ((instr & 0x001c) << 4) |
1380 ((instr & 0x1000) >> 7) | ((instr & 0x0060) >> 2);
1381
1382 dis_riscv_c_loadstore(dhp, table->drv_c_name,
1383 dis_riscv_regs[DIS_RISCV_C_RD(instr)], dis_riscv_regs[2],
1384 imm, buf, buflen);
1385 }
1386
1387 static void
1388 dis_riscv_c_flwsp(dis_handle_t *dhp, uint32_t instr,
1389 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1390 {
1391 uint32_t imm = ((instr & 0x000c) << 4) |
1392 ((instr & 0x1000) >> 7) | ((instr & 0x0070) >> 2);
1393
1394 dis_riscv_c_loadstore(dhp, table->drv_c_name,
1395 dis_riscv_fpregs[DIS_RISCV_C_RD(instr)], dis_riscv_regs[2],
1396 imm, buf, buflen);
1397 }
1398
1399 static void
1400 dis_riscv_c_fldsp(dis_handle_t *dhp, uint32_t instr,
1401 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1402 {
1403 uint32_t imm = ((instr & 0x001c) << 4) |
1404 ((instr & 0x1000) >> 7) | ((instr & 0x0060) >> 2);
1405
1406 dis_riscv_c_loadstore(dhp, table->drv_c_name,
1407 dis_riscv_fpregs[DIS_RISCV_C_RD(instr)], dis_riscv_regs[2],
1408 imm, buf, buflen);
1409 }
1410
1411 static void
1412 dis_riscv_c_swsp(dis_handle_t *dhp, uint32_t instr,
1413 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1414 {
1415 uint32_t imm = ((instr & 0x0180) >> 1) | ((instr & 0x1e00) >> 7);
1416
1417 dis_riscv_c_loadstore(dhp, table->drv_c_name,
1418 dis_riscv_regs[DIS_RISCV_C_RS2(instr)], dis_riscv_regs[2], imm,
1419 buf, buflen);
1420 }
1421
1422 static void
1423 dis_riscv_c_sdsp(dis_handle_t *dhp, uint32_t instr,
1424 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1425 {
1426 uint32_t imm = ((instr & 0x0380) >> 1) | ((instr & 0x1c00) >> 7);
1427
1428 dis_riscv_c_loadstore(dhp, table->drv_c_name,
1429 dis_riscv_regs[DIS_RISCV_C_RS2(instr)], dis_riscv_regs[2], imm,
1430 buf, buflen);
1431 }
1432
1433 static void
1434 dis_riscv_c_fswsp(dis_handle_t *dhp, uint32_t instr,
1435 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1436 {
1437 uint32_t imm = ((instr & 0x0180) >> 1) | ((instr & 0x1e00) >> 7);
1438
1439 dis_riscv_c_loadstore(dhp, table->drv_c_name,
1440 dis_riscv_fpregs[DIS_RISCV_C_RS2(instr)], dis_riscv_regs[2], imm,
1441 buf, buflen);
1442 }
1443
1444 static void
1445 dis_riscv_c_fsdsp(dis_handle_t *dhp, uint32_t instr,
1446 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1447 {
1448 uint32_t imm = ((instr & 0x0380) >> 1) | ((instr & 0x1c00) >> 7);
1449
1450 dis_riscv_c_loadstore(dhp, table->drv_c_name,
1451 dis_riscv_fpregs[DIS_RISCV_C_RS2(instr)], dis_riscv_regs[2], imm,
1452 buf, buflen);
1453 }
1454
1455 static void
1456 dis_riscv_c_lw(dis_handle_t *dhp, uint32_t instr,
1457 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1458 {
1459 uint32_t imm = ((instr & 0x0020) << 1) | ((instr & 0x1c) >> 7) |
1460 ((instr & 0x0040) >> 3);
1461
1462 dis_riscv_c_loadstore(dhp, table->drv_c_name,
1463 dis_riscv_c_regs[DIS_RISCV_C_RDP(instr)],
1464 dis_riscv_c_regs[DIS_RISCV_C_RS1P(instr)],
1465 imm, buf, buflen);
1466 }
1467
1468 static void
1469 dis_riscv_c_ld(dis_handle_t *dhp, uint32_t instr,
1470 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1471 {
1472 uint32_t imm = ((instr & 0x0060) << 1) | ((instr & 0x1c) >> 7);
1473
1474 dis_riscv_c_loadstore(dhp, table->drv_c_name,
1475 dis_riscv_c_regs[DIS_RISCV_C_RDP(instr)],
1476 dis_riscv_c_regs[DIS_RISCV_C_RS1P(instr)],
1477 imm, buf, buflen);
1478 }
1479
1480 static void
1481 dis_riscv_c_flw(dis_handle_t *dhp, uint32_t instr,
1482 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1483 {
1484 uint32_t imm = ((instr & 0x0020) << 1) | ((instr & 0x1c) >> 7) |
1485 ((instr & 0x0040) >> 3);
1486
1487 dis_riscv_c_loadstore(dhp, table->drv_c_name,
1488 dis_riscv_c_fpregs[DIS_RISCV_C_RDP(instr)],
1489 dis_riscv_c_regs[DIS_RISCV_C_RS1P(instr)],
1490 imm, buf, buflen);
1491 }
1492
1493 static void
1494 dis_riscv_c_fld(dis_handle_t *dhp, uint32_t instr,
1495 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1496 {
1497 uint32_t imm = ((instr & 0x0060) << 1) | ((instr & 0x1c) >> 7);
1498
1499 dis_riscv_c_loadstore(dhp, table->drv_c_name,
1500 dis_riscv_c_fpregs[DIS_RISCV_C_RDP(instr)],
1501 dis_riscv_c_regs[DIS_RISCV_C_RS1P(instr)],
1502 imm, buf, buflen);
1503 }
1504
1505 /*
1506 * The J type has the 11 bit immediate arranged as:
1507 *
1508 * offset[11|4|9:8|10|6|7|3:1|5] going from bits 2 to 12.
1509 */
1510 static void
1511 dis_riscv_c_j(dis_handle_t *dhp, uint32_t instr,
1512 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1513 {
1514 const char *s;
1515 uint_t jimm = DIS_RISCV_C_J_11(instr) | DIS_RISCV_C_J_10(instr) |
1516 DIS_RISCV_C_J_9_8(instr) | DIS_RISCV_C_J_7(instr) |
1517 DIS_RISCV_C_J_6(instr) | DIS_RISCV_C_J_5(instr) |
1518 DIS_RISCV_C_J_4(instr) | DIS_RISCV_C_J_3_1(instr);
1519 uint_t imm = dis_riscv_sign_extend(jimm, 11, &s);
1520
1521 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
1522 (void) dis_snprintf(buf, buflen, "%s %s0%o", table->drv_c_name,
1523 s, imm);
1524 } else {
1525 (void) dis_snprintf(buf, buflen, "%s %s0x%x", table->drv_c_name,
1526 s, imm);
1527 }
1528 }
1529
1530 static void
1531 dis_riscv_c_jr(dis_handle_t *dhp, uint32_t instr,
1532 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1533 {
1534 (void) dis_snprintf(buf, buflen, "%s %s", table->drv_c_name,
1535 dis_riscv_regs[DIS_RISCV_C_RS1(instr)]);
1536 }
1537
1538 static void
1539 dis_riscv_c_regimm(dis_handle_t *dhp, const char *instr, const char *dreg,
1540 const char *sign, uint_t imm, char *buf, size_t buflen)
1541 {
1542 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
1543 (void) dis_snprintf(buf, buflen, "%s %s,%s0%o", instr, dreg,
1544 sign, imm);
1545 } else {
1546 (void) dis_snprintf(buf, buflen, "%s %s,%s0x%x", instr, dreg,
1547 sign, imm);
1548 }
1549 }
1550
1551 static void
1552 dis_riscv_c_branch(dis_handle_t *dhp, uint32_t instr,
1553 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1554 {
1555 const char *s;
1556 uint_t bimm = DIS_RISCV_C_B_8(instr) | DIS_RISCV_C_B_7_6(instr) |
1557 DIS_RISCV_C_B_5(instr) | DIS_RISCV_C_B_4_3(instr) |
1558 DIS_RISCV_C_B_2_1(instr);
1559 uint_t imm = dis_riscv_sign_extend(bimm, 8, &s);
1560
1561 dis_riscv_c_regimm(dhp, table->drv_c_name,
1562 dis_riscv_c_regs[DIS_RISCV_C_RS1P(instr)], s, imm, buf, buflen);
1563 }
1564
1565 static void
1566 dis_riscv_c_bigimmint(dis_handle_t *dhp, uint32_t instr,
1567 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1568 {
1569 const char *s;
1570 uint_t limm = ((instr & 0x1000) >> 7) | ((instr & 0x007c) >> 2);
1571 uint_t imm = dis_riscv_sign_extend(limm, 5, &s);
1572
1573 dis_riscv_c_regimm(dhp, table->drv_c_name,
1574 dis_riscv_regs[DIS_RISCV_C_RD(instr)], s, imm, buf, buflen);
1575 }
1576
1577 static void
1578 dis_riscv_c_zext_bigimmint(dis_handle_t *dhp, uint32_t instr,
1579 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1580 {
1581 uint_t imm = ((instr & 0x1000) >> 7) | ((instr & 0x007c) >> 2);
1582
1583 dis_riscv_c_regimm(dhp, table->drv_c_name,
1584 dis_riscv_regs[DIS_RISCV_C_RD(instr)], "", imm, buf, buflen);
1585 }
1586
1587 static void
1588 dis_riscv_c_addi16sp(dis_handle_t *dhp, uint32_t instr,
1589 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1590 {
1591 const char *s;
1592 uint_t aimm = DIS_RISCV_C_A16_9(instr) | DIS_RISCV_C_A16_8_7(instr) |
1593 DIS_RISCV_C_A16_6(instr) | DIS_RISCV_C_A16_5(instr) |
1594 DIS_RISCV_C_A16_4(instr);
1595 int imm = dis_riscv_sign_extend(aimm, 9, &s);
1596
1597 dis_riscv_c_regimm(dhp, table->drv_c_name,
1598 dis_riscv_regs[DIS_RISCV_C_RD(instr)], s, imm, buf, buflen);
1599 }
1600
1601 static void
1602 dis_riscv_c_addi4spn(dis_handle_t *dhp, uint32_t instr,
1603 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1604 {
1605 uint_t imm = DIS_RISCV_C_A4_9_6(instr) | DIS_RISCV_C_A4_5_4(instr) |
1606 DIS_RISCV_C_A4_3(instr) | DIS_RISCV_C_A4_2(instr);
1607
1608 if ((dhp->dh_flags & DIS_OCTAL) != 0) {
1609 (void) dis_snprintf(buf, buflen, "%s %s,sp,0%o",
1610 table->drv_c_name, dis_riscv_c_regs[DIS_RISCV_C_RDP(instr)],
1611 imm);
1612 } else {
1613 (void) dis_snprintf(buf, buflen, "%s %s,sp,0x%x",
1614 table->drv_c_name, dis_riscv_c_regs[DIS_RISCV_C_RDP(instr)],
1615 imm);
1616 }
1617 }
1618
1619 static void
1620 dis_riscv_c_immint(dis_handle_t *dhp, uint32_t instr,
1621 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1622 {
1623 const char *s;
1624 uint_t limm = ((instr & 0x1000) >> 7) | ((instr & 0x007c) >> 2);
1625 uint_t imm = dis_riscv_sign_extend(limm, 5, &s);
1626
1627 dis_riscv_c_regimm(dhp, table->drv_c_name,
1628 dis_riscv_c_regs[DIS_RISCV_C_RS1P(instr)], s, imm, buf, buflen);
1629 }
1630
1631 static void
1632 dis_riscv_c_zext_immint(dis_handle_t *dhp, uint32_t instr,
1633 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1634 {
1635 uint_t imm = ((instr & 0x1000) >> 7) | ((instr & 0x007c) >> 2);
1636
1637 dis_riscv_c_regimm(dhp, table->drv_c_name,
1638 dis_riscv_c_regs[DIS_RISCV_C_RS1P(instr)], "", imm, buf, buflen);
1639 }
1640
1641 static void
1642 dis_riscv_c_bigint(dis_handle_t *dhp, uint32_t instr,
1643 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1644 {
1645 (void) dis_snprintf(buf, buflen, "%s %s,%s", table->drv_c_name,
1646 dis_riscv_regs[DIS_RISCV_C_RD(instr)],
1647 dis_riscv_regs[DIS_RISCV_C_RS2(instr)]);
1648 }
1649
1650
1651 static void
1652 dis_riscv_c_int(dis_handle_t *dhp, uint32_t instr,
1653 dis_riscv_c_instr_t *table, char *buf, size_t buflen)
1654 {
1655 (void) dis_snprintf(buf, buflen, "%s %s,%s", table->drv_c_name,
1656 dis_riscv_c_regs[DIS_RISCV_C_RS1P(instr)],
1657 dis_riscv_c_regs[DIS_RISCV_C_RS2P(instr)]);
1658 }
1659
1660 #define DIS_RISCV_CFUNCT3(name, class, op, funct, print) \
1661 { name, DIS_RISCV_C_FUNCT3, print, class, op, funct, 0, 0 }
1662 #define DIS_RISCV_CMATCH(name, class, op, funct, mask, match, print) \
1663 { name, DIS_RISCV_C_MATCH, print, class, op, funct, mask, match }
1664
1665 static dis_riscv_c_instr_t dis_riscv_2byte[] = {
1666 /* Quadrant 0 */
1667 DIS_RISCV_CFUNCT3("c.addi4spn", DIS_RISCV_CL_32_64, 0x0, 0x0,
1668 dis_riscv_c_addi4spn),
1669 DIS_RISCV_CFUNCT3("c.fld", DIS_RISCV_CL_32_64, 0x0, 0x01,
1670 dis_riscv_c_fld),
1671 DIS_RISCV_CFUNCT3("c.lw", DIS_RISCV_CL_ALL, 0x0, 0x2,
1672 dis_riscv_c_lw),
1673 DIS_RISCV_CFUNCT3("c.flw", DIS_RISCV_CL_32, 0x0, 0x3,
1674 dis_riscv_c_flw),
1675 DIS_RISCV_CFUNCT3("f.ld", DIS_RISCV_CL_64_128, 0x0, 0x3,
1676 dis_riscv_c_ld),
1677 DIS_RISCV_CFUNCT3("c.fsd", DIS_RISCV_CL_32_64, 0x0, 0x5,
1678 dis_riscv_c_fld),
1679 DIS_RISCV_CFUNCT3("c.sw", DIS_RISCV_CL_ALL, 0x0, 0x6,
1680 dis_riscv_c_lw),
1681 DIS_RISCV_CFUNCT3("c.fsw", DIS_RISCV_CL_32, 0x0, 0x7,
1682 dis_riscv_c_flw),
1683 DIS_RISCV_CFUNCT3("c.sd", DIS_RISCV_CL_64_128, 0x0, 0x7,
1684 dis_riscv_c_ld),
1685 /* Quadrant 1 */
1686 DIS_RISCV_CMATCH("c.nop", DIS_RISCV_CL_ALL, 0x01, 0x00, 0x1ffc, 0x0,
1687 dis_riscv_c_name),
1688 DIS_RISCV_CFUNCT3("c.addi", DIS_RISCV_CL_ALL, 0x01, 0x00,
1689 dis_riscv_c_bigimmint),
1690 DIS_RISCV_CFUNCT3("c.jal", DIS_RISCV_CL_32, 0x01, 0x01,
1691 dis_riscv_c_j),
1692 DIS_RISCV_CFUNCT3("c.addiw", DIS_RISCV_CL_64_128, 0x01, 0x01,
1693 dis_riscv_c_bigimmint),
1694 DIS_RISCV_CFUNCT3("c.li", DIS_RISCV_CL_ALL, 0x01, 0x02,
1695 dis_riscv_c_bigimmint),
1696 DIS_RISCV_CMATCH("c.addi16sp", DIS_RISCV_CL_ALL, 0x01, 0x03, 0x0f80,
1697 0x0100, dis_riscv_c_addi16sp),
1698 DIS_RISCV_CFUNCT3("c.lui", DIS_RISCV_CL_ALL, 0x01, 0x03,
1699 dis_riscv_c_zext_bigimmint),
1700 DIS_RISCV_CMATCH("c.srli", DIS_RISCV_CL_ALL, 0x1, 0x4, 0x0c00, 0x0000,
1701 dis_riscv_c_zext_immint),
1702 DIS_RISCV_CMATCH("c.srai", DIS_RISCV_CL_ALL, 0x1, 0x4, 0x0c00, 0x0400,
1703 dis_riscv_c_zext_immint),
1704 DIS_RISCV_CMATCH("c.andi", DIS_RISCV_CL_ALL, 0x1, 0x4, 0x0c00, 0x0800,
1705 dis_riscv_c_immint),
1706 DIS_RISCV_CMATCH("c.sub", DIS_RISCV_CL_ALL, 0x1, 0x4, 0x1c60, 0x0c00,
1707 dis_riscv_c_int),
1708 DIS_RISCV_CMATCH("c.xor", DIS_RISCV_CL_ALL, 0x1, 0x4, 0x1c60, 0x0c20,
1709 dis_riscv_c_int),
1710 DIS_RISCV_CMATCH("c.or", DIS_RISCV_CL_ALL, 0x1, 0x4, 0x1c60, 0x0c40,
1711 dis_riscv_c_int),
1712 DIS_RISCV_CMATCH("c.and", DIS_RISCV_CL_ALL, 0x1, 0x4, 0x1c60, 0x0c60,
1713 dis_riscv_c_int),
1714 DIS_RISCV_CMATCH("c.subw", DIS_RISCV_CL_64_128, 0x1, 0x4, 0x1c60,
1715 0x1c00, dis_riscv_c_int),
1716 DIS_RISCV_CMATCH("c.addw", DIS_RISCV_CL_64_128, 0x1, 0x4, 0x1c60,
1717 0x1c20, dis_riscv_c_int),
1718 DIS_RISCV_CFUNCT3("c.j", DIS_RISCV_CL_ALL, 0x1, 0x5,
1719 dis_riscv_c_j),
1720 DIS_RISCV_CFUNCT3("c.beqz", DIS_RISCV_CL_ALL, 0x1, 0x6,
1721 dis_riscv_c_branch),
1722 DIS_RISCV_CFUNCT3("c.bnez", DIS_RISCV_CL_ALL, 0x1, 0x7,
1723 dis_riscv_c_branch),
1724 /* Quadrant 2 */
1725 DIS_RISCV_CFUNCT3("c.slli", DIS_RISCV_CL_ALL, 0x2, 0x0,
1726 dis_riscv_c_zext_bigimmint),
1727 DIS_RISCV_CFUNCT3("c.fldsp", DIS_RISCV_CL_32_64, 0x2, 0x1,
1728 dis_riscv_c_fldsp),
1729 DIS_RISCV_CFUNCT3("c.lwsp", DIS_RISCV_CL_ALL, 0x2, 0x2,
1730 dis_riscv_c_lwsp),
1731 DIS_RISCV_CFUNCT3("c.flwsp", DIS_RISCV_CL_32, 0x2, 0x3,
1732 dis_riscv_c_flwsp),
1733 DIS_RISCV_CFUNCT3("c.ldsp", DIS_RISCV_CL_64_128, 0x2, 0x3,
1734 dis_riscv_c_ldsp),
1735 DIS_RISCV_CMATCH("c.jr", DIS_RISCV_CL_ALL, 0x2, 0x4, 0x107c, 0x0,
1736 dis_riscv_c_jr),
1737 DIS_RISCV_CMATCH("c.mv", DIS_RISCV_CL_ALL, 0x2, 0x4, 0x1000, 0x0,
1738 dis_riscv_c_bigint),
1739 DIS_RISCV_CMATCH("c.ebreak", DIS_RISCV_CL_ALL, 0x2, 0x4, 0x1ffc, 0x1000,
1740 dis_riscv_c_name),
1741 DIS_RISCV_CMATCH("c.jalr", DIS_RISCV_CL_ALL, 0x2, 0x4, 0x107c, 0x1000,
1742 dis_riscv_c_jr),
1743 DIS_RISCV_CMATCH("c.add", DIS_RISCV_CL_ALL, 0x2, 0x4, 0x1000, 0x1000,
1744 dis_riscv_c_bigint),
1745 DIS_RISCV_CFUNCT3("c.fsdsp", DIS_RISCV_CL_32_64, 0x2, 0x5,
1746 dis_riscv_c_fsdsp),
1747 DIS_RISCV_CFUNCT3("c.swsp", DIS_RISCV_CL_ALL, 0x2, 0x6,
1748 dis_riscv_c_swsp),
1749 DIS_RISCV_CFUNCT3("c.fswsp", DIS_RISCV_CL_32, 0x2, 0x7,
1750 dis_riscv_c_fswsp),
1751 DIS_RISCV_CFUNCT3("c.sdsp", DIS_RISCV_CL_64_128, 0x2, 0x7,
1752 dis_riscv_c_sdsp),
1753 };
1754
1755 static void
1756 dis_riscv_decode_2byte(dis_handle_t *dhp, uint32_t instr, char *buf,
1757 size_t buflen)
1758 {
1759 uint_t i;
1760
1761 for (i = 0; i < ARRAY_SIZE(dis_riscv_2byte); i++) {
1762 dis_riscv_c_instr_t *t = &dis_riscv_2byte[i];
1763 switch (t->drv_c_class) {
1764 case DIS_RISCV_CL_ALL:
1765 break;
1766 case DIS_RISCV_CL_32:
1767 if ((dhp->dh_flags & DIS_RISCV_32) == 0)
1768 continue;
1769 break;
1770 case DIS_RISCV_CL_64:
1771 if ((dhp->dh_flags & DIS_RISCV_64) == 0)
1772 continue;
1773 break;
1774 case DIS_RISCV_CL_32_64:
1775 if ((dhp->dh_flags &
1776 (DIS_RISCV_32 | DIS_RISCV_64)) == 0) {
1777 continue;
1778 }
1779 break;
1780 case DIS_RISCV_CL_64_128:
1781 if ((dhp->dh_flags & DIS_RISCV_64) == 0)
1782 continue;
1783 break;
1784 }
1785
1786 switch (t->drv_c_type) {
1787 case DIS_RISCV_C_FUNCT3:
1788 if (DIS_RISCV_C_OPCODE(instr) == t->drv_c_opcode &&
1789 DIS_RISCV_C_FUNCT3(instr) == t->drv_c_funct) {
1790 break;
1791 }
1792 continue;
1793 case DIS_RISCV_C_MATCH:
1794 if (DIS_RISCV_C_OPCODE(instr) == t->drv_c_opcode &&
1795 DIS_RISCV_C_FUNCT3(instr) == t->drv_c_funct &&
1796 ((instr & t->drv_c_mask) == t->drv_c_match)) {
1797 break;
1798 }
1799 continue;
1800 default:
1801 continue;
1802 }
1803
1804 t->drv_c_print(dhp, instr, t, buf, buflen);
1805 return;
1806 }
1807
1808 (void) dis_snprintf(buf, buflen, "<unknown>");
1809 }
1810
1811
1812 /*
1813 * RISC-V instructions always come in parcels of two bytes. Read the next two
1814 * byte parcel and advance the address in the handle. Also, take care of endian
1815 * issues if required.
1816 */
1817 static int
1818 dis_riscv_read_parcel(dis_handle_t *dhp, uint16_t *valp)
1819 {
1820 if ((dhp->dh_addr % 2) != 0)
1821 return (-1);
1822
1823 if (dhp->dh_read(dhp->dh_data, dhp->dh_addr, valp, sizeof (*valp)) !=
1824 sizeof (*valp))
1825 return (-1);
1826
1827 *valp = LE_16(*valp);
1828
1829 dhp->dh_addr += 2;
1830
1831 return (0);
1832 }
1833
1834 /*
1835 * The first 'parcel' (uint16_t) of any instruction can be used to determine the
1836 * instruction length. This is derived from Section 1.2 Instruction Length
1837 * Encoding of Volume I: RISC-V User-Level ISA V2.2.
1838 *
1839 * | xxxxxxxxxxxxxxaa | 16-bit iff aa != 11
1840 * | xxxxxxxxxxxbbb11 | 32-bit iff bbb != 111
1841 * | xxxxxxxxxx011111 | 48-bit iff bbb != 111
1842 * | xxxxxxxxx0111111 | 64-bit iff bbb != 111
1843 * | xnnnxxxxx1111111 | (80 + 16*nnn)-bit iff nnn != 111
1844 */
1845 #define RISCV_LEN_16_MASK 0x0003
1846 #define RISCV_LEN_32_MASK 0x001c
1847 #define RISCV_LEN_48_MASK 0x0020
1848 #define RISCV_LEN_64_MASK 0x0040
1849 #define RISCV_LEN_80_MASK 0x7000
1850 #define RISCV_LEN_80_SHIFT 12
1851
1852 static int
1853 dis_riscv_decode_len(uint16_t instr)
1854 {
1855 if ((instr & RISCV_LEN_16_MASK) != RISCV_LEN_16_MASK)
1856 return (2);
1857
1858 if ((instr & RISCV_LEN_32_MASK) != RISCV_LEN_32_MASK)
1859 return (4);
1860
1861 if ((instr & RISCV_LEN_48_MASK) != RISCV_LEN_48_MASK)
1862 return (6);
1863
1864 if ((instr & RISCV_LEN_64_MASK) != RISCV_LEN_64_MASK)
1865 return (8);
1866
1867 if ((instr & RISCV_LEN_80_MASK) != RISCV_LEN_80_MASK) {
1868 uint_t factor = (instr & RISCV_LEN_80_MASK) >>
1869 RISCV_LEN_80_SHIFT;
1870 return ((10 + 2 * factor));
1871 }
1872
1873 return (-1);
1874 }
1875
1876 static int
1877 dis_riscv_supports_flags(int flags)
1878 {
1879 int archflags = flags & DIS_ARCH_MASK;
1880
1881 return (archflags == DIS_RISCV_32 || archflags == DIS_RISCV_64);
1882 }
1883
1884 static int
1885 dis_riscv_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf,
1886 size_t buflen)
1887 {
1888 int len;
1889 uint16_t parcel;
1890 uint32_t instr;
1891
1892
1893 dhp->dh_addr = addr;
1894
1895 /*
1896 * All instructions have to be 2-byte aligned. Most have to be four byte
1897 * aligned, but we determine that after we decode the instruction size.
1898 * The 2-byte alignment check is done when we read the parcel.
1899 */
1900 if (dis_riscv_read_parcel(dhp, &parcel) != 0)
1901 return (-1);
1902
1903 len = dis_riscv_decode_len(parcel);
1904 if (len < 2 || (len % 2) != 0)
1905 return (-1);
1906 switch (len) {
1907 case 2:
1908 instr = parcel;
1909 dis_riscv_decode_2byte(dhp, instr, buf, buflen);
1910 break;
1911 case 4:
1912 instr = parcel;
1913 if (dis_riscv_read_parcel(dhp, &parcel) != 0)
1914 return (-1);
1915 instr |= parcel << 16;
1916 dis_riscv_decode_4byte(dhp, instr, buf, buflen);
1917 break;
1918 default:
1919 /*
1920 * This case represents a valid instruction length, but
1921 * something we don't understand. Treat this as an unknown
1922 * instruction. However, read the rest of the length of the
1923 * instruction to make sure that we read things correctly.
1924 */
1925 (void) dis_snprintf(buf, buflen, "<unknown>");
1926 for (; len > 0; len -= 2) {
1927 if (dis_riscv_read_parcel(dhp, &parcel) != 0) {
1928 return (-1);
1929 }
1930 }
1931 break;
1932 }
1933
1934 return (0);
1935 }
1936
1937 static int
1938 dis_riscv_min_instrlen(dis_handle_t *dhp)
1939 {
1940 return (2);
1941 }
1942
1943 static int
1944 dis_riscv_max_instrlen(dis_handle_t *dhp)
1945 {
1946 return (22);
1947 }
1948
1949 static int
1950 dis_riscv_instrlen(dis_handle_t *dhp, uint64_t addr)
1951 {
1952 int ret;
1953 uint16_t parcel;
1954
1955 dhp->dh_addr = addr;
1956
1957 if (dis_riscv_read_parcel(dhp, &parcel) != 0)
1958 return (-1);
1959
1960 /*
1961 * Get length based on this parcel. Check for required alignment. 2-byte
1962 * alignment was already taken care of when we read the parcel.
1963 */
1964 ret = dis_riscv_decode_len(parcel);
1965 if (ret >= 4 && (addr % 4) != 0)
1966 return (-1);
1967
1968 return (ret);
1969 }
1970
1971 dis_arch_t dis_arch_riscv = {
1972 .da_supports_flags = dis_riscv_supports_flags,
1973 .da_disassemble = dis_riscv_disassemble,
1974 .da_min_instrlen = dis_riscv_min_instrlen,
1975 .da_max_instrlen = dis_riscv_max_instrlen,
1976 .da_instrlen = dis_riscv_instrlen
1977 };