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