xref: /netbsd-src/sys/arch/riscv/riscv/db_disasm.c (revision 562e6fd967b25c12f7a17ed1d9b57876f3a7bbec)
1 /*	$NetBSD: db_disasm.c,v 1.13 2024/11/24 19:41:18 skrll Exp $	*/
2 
3 /*-
4  * Copyright (c) 2014 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Matt Thomas of 3am Software Foundry.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 
34 __RCSID("$NetBSD: db_disasm.c,v 1.13 2024/11/24 19:41:18 skrll Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 
39 #include <riscv/db_machdep.h>
40 #include <riscv/frame.h>
41 #include <riscv/insn.h>
42 
43 #include <ddb/db_access.h>
44 #include <ddb/db_user.h>
45 #include <ddb/db_interface.h>
46 #include <ddb/db_output.h>
47 #include <ddb/db_extern.h>
48 #include <ddb/db_sym.h>
49 
50 ////////////////////////////////////////////////////////////
51 // registers
52 
53 static const char *riscv_registers[32] = {
54 	"zero", "ra", "sp", "gp", "tp",
55 	"t0", "t1", "t2",
56 	"s0", "s1",
57 	"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
58 	"s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11",
59 	"t3", "t4", "t5", "t6"
60 };
61 
62 /* XXX this should be in MI ddb */
63 static void
64 db_print_addr(db_addr_t loc)
65 {
66 	db_expr_t diff;
67 	db_sym_t sym;
68 	const char *symname;
69 
70 /* hack for testing since the test program is ASLR'd */
71 #ifndef _KERNEL
72 	loc &= 0xfff;
73 #endif
74 
75 	diff = INT_MAX;
76 	symname = NULL;
77 	sym = db_search_symbol(loc, DB_STGY_ANY, &diff);
78 	db_symbol_values(sym, &symname, 0);
79 
80 	if (symname) {
81 		if (diff == 0)
82 			db_printf("%s", symname);
83 		else
84 			db_printf("<%s+%"DDB_EXPR_FMT"x>", symname, diff);
85 		db_printf("\t[addr:%#"PRIxVADDR"]", loc);
86 	} else {
87 		db_printf("%#"PRIxVADDR, loc);
88 	}
89 }
90 
91 ////////////////////////////////////////////////////////////
92 // 16-bit instructions
93 
94 /*
95  * This is too tightly wedged in to make it worth trying to make it
96  * table-driven. But I'm going to hack it up to use a 1-level switch.
97  *
98  * Note that quite a few instructions depend on the architecture word
99  * size. I've used the #defines for that to conditionalize it, on the
100  * grounds that ddb is disassembling itself so the build machine
101  * version is the target machine version. This is not true for crash
102  * necessarily but I don't think
103  */
104 
105 #define COMBINE(op, q) (((op) << 2) | (q))
106 
107 #define IN_Q0(op) COMBINE(op, OPCODE16_Q0)
108 #define IN_Q1(op) COMBINE(op, OPCODE16_Q1)
109 #define IN_Q2(op) COMBINE(op, OPCODE16_Q2)
110 
111 /*
112  * All the 16-bit immediate bit-wrangling is done in uint32_t, which
113  * is sufficient, but on RV64 the resulting values should be printed
114  * as 64-bit. Continuing the assumption that we're disassembling for
115  * the size we're built on, do nothing for RV32 and sign-extend from
116  * 32 to 64 for RV64. (And bail on RV128 since it's not clear what
117  * the C type sizes are going to be there anyway...)
118  */
119 static unsigned long
120 maybe_signext64(uint32_t x)
121 {
122 #if __riscv_xlen == 32
123 	return x;
124 #elif __riscv_xlen == 64
125 	uint64_t xx;
126 
127 	xx = ((x & 0x80000000) ? 0xffffffff00000000 : 0) | x;
128 	return xx;
129 #else
130 #error Oops.
131 #endif
132 }
133 
134 static int
135 db_disasm_16(db_addr_t loc, uint32_t insn, bool altfmt)
136 {
137 	/* note: insn needs to be uint32_t for immediate computations */
138 
139 	uint32_t imm;
140 	unsigned rd, rs1, rs2;
141 
142 	switch (COMBINE(INSN16_FUNCT3(insn), INSN16_QUADRANT(insn))) {
143 	    case IN_Q0(Q0_ADDI4SPN):
144 		rd = INSN16_RS2x(insn);
145 		imm = INSN16_IMM_CIW(insn);
146 		if (imm == 0) {
147 			/* reserved (all bits 0 -> invalid) */
148 			return EINVAL;
149 		}
150 		db_printf("c.addi4spn %s, 0x%x\n", riscv_registers[rd], imm);
151 		break;
152 	    case IN_Q0(Q0_FLD_LQ):
153 		rs1 = INSN16_RS1x(insn);
154 		rd = INSN16_RS2x(insn);
155 #if __riscv_xlen < 128
156 		imm = INSN16_IMM_CL_D(insn);
157 		db_printf("c.fld f%d, %d(%s)\n", rd, (int32_t)imm,
158 			  riscv_registers[rs1]);
159 #else
160 		imm = INSN16_IMM_CL_Q(insn);
161 		db_printf("c.lq %s, %d(%s)\n", riscv_registers[rd],
162 			  (int32_t)imm, riscv_registers[rs1]);
163 #endif
164 		break;
165 	    case IN_Q0(Q0_LW):
166 		rs1 = INSN16_RS1x(insn);
167 		rd = INSN16_RS2x(insn);
168 		imm = INSN16_IMM_CL_W(insn);
169 		db_printf("c.lw %s, %d(%s)\n", riscv_registers[rd],
170 			  (int32_t)imm, riscv_registers[rs1]);
171 		break;
172 	    case IN_Q0(Q0_FLW_LD):
173 		rs1 = INSN16_RS1x(insn);
174 		rd = INSN16_RS2x(insn);
175 #if __riscv_xlen == 32
176 		imm = INSN16_IMM_CL_W(insn);
177 		db_printf("c.flw f%d, %d(%s)\n", rd, (int32_t)imm,
178 			  riscv_registers[rs1]);
179 #else
180 		imm = INSN16_IMM_CL_D(insn);
181 		db_printf("c.ld %s, %d(%s)\n", riscv_registers[rd],
182 			  (int32_t)imm, riscv_registers[rs1]);
183 #endif
184 		break;
185 	    case IN_Q0(Q0_FSD_SQ):
186 		rs1 = INSN16_RS1x(insn);
187 		rs2 = INSN16_RS2x(insn);
188 #if __riscv_xlen < 128
189 		imm = INSN16_IMM_CS_D(insn);
190 		db_printf("c.fsd f%d, %d(%s)\n", rs2, (int32_t)imm,
191 			  riscv_registers[rs1]);
192 #else
193 		imm = INSN16_IMM_CS_Q(insn);
194 		db_printf("c.sq %s, %d(%s)\n", riscv_registers[rs2],
195 			  (int32_t)imm, riscv_registers[rs1]);
196 #endif
197 		break;
198 	    case IN_Q0(Q0_SW):
199 		rs1 = INSN16_RS1x(insn);
200 		rs2 = INSN16_RS2x(insn);
201 		imm = INSN16_IMM_CS_W(insn);
202 		db_printf("c.sw %s, %d(%s)\n", riscv_registers[rs2],
203 			  (int32_t)imm, riscv_registers[rs1]);
204 		break;
205 	    case IN_Q0(Q0_FSW_SD):
206 		rs1 = INSN16_RS1x(insn);
207 		rs2 = INSN16_RS2x(insn);
208 #if __riscv_xlen == 32
209 		imm = INSN16_IMM_CS_W(insn);
210 		db_printf("c.fsw f%d, %d(%s)\n", rs2, (int32_t)imm,
211 			  riscv_registers[rs1]);
212 #else
213 		imm = INSN16_IMM_CS_D(insn);
214 		db_printf("c.sd %s, %d(%s)\n", riscv_registers[rs2],
215 			  (int32_t)imm, riscv_registers[rs1]);
216 #endif
217 		break;
218 	    case IN_Q1(Q1_NOP_ADDI):
219 		rd = INSN16_RS1(insn);
220 		imm = INSN16_IMM_CI_K(insn);
221 		if (rd == 0 && imm == 0) {
222 			db_printf("c.nop\n");
223 		} else if (rd == 0 && imm != 0) {
224 			/* undefined hint */
225 			return EINVAL;
226 		} else if (rd != 0 && imm == 0) {
227 			/* undefined hint */
228 			return EINVAL;
229 		} else {
230 			db_printf("c.addi %s, %s, 0x%lx\n",
231 				  riscv_registers[rd],
232 				  riscv_registers[rd],
233 				  maybe_signext64(imm));
234 		}
235 		break;
236 	    case IN_Q1(Q1_JAL_ADDIW):
237 #if __riscv_xlen == 32
238 		imm = INSN16_IMM_CJ(insn);
239 		db_printf("c.jal ");
240 		db_print_addr(loc + (int32_t)imm);
241 		db_printf("\n");
242 #else
243 		rd = INSN16_RS1(insn);
244 		imm = INSN16_IMM_CI_K(insn);
245 		db_printf("c.addiw %s, %s, 0x%lx\n", riscv_registers[rd],
246 			  riscv_registers[rd], maybe_signext64(imm));
247 #endif
248 		break;
249 	    case IN_Q1(Q1_LI):
250 		rd = INSN16_RS1(insn);
251 		imm = INSN16_IMM_CI_K(insn);
252 		db_printf("c.li %s, 0x%lx\n", riscv_registers[rd],
253 			  maybe_signext64(imm));
254 		break;
255 	    case IN_Q1(Q1_ADDI16SP_LUI):
256 		rd = INSN16_RS1(insn);
257 		if (rd == 2/*sp*/) {
258 			imm = INSN16_IMM_CI_K4(insn);
259 			db_printf("c.add16sp sp, 0x%lx\n",
260 				  maybe_signext64(imm));
261 		}
262 		else {
263 			imm = INSN16_IMM_CI_K12(insn);
264 			db_printf("c.lui %s, 0x%lx\n", riscv_registers[rd],
265 				  maybe_signext64(imm));
266 		}
267 		break;
268 	    case IN_Q1(Q1_MISC):
269 		imm = INSN16_IMM_CI_K(insn);
270 		rd = INSN16_RS1x(insn);
271 		switch (INSN16_FUNCT2a(insn)) {
272 		    case Q1MISC_SRLI:
273 		    case Q1MISC_SRAI:
274 #if __riscv_xlen == 32
275 			if (imm > 31) {
276 				/* reserved */
277 				return EINVAL;
278 			}
279 #elif __riscv_xlen == 64
280 			/* drop the sign-extension */
281 			imm &= 63;
282 #elif __riscv_xlen == 128
283 			if (imm == 0) {
284 				imm = 64;
285 			}
286 			else {
287 				imm &= 127;
288 			}
289 #endif
290 			db_printf("c.%s %s, %d\n",
291 				  INSN16_FUNCT2a(insn) == Q1MISC_SRLI ?
292 					  "srli" : "srai",
293 				  riscv_registers[rd], imm);
294 			break;
295 		    case Q1MISC_ANDI:
296 			db_printf("c.andi %s, 0x%lx\n", riscv_registers[rd],
297 				  maybe_signext64(imm));
298 			break;
299 		    case Q1MISC_MORE:
300 			rs2 = INSN16_RS2x(insn);
301 			switch (INSN16_FUNCT3c(insn)) {
302 			    case Q1MORE_SUB:
303 				db_printf("c.sub");
304 				break;
305 			    case Q1MORE_XOR:
306 				db_printf("c.xor");
307 				break;
308 			    case Q1MORE_OR:
309 				db_printf("c.or");
310 				break;
311 			    case Q1MORE_AND:
312 				db_printf("c.and");
313 				break;
314 			    case Q1MORE_SUBW:
315 				db_printf("c.subw");
316 				break;
317 			    case Q1MORE_ADDW:
318 				db_printf("c.addw");
319 				break;
320 			    default:
321 				return EINVAL;
322 			}
323 			db_printf(" %s, %s, %s\n", riscv_registers[rd],
324 				  riscv_registers[rd], riscv_registers[rs2]);
325 			break;
326 		}
327 		break;
328 	    case IN_Q1(Q1_J):
329 		imm = INSN16_IMM_CJ(insn);
330 		db_printf("c.j ");
331 		db_print_addr(loc + (int32_t)imm);
332 		db_printf("\n");
333 		break;
334 	    case IN_Q1(Q1_BEQZ):
335 		rs1 = INSN16_RS1x(insn);
336 		imm = INSN16_IMM_CB(insn);
337 		db_printf("c.beqz %s, ", riscv_registers[rs1]);
338 		db_print_addr(loc + (int32_t)imm);
339 		db_printf("\n");
340 		break;
341 	    case IN_Q1(Q1_BNEZ):
342 		rs1 = INSN16_RS1x(insn);
343 		imm = INSN16_IMM_CB(insn);
344 		db_printf("c.bnez %s, ", riscv_registers[rs1]);
345 		db_print_addr(loc + (int32_t)imm);
346 		db_printf("\n");
347 		break;
348 	    case IN_Q2(Q2_SLLI):
349 		rd = INSN16_RS1(insn);
350 		imm = INSN16_IMM_CI_K(insn);
351 #if __riscv_xlen == 32
352 		if (imm > 31) {
353 				/* reserved */
354 			return EINVAL;
355 		}
356 #elif __riscv_xlen == 64
357 		/* drop the sign-extension */
358 		imm &= 63;
359 #elif __riscv_xlen == 128
360 		if (imm == 0) {
361 			imm = 64;
362 		}
363 		else {
364 			/*
365 			 * XXX the manual is not clear on
366 			 * whether this is like c.srli/c.srai
367 			 * or truncates to 6 bits. I'm assuming
368 			 * the former.
369 			 */
370 			imm &= 127;
371 		}
372 #endif
373 		db_printf("c.slli %s, %d\n", riscv_registers[rd], imm);
374 		break;
375 	    case IN_Q2(Q2_FLDSP_LQSP):
376 		rd = INSN16_RS1(insn);
377 #if __riscv_xlen < 128
378 		imm = INSN16_IMM_CI_D(insn);
379 		db_printf("c.fldsp f%d, %d(sp)\n", rd, imm);
380 #else
381 		if (rd == 0) {
382 			/* reserved */
383 			return EINVAL;
384 		}
385 		imm = INSN16_IMM_CI_Q(insn);
386 		db_printf("c.lqsp %s, %d(sp)\n", riscv_registers[rd], imm);
387 #endif
388 		break;
389 	    case IN_Q2(Q2_LWSP):
390 		rd = INSN16_RS1(insn);
391 		if (rd == 0) {
392 			/* reserved */
393 			return EINVAL;
394 		}
395 		imm = INSN16_IMM_CI_W(insn);
396 		db_printf("c.lwsp %s, %d(sp)\n", riscv_registers[rd], imm);
397 		break;
398 	    case IN_Q2(Q2_FLWSP_LDSP):
399 		rd = INSN16_RS1(insn);
400 #if __riscv_xlen == 32
401 		imm = INSN16_IMM_CI_W(insn);
402 		db_printf("c.flwsp f%d, %d(sp)\n", rd, imm);
403 #else
404 		if (rd == 0) {
405 			/* reserved */
406 			return EINVAL;
407 		}
408 		imm = INSN16_IMM_CI_D(insn);
409 		db_printf("c.ldsp %s, %d(sp)\n", riscv_registers[rd], imm);
410 #endif
411 		break;
412 	    case IN_Q2(Q2_MISC):
413 		rs1 = INSN16_RS1(insn);
414 		rs2 = INSN16_RS2(insn);
415 		switch (INSN16_FUNCT1b(insn)) {
416 		    case Q2MISC_JR_MV:
417 			if (rs1 == 0) {
418 				return EINVAL;
419 			} else if (rs2 == 0) {
420 				db_printf("c.jr %s\n", riscv_registers[rs1]);
421 			} else {
422 				db_printf("c.mv %s, %s\n",
423 					  riscv_registers[rs1],
424 					  riscv_registers[rs2]);
425 			}
426 			break;
427 		    case Q2MISC_EBREAK_JALR_ADD:
428 			if (rs1 == 0 && rs2 == 0) {
429 				db_printf("c.ebreak\n");
430 			} else if (rs2 == 0) {
431 				db_printf("c.jalr %s\n", riscv_registers[rs1]);
432 			} else if (rs1 == 0) {
433 				return EINVAL;
434 			} else {
435 				db_printf("c.add %s, %s, %s\n",
436 					  riscv_registers[rs1],
437 					  riscv_registers[rs1],
438 					  riscv_registers[rs2]);
439 			}
440 		    break;
441 		}
442 		break;
443 	    case IN_Q2(Q2_FSDSP_SQSP):
444 		rs2 = INSN16_RS2(insn);
445 #if __riscv_xlen < 128
446 		imm = INSN16_IMM_CSS_D(insn);
447 		db_printf("c.fsdsp f%d, %d(sp)\n", rs2, imm);
448 #else
449 		imm = INSN16_IMM_CSS_Q(insn);
450 		db_printf("c.sqsp %s, %d(sp)\n", riscv_registers[rs2], imm);
451 #endif
452 		break;
453 	    case IN_Q2(Q2_SWSP):
454 		rs2 = INSN16_RS2(insn);
455 		imm = INSN16_IMM_CSS_W(insn);
456 		db_printf("c.swsp %s, %d(sp)\n", riscv_registers[rs2], imm);
457 		break;
458 	    case IN_Q2(Q2_FSWSP_SDSP):
459 		rs2 = INSN16_RS2(insn);
460 #if __riscv_xlen == 32
461 		imm = INSN16_IMM_CSS_W(insn);
462 		db_printf("c.fswsp f%d, %d(sp)\n", rs2, imm);
463 #else
464 		imm = INSN16_IMM_CSS_D(insn);
465 		db_printf("c.sdsp %s, %d(sp)\n", riscv_registers[rs2], imm);
466 #endif
467 		break;
468 	    default:
469 		/* 0b11 marks 32-bit instructions and shouldn't come here */
470 		return EINVAL;
471 	}
472 	return 0;
473 }
474 
475 ////////////////////////////////////////////////////////////
476 // 32-bit instructions
477 
478 /* match flags */
479 #define CHECK_F3	0x0001		/* check funct3 field */
480 #define CHECK_F7	0x0002		/* check funct7 field */
481 #define CHECK_F5	0x0004		/* check tpo of funct7 field only */
482 #define CHECK_RS2	0x0008		/* check rs2 as quaternary opcode */
483 #define SHIFT32		0x0010		/* 32-bit immediate shift */
484 #define SHIFT64		0x0020		/* 64-bit immediate shift */
485 #define RD_0		0x0040		/* rd field should be 0 */
486 #define RS1_0		0x0080		/* rs1 field should be 0 */
487 #define RS2_0		0x0100		/* rs2 field should be 0 */
488 #define IMM_0		0x0200		/* immediate value should be 0 */
489 #define F3AMO		0x0400		/* expect amo size in funct3 */
490 #define F3ROUND		0x0800		/* expect fp rounding mode in funct3 */
491 #define F7SIZE		0x1000		/* expect fp size in funct7:0-1 */
492 #define RS2_FSIZE	0x2000		/* expect fp size in rs2 */
493 #define RS2_FSIZE_INT	0x4000		/* expect fp size in rs2 */
494 #define FENCEFM		0x8000		/* fence mode in top 4 bits of imm */
495 /* do not add more without increasing the field size below */
496 
497 #ifdef _LP64 /* disassembling ourself so can use our build flags... */
498 #define SHIFTNATIVE SHIFT64
499 #else
500 #define SHIFTNATIVE SHIFT32
501 #endif
502 
503 /* print flags */
504 #define MEMORYIMM	0x001		/* print immediate as 0(reg) */
505 #define FENCEIMM	0x002		/* print fence instruction codes */
506 #define DECIMM		0x004  		/* print immediate in decimal */
507 #define BRANCHIMM	0x008		/* print immediate as branch target */
508 #define CSRIMM		0x010		/* immediate is csr number */
509 #define CSRIIMM		0x020		/* ... also an immediate in rs1 */
510 #define AMOAQRL		0x040		/* print acquire/release bits of amo */
511 #define RS2SIZE_FIRST	0x080		/* print rs2 size before funct7 size */
512 #define RD_FREG		0x100		/* rd is a fpu reg */
513 #define RS1_FREG	0x200		/* rs1 is a fpu reg */
514 #define RS2_FREG	0x400		/* rs2 is a fpu reg */
515 #define ISCVT		0x800		/* is an fpu conversion op */
516 /* do not add more without increasing the field size below */
517 
518 #define ALL_FREG (RD_FREG | RS1_FREG | RS2_FREG)
519 #define RS12_FREG (RS1_FREG | RS2_FREG)
520 
521 /* entries for matching within a major opcode */
522 struct riscv_disasm_insn {
523 	const char *name;
524 	unsigned int matchflags: 16,
525 		funct3: 3,
526 		funct7: 7,
527 		rs2: 5;
528 	unsigned int printflags: 12;
529 };
530 
531 /* format codes */
532 #define FMT_R	0
533 #define FMT_R4	1
534 #define FMT_I	2
535 #define FMT_In	3
536 #define FMT_S	4
537 #define FMT_B	5
538 #define FMT_U	6
539 #define FMT_J	7
540 #define FMT_UNKNOWN 8
541 #define FMT_ASSERT 9
542 
543 /* top-level opcode dispatch */
544 struct riscv_disasm32_entry {
545 	uint8_t fmt;
546 	union {
547 		// R4, In, U, J
548 		const char *name;
549 		// R, I, S, B
550 		struct {
551 			const struct riscv_disasm_insn *v;
552 			unsigned n;
553 		} entries;
554 	} u;
555 };
556 
557 #define INSN_F3(n, f3, moretests, pflags) \
558 	{						\
559 		.name = n,				\
560 		.matchflags = CHECK_F3 | moretests,	\
561 		.funct3 = f3, .funct7 = 0, .rs2 = 0,	\
562 		.printflags = pflags,			\
563 	}
564 
565 #define INSN_F5(n, f5, moretests, pflags) \
566 	{						\
567 		.name = n,				\
568 		.matchflags = CHECK_F7 | CHECK_F5 | moretests,	\
569 		.funct3 = 0, .funct7 = f5 << 2,	.rs2 = 0, \
570 		.printflags = pflags,			\
571 	}
572 
573 #define INSN_F53(n, f5, f3, moretests, pflags) \
574 	{						\
575 		.name = n,				\
576 		.matchflags = CHECK_F7 | CHECK_F5 | CHECK_F3 | moretests, \
577 		.funct3 = f3, .funct7 = f5 << 2, .rs2 = 0, \
578 		.printflags = pflags,			\
579 	}
580 
581 #define INSN_F7(n, f7, moretests, pflags) \
582 	{						\
583 		.name = n,				\
584 		.matchflags = CHECK_F7 | moretests,	\
585 		.funct3 = 0, .funct7 = f7, .rs2 = 0,	\
586 		.printflags = pflags,			\
587 	}
588 
589 #define INSN_F73(n, f7, f3, moretests, pflags) \
590 	{						\
591 		.name = n,				\
592 		.matchflags = CHECK_F7 | CHECK_F3 | moretests,	\
593 		.funct3 = f3, .funct7 = f7, .rs2 = 0,	\
594 		.printflags = pflags,			\
595 	}
596 
597 #define INSN_F37(n, f3, f7, moretests, pflags) \
598 	INSN_F73(n, f7, f3, moretests, pflags)
599 
600 #define INSN_USER(n, rs2val, moretests, pflags) \
601 	{						\
602 		.name = n,				\
603 		.matchflags = CHECK_F7 | CHECK_F3 | CHECK_RS2 | moretests, \
604 		.funct3 = SYSTEM_PRIV, .funct7 = PRIV_USER, \
605 		.rs2 = rs2val,				\
606 		.printflags = pflags,			\
607 	}
608 
609 #define INSN_SYSTEM(n, rs2val, moretests, pflags) \
610 	{						\
611 		.name = n,				\
612 		.matchflags = CHECK_F7 | CHECK_F3 | CHECK_RS2 | moretests, \
613 		.funct3 = SYSTEM_PRIV, .funct7 = PRIV_SYSTEM, \
614 		.rs2 = rs2val,				\
615 		.printflags = pflags,			\
616 	}
617 
618 #define INSN_MACHINE(n, rs2val, moretests, pflags) \
619 	{						\
620 		.name = n,				\
621 		.matchflags = CHECK_F7 | CHECK_F3 | CHECK_RS2 | moretests, \
622 		.funct3 = SYSTEM_PRIV, .funct7 = PRIV_MACHINE, \
623 		.rs2 = rs2val,				\
624 		.printflags = pflags,			\
625 	}
626 
627 static const struct riscv_disasm_insn riscv_disasm_miscmem[] = {
628 	INSN_F3("fence",   MISCMEM_FENCE,  RD_0 | RS1_0 | FENCEFM, FENCEIMM),
629 	INSN_F3("fence.i", MISCMEM_FENCEI, RD_0 | RS1_0 | IMM_0, 0),
630 };
631 
632 static const struct riscv_disasm_insn riscv_disasm_load[] = {
633 	INSN_F3("lb", LOAD_LB, 0, MEMORYIMM),
634 	INSN_F3("lh", LOAD_LH, 0, MEMORYIMM),
635 	INSN_F3("lw", LOAD_LW, 0, MEMORYIMM),
636 	INSN_F3("ld", LOAD_LD, 0, MEMORYIMM),
637 	INSN_F3("lbu", LOAD_LBU, 0, MEMORYIMM),
638 	INSN_F3("lhu", LOAD_LHU, 0, MEMORYIMM),
639 	INSN_F3("lwu", LOAD_LWU, 0, MEMORYIMM),
640 };
641 
642 static const struct riscv_disasm_insn riscv_disasm_loadfp[] = {
643 	INSN_F3("flw", LOADFP_FLW, 0, MEMORYIMM | RD_FREG),
644 	INSN_F3("fld", LOADFP_FLD, 0, MEMORYIMM | RD_FREG),
645 	INSN_F3("flq", LOADFP_FLQ, 0, MEMORYIMM | RD_FREG),
646 };
647 
648 static const struct riscv_disasm_insn riscv_disasm_opimm[] = {
649 	INSN_F3("nop", OP_ADDSUB, RD_0 | RS1_0 | IMM_0, 0),
650 	INSN_F3("addi", OP_ADDSUB, 0, 0),
651 	INSN_F3("slti", OP_SLT, 0, 0),
652 	INSN_F3("sltiu", OP_SLTU, 0, 0),
653 	INSN_F3("xori", OP_XOR, 0, 0),
654 	INSN_F3("ori", OP_OR, 0, 0),
655 	INSN_F3("andi", OP_AND, 0, 0),
656 	INSN_F37("slli", OP_SLL, OP_ARITH, SHIFTNATIVE, DECIMM),
657 	INSN_F37("srli", OP_SRX, OP_ARITH, SHIFTNATIVE, DECIMM),
658 	INSN_F37("srai", OP_SRX, OP_NARITH, SHIFTNATIVE, DECIMM),
659 };
660 
661 static const struct riscv_disasm_insn riscv_disasm_opimm32[] = {
662 	INSN_F3("addiw", OP_ADDSUB, 0, 0),
663 	INSN_F37("slliw", OP_SLL, OP_ARITH, SHIFT32, DECIMM),
664 	INSN_F37("srliw", OP_SRX, OP_ARITH, SHIFT32, DECIMM),
665 	INSN_F37("sraiw", OP_SRX, OP_NARITH, SHIFT32, DECIMM),
666 };
667 
668 static const struct riscv_disasm_insn riscv_disasm_store[] = {
669 	INSN_F3("sb", STORE_SB, 0, MEMORYIMM),
670 	INSN_F3("sh", STORE_SH, 0, MEMORYIMM),
671 	INSN_F3("sw", STORE_SW, 0, MEMORYIMM),
672 	INSN_F3("sd", STORE_SD, 0, MEMORYIMM),
673 };
674 
675 static const struct riscv_disasm_insn riscv_disasm_storefp[] = {
676 	INSN_F3("fsw", STOREFP_FSW, 0, MEMORYIMM | RS2_FREG),
677 	INSN_F3("fsd", STOREFP_FSD, 0, MEMORYIMM | RS2_FREG),
678 	INSN_F3("fsq", STOREFP_FSQ, 0, MEMORYIMM | RS2_FREG),
679 };
680 
681 static const struct riscv_disasm_insn riscv_disasm_branch[] = {
682 	INSN_F3("beq", BRANCH_BEQ, 0, BRANCHIMM),
683 	INSN_F3("bne", BRANCH_BNE, 0, BRANCHIMM),
684 	INSN_F3("blt", BRANCH_BLT, 0, BRANCHIMM),
685 	INSN_F3("bge", BRANCH_BGE, 0, BRANCHIMM),
686 	INSN_F3("bltu", BRANCH_BLTU, 0, BRANCHIMM),
687 	INSN_F3("bgeu", BRANCH_BGEU, 0, BRANCHIMM),
688 };
689 
690 static const struct riscv_disasm_insn riscv_disasm_system[] = {
691 	INSN_F3("csrw", SYSTEM_CSRRW, RD_0, CSRIMM),
692 	INSN_F3("csrrw", SYSTEM_CSRRW, 0, CSRIMM),
693 	INSN_F3("csrr", SYSTEM_CSRRS, RS1_0, CSRIMM),
694 	INSN_F3("csrrs", SYSTEM_CSRRS, 0, CSRIMM),
695 	INSN_F3("csrrc", SYSTEM_CSRRC, 0, CSRIMM),
696 	INSN_F3("csrwi", SYSTEM_CSRRWI, RD_0, CSRIIMM),
697 	INSN_F3("csrrwi", SYSTEM_CSRRWI, 0, CSRIIMM),
698 	INSN_F3("csrrsi", SYSTEM_CSRRSI, 0, CSRIIMM),
699 	INSN_F3("csrrci", SYSTEM_CSRRCI, 0, CSRIIMM),
700 	INSN_F37("sfence.vma", SYSTEM_PRIV, PRIV_SFENCE_VMA, RD_0, 0),
701 	INSN_F37("hfence.bvma", SYSTEM_PRIV, PRIV_HFENCE_BVMA, 0, 0),
702 	INSN_F37("hfence.gvma", SYSTEM_PRIV, PRIV_HFENCE_GVMA, 0, 0),
703 	INSN_USER("ecall", USER_ECALL, RD_0 | RS1_0, 0),
704 	INSN_USER("ebreak", USER_EBREAK, RD_0 | RS1_0, 0),
705 	INSN_USER("uret", USER_URET, RD_0 | RS1_0, 0),
706 	INSN_SYSTEM("sret", SYSTEM_SRET, RD_0 | RS1_0, 0),
707 	INSN_SYSTEM("wfi", SYSTEM_WFI, RD_0 | RS1_0, 0),
708 	INSN_MACHINE("mret", MACHINE_MRET, RD_0 | RS1_0, 0),
709 };
710 
711 static const struct riscv_disasm_insn riscv_disasm_amo[] = {
712 	INSN_F5("amoadd",  AMO_ADD,  F3AMO, AMOAQRL),
713 	INSN_F5("amoswap", AMO_SWAP, F3AMO, AMOAQRL),
714 	INSN_F5("lr",      AMO_LR,   F3AMO | RS2_0, AMOAQRL),
715 	INSN_F5("sc",      AMO_SC,   F3AMO, AMOAQRL),
716 	INSN_F5("amoxor",  AMO_XOR,  F3AMO, AMOAQRL),
717 	INSN_F5("amoor",   AMO_OR,   F3AMO, AMOAQRL),
718 	INSN_F5("amoand",  AMO_AND,  F3AMO, AMOAQRL),
719 	INSN_F5("amomin",  AMO_MIN,  F3AMO, AMOAQRL),
720 	INSN_F5("amomax",  AMO_MAX,  F3AMO, AMOAQRL),
721 	INSN_F5("amominu", AMO_MINU, F3AMO, AMOAQRL),
722 	INSN_F5("amomaxu", AMO_MAXU, F3AMO, AMOAQRL),
723 };
724 
725 static const struct riscv_disasm_insn riscv_disasm_op[] = {
726 	INSN_F37("add", OP_ADDSUB, OP_ARITH, 0, 0),
727 	INSN_F37("sub", OP_ADDSUB, OP_NARITH, 0, 0),
728 	INSN_F37("sll", OP_SLL,    OP_ARITH, 0, 0),
729 	INSN_F37("slt", OP_SLT,    OP_ARITH, 0, 0),
730 	INSN_F37("sltu", OP_SLTU,  OP_ARITH, 0, 0),
731 	INSN_F37("xor", OP_XOR,    OP_ARITH, 0, 0),
732 	INSN_F37("srl", OP_SRX,    OP_ARITH, 0, 0),
733 	INSN_F37("sra", OP_SRX,    OP_NARITH, 0, 0),
734 	INSN_F37("or",  OP_OR,     OP_ARITH, 0, 0),
735 	INSN_F37("and", OP_AND,    OP_ARITH, 0, 0),
736 	INSN_F37("mul", OP_MUL,    OP_MULDIV, 0, 0),
737 	INSN_F37("mulh", OP_MULH,  OP_MULDIV, 0, 0),
738 	INSN_F37("mulhsu", OP_MULHSU, OP_MULDIV, 0, 0),
739 	INSN_F37("mulhu", OP_MULHU, OP_MULDIV, 0, 0),
740 	INSN_F37("div", OP_DIV,    OP_MULDIV, 0, 0),
741 	INSN_F37("divu", OP_DIVU,  OP_MULDIV, 0, 0),
742 	INSN_F37("rem", OP_REM,    OP_MULDIV, 0, 0),
743 	INSN_F37("remu", OP_REMU,  OP_MULDIV, 0, 0),
744 };
745 
746 static const struct riscv_disasm_insn riscv_disasm_op32[] = {
747 	INSN_F37("addw", OP_ADDSUB, OP_ARITH, 0, 0),
748 	INSN_F37("subw", OP_ADDSUB, OP_NARITH, 0, 0),
749 	INSN_F37("sllw", OP_SLL,    OP_ARITH, 0, 0),
750 	INSN_F37("srlw", OP_SRX,    OP_ARITH, 0, 0),
751 	INSN_F37("sraw", OP_SRX,    OP_NARITH, 0, 0),
752 	INSN_F37("mulw", OP_MUL,    OP_MULDIV, 0, 0),
753 	INSN_F37("divw", OP_DIV,    OP_MULDIV, 0, 0),
754 	INSN_F37("divuw", OP_DIVU,  OP_MULDIV, 0, 0),
755 	INSN_F37("remw", OP_REM,    OP_MULDIV, 0, 0),
756 	INSN_F37("remuw", OP_REMU,  OP_MULDIV, 0, 0),
757 };
758 
759 static const struct riscv_disasm_insn riscv_disasm_opfp[] = {
760 	INSN_F5("fadd", OPFP_ADD, F7SIZE|F3ROUND, ALL_FREG),
761 	INSN_F5("fsub", OPFP_SUB, F7SIZE|F3ROUND, ALL_FREG),
762 	INSN_F5("fmul", OPFP_MUL, F7SIZE|F3ROUND, ALL_FREG),
763 	INSN_F5("fdiv", OPFP_DIV, F7SIZE|F3ROUND, ALL_FREG),
764 	INSN_F53("fsgnj", OPFP_SGNJ, SGN_SGNJ, F7SIZE, ALL_FREG),
765 	INSN_F53("fsgnjn", OPFP_SGNJ, SGN_SGNJN, F7SIZE, ALL_FREG),
766 	INSN_F53("fsgnjx", OPFP_SGNJ, SGN_SGNJX, F7SIZE, ALL_FREG),
767 	INSN_F53("fmin", OPFP_MINMAX, MINMAX_MIN, F7SIZE, ALL_FREG),
768 	INSN_F53("fmax", OPFP_MINMAX, MINMAX_MAX, F7SIZE, ALL_FREG),
769 	INSN_F5("fcvt", OPFP_CVTFF, F7SIZE|F3ROUND|RS2_FSIZE,
770 		ISCVT | ALL_FREG),
771 	INSN_F5("fsqrt", OPFP_SQRT, F7SIZE|F3ROUND|RS2_0, ALL_FREG),
772 	INSN_F53("fle", OPFP_CMP, CMP_LE, F7SIZE, RS12_FREG),
773 	INSN_F53("flt", OPFP_CMP, CMP_LT, F7SIZE, RS12_FREG),
774 	INSN_F53("feq", OPFP_CMP, CMP_EQ, F7SIZE, RS12_FREG),
775 	INSN_F5("fcvt", OPFP_CVTIF, F7SIZE|F3ROUND|RS2_FSIZE|RS2_FSIZE_INT,
776 		ISCVT | RS2SIZE_FIRST | RS1_FREG),
777 	INSN_F5("fcvt", OPFP_CVTFI, F7SIZE|F3ROUND|RS2_FSIZE|RS2_FSIZE_INT,
778 		ISCVT | RD_FREG),
779 	INSN_F53("fclass", OPFP_MVFI_CLASS, MVFI_CLASS_CLASS, F7SIZE|RS2_0,
780 		 RS1_FREG),
781 	INSN_F73("fmv.x.w", (OPFP_MVFI_CLASS << 2) | OPFP_S, MVFI_CLASS_MVFI,
782 		 RS2_0, RS1_FREG),
783 	INSN_F73("fmv.w.x", (OPFP_MVIF << 2) | OPFP_S, 0,
784 		 RS2_0, RD_FREG),
785 	INSN_F73("fmv.x.d", (OPFP_MVFI_CLASS << 2) | OPFP_D, MVFI_CLASS_MVFI,
786 		 RS2_0, RS1_FREG),
787 	INSN_F73("fmv.d.x", (OPFP_MVIF << 2) | OPFP_D, 0,
788 		 RS2_0, RD_FREG),
789 };
790 
791 #define TABLE(table) \
792 	.u.entries.v = table, .u.entries.n = __arraycount(table)
793 
794 static const struct riscv_disasm32_entry riscv_disasm32[32] = {
795 	[OPCODE_AUIPC] =   { .fmt = FMT_U, .u.name = "auipc" },
796 	[OPCODE_LUI] =     { .fmt = FMT_U, .u.name = "lui" },
797 	[OPCODE_JAL] =     { .fmt = FMT_J, .u.name = "jal" },
798 	[OPCODE_JALR] =    { .fmt = FMT_In, .u.name = "jalr" },
799 	[OPCODE_MISCMEM] = { .fmt = FMT_I, TABLE(riscv_disasm_miscmem) },
800 	[OPCODE_LOAD] =    { .fmt = FMT_I, TABLE(riscv_disasm_load) },
801 	[OPCODE_LOADFP] =  { .fmt = FMT_I, TABLE(riscv_disasm_loadfp) },
802 	[OPCODE_OPIMM] =   { .fmt = FMT_I, TABLE(riscv_disasm_opimm) },
803 	[OPCODE_OPIMM32] = { .fmt = FMT_I, TABLE(riscv_disasm_opimm32) },
804 	[OPCODE_STORE] =   { .fmt = FMT_S, TABLE(riscv_disasm_store) },
805 	[OPCODE_STOREFP] = { .fmt = FMT_S, TABLE(riscv_disasm_storefp) },
806 	[OPCODE_BRANCH] =  { .fmt = FMT_B, TABLE(riscv_disasm_branch) },
807 	[OPCODE_SYSTEM] =  { .fmt = FMT_R, TABLE(riscv_disasm_system) },
808 	[OPCODE_AMO] =     { .fmt = FMT_R, TABLE(riscv_disasm_amo) },
809 	[OPCODE_OP] =      { .fmt = FMT_R, TABLE(riscv_disasm_op) },
810 	[OPCODE_OP32] =    { .fmt = FMT_R, TABLE(riscv_disasm_op32) },
811 	[OPCODE_OPFP] =    { .fmt = FMT_R, TABLE(riscv_disasm_opfp) },
812 	[OPCODE_MADD] =    { .fmt = FMT_R4, .u.name = "fmadd" },
813 	[OPCODE_MSUB] =    { .fmt = FMT_R4, .u.name = "fmsub" },
814 	[OPCODE_NMADD] =   { .fmt = FMT_R4, .u.name = "fnmadd" },
815 	[OPCODE_NMSUB] =   { .fmt = FMT_R4, .u.name = "fnmsub" },
816 	[OPCODE_CUSTOM0] = { .fmt = FMT_UNKNOWN },
817 	[OPCODE_CUSTOM1] = { .fmt = FMT_UNKNOWN },
818 	[OPCODE_CUSTOM2] = { .fmt = FMT_UNKNOWN },
819 	[OPCODE_CUSTOM3] = { .fmt = FMT_UNKNOWN },
820 	[OPCODE_rsvd21] =  { .fmt = FMT_UNKNOWN },
821 	[OPCODE_rsvd26] =  { .fmt = FMT_UNKNOWN },
822 	[OPCODE_rsvd29] =  { .fmt = FMT_UNKNOWN },
823 	[OPCODE_X48a] =    { .fmt = FMT_ASSERT },
824 	[OPCODE_X48b] =    { .fmt = FMT_ASSERT },
825 	[OPCODE_X64] =     { .fmt = FMT_ASSERT },
826 	[OPCODE_X80] =     { .fmt = FMT_ASSERT },
827 };
828 
829 static const struct riscv_disasm_insn *
830 riscv_disasm_match(const struct riscv_disasm_insn *table, unsigned num,
831 		   uint32_t insn, uint32_t imm)
832 {
833 	unsigned i, f3, f7, testf7;
834 	const struct riscv_disasm_insn *info;
835 
836 	f3 = INSN_FUNCT3(insn);
837 	f7 = INSN_FUNCT7(insn);
838 	for (i=0; i<num; i++) {
839 		info = &table[i];
840 
841 		/* always check funct3 first */
842 		if (info->matchflags & CHECK_F3) {
843 			if (info->funct3 != f3) {
844 				continue;
845 			}
846 		}
847 
848 		/* now funct7 */
849 		testf7 = f7;
850 		if (info->matchflags & SHIFT64) {
851 			/* shift count leaks into the bottom bit of funct7 */
852 			testf7 &= 0b1111110;
853 		}
854 		if (info->matchflags & CHECK_F5) {
855 			/* other stuff in the bottom two bits, don't look */
856 			testf7 &= 0b1111100;
857 		}
858 		if (info->matchflags & CHECK_F7) {
859 			if (info->funct7 != testf7) {
860 				continue;
861 			}
862 		}
863 
864 		/* finally rs2 as the 4th opcode field */
865 		if (info->matchflags & CHECK_RS2) {
866 			if (info->rs2 != INSN_RS2(insn)) {
867 				continue;
868 			}
869 		}
870 
871 		/* check fields that are supposed to be 0 */
872 		if (info->matchflags & RD_0) {
873 			if (INSN_RD(insn) != 0) {
874 				continue;
875 			}
876 		}
877 		if (info->matchflags & RS1_0) {
878 			if (INSN_RS1(insn) != 0) {
879 				continue;
880 			}
881 		}
882 		if (info->matchflags & RS2_0) {
883 			/* this could be folded into CHECK_RS2 */
884 			/* (but would make the initializations uglier) */
885 			if (INSN_RS2(insn) != 0) {
886 				continue;
887 			}
888 		}
889 		if (info->matchflags & IMM_0) {
890 			if (imm != 0) {
891 				continue;
892 			}
893 		}
894 
895 		/* other checks */
896 		if (info->matchflags & F3AMO) {
897 			if (f3 != AMO_W && f3 != AMO_D) {
898 				continue;
899 			}
900 		}
901 		if (info->matchflags & F3ROUND) {
902 			switch (f3) {
903 			    case ROUND_RNE:
904 			    case ROUND_RTZ:
905 			    case ROUND_RDN:
906 			    case ROUND_RUP:
907 			    case ROUND_RMM:
908 			    case ROUND_DYN:
909 				break;
910 			    default:
911 				continue;
912 			}
913 		}
914 		if (info->matchflags & F7SIZE) {
915 			/* fpu size bits at bottom of funct7 */
916 			/* always floating sizes */
917 			switch (f7 & 3) {
918 			    case OPFP_S:
919 			    case OPFP_D:
920 			    case OPFP_Q:
921 				break;
922 			    default:
923 				continue;
924 			}
925 		}
926 		if (info->matchflags & RS2_FSIZE) {
927 			/* fpu size bits in rs2 field */
928 			if (info->matchflags & RS2_FSIZE_INT) {
929 				/* integer sizes */
930 				switch (INSN_RS2(insn)) {
931 				    case OPFP_W:
932 				    case OPFP_WU:
933 				    case OPFP_L:
934 				    case OPFP_LU:
935 					break;
936 				    default:
937 					continue;
938 				}
939 			}
940 			else {
941 				/* floating sizes */
942 				switch (INSN_RS2(insn)) {
943 				    case OPFP_S:
944 				    case OPFP_D:
945 				    case OPFP_Q:
946 					break;
947 				    default:
948 					continue;
949 				}
950 			}
951 		}
952 		if (info->matchflags & FENCEFM) {
953 			/* imm is 12 bits, upper 4 are a fence mode */
954 			switch (imm >> 8) {
955 			    case FENCE_FM_NORMAL:
956 			    case FENCE_FM_TSO:
957 				break;
958 			    default:
959 				continue;
960 			}
961 		}
962 
963 		/* passed all tests */
964 		return info;
965 	}
966 	/* no match */
967 	return NULL;
968 }
969 
970 static void
971 db_print_riscv_fencebits(unsigned bits)
972 {
973 	if (bits == 0) {
974 		db_printf("0");
975 	}
976 	else {
977 		db_printf("%s%s%s%s",
978 			  (bits & FENCE_INPUT) ? "i" : "",
979 			  (bits & FENCE_OUTPUT) ? "o" : "",
980 			  (bits & FENCE_READ) ? "r" : "",
981 			  (bits & FENCE_WRITE) ? "w" : "");
982 	}
983 }
984 
985 static void
986 db_print_riscv_reg(unsigned reg, bool isfreg)
987 {
988 	if (isfreg) {
989 		db_printf("f%d", reg);
990 	}
991 	else {
992 		db_printf("%s", riscv_registers[reg]);
993 	}
994 }
995 
996 static const char *
997 riscv_int_size(unsigned fpsize)
998 {
999 	switch (fpsize) {
1000 	    case OPFP_W: return ".w";
1001 	    case OPFP_WU: return ".wu";
1002 	    case OPFP_L: return ".l";
1003 	    case OPFP_LU: return ".lu";
1004 	    default:
1005 		/* matching should prevent it coming here */
1006 		return ".?";
1007 	}
1008 }
1009 
1010 static const char *
1011 riscv_fp_size(unsigned fpsize)
1012 {
1013 	switch (fpsize) {
1014 	    case OPFP_S: return ".s";
1015 	    case OPFP_D: return ".d";
1016 	    case OPFP_Q: return ".q";
1017 	    default:
1018 		/* matching should prevent it coming here */
1019 		return ".?";
1020 	}
1021 }
1022 
1023 static bool
1024 larger_f_i(unsigned sz1, unsigned sz2)
1025 {
1026 	switch (sz1) {
1027 	    case OPFP_S:
1028 		break;
1029 	    case OPFP_D:
1030 		switch (sz2) {
1031 		    case OPFP_W:
1032 		    case OPFP_WU:
1033 			return true;
1034 		    default:
1035 			break;
1036 		}
1037 		break;
1038 	    case OPFP_Q:
1039 		switch (sz2) {
1040 		    case OPFP_W:
1041 		    case OPFP_WU:
1042 		    case OPFP_L:
1043 		    case OPFP_LU:
1044 			return true;
1045 		    default:
1046 			break;
1047 		}
1048 		break;
1049 	    default:
1050 		/* matching should keep it from coming here */
1051 		break;
1052 	}
1053 	return false;
1054 }
1055 
1056 static bool
1057 larger_f_f(unsigned sz1, unsigned sz2)
1058 {
1059 	switch (sz1) {
1060 	    case OPFP_S:
1061 		break;
1062 	    case OPFP_D:
1063 		switch (sz2) {
1064 		    case OPFP_S:
1065 			return true;
1066 		    default:
1067 			break;
1068 		}
1069 		break;
1070 	    case OPFP_Q:
1071 		switch (sz2) {
1072 		    case OPFP_S:
1073 		    case OPFP_D:
1074 			return true;
1075 		    default:
1076 			break;
1077 		}
1078 		break;
1079 	    default:
1080 		/* matching should keep it from coming here */
1081 		break;
1082 	}
1083 	return false;
1084 }
1085 
1086 static void
1087 db_print_riscv_fpround(const char *sep, unsigned round)
1088 {
1089 	switch (round) {
1090 	    case ROUND_RNE: db_printf("%srne", sep); break;
1091 	    case ROUND_RTZ: db_printf("%srtz", sep); break;
1092 	    case ROUND_RDN: db_printf("%srdn", sep); break;
1093 	    case ROUND_RUP: db_printf("%srup", sep); break;
1094 	    case ROUND_RMM: db_printf("%srmm", sep); break;
1095 	    case ROUND_DYN: break;
1096 	    default:
1097 		/* matching should prevent it coming here */
1098 		db_printf("%s<unknown-rounding-mode>", sep);
1099 		break;
1100 	}
1101 }
1102 
1103 
1104 static void
1105 db_print_riscv_insnname(uint32_t insn, const struct riscv_disasm_insn *info)
1106 {
1107 	db_printf("%s", info->name);
1108 
1109 	/* accumulated mode cruft on the name */
1110 	if (info->matchflags & F3AMO) {
1111 		db_printf("%s", INSN_FUNCT3(insn) == AMO_W ? ".w" : ".d");
1112 	}
1113 	if ((info->matchflags & RS2_FSIZE) &&
1114 	    (info->printflags & RS2SIZE_FIRST)) {
1115 		if (info->matchflags & RS2_FSIZE_INT) {
1116 			db_printf("%s", riscv_int_size(INSN_RS2(insn)));
1117 		}
1118 		else {
1119 			db_printf("%s", riscv_fp_size(INSN_RS2(insn)));
1120 		}
1121 	}
1122 	if (info->matchflags & F7SIZE) {
1123 		db_printf("%s", riscv_fp_size(INSN_FUNCT7(insn) & 3));
1124 	}
1125 	if ((info->matchflags & RS2_FSIZE) &&
1126 	    (info->printflags & RS2SIZE_FIRST) == 0) {
1127 		if (info->matchflags & RS2_FSIZE_INT) {
1128 			db_printf("%s", riscv_int_size(INSN_RS2(insn)));
1129 		}
1130 		else {
1131 			db_printf("%s", riscv_fp_size(INSN_RS2(insn)));
1132 		}
1133 	}
1134 	if (info->matchflags & FENCEFM) {
1135 		/*
1136 		 * The fence mode is the top 4 bits of the instruction,
1137 		 * which is the top 4 bits of funct7, so get it from
1138 		 * there. Elsewhere in this file it's defined in terms
1139 		 * of the immediate though. XXX tidy up
1140 		 */
1141 		if ((INSN_FUNCT7(insn) >> 3) == FENCE_FM_TSO) {
1142 			db_printf(".tso");
1143 		}
1144 	}
1145 	if (info->printflags & AMOAQRL) {
1146 		db_printf("%s%s",
1147 			  INSN_FUNCT7(insn) & AMO_AQ ? ".aq" : "",
1148 			  INSN_FUNCT7(insn) & AMO_RL ? ".rl" : "");
1149 	}
1150 }
1151 
1152 static int
1153 db_disasm_32(db_addr_t loc, uint32_t insn, bool altfmt)
1154 {
1155 	unsigned opcode;
1156 	const struct riscv_disasm32_entry *d;
1157 	unsigned numtable;
1158 	const struct riscv_disasm_insn *table, *info;
1159 	const char *sep = " ";
1160 	uint32_t imm;
1161 
1162 	opcode = INSN_OPCODE32(insn);
1163 	d = &riscv_disasm32[opcode];
1164 	switch (d->fmt) {
1165 	    case FMT_R:
1166 		/* register ops */
1167 		table = d->u.entries.v;
1168 		numtable = d->u.entries.n;
1169 		info = riscv_disasm_match(table, numtable, insn, 0);
1170 		if (info == NULL) {
1171 			return EINVAL;
1172 		}
1173 
1174 		/* name */
1175 		db_print_riscv_insnname(insn, info);
1176 
1177 		/* rd */
1178 		if ((info->matchflags & RD_0) == 0) {
1179 			db_printf("%s", sep);
1180 			db_print_riscv_reg(INSN_RD(insn),
1181 					   info->printflags & RD_FREG);
1182 			sep = ", ";
1183 		}
1184 
1185 		if (info->printflags & CSRIMM) {
1186 			/*
1187 			 * CSR instruction; these appear under a major
1188 			 * opcode with register format, but they
1189 			 * actually use the I format. Sigh. The
1190 			 * immediate field contains the CSR number and
1191 			 * prints _before_ rs1.
1192 			 */
1193 			imm = INSN_IMM_I(insn);
1194 			db_printf("%s0x%x, ", sep, (int32_t)imm);
1195 			db_print_riscv_reg(INSN_RS1(insn),
1196 					   info->printflags & RS1_FREG);
1197 		} else if (info->printflags & CSRIIMM) {
1198 			/*
1199 			 * CSR instruction with immediate; the CSR
1200 			 * number is in the immediate field and the RS1
1201 			 * field contains the immediate. Bleck.
1202 			 */
1203 			imm = INSN_IMM_I(insn);
1204 			db_printf("%s0x%x, %d", sep, (int32_t)imm,
1205 				  INSN_RS1(insn));
1206 		}
1207 		else {
1208 			/* rs1 */
1209 			if ((info->matchflags & RS1_0) == 0) {
1210 				db_printf("%s", sep);
1211 				db_print_riscv_reg(INSN_RS1(insn),
1212 					   info->printflags & RS1_FREG);
1213 				sep = ", ";
1214 			}
1215 
1216 			/* rs2 */
1217 			if ((info->matchflags & RS2_0) == 0 &&
1218 			    (info->matchflags & CHECK_RS2) == 0 &&
1219 			    (info->matchflags & RS2_FSIZE) == 0) {
1220 				db_printf("%s", sep);
1221 				db_print_riscv_reg(INSN_RS2(insn),
1222 					   info->printflags & RS2_FREG);
1223 			}
1224 		}
1225 
1226 		if (info->matchflags & F3ROUND) {
1227 			/*
1228 			 * Suppress rounding mode print for insns that
1229 			 * never round, because gas encodes it as 0
1230 			 * ("rup") rather than the normal default
1231 			 * ("dyn").
1232 			 *
1233 			 * These are: convert float to larger float,
1234 			 * convert int to float larger than the float.
1235 			 */
1236 			bool suppress;
1237 
1238 			if (info->printflags & ISCVT) {
1239 				if (info->matchflags & RS2SIZE_FIRST) {
1240 					/* convert to int */
1241 					suppress = false;
1242 				}
1243 				else if (info->matchflags & RS2_FSIZE_INT) {
1244 					/* convert from int */
1245 					suppress = larger_f_i(
1246 						INSN_FUNCT7(insn) & 3,
1247 						INSN_RS2(insn));
1248 				}
1249 				else {
1250 					/* convert from float */
1251 					suppress = larger_f_f(
1252 						INSN_FUNCT7(insn) & 3,
1253 						INSN_RS2(insn));
1254 				}
1255 			}
1256 			else {
1257 				suppress = false;
1258 			}
1259 
1260 			if (!suppress) {
1261 				db_print_riscv_fpround(sep, INSN_FUNCT3(insn));
1262 			}
1263 		}
1264 
1265 		db_printf("\n");
1266 		break;
1267 	    case FMT_R4:
1268 		db_printf("%s%s f%d, f%d, f%d, f%d", d->u.name,
1269 			  riscv_fp_size(INSN_FUNCT7(insn) & 3),
1270 			  INSN_RD(insn),
1271 			  INSN_RS1(insn),
1272 			  INSN_RS2(insn),
1273 			  INSN_FUNCT7(insn) >> 2);
1274 		db_print_riscv_fpround(", ", INSN_FUNCT3(insn));
1275 		db_printf("\n");
1276 		break;
1277 	    case FMT_I:
1278 		/* immediates */
1279 		imm = INSN_IMM_I(insn);
1280 
1281 		table = d->u.entries.v;
1282 		numtable = d->u.entries.n;
1283 		info = riscv_disasm_match(table, numtable, insn, imm);
1284 		if (info == NULL) {
1285 			return EINVAL;
1286 		}
1287 
1288 		if (info->matchflags & SHIFT32) {
1289 			imm &= 31;
1290 		} else if (info->matchflags & SHIFT64) {
1291 			imm &= 63;
1292 		}
1293 
1294 		/* name */
1295 		db_print_riscv_insnname(insn, info);
1296 
1297 		/* rd */
1298 		if ((info->matchflags & RD_0) == 0) {
1299 			db_printf("%s", sep);
1300 			db_print_riscv_reg(INSN_RD(insn),
1301 					   info->printflags & RD_FREG);
1302 			sep = ", ";
1303 		}
1304 
1305 		if (info->printflags & MEMORYIMM) {
1306 			db_printf("%s", sep);
1307 			db_printf("%d(", (int32_t)imm);
1308 			db_print_riscv_reg(INSN_RS1(insn),
1309 					   info->printflags & RS1_FREG);
1310 			db_printf(")");
1311 		}
1312 		else {
1313 			/* rs1 */
1314 			if ((info->matchflags & RS1_0) == 0) {
1315 				db_printf("%s", sep);
1316 				db_print_riscv_reg(INSN_RS1(insn),
1317 						  info->printflags & RS1_FREG);
1318 				sep = ", ";
1319 			}
1320 
1321 			/* imm */
1322 			if (info->matchflags & IMM_0) {
1323 				/* nothing */
1324 			} else if (info->printflags & FENCEIMM) {
1325 				unsigned pred, succ;
1326 
1327 				/* fm is part of the name, doesn't go here */
1328 				pred = (imm >> 4) & 0xf;
1329 				succ = imm & 0xf;
1330 				db_printf("%s", sep);
1331 				db_print_riscv_fencebits(pred);
1332 				db_printf(", ");
1333 				db_print_riscv_fencebits(succ);
1334 			} else if (info->printflags & BRANCHIMM) {
1335 				/* should be B format and not come here */
1336 			} else if (info->printflags & DECIMM) {
1337 				db_printf("%s%d", sep, (int32_t)imm);
1338 			} else {
1339 				db_printf("%s0x%x", sep, imm);
1340 			}
1341 		}
1342 		db_printf("\n");
1343 		break;
1344 	    case FMT_In:
1345 		/* same as I but funct3 should be 0 so just one case */
1346 		if (INSN_FUNCT3(insn) != 0) {
1347 			return EINVAL;
1348 		}
1349 		db_printf("%s %s, %s, 0x%x\n",
1350 			  d->u.name,
1351 			  riscv_registers[INSN_RD(insn)],
1352 			  riscv_registers[INSN_RS1(insn)],
1353 			  INSN_IMM_I(insn));
1354 		break;
1355 	    case FMT_S:
1356 		/* stores */
1357 		imm = INSN_IMM_S(insn);
1358 
1359 		table = d->u.entries.v;
1360 		numtable = d->u.entries.n;
1361 		info = riscv_disasm_match(table, numtable, insn, imm);
1362 		if (info == NULL) {
1363 			return EINVAL;
1364 		}
1365 
1366 		/* name */
1367 		db_print_riscv_insnname(insn, info);
1368 		db_printf(" ");
1369 
1370 		db_print_riscv_reg(INSN_RS2(insn),
1371 				   info->printflags & RS2_FREG);
1372 		db_printf("%s", sep);
1373 
1374 		db_printf("%d(", (int32_t)imm);
1375 		db_print_riscv_reg(INSN_RS1(insn),
1376 				   info->printflags & RS1_FREG);
1377 		db_printf(")\n");
1378 		break;
1379 	    case FMT_B:
1380 		/* branches */
1381 		imm = INSN_IMM_B(insn);
1382 
1383 		table = d->u.entries.v;
1384 		numtable = d->u.entries.n;
1385 		info = riscv_disasm_match(table, numtable, insn, imm);
1386 		if (info == NULL) {
1387 			return EINVAL;
1388 		}
1389 
1390 		/* name */
1391 		db_print_riscv_insnname(insn, info);
1392 		db_printf(" ");
1393 
1394 		db_print_riscv_reg(INSN_RS1(insn),
1395 				   info->printflags & RS1_FREG);
1396 		db_printf(", ");
1397 
1398 		db_print_riscv_reg(INSN_RS2(insn),
1399 				   info->printflags & RS2_FREG);
1400 		db_printf(", ");
1401 		db_print_addr(loc + (int32_t)imm);
1402 		db_printf("\n");
1403 		break;
1404 	    case FMT_U:
1405 		/* large immediates */
1406 		db_printf("%s %s, 0x%x\n",
1407 			  d->u.name,
1408 			  riscv_registers[INSN_RD(insn)],
1409 			  INSN_IMM_U(insn));
1410 		break;
1411 	    case FMT_J:
1412 		/* jal */
1413 		db_printf("%s %s, ",
1414 			  d->u.name,
1415 			  riscv_registers[INSN_RD(insn)]);
1416 		db_print_addr(loc + (int32_t)INSN_IMM_J(insn));
1417 		db_printf("\n");
1418 		break;
1419 	    case FMT_UNKNOWN:
1420 		/* reserved, custom, etc. */
1421 		return EINVAL;
1422 	    case FMT_ASSERT:
1423 		/* shouldn't have come here */
1424 		return EINVAL;
1425 	}
1426 	return 0;
1427 }
1428 
1429 ////////////////////////////////////////////////////////////
1430 
1431 static void
1432 db_disasm_unknown(const uint16_t *insn, unsigned n)
1433 {
1434 	unsigned i;
1435 
1436 	db_printf(".insn%u 0x", n*16);
1437 	for (i=n; i-- > 0; ) {
1438 		db_printf("%02x", insn[i]);
1439 	}
1440 	db_printf("\n");
1441 }
1442 
1443 db_addr_t
1444 db_disasm(db_addr_t loc, bool altfmt)
1445 {
1446 	/* instructions are up to 5 halfwords */
1447 	uint16_t insn[5];
1448 	unsigned n, i;
1449 	uint32_t insn32;
1450 
1451 	/*
1452 	 * Fetch the instruction. The first halfword tells us how many
1453 	 * more there are, and they're always in little-endian order.
1454 	 */
1455 	db_read_bytes(loc, sizeof(insn[0]), (void *)&insn[0]);
1456 	n = INSN_HALFWORDS(insn[0]);
1457 	for (i = 1; i < n; i++) {
1458 		db_read_bytes(loc + i * sizeof(insn[i]), sizeof(insn[i]),
1459 			      (void *)&insn[i]);
1460 	}
1461 
1462 	switch (n) {
1463 	    case 1:
1464 		if (db_disasm_16(loc, insn[0], altfmt) != 0) {
1465 			db_disasm_unknown(insn, n);
1466 		}
1467 		break;
1468 	    case 2:
1469 		insn32 = ((uint32_t)insn[1] << 16) | insn[0];
1470 		if (db_disasm_32(loc, insn32, altfmt) != 0) {
1471 			db_disasm_unknown(insn, n);
1472 		}
1473 		break;
1474 	    default:
1475 		/* no standard instructions of size 3+ */
1476 		db_disasm_unknown(insn, n);
1477 		break;
1478 	}
1479 	return loc + n * sizeof(uint16_t);
1480 }
1481