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