11f154020SRobert Mustacchi /*
21f154020SRobert Mustacchi  * This file and its contents are supplied under the terms of the
31f154020SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
41f154020SRobert Mustacchi  * You may only use this file in accordance with the terms of version
51f154020SRobert Mustacchi  * 1.0 of the CDDL.
61f154020SRobert Mustacchi  *
71f154020SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
81f154020SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
91f154020SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
101f154020SRobert Mustacchi  */
111f154020SRobert Mustacchi 
121f154020SRobert Mustacchi /*
131f154020SRobert Mustacchi  * Copyright (c) 2018, Joyent, Inc.
141f154020SRobert Mustacchi  */
151f154020SRobert Mustacchi 
161f154020SRobert Mustacchi /*
171f154020SRobert Mustacchi  * RISC-V Instruction set decoder
181f154020SRobert Mustacchi  */
191f154020SRobert Mustacchi 
201f154020SRobert Mustacchi #include <libdisasm.h>
211f154020SRobert Mustacchi #include <sys/byteorder.h>
221f154020SRobert Mustacchi #include <sys/debug.h>
231f154020SRobert Mustacchi 
241f154020SRobert Mustacchi #include "libdisasm_impl.h"
251f154020SRobert Mustacchi 
261f154020SRobert Mustacchi #include <stdio.h>
271f154020SRobert Mustacchi 
281f154020SRobert Mustacchi extern int strcmp(const char *, const char *);
291f154020SRobert Mustacchi 
301f154020SRobert Mustacchi /*
311f154020SRobert Mustacchi  * Register names based on their ABI name.
321f154020SRobert Mustacchi  */
331f154020SRobert Mustacchi static const char *dis_riscv_regs[32] = {
341f154020SRobert Mustacchi 	"x0", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
351f154020SRobert Mustacchi 	"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
361f154020SRobert Mustacchi 	"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
371f154020SRobert Mustacchi 	"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
381f154020SRobert Mustacchi };
391f154020SRobert Mustacchi 
401f154020SRobert Mustacchi static const char *dis_riscv_fpregs[32] = {
411f154020SRobert Mustacchi 	"ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
421f154020SRobert Mustacchi 	"fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
431f154020SRobert Mustacchi 	"fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
441f154020SRobert Mustacchi 	"fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11",
451f154020SRobert Mustacchi };
461f154020SRobert Mustacchi 
471f154020SRobert Mustacchi static const char *dis_riscv_c_regs[8] = {
481f154020SRobert Mustacchi 	"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5"
491f154020SRobert Mustacchi };
501f154020SRobert Mustacchi 
511f154020SRobert Mustacchi static const char *dis_riscv_c_fpregs[8] = {
521f154020SRobert Mustacchi 	"fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5"
531f154020SRobert Mustacchi };
541f154020SRobert Mustacchi 
551f154020SRobert Mustacchi /*
561f154020SRobert Mustacchi  * RM names have the leading comma in them because the last value represents
571f154020SRobert Mustacchi  * that the hardware register decides the rounding mode and therefore nothing
581f154020SRobert Mustacchi  * should be appended to the instruction.
591f154020SRobert Mustacchi  */
601f154020SRobert Mustacchi static const char *dis_riscv_rm[8] = {
611f154020SRobert Mustacchi 	",rne", ",rtz", ",rdn", ",rup", ",rmm", ",???", ",???", ""
621f154020SRobert Mustacchi };
631f154020SRobert Mustacchi 
641f154020SRobert Mustacchi typedef struct dis_riscv_csr {
651f154020SRobert Mustacchi 	uint_t		drc_val;
661f154020SRobert Mustacchi 	const char	*drc_name;
671f154020SRobert Mustacchi } dis_riscv_csr_t;
681f154020SRobert Mustacchi 
691f154020SRobert Mustacchi /*
701f154020SRobert Mustacchi  * The current set of CSR names as per Table 2.2-2.5 from RISC-V Privileged
711f154020SRobert Mustacchi  * Architectures V1.10. These include all of the ones in the User-Level ISA.
721f154020SRobert Mustacchi  * These are ordered per the doc.
731f154020SRobert Mustacchi  */
741f154020SRobert Mustacchi static dis_riscv_csr_t dis_riscv_csr_map[] = {
751f154020SRobert Mustacchi 	/* User Trap */
761f154020SRobert Mustacchi 	{ 0x000, "ustatus" },	{ 0x004, "uie" },	{ 0x005, "utvec" },
771f154020SRobert Mustacchi 	/* User Trap Handling */
781f154020SRobert Mustacchi 	{ 0x040, "uscratch" },	{ 0x041, "uepc" },	{ 0x042, "ucause" },
791f154020SRobert Mustacchi 	{ 0x043, "utval" },	{ 0x044, "uip" },
801f154020SRobert Mustacchi 	/* User Floating-Point CSRs */
811f154020SRobert Mustacchi 	{ 0x001, "fflags" },	{ 0x002, "frm" },	{ 0x003, "fcsr" },
821f154020SRobert Mustacchi 	/* User Counters/Timers */
831f154020SRobert Mustacchi 	{ 0xc00, "cycle" },	{ 0xc01, "time" },	{ 0xc02, "instret" },
841f154020SRobert Mustacchi 	{ 0xc03, "hpmcounter3" },	{ 0xc04, "hpmcounter4" },
851f154020SRobert Mustacchi 	{ 0xc05, "hpmcounter5" },	{ 0xc06, "hpmcounter6" },
861f154020SRobert Mustacchi 	{ 0xc07, "hpmcounter7" },	{ 0xc08, "hpmcounter8" },
871f154020SRobert Mustacchi 	{ 0xc09, "hpmcounter9" },	{ 0xc0a, "hpmcounter10" },
881f154020SRobert Mustacchi 	{ 0xc0b, "hpmcounter11" },	{ 0xc0c, "hpmcounter12" },
891f154020SRobert Mustacchi 	{ 0xc0d, "hpmcounter13" },	{ 0xc0e, "hpmcounter14" },
901f154020SRobert Mustacchi 	{ 0xc0f, "hpmcounter15" },	{ 0xc10, "hpmcounter16" },
911f154020SRobert Mustacchi 	{ 0xc11, "hpmcounter17" },	{ 0xc12, "hpmcounter18" },
921f154020SRobert Mustacchi 	{ 0xc13, "hpmcounter19" },	{ 0xc14, "hpmcounter20" },
931f154020SRobert Mustacchi 	{ 0xc15, "hpmcounter21" },	{ 0xc16, "hpmcounter22" },
941f154020SRobert Mustacchi 	{ 0xc17, "hpmcounter23" },	{ 0xc18, "hpmcounter24" },
951f154020SRobert Mustacchi 	{ 0xc19, "hpmcounter25" },	{ 0xc1a, "hpmcounter26" },
961f154020SRobert Mustacchi 	{ 0xc1b, "hpmcounter27" },	{ 0xc1c, "hpmcounter28" },
971f154020SRobert Mustacchi 	{ 0xc1d, "hpmcounter29" },	{ 0xc1e, "hpmcounter30" },
981f154020SRobert Mustacchi 	{ 0xc1f, "hpmcounter31" },
991f154020SRobert Mustacchi 	{ 0xc80, "cycleh" },	{ 0xc81, "timeh" },	{ 0xc82, "instreth" },
1001f154020SRobert Mustacchi 	{ 0xc83, "hpmcounter3h" },	{ 0xc84, "hpmcounter4h" },
1011f154020SRobert Mustacchi 	{ 0xc85, "hpmcounter5h" },	{ 0xc86, "hpmcounter6h" },
1021f154020SRobert Mustacchi 	{ 0xc87, "hpmcounter7h" },	{ 0xc88, "hpmcounter8h" },
1031f154020SRobert Mustacchi 	{ 0xc89, "hpmcounter9h" },	{ 0xc8a, "hpmcounter10h" },
1041f154020SRobert Mustacchi 	{ 0xc8b, "hpmcounter11h" },	{ 0xc8c, "hpmcounter12h" },
1051f154020SRobert Mustacchi 	{ 0xc8d, "hpmcounter13h" },	{ 0xc8e, "hpmcounter14h" },
1061f154020SRobert Mustacchi 	{ 0xc8f, "hpmcounter15h" },	{ 0xc90, "hpmcounter16h" },
1071f154020SRobert Mustacchi 	{ 0xc91, "hpmcounter17h" },	{ 0xc92, "hpmcounter18h" },
1081f154020SRobert Mustacchi 	{ 0xc93, "hpmcounter19h" },	{ 0xc94, "hpmcounter20h" },
1091f154020SRobert Mustacchi 	{ 0xc95, "hpmcounter21h" },	{ 0xc96, "hpmcounter22h" },
1101f154020SRobert Mustacchi 	{ 0xc97, "hpmcounter23h" },	{ 0xc98, "hpmcounter24h" },
1111f154020SRobert Mustacchi 	{ 0xc99, "hpmcounter25h" },	{ 0xc9a, "hpmcounter26h" },
1121f154020SRobert Mustacchi 	{ 0xc9b, "hpmcounter27h" },	{ 0xc9c, "hpmcounter28h" },
1131f154020SRobert Mustacchi 	{ 0xc9d, "hpmcounter29h" },	{ 0xc9e, "hpmcounter30h" },
1141f154020SRobert Mustacchi 	{ 0xc9f, "hpmcounter31h" },
1151f154020SRobert Mustacchi 	/* Supervisor Trap Status */
1161f154020SRobert Mustacchi 	{ 0x100, "sstatus" },	{ 0x102, "sedeleg" },	{ 0x103, "sideleg" },
1171f154020SRobert Mustacchi 	{ 0x104, "sie" },	{ 0x105, "stvec" },	{ 0x106, "scounteren" },
1181f154020SRobert Mustacchi 	/* Supervisor Trap Handling */
1191f154020SRobert Mustacchi 	{ 0x140, "sscratch" },	{ 0x141, "sepc" },	{ 0x142, "scause" },
1201f154020SRobert Mustacchi 	{ 0x143, "stval" },	{ 0x144, "sip" },
1211f154020SRobert Mustacchi 	/* Supervisor Protection and Translation */
1221f154020SRobert Mustacchi 	{ 0x180, "satp" },
1231f154020SRobert Mustacchi 	/* Machine Information Registers */
1241f154020SRobert Mustacchi 	{ 0xf11, "mvendorid" },	{ 0xf12, "marchid" },
1251f154020SRobert Mustacchi 	{ 0xf13, "mimpid" },	{ 0xf14, "mhartid" },
1261f154020SRobert Mustacchi 	/* Machine Trap Setup */
1271f154020SRobert Mustacchi 	{ 0x300, "mstatus" },	{ 0x301, "misa" },	{ 0x302, "medeleg" },
1281f154020SRobert Mustacchi 	{ 0x303, "mideleg" },	{ 0x304, "mie" },	{ 0x305, "mtvec" },
1291f154020SRobert Mustacchi 	{ 0x306, "mcounteren" },
1301f154020SRobert Mustacchi 	/* Machine Trap Handling */
1311f154020SRobert Mustacchi 	{ 0x340, "mscratch" },	{ 0x341, "mepc" },	{ 0x342, "mcause" },
1321f154020SRobert Mustacchi 	{ 0x343, "mtval" },	{ 0x344, "mip" },
1331f154020SRobert Mustacchi 	/* Machine Protection and Translation */
1341f154020SRobert Mustacchi 	{ 0x3a0, "pmpcfg0" },	{ 0x3a1, "pmpcfg1" },
1351f154020SRobert Mustacchi 	{ 0x3a2, "pmpcfg2" },	{ 0x3a3, "pmpcfg3" },
1361f154020SRobert Mustacchi 	{ 0x3b0, "pmpaddr0" },	{ 0x3b1, "pmpaddr1" },
1371f154020SRobert Mustacchi 	{ 0x3b2, "pmpaddr2" },	{ 0x3b3, "pmpaddr3" },
1381f154020SRobert Mustacchi 	{ 0x3b4, "pmpaddr4" },	{ 0x3b5, "pmpaddr5" },
1391f154020SRobert Mustacchi 	{ 0x3b6, "pmpaddr6" },	{ 0x3b7, "pmpaddr7" },
1401f154020SRobert Mustacchi 	{ 0x3b8, "pmpaddr8" },	{ 0x3b9, "pmpaddr9" },
1411f154020SRobert Mustacchi 	{ 0x3ba, "pmpaddr10" },	{ 0x3bb, "pmpaddr11" },
1421f154020SRobert Mustacchi 	{ 0x3bc, "pmpaddr12" },	{ 0x3bd, "pmpaddr13" },
1431f154020SRobert Mustacchi 	{ 0x3be, "pmpaddr14" },	{ 0x3bf, "pmpaddr15" }
1441f154020SRobert Mustacchi };
1451f154020SRobert Mustacchi 
1461f154020SRobert Mustacchi typedef enum dis_riscv_csr_alias_type {
1471f154020SRobert Mustacchi 	DIS_RISCV_CSR_READ,
1481f154020SRobert Mustacchi 	DIS_RISCV_CSR_READ_GEN,
1491f154020SRobert Mustacchi 	DIS_RISCV_CSR_SWAP,
1501f154020SRobert Mustacchi 	DIS_RISCV_CSR_SWAP_IMM,
1511f154020SRobert Mustacchi 	DIS_RISCV_CSR_WRITE,
1521f154020SRobert Mustacchi 	DIS_RISCV_CSR_WRITE_GEN,
1531f154020SRobert Mustacchi 	DIS_RISCV_CSR_WRITE_IMM,
1541f154020SRobert Mustacchi 	DIS_RISCV_CSR_WRITE_IMM_GEN
1551f154020SRobert Mustacchi } dis_riscv_csr_alias_type_t;
1561f154020SRobert Mustacchi 
1571f154020SRobert Mustacchi typedef struct dis_riscv_csr_alias {
1581f154020SRobert Mustacchi 	const char *drca_alias;
1591f154020SRobert Mustacchi 	dis_riscv_csr_alias_type_t drca_type;
1601f154020SRobert Mustacchi 	const char *drca_base;
1611f154020SRobert Mustacchi 	const char *drca_csr;
1621f154020SRobert Mustacchi 	int drca_rd;
1631f154020SRobert Mustacchi 	int drca_rs;
1641f154020SRobert Mustacchi } dis_riscv_csr_alias_t;
1651f154020SRobert Mustacchi 
1661f154020SRobert Mustacchi /*
1671f154020SRobert Mustacchi  * Table of aliases. A NULL or -1 indicates a don't care.
1681f154020SRobert Mustacchi  */
1691f154020SRobert Mustacchi static dis_riscv_csr_alias_t dis_riscv_csr_alias[] = {
1701f154020SRobert Mustacchi 	{ "rdinstret", DIS_RISCV_CSR_READ, "csrrs", "instret", -1, 0 },
1711f154020SRobert Mustacchi 	{ "rdinstreth", DIS_RISCV_CSR_READ, "csrrs", "instreth", -1, 0 },
1721f154020SRobert Mustacchi 	{ "rdcycle", DIS_RISCV_CSR_READ, "csrrs", "cycle", -1, 0 },
1731f154020SRobert Mustacchi 	{ "rdcycleh", DIS_RISCV_CSR_READ, "csrrs", "cycleh", -1, 0 },
1741f154020SRobert Mustacchi 	{ "rdtime", DIS_RISCV_CSR_READ, "csrrs", "time", -1, 0 },
1751f154020SRobert Mustacchi 	{ "rdtimeh", DIS_RISCV_CSR_READ, "csrrs", "timeh", -1, 0 },
1761f154020SRobert Mustacchi 	{ "frcsr", DIS_RISCV_CSR_READ, "csrrs", "fcsr", -1, 0 },
1771f154020SRobert Mustacchi 	{ "fscsr", DIS_RISCV_CSR_WRITE, "csrrw", "fcsr", 0, -1 },
1781f154020SRobert Mustacchi 	{ "fscsr", DIS_RISCV_CSR_SWAP, "csrrw", "fcsr", -1, -1 },
1791f154020SRobert Mustacchi 	{ "frrm", DIS_RISCV_CSR_READ, "csrrs", "frm", -1, 0 },
1801f154020SRobert Mustacchi 	{ "fsrm", DIS_RISCV_CSR_WRITE, "csrrw", "frm", 0, -1 },
1811f154020SRobert Mustacchi 	{ "fsrm", DIS_RISCV_CSR_SWAP, "csrrw", "frm", -1, -1 },
1821f154020SRobert Mustacchi 	{ "fsrmi", DIS_RISCV_CSR_WRITE_IMM, "csrrwi", "frm", 0, -1 },
1831f154020SRobert Mustacchi 	{ "fsrmi", DIS_RISCV_CSR_SWAP_IMM, "csrrwi", "frm", -1, -1 },
1841f154020SRobert Mustacchi 	{ "frflags", DIS_RISCV_CSR_READ, "csrrs", "fflags", -1, 0 },
1851f154020SRobert Mustacchi 	{ "fsflags", DIS_RISCV_CSR_WRITE, "csrrw", "fflags", 0, -1 },
1861f154020SRobert Mustacchi 	{ "fsflags", DIS_RISCV_CSR_SWAP, "csrrw", "fflags", -1, -1 },
1871f154020SRobert Mustacchi 	{ "fsflagsi", DIS_RISCV_CSR_WRITE_IMM, "csrrwi", "fflags", 0, -1 },
1881f154020SRobert Mustacchi 	{ "fsflagsi", DIS_RISCV_CSR_SWAP_IMM, "csrrwi", "fflags", -1, -1 },
1891f154020SRobert Mustacchi 	/*
1901f154020SRobert Mustacchi 	 * These are the generic aliases that aren't based on the CSR. Keep
1911f154020SRobert Mustacchi 	 * them last.
1921f154020SRobert Mustacchi 	 */
1931f154020SRobert Mustacchi 	{ "csrr", DIS_RISCV_CSR_READ_GEN, "csrrs", NULL, -1, 0 },
1941f154020SRobert Mustacchi 	{ "csrw", DIS_RISCV_CSR_WRITE_GEN, "csrrw", NULL, 0, -1 },
1951f154020SRobert Mustacchi 	{ "csrs", DIS_RISCV_CSR_WRITE_GEN, "csrrs", NULL, 0, -1 },
1961f154020SRobert Mustacchi 	{ "csrc", DIS_RISCV_CSR_WRITE_GEN, "csrrc", NULL, 0, -1 },
1971f154020SRobert Mustacchi 	{ "csrwi", DIS_RISCV_CSR_WRITE_IMM_GEN, "csrrwi", NULL, 0, -1 },
1981f154020SRobert Mustacchi 	{ "csrsi", DIS_RISCV_CSR_WRITE_IMM_GEN, "csrrsi", NULL, 0, -1 },
1991f154020SRobert Mustacchi 	{ "csrci", DIS_RISCV_CSR_WRITE_IMM_GEN, "csrrci", NULL, 0, -1 },
2001f154020SRobert Mustacchi };
2011f154020SRobert Mustacchi 
2021f154020SRobert Mustacchi /*
2031f154020SRobert Mustacchi  * Take an n-bit value whose sign bit is indicated by the big sign and convert
2041f154020SRobert Mustacchi  * to a signed type.
2051f154020SRobert Mustacchi  */
2061f154020SRobert Mustacchi static uint_t
dis_riscv_sign_extend(uint_t val,uint_t sbit,const char ** sign)2071f154020SRobert Mustacchi dis_riscv_sign_extend(uint_t val, uint_t sbit, const char **sign)
2081f154020SRobert Mustacchi {
2091f154020SRobert Mustacchi 	VERIFY3U(sbit, <=, 31);
2101f154020SRobert Mustacchi 
2111f154020SRobert Mustacchi 	if (val >= 1 << sbit) {
2121f154020SRobert Mustacchi 		*sign = "-";
2131f154020SRobert Mustacchi 		return ((1 << (sbit + 1)) - val);
2141f154020SRobert Mustacchi 	} else {
2151f154020SRobert Mustacchi 		*sign = "";
2161f154020SRobert Mustacchi 		return (val);
2171f154020SRobert Mustacchi 	}
2181f154020SRobert Mustacchi }
2191f154020SRobert Mustacchi 
2201f154020SRobert Mustacchi /*
2211f154020SRobert Mustacchi  * Four byte decode tables. This is derived from the RV32/64G Instruction Set
2221f154020SRobert Mustacchi  * Listings. We describe a table entry based on the opcode and optional opcodes
2231f154020SRobert Mustacchi  * based on the type of instruction that it is and its encoding format. Most
2241f154020SRobert Mustacchi  * sets of instructions have one of several uniform encoding types.
2251f154020SRobert Mustacchi  *
2261f154020SRobert Mustacchi  *  31             25 24     20 19  15 14    12  11        7  6      0
2271f154020SRobert Mustacchi  * |    funct7       |   r2    |  rs1 | funct3 | rd          | opcode | R-type
2281f154020SRobert Mustacchi  * |    imm[11:0]              |  rs1 | funct3 | rd          | opcode | I-type
2291f154020SRobert Mustacchi  * |    imm[11:5]    |   r2    |  rs1 | funct3 | imm[4:0]    | opcode | S-type
2301f154020SRobert Mustacchi  * |    imm[12|10:5] |   r2    |  rs1 | funct3 | imm[4:1|11] | opcode | B-type
2311f154020SRobert Mustacchi  * |    imm[31:12]                             | rd          | opcode | U-type
2321f154020SRobert Mustacchi  * |    imm[10|10:1|11|19:12]                  | rd          | opcode | J-type
2331f154020SRobert Mustacchi  */
2341f154020SRobert Mustacchi typedef enum dis_riscv_itype {
2351f154020SRobert Mustacchi 	DIS_RISCV_I_R_TYPE,
2361f154020SRobert Mustacchi 	DIS_RISCV_I_I_TYPE,
2371f154020SRobert Mustacchi 	DIS_RISCV_I_S_TYPE,
2381f154020SRobert Mustacchi 	DIS_RISCV_I_B_TYPE,
2391f154020SRobert Mustacchi 	DIS_RISCV_I_U_TYPE,
2401f154020SRobert Mustacchi 	DIS_RISCV_I_J_TYPE,
2411f154020SRobert Mustacchi 	DIS_RISCV_I_R4_TYPE,
2421f154020SRobert Mustacchi 	/*
2431f154020SRobert Mustacchi 	 * This is a variant of the standard R type where the first bit of
2441f154020SRobert Mustacchi 	 * funct7 is actually used for this shift.
2451f154020SRobert Mustacchi 	 */
2461f154020SRobert Mustacchi 	DIS_RISCV_I_SHIFT64_TYPE,
2471f154020SRobert Mustacchi 	/*
2481f154020SRobert Mustacchi 	 * This type isn't explicitly defined in the ISA doc; however, it is a
2491f154020SRobert Mustacchi 	 * standard format that is for all of the Atomic class instructions.
2501f154020SRobert Mustacchi 	 * This is treated like an R-type, except the funct7 is really a funct5.
2511f154020SRobert Mustacchi 	 * The load variant is similar; however, rs2 must be zero.
2521f154020SRobert Mustacchi 	 */
2531f154020SRobert Mustacchi 	DIS_RISCV_I_RV32A_TYPE,
2541f154020SRobert Mustacchi 	DIS_RISCV_I_RV32A_LOAD_TYPE,
2551f154020SRobert Mustacchi 	/*
2561f154020SRobert Mustacchi 	 * This is a custom type we've defined where the first value is the
2571f154020SRobert Mustacchi 	 * instruction mask and the second value is the value of the bits in it.
2581f154020SRobert Mustacchi 	 * This is used for a few irregular instructions ala FENCE and ECALL.
2591f154020SRobert Mustacchi 	 */
2601f154020SRobert Mustacchi 	DIS_RISCV_I_MASK_TYPE,
2611f154020SRobert Mustacchi 	/*
2621f154020SRobert Mustacchi 	 * This type is used for FP arguments that use rs2 as an opcode.
2631f154020SRobert Mustacchi 	 */
2641f154020SRobert Mustacchi 	DIS_RISCV_I_FP_RS2OP_TYPE,
2651f154020SRobert Mustacchi 	/*
2661f154020SRobert Mustacchi 	 * This type uses the opcode and funct7 and uses funct3 as a rounding
2671f154020SRobert Mustacchi 	 * mode argument.
2681f154020SRobert Mustacchi 	 */
2691f154020SRobert Mustacchi 	DIS_RISCV_I_FP_RM_TYPE,
2701f154020SRobert Mustacchi 	/*
2711f154020SRobert Mustacchi 	 * This fp type uses the opcode, funct7, funct3, and rs2 as an op type.
2721f154020SRobert Mustacchi 	 */
2731f154020SRobert Mustacchi 	DIS_RISCV_I_FP_R_RS2_TYPE,
2741f154020SRobert Mustacchi } dis_riscv_itype_t;
2751f154020SRobert Mustacchi 
2761f154020SRobert Mustacchi #define	DIS_RISCV_OPCODE(x)	((x) & 0x7f)
2771f154020SRobert Mustacchi #define	DIS_RISCV_FUNCT3(x)	(((x) >> 12) & 0x7)
2781f154020SRobert Mustacchi #define	DIS_RISCV_FUNCT7(x)	(((x) >> 25) & 0x7f)
2791f154020SRobert Mustacchi #define	DIS_RISCV_RD(x)		(((x) >> 7) & 0x1f)
2801f154020SRobert Mustacchi #define	DIS_RISCV_RS1(x)	(((x) >> 15) & 0x1f)
2811f154020SRobert Mustacchi #define	DIS_RISCV_RS2(x)	(((x) >> 20) & 0x1f)
2821f154020SRobert Mustacchi #define	DIS_RISCV_FP_RS3(x)	(((x) >> 27) & 0x1f)
2831f154020SRobert Mustacchi #define	DIS_RISCV_FUNCT2(x)	(((x) >> 25) & 0x03)
2841f154020SRobert Mustacchi 
2851f154020SRobert Mustacchi /*
2861f154020SRobert Mustacchi  * SHIFT funct7 variant.
2871f154020SRobert Mustacchi  */
2881f154020SRobert Mustacchi #define	DIS_RISCV_SFUNCT7(x)	(((x) >> 26) & 0x3f)
2891f154020SRobert Mustacchi 
2901f154020SRobert Mustacchi #define	DIS_RISCV_UIMM(x)	(((x) >> 12) & 0xfffff)
2911f154020SRobert Mustacchi 
2921f154020SRobert Mustacchi #define	DIS_RISCV_IIMM(x)	(((x) >> 20) & 0xfff)
2931f154020SRobert Mustacchi 
2941f154020SRobert Mustacchi #define	DIS_RISCV_BIMM_12(x)	(((x) >> 19) & 0x1000)
2951f154020SRobert Mustacchi #define	DIS_RISCV_BIMM_11(x)	(((x) & 0x80) << 4)
2961f154020SRobert Mustacchi #define	DIS_RISCV_BIMM_10_5(x)	(((x) >> 20) & 0x7e0)
2971f154020SRobert Mustacchi #define	DIS_RISCV_BIMM_4_1(x)	(((x) >> 7) & 0x1e)
2981f154020SRobert Mustacchi 
2991f154020SRobert Mustacchi #define	DIS_RISCV_SIMM_UP(x)	((((x) >> 25) & 0x7f) << 5)
3001f154020SRobert Mustacchi #define	DIS_RISCV_SIMM_LOW(x)	(((x) >> 7) & 0x1f)
3011f154020SRobert Mustacchi 
3021f154020SRobert Mustacchi #define	DIS_RISCV_JIMM_20(x)	(((x) & 0x80000000) >> 11)
3031f154020SRobert Mustacchi #define	DIS_RISCV_JIMM_19_12(x)	((x) & 0xff000)
3041f154020SRobert Mustacchi #define	DIS_RISCV_JIMM_11(x)	(((x) & 100000) >> 9)
3051f154020SRobert Mustacchi #define	DIS_RISCV_JIMM_10_1(x)	(((x) & 0x7fe00000) >> 20)
3061f154020SRobert Mustacchi 
3071f154020SRobert Mustacchi #define	DIS_RISCV_RVA_FUNCT5(x)	(((x) >> 27) & 0x1f)
3081f154020SRobert Mustacchi #define	DIS_RISCV_RVA_AQ(x)	(((x) >> 26) & 0x1)
3091f154020SRobert Mustacchi #define	DIS_RISCV_RVA_RL(x)	(((x) >> 25) & 0x1)
3101f154020SRobert Mustacchi 
3111f154020SRobert Mustacchi struct dis_riscv_instr;
3121f154020SRobert Mustacchi typedef void (*dis_riscv_func_t)(dis_handle_t *, uint32_t,
3131f154020SRobert Mustacchi     struct dis_riscv_instr *, char *, size_t);
3141f154020SRobert Mustacchi 
3151f154020SRobert Mustacchi typedef struct dis_riscv_instr {
316*38848811SRobert Mustacchi 	const char		*drv_name;
3171f154020SRobert Mustacchi 	dis_riscv_itype_t	drv_type;
3181f154020SRobert Mustacchi 	dis_riscv_func_t	drv_print;
3191f154020SRobert Mustacchi 	uint_t			drv_opcode;
3201f154020SRobert Mustacchi 	uint_t			drv_funct3;
3211f154020SRobert Mustacchi 	uint_t			drv_funct7;
3221f154020SRobert Mustacchi 	uint_t			drv_funct2;
3231f154020SRobert Mustacchi } dis_riscv_instr_t;
3241f154020SRobert Mustacchi 
3251f154020SRobert Mustacchi /*ARGSUSED*/
3261f154020SRobert Mustacchi static void
dis_riscv_rtype_32(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)3271f154020SRobert Mustacchi dis_riscv_rtype_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
3281f154020SRobert Mustacchi     char *buf, size_t buflen)
3291f154020SRobert Mustacchi {
3301f154020SRobert Mustacchi 	(void) dis_snprintf(buf, buflen, "%s %s,%s,%s", table->drv_name,
3311f154020SRobert Mustacchi 	    dis_riscv_regs[DIS_RISCV_RD(instr)],
3321f154020SRobert Mustacchi 	    dis_riscv_regs[DIS_RISCV_RS1(instr)],
3331f154020SRobert Mustacchi 	    dis_riscv_regs[DIS_RISCV_RS2(instr)]);
3341f154020SRobert Mustacchi }
3351f154020SRobert Mustacchi 
3361f154020SRobert Mustacchi static void
dis_riscv_itype_32(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)3371f154020SRobert Mustacchi dis_riscv_itype_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
3381f154020SRobert Mustacchi     char *buf, size_t buflen)
3391f154020SRobert Mustacchi {
3401f154020SRobert Mustacchi 	const char *s;
3411f154020SRobert Mustacchi 	uint_t imm = dis_riscv_sign_extend(DIS_RISCV_IIMM(instr), 11, &s);
3421f154020SRobert Mustacchi 
3431f154020SRobert Mustacchi 	if ((dhp->dh_flags & DIS_OCTAL) != 0) {
3441f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s,%s0%o",
3451f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
3461f154020SRobert Mustacchi 		    dis_riscv_regs[DIS_RISCV_RS1(instr)], s, imm);
3471f154020SRobert Mustacchi 	} else {
3481f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s,%s0x%x",
3491f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
3501f154020SRobert Mustacchi 		    dis_riscv_regs[DIS_RISCV_RS1(instr)], s, imm);
3511f154020SRobert Mustacchi 	}
3521f154020SRobert Mustacchi }
3531f154020SRobert Mustacchi 
3541f154020SRobert Mustacchi static void
dis_riscv_btype_32(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)3551f154020SRobert Mustacchi dis_riscv_btype_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
3561f154020SRobert Mustacchi     char *buf, size_t buflen)
3571f154020SRobert Mustacchi {
3581f154020SRobert Mustacchi 	const char *s;
3591f154020SRobert Mustacchi 	uint_t bimm = DIS_RISCV_BIMM_12(instr) | DIS_RISCV_BIMM_11(instr) |
3601f154020SRobert Mustacchi 	    DIS_RISCV_BIMM_10_5(instr) | DIS_RISCV_BIMM_4_1(instr);
3611f154020SRobert Mustacchi 	uint_t imm = dis_riscv_sign_extend(bimm, 12, &s);
3621f154020SRobert Mustacchi 
3631f154020SRobert Mustacchi 	if ((dhp->dh_flags & DIS_OCTAL) != 0) {
3641f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s,%s0%o",
3651f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
3661f154020SRobert Mustacchi 		    dis_riscv_regs[DIS_RISCV_RS1(instr)], s, imm);
3671f154020SRobert Mustacchi 	} else {
3681f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s,%s0x%x",
3691f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
3701f154020SRobert Mustacchi 		    dis_riscv_regs[DIS_RISCV_RS1(instr)], s, imm);
3711f154020SRobert Mustacchi 	}
3721f154020SRobert Mustacchi }
3731f154020SRobert Mustacchi 
3741f154020SRobert Mustacchi static void
dis_riscv_load(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)3751f154020SRobert Mustacchi dis_riscv_load(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
3761f154020SRobert Mustacchi     char *buf, size_t buflen)
3771f154020SRobert Mustacchi {
3781f154020SRobert Mustacchi 	const char *s;
3791f154020SRobert Mustacchi 	uint_t imm = dis_riscv_sign_extend(DIS_RISCV_IIMM(instr), 11, &s);
3801f154020SRobert Mustacchi 
3811f154020SRobert Mustacchi 	if ((dhp->dh_flags & DIS_OCTAL) != 0) {
3821f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s0%o(%s)",
3831f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
3841f154020SRobert Mustacchi 		    s, imm, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
3851f154020SRobert Mustacchi 	} else {
3861f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s0x%x(%s)",
3871f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
3881f154020SRobert Mustacchi 		    s, imm, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
3891f154020SRobert Mustacchi 	}
3901f154020SRobert Mustacchi }
3911f154020SRobert Mustacchi 
3921f154020SRobert Mustacchi static void
dis_riscv_stype_32(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)3931f154020SRobert Mustacchi dis_riscv_stype_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
3941f154020SRobert Mustacchi     char *buf, size_t buflen)
3951f154020SRobert Mustacchi {
3961f154020SRobert Mustacchi 	const char *s;
3971f154020SRobert Mustacchi 	uint_t simm = DIS_RISCV_SIMM_UP(instr) | DIS_RISCV_SIMM_LOW(instr);
3981f154020SRobert Mustacchi 	uint_t val = dis_riscv_sign_extend(simm, 11, &s);
3991f154020SRobert Mustacchi 
4001f154020SRobert Mustacchi 	if ((dhp->dh_flags & DIS_OCTAL) != 0) {
4011f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s0%o(%s)",
4021f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RS2(instr)],
4031f154020SRobert Mustacchi 		    s, val, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
4041f154020SRobert Mustacchi 	} else {
4051f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s0x%x(%s)",
4061f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RS2(instr)],
4071f154020SRobert Mustacchi 		    s, val, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
4081f154020SRobert Mustacchi 	}
4091f154020SRobert Mustacchi }
4101f154020SRobert Mustacchi 
4111f154020SRobert Mustacchi /*ARGSUSED*/
4121f154020SRobert Mustacchi static void
dis_riscv_utype_32(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)4131f154020SRobert Mustacchi dis_riscv_utype_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
4141f154020SRobert Mustacchi     char *buf, size_t buflen)
4151f154020SRobert Mustacchi {
4161f154020SRobert Mustacchi 	(void) dis_snprintf(buf, buflen, "%s %s,0x%x", table->drv_name,
4171f154020SRobert Mustacchi 	    dis_riscv_regs[DIS_RISCV_RD(instr)], DIS_RISCV_UIMM(instr));
4181f154020SRobert Mustacchi }
4191f154020SRobert Mustacchi 
4201f154020SRobert Mustacchi static void
dis_riscv_jtype_32(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)4211f154020SRobert Mustacchi dis_riscv_jtype_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
4221f154020SRobert Mustacchi     char *buf, size_t buflen)
4231f154020SRobert Mustacchi {
4241f154020SRobert Mustacchi 	const char *s;
4251f154020SRobert Mustacchi 	uint_t jimm = DIS_RISCV_JIMM_20(instr) | DIS_RISCV_JIMM_19_12(instr) |
4261f154020SRobert Mustacchi 	    DIS_RISCV_JIMM_11(instr) | DIS_RISCV_JIMM_10_1(instr);
4271f154020SRobert Mustacchi 	uint_t imm = dis_riscv_sign_extend(jimm, 20, &s);
4281f154020SRobert Mustacchi 
4291f154020SRobert Mustacchi 	if ((dhp->dh_flags & DIS_OCTAL) != 0) {
4301f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s0%o",
4311f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
4321f154020SRobert Mustacchi 		    s, imm);
4331f154020SRobert Mustacchi 	} else {
4341f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s0x%x",
4351f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
4361f154020SRobert Mustacchi 		    s, imm);
4371f154020SRobert Mustacchi 	}
4381f154020SRobert Mustacchi }
4391f154020SRobert Mustacchi 
4401f154020SRobert Mustacchi /*
4411f154020SRobert Mustacchi  * The shift instructions are a variant on the R-type instructions where RS2 is
4421f154020SRobert Mustacchi  * an immediate to perform the shift by as opposed to a register.
4431f154020SRobert Mustacchi  */
4441f154020SRobert Mustacchi static void
dis_riscv_shift_32(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)4451f154020SRobert Mustacchi dis_riscv_shift_32(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
4461f154020SRobert Mustacchi     char *buf, size_t buflen)
4471f154020SRobert Mustacchi {
4481f154020SRobert Mustacchi 	if ((dhp->dh_flags & DIS_OCTAL) != 0) {
4491f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s,0%o",
4501f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
4511f154020SRobert Mustacchi 		    dis_riscv_regs[DIS_RISCV_RS1(instr)], DIS_RISCV_RS2(instr));
4521f154020SRobert Mustacchi 	} else {
4531f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s,0x%x",
4541f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
4551f154020SRobert Mustacchi 		    dis_riscv_regs[DIS_RISCV_RS1(instr)], DIS_RISCV_RS2(instr));
4561f154020SRobert Mustacchi 	}
4571f154020SRobert Mustacchi }
4581f154020SRobert Mustacchi 
4591f154020SRobert Mustacchi /*
4601f154020SRobert Mustacchi  * The 64-bit version of shift instructions steals an extra bit from funct7 to
4611f154020SRobert Mustacchi  * construct the shift amount.
4621f154020SRobert Mustacchi  */
4631f154020SRobert Mustacchi static void
dis_riscv_shift_64(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)4641f154020SRobert Mustacchi dis_riscv_shift_64(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
4651f154020SRobert Mustacchi     char *buf, size_t buflen)
4661f154020SRobert Mustacchi {
4671f154020SRobert Mustacchi 	uint_t shift = DIS_RISCV_RS2(instr) | ((instr & (1UL << 25)) >> 20);
4681f154020SRobert Mustacchi 	if ((dhp->dh_flags & DIS_OCTAL) != 0) {
4691f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s,0%o",
4701f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
4711f154020SRobert Mustacchi 		    dis_riscv_regs[DIS_RISCV_RS1(instr)], shift);
4721f154020SRobert Mustacchi 	} else {
4731f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s,0x%x",
4741f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_regs[DIS_RISCV_RD(instr)],
4751f154020SRobert Mustacchi 		    dis_riscv_regs[DIS_RISCV_RS1(instr)], shift);
4761f154020SRobert Mustacchi 	}
4771f154020SRobert Mustacchi }
4781f154020SRobert Mustacchi 
4791f154020SRobert Mustacchi /*ARGSUSED*/
4801f154020SRobert Mustacchi static void
dis_riscv_csr(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)4811f154020SRobert Mustacchi dis_riscv_csr(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
4821f154020SRobert Mustacchi     char *buf, size_t buflen)
4831f154020SRobert Mustacchi {
4841f154020SRobert Mustacchi 	uint_t rd, csr, rs, i;
4851f154020SRobert Mustacchi 	const char *csrstr = NULL;
4861f154020SRobert Mustacchi 	char csrval[32];
4871f154020SRobert Mustacchi 	dis_riscv_csr_alias_t *alias = NULL;
4881f154020SRobert Mustacchi 
4891f154020SRobert Mustacchi 	rd = DIS_RISCV_RD(instr);
4901f154020SRobert Mustacchi 	rs = DIS_RISCV_RS1(instr);
4911f154020SRobert Mustacchi 	csr = DIS_RISCV_IIMM(instr);
4921f154020SRobert Mustacchi 
4931f154020SRobert Mustacchi 	for (i = 0; i < ARRAY_SIZE(dis_riscv_csr_map); i++) {
4941f154020SRobert Mustacchi 		if (csr == dis_riscv_csr_map[i].drc_val) {
4951f154020SRobert Mustacchi 			csrstr = dis_riscv_csr_map[i].drc_name;
4961f154020SRobert Mustacchi 			break;
4971f154020SRobert Mustacchi 		}
4981f154020SRobert Mustacchi 	}
4991f154020SRobert Mustacchi 
5001f154020SRobert Mustacchi 	if (csrstr == NULL) {
5011f154020SRobert Mustacchi 		(void) dis_snprintf(csrval, sizeof (csrval), "0x%x", csr);
5021f154020SRobert Mustacchi 		csrstr = csrval;
5031f154020SRobert Mustacchi 	}
5041f154020SRobert Mustacchi 
5051f154020SRobert Mustacchi 	for (i = 0; i < ARRAY_SIZE(dis_riscv_csr_alias); i++) {
5061f154020SRobert Mustacchi 		dis_riscv_csr_alias_t *a = &dis_riscv_csr_alias[i];
5071f154020SRobert Mustacchi 		if (strcmp(a->drca_base, table->drv_name) != 0)
5081f154020SRobert Mustacchi 			continue;
5091f154020SRobert Mustacchi 		if (a->drca_csr != NULL && strcmp(a->drca_csr, csrstr) != 0)
5101f154020SRobert Mustacchi 			continue;
5111f154020SRobert Mustacchi 		if (a->drca_rd != -1 && a->drca_rd != rd)
5121f154020SRobert Mustacchi 			continue;
5131f154020SRobert Mustacchi 		if (a->drca_rs != -1 && a->drca_rs != rs)
5141f154020SRobert Mustacchi 			continue;
5151f154020SRobert Mustacchi 		alias = a;
5161f154020SRobert Mustacchi 		break;
5171f154020SRobert Mustacchi 	}
5181f154020SRobert Mustacchi 
5191f154020SRobert Mustacchi 	if (alias == NULL) {
5201f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s,%s", table->drv_name,
5211f154020SRobert Mustacchi 		    dis_riscv_regs[rd], csrstr, dis_riscv_regs[rs]);
5221f154020SRobert Mustacchi 		return;
5231f154020SRobert Mustacchi 	}
5241f154020SRobert Mustacchi 
5251f154020SRobert Mustacchi 	switch (alias->drca_type) {
5261f154020SRobert Mustacchi 	case DIS_RISCV_CSR_READ:
5271f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s", alias->drca_alias,
5281f154020SRobert Mustacchi 		    dis_riscv_regs[rd]);
5291f154020SRobert Mustacchi 		break;
5301f154020SRobert Mustacchi 	case DIS_RISCV_CSR_READ_GEN:
5311f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s", alias->drca_alias,
5321f154020SRobert Mustacchi 		    dis_riscv_regs[rd], csrstr);
5331f154020SRobert Mustacchi 		break;
5341f154020SRobert Mustacchi 	case DIS_RISCV_CSR_SWAP:
5351f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s", alias->drca_alias,
5361f154020SRobert Mustacchi 		    dis_riscv_regs[rd], dis_riscv_regs[rs]);
5371f154020SRobert Mustacchi 		break;
5381f154020SRobert Mustacchi 	case DIS_RISCV_CSR_WRITE:
5391f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s", alias->drca_alias,
5401f154020SRobert Mustacchi 		    dis_riscv_regs[rs]);
5411f154020SRobert Mustacchi 		break;
5421f154020SRobert Mustacchi 	case DIS_RISCV_CSR_WRITE_GEN:
5431f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s", alias->drca_alias,
5441f154020SRobert Mustacchi 		    csrstr, dis_riscv_regs[rs]);
5451f154020SRobert Mustacchi 		break;
5461f154020SRobert Mustacchi 	default:
5471f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "<unknown>");
5481f154020SRobert Mustacchi 		break;
5491f154020SRobert Mustacchi 	}
5501f154020SRobert Mustacchi }
5511f154020SRobert Mustacchi 
5521f154020SRobert Mustacchi static void
dis_riscv_csri(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)5531f154020SRobert Mustacchi dis_riscv_csri(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
5541f154020SRobert Mustacchi     char *buf, size_t buflen)
5551f154020SRobert Mustacchi {
5561f154020SRobert Mustacchi 	uint_t rd, csr, imm, i;
5571f154020SRobert Mustacchi 	const char *csrstr = NULL;
5581f154020SRobert Mustacchi 	char csrval[32];
5591f154020SRobert Mustacchi 	dis_riscv_csr_alias_t *alias = NULL;
5601f154020SRobert Mustacchi 
5611f154020SRobert Mustacchi 	rd = DIS_RISCV_RD(instr);
5621f154020SRobert Mustacchi 	imm = DIS_RISCV_RS1(instr);
5631f154020SRobert Mustacchi 	csr = DIS_RISCV_IIMM(instr);
5641f154020SRobert Mustacchi 
5651f154020SRobert Mustacchi 	for (i = 0; i < ARRAY_SIZE(dis_riscv_csr_map); i++) {
5661f154020SRobert Mustacchi 		if (csr == dis_riscv_csr_map[i].drc_val) {
5671f154020SRobert Mustacchi 			csrstr = dis_riscv_csr_map[i].drc_name;
5681f154020SRobert Mustacchi 			break;
5691f154020SRobert Mustacchi 		}
5701f154020SRobert Mustacchi 	}
5711f154020SRobert Mustacchi 
5721f154020SRobert Mustacchi 	if (csrstr == NULL) {
5731f154020SRobert Mustacchi 		(void) dis_snprintf(csrval, sizeof (csrval), "0x%x", csr);
5741f154020SRobert Mustacchi 		csrstr = csrval;
5751f154020SRobert Mustacchi 	}
5761f154020SRobert Mustacchi 
5771f154020SRobert Mustacchi 	for (i = 0; i < ARRAY_SIZE(dis_riscv_csr_alias); i++) {
5781f154020SRobert Mustacchi 		dis_riscv_csr_alias_t *a = &dis_riscv_csr_alias[i];
5791f154020SRobert Mustacchi 		if (strcmp(a->drca_base, table->drv_name) != 0)
5801f154020SRobert Mustacchi 			continue;
5811f154020SRobert Mustacchi 		if (a->drca_csr != NULL && strcmp(a->drca_csr, csrstr) != 0)
5821f154020SRobert Mustacchi 			continue;
5831f154020SRobert Mustacchi 		if (a->drca_rd != -1 && a->drca_rd != rd)
5841f154020SRobert Mustacchi 			continue;
5851f154020SRobert Mustacchi 		if (a->drca_rs != -1)
5861f154020SRobert Mustacchi 			continue;
5871f154020SRobert Mustacchi 		alias = a;
5881f154020SRobert Mustacchi 		break;
5891f154020SRobert Mustacchi 	}
5901f154020SRobert Mustacchi 
5911f154020SRobert Mustacchi 	if (alias == NULL) {
5921f154020SRobert Mustacchi 		if ((dhp->dh_flags & DIS_OCTAL) != 0) {
5931f154020SRobert Mustacchi 			(void) dis_snprintf(buf, buflen, "%s %s,%s,0%o",
5941f154020SRobert Mustacchi 			    table->drv_name, dis_riscv_regs[rd], csrstr, imm);
5951f154020SRobert Mustacchi 		} else {
5961f154020SRobert Mustacchi 			(void) dis_snprintf(buf, buflen, "%s %s,%s,0x%x",
5971f154020SRobert Mustacchi 			    table->drv_name, dis_riscv_regs[rd], csrstr, imm);
5981f154020SRobert Mustacchi 		}
5991f154020SRobert Mustacchi 		return;
6001f154020SRobert Mustacchi 	}
6011f154020SRobert Mustacchi 
6021f154020SRobert Mustacchi 	switch (alias->drca_type) {
6031f154020SRobert Mustacchi 	case DIS_RISCV_CSR_SWAP_IMM:
6041f154020SRobert Mustacchi 		if ((dhp->dh_flags & DIS_OCTAL) != 0) {
6051f154020SRobert Mustacchi 			(void) dis_snprintf(buf, buflen, "%s %s,0%o",
6061f154020SRobert Mustacchi 			    alias->drca_alias, dis_riscv_regs[rd], imm);
6071f154020SRobert Mustacchi 		} else {
6081f154020SRobert Mustacchi 			(void) dis_snprintf(buf, buflen, "%s %s,0x%x",
6091f154020SRobert Mustacchi 			    alias->drca_alias, dis_riscv_regs[rd], imm);
6101f154020SRobert Mustacchi 		}
6111f154020SRobert Mustacchi 		break;
6121f154020SRobert Mustacchi 	case DIS_RISCV_CSR_WRITE_IMM:
6131f154020SRobert Mustacchi 		if ((dhp->dh_flags & DIS_OCTAL) != 0) {
6141f154020SRobert Mustacchi 			(void) dis_snprintf(buf, buflen, "%s 0%o",
6151f154020SRobert Mustacchi 			    alias->drca_alias, imm);
6161f154020SRobert Mustacchi 		} else {
6171f154020SRobert Mustacchi 			(void) dis_snprintf(buf, buflen, "%s 0x%x",
6181f154020SRobert Mustacchi 			    alias->drca_alias, imm);
6191f154020SRobert Mustacchi 		}
6201f154020SRobert Mustacchi 		break;
6211f154020SRobert Mustacchi 	case DIS_RISCV_CSR_WRITE_IMM_GEN:
6221f154020SRobert Mustacchi 		if ((dhp->dh_flags & DIS_OCTAL) != 0) {
6231f154020SRobert Mustacchi 			(void) dis_snprintf(buf, buflen, "%s %s,0%o",
6241f154020SRobert Mustacchi 			    alias->drca_alias, csrstr, imm);
6251f154020SRobert Mustacchi 		} else {
6261f154020SRobert Mustacchi 			(void) dis_snprintf(buf, buflen, "%s %s,0x%x",
6271f154020SRobert Mustacchi 			    alias->drca_alias, csrstr, imm);
6281f154020SRobert Mustacchi 		}
6291f154020SRobert Mustacchi 		break;
6301f154020SRobert Mustacchi 	default:
6311f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "<unknown>");
6321f154020SRobert Mustacchi 		break;
6331f154020SRobert Mustacchi 	}
6341f154020SRobert Mustacchi }
6351f154020SRobert Mustacchi 
6361f154020SRobert Mustacchi #define	DIS_RISCV_FENCE_PRED(x)	(((x) >> 24) & 0xf)
6371f154020SRobert Mustacchi #define	DIS_RISCV_FENCE_SUCC(x)	(((x) >> 20) & 0xf)
6381f154020SRobert Mustacchi #define	DIS_RISCV_FENCE_I	0x8
6391f154020SRobert Mustacchi #define	DIS_RISCV_FENCE_O	0x4
6401f154020SRobert Mustacchi #define	DIS_RISCV_FENCE_R	0x2
6411f154020SRobert Mustacchi #define	DIS_RISCV_FENCE_W	0x1
6421f154020SRobert Mustacchi #define	DIS_RISCV_FENCE_IORW	0xf
6431f154020SRobert Mustacchi 
6441f154020SRobert Mustacchi /*ARGSUSED*/
6451f154020SRobert Mustacchi static void
dis_riscv_fence(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)6461f154020SRobert Mustacchi dis_riscv_fence(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
6471f154020SRobert Mustacchi     char *buf, size_t buflen)
6481f154020SRobert Mustacchi {
6491f154020SRobert Mustacchi 	uint_t pred, succ;
6501f154020SRobert Mustacchi 
6511f154020SRobert Mustacchi 	pred = DIS_RISCV_FENCE_PRED(instr);
6521f154020SRobert Mustacchi 	succ = DIS_RISCV_FENCE_SUCC(instr);
6531f154020SRobert Mustacchi 
6541f154020SRobert Mustacchi 	/*
6551f154020SRobert Mustacchi 	 * If both halves are iorw that is aliased to just an empty fence
6561f154020SRobert Mustacchi 	 * instruction per Chapter 20 - RISC-V Assembly Programmer's Handbook in
6571f154020SRobert Mustacchi 	 * the RISC-V user spec.
6581f154020SRobert Mustacchi 	 */
6591f154020SRobert Mustacchi 	if (pred == DIS_RISCV_FENCE_IORW && succ == DIS_RISCV_FENCE_IORW) {
6601f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s", table->drv_name);
6611f154020SRobert Mustacchi 		return;
6621f154020SRobert Mustacchi 	}
6631f154020SRobert Mustacchi 
6641f154020SRobert Mustacchi 	(void) dis_snprintf(buf, buflen, "%s %s%s%s%s, %s%s%s%s",
6651f154020SRobert Mustacchi 	    table->drv_name,
6661f154020SRobert Mustacchi 	    pred & DIS_RISCV_FENCE_I ? "i" : "",
6671f154020SRobert Mustacchi 	    pred & DIS_RISCV_FENCE_O ? "o" : "",
6681f154020SRobert Mustacchi 	    pred & DIS_RISCV_FENCE_R ? "r" : "",
6691f154020SRobert Mustacchi 	    pred & DIS_RISCV_FENCE_W ? "w" : "",
6701f154020SRobert Mustacchi 	    succ & DIS_RISCV_FENCE_I ? "i" : "",
6711f154020SRobert Mustacchi 	    succ & DIS_RISCV_FENCE_O ? "o" : "",
6721f154020SRobert Mustacchi 	    succ & DIS_RISCV_FENCE_R ? "r" : "",
6731f154020SRobert Mustacchi 	    succ & DIS_RISCV_FENCE_W ? "w" : "");
6741f154020SRobert Mustacchi }
6751f154020SRobert Mustacchi 
6761f154020SRobert Mustacchi /*ARGSUSED*/
6771f154020SRobert Mustacchi static void
dis_riscv_name(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)6781f154020SRobert Mustacchi dis_riscv_name(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
6791f154020SRobert Mustacchi     char *buf, size_t buflen)
6801f154020SRobert Mustacchi {
6811f154020SRobert Mustacchi 	(void) dis_snprintf(buf, buflen, "%s", table->drv_name);
6821f154020SRobert Mustacchi }
6831f154020SRobert Mustacchi 
6841f154020SRobert Mustacchi /*ARGSUSED*/
6851f154020SRobert Mustacchi static void
dis_riscv_rs1_rs2(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)6861f154020SRobert Mustacchi dis_riscv_rs1_rs2(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
6871f154020SRobert Mustacchi     char *buf, size_t buflen)
6881f154020SRobert Mustacchi {
6891f154020SRobert Mustacchi 	(void) dis_snprintf(buf, buflen, "%s %s,%s", table->drv_name,
6901f154020SRobert Mustacchi 	    dis_riscv_regs[DIS_RISCV_RS1(instr)],
6911f154020SRobert Mustacchi 	    dis_riscv_regs[DIS_RISCV_RS2(instr)]);
6921f154020SRobert Mustacchi }
6931f154020SRobert Mustacchi 
6941f154020SRobert Mustacchi /*ARGSUSED*/
6951f154020SRobert Mustacchi static void
dis_riscv_rv32a_load(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)6961f154020SRobert Mustacchi dis_riscv_rv32a_load(dis_handle_t *dhp, uint32_t instr,
6971f154020SRobert Mustacchi     dis_riscv_instr_t *table, char *buf, size_t buflen)
6981f154020SRobert Mustacchi {
6991f154020SRobert Mustacchi 	const char *suffix = "";
7001f154020SRobert Mustacchi 
7011f154020SRobert Mustacchi 	if (DIS_RISCV_RVA_AQ(instr) && DIS_RISCV_RVA_RL(instr)) {
7021f154020SRobert Mustacchi 		suffix = ".aqrl";
7031f154020SRobert Mustacchi 	} else if (DIS_RISCV_RVA_AQ(instr)) {
7041f154020SRobert Mustacchi 		suffix = ".aq";
7051f154020SRobert Mustacchi 	} else if (DIS_RISCV_RVA_RL(instr)) {
7061f154020SRobert Mustacchi 		suffix = ".rl";
7071f154020SRobert Mustacchi 	}
7081f154020SRobert Mustacchi 
7091f154020SRobert Mustacchi 	(void) dis_snprintf(buf, buflen, "%s%s %s,(%s)", table->drv_name,
7101f154020SRobert Mustacchi 	    suffix, dis_riscv_regs[DIS_RISCV_RD(instr)],
7111f154020SRobert Mustacchi 	    dis_riscv_regs[DIS_RISCV_RS1(instr)]);
7121f154020SRobert Mustacchi }
7131f154020SRobert Mustacchi 
7141f154020SRobert Mustacchi /*ARGSUSED*/
7151f154020SRobert Mustacchi static void
dis_riscv_rv32a(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)7161f154020SRobert Mustacchi dis_riscv_rv32a(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
7171f154020SRobert Mustacchi     char *buf, size_t buflen)
7181f154020SRobert Mustacchi {
7191f154020SRobert Mustacchi 	const char *suffix = "";
7201f154020SRobert Mustacchi 
7211f154020SRobert Mustacchi 	if (DIS_RISCV_RVA_AQ(instr) && DIS_RISCV_RVA_RL(instr)) {
7221f154020SRobert Mustacchi 		suffix = ".aqrl";
7231f154020SRobert Mustacchi 	} else if (DIS_RISCV_RVA_AQ(instr)) {
7241f154020SRobert Mustacchi 		suffix = ".aq";
7251f154020SRobert Mustacchi 	} else if (DIS_RISCV_RVA_RL(instr)) {
7261f154020SRobert Mustacchi 		suffix = ".rl";
7271f154020SRobert Mustacchi 	}
7281f154020SRobert Mustacchi 
7291f154020SRobert Mustacchi 	(void) dis_snprintf(buf, buflen, "%s%s %s,%s,(%s)", table->drv_name,
7301f154020SRobert Mustacchi 	    suffix, dis_riscv_regs[DIS_RISCV_RD(instr)],
7311f154020SRobert Mustacchi 	    dis_riscv_regs[DIS_RISCV_RS2(instr)],
7321f154020SRobert Mustacchi 	    dis_riscv_regs[DIS_RISCV_RS1(instr)]);
7331f154020SRobert Mustacchi }
7341f154020SRobert Mustacchi 
7351f154020SRobert Mustacchi static void
dis_riscv_fp_load(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)7361f154020SRobert Mustacchi dis_riscv_fp_load(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
7371f154020SRobert Mustacchi     char *buf, size_t buflen)
7381f154020SRobert Mustacchi {
7391f154020SRobert Mustacchi 	const char *s;
7401f154020SRobert Mustacchi 	uint_t imm = dis_riscv_sign_extend(DIS_RISCV_IIMM(instr), 11, &s);
7411f154020SRobert Mustacchi 
7421f154020SRobert Mustacchi 	if ((dhp->dh_flags & DIS_OCTAL) != 0) {
7431f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s0%o(%s)",
7441f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_fpregs[DIS_RISCV_RD(instr)],
7451f154020SRobert Mustacchi 		    s, imm, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
7461f154020SRobert Mustacchi 	} else {
7471f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s0x%x(%s)",
7481f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_fpregs[DIS_RISCV_RD(instr)],
7491f154020SRobert Mustacchi 		    s, imm, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
7501f154020SRobert Mustacchi 	}
7511f154020SRobert Mustacchi }
7521f154020SRobert Mustacchi 
7531f154020SRobert Mustacchi static void
dis_riscv_fp_store(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)7541f154020SRobert Mustacchi dis_riscv_fp_store(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
7551f154020SRobert Mustacchi     char *buf, size_t buflen)
7561f154020SRobert Mustacchi {
7571f154020SRobert Mustacchi 	const char *s;
7581f154020SRobert Mustacchi 	uint_t simm = DIS_RISCV_SIMM_UP(instr) | DIS_RISCV_SIMM_LOW(instr);
7591f154020SRobert Mustacchi 	uint_t val = dis_riscv_sign_extend(simm, 11, &s);
7601f154020SRobert Mustacchi 
7611f154020SRobert Mustacchi 	if ((dhp->dh_flags & DIS_OCTAL) != 0) {
7621f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s0%o(%s)",
7631f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_fpregs[DIS_RISCV_RS2(instr)],
7641f154020SRobert Mustacchi 		    s, val, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
7651f154020SRobert Mustacchi 	} else {
7661f154020SRobert Mustacchi 		(void) dis_snprintf(buf, buflen, "%s %s,%s0x%x(%s)",
7671f154020SRobert Mustacchi 		    table->drv_name, dis_riscv_fpregs[DIS_RISCV_RS2(instr)],
7681f154020SRobert Mustacchi 		    s, val, dis_riscv_regs[DIS_RISCV_RS1(instr)]);
7691f154020SRobert Mustacchi 	}
7701f154020SRobert Mustacchi }
7711f154020SRobert Mustacchi 
7721f154020SRobert Mustacchi /*ARGSUSED*/
7731f154020SRobert Mustacchi static void
dis_riscv_fp_r(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)7741f154020SRobert Mustacchi dis_riscv_fp_r(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
7751f154020SRobert Mustacchi     char *buf, size_t buflen)
7761f154020SRobert Mustacchi {
7771f154020SRobert Mustacchi 	(void) dis_snprintf(buf, buflen, "%s %s,%s,%s", table->drv_name,
7781f154020SRobert Mustacchi 	    dis_riscv_fpregs[DIS_RISCV_RD(instr)],
7791f154020SRobert Mustacchi 	    dis_riscv_fpregs[DIS_RISCV_RS1(instr)],
7801f154020SRobert Mustacchi 	    dis_riscv_fpregs[DIS_RISCV_RS2(instr)]);
7811f154020SRobert Mustacchi }
7821f154020SRobert Mustacchi 
7831f154020SRobert Mustacchi /*
7841f154020SRobert Mustacchi  * Variant of fp_r type that goes to integer destination registers.
7851f154020SRobert Mustacchi  */
7861f154020SRobert Mustacchi /*ARGSUSED*/
7871f154020SRobert Mustacchi static void
dis_riscv_fp_r_fpi(dis_handle_t * dhp,uint32_t instr,dis_riscv_instr_t * table,char * buf,size_t buflen)7881f154020SRobert Mustacchi dis_riscv_fp_r_fpi(dis_handle_t *dhp, uint32_t instr, dis_riscv_instr_t *table,
7891f154020SRobert Mustacchi     char *buf, size_t buflen)
7901f154020SRobert Mustacchi {
7911f154020SRobert Mustacchi 	(void) dis_snprintf(buf, buflen, "%s %s,%s,%s", table->drv_name,
7921f154020SRobert Mustacchi 	    dis_riscv_regs[DIS_RISCV_RD(instr)],
7931f154020SRobert Mustacchi 	    dis_riscv_fpregs[DIS_RISCV_RS1(instr)],
7941f154020SRobert Mustacchi 	    dis_riscv_fpregs[DIS_RISCV_RS2(instr)]);
7951f154020SRobert Mustacchi }
7961f154020SRobert Mustacchi 
7971f154020SRobert Mustacchi /*ARGSUSED*/
798