Home | History | Annotate | Line # | Download | only in riscv
      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