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