isa.c (62102B)
1 /* RV64 instruction descriptor table + operand print dispatch. 2 * 3 * Mirrors the aa64_isa.c pattern. Each row records (mnemonic, match, 4 * mask, format, flags); rv64_disasm_find returns the first row whose 5 * masked bits match the word, and rv64_print_operands renders the 6 * operand text using the format's unpack helper. 7 * 8 * Row ordering: first-match wins. Aliases (rows with RV64_ASMFL_ALIAS) 9 * use tighter masks placed BEFORE the canonical row they alias so the 10 * disassembler renders the alias spelling. The assembler accepts both 11 * forms via rv64_asm_find which prefers the canonical row. */ 12 13 #include "arch/rv64/isa.h" 14 15 #include <string.h> 16 17 #include "core/slice.h" 18 #include "core/strbuf.h" 19 20 /* True if `s` begins with the NUL-terminated literal `pfx` (length-explicit). 21 */ 22 static bool slice_has_prefix_cstr(Slice s, const char* pfx, size_t n) { 23 return s.len >= n && memcmp(s.s, pfx, n) == 0; 24 } 25 26 /* Family-match bit patterns. The opcode (bits 6:0) plus 27 * funct3/funct7/funct5 selectors narrow each match. For aliases we pin 28 * specific register fields (e.g. rs1=x0 for `li`, rd=x0 for `j`). */ 29 30 /* Helper: build a 32-bit match for R-type with fixed funct7/funct3/op. */ 31 #define MATCH_R(funct7, funct3, op) \ 32 (((u32)(funct7) << 25) | ((u32)(funct3) << 12) | (u32)(op)) 33 #define MASK_R (0xfe00707fu) /* funct7 + funct3 + opcode */ 34 35 #define MATCH_I(funct3, op) (((u32)(funct3) << 12) | (u32)(op)) 36 #define MASK_I (0x0000707fu) /* funct3 + opcode */ 37 38 #define MATCH_S(funct3, op) (((u32)(funct3) << 12) | (u32)(op)) 39 #define MASK_S (0x0000707fu) 40 41 #define MATCH_B(funct3, op) (((u32)(funct3) << 12) | (u32)(op)) 42 #define MASK_B (0x0000707fu) 43 44 #define MATCH_U(op) ((u32)(op)) 45 #define MASK_U (0x0000007fu) 46 47 #define MATCH_J(op) ((u32)(op)) 48 #define MASK_J (0x0000007fu) 49 50 /* FP fused multiply-add/sub: rs3(31:27) fmt(26:25) rs2 rs1 rm rd op. */ 51 #define MATCH_R4(fmt, op) (((u32)(fmt) << 25) | (u32)(op)) 52 #define MASK_R4 (0x0600007fu) 53 54 /* I-type shift in RV64: funct6 (bits 31:26) is the selector + opcode + 55 * funct3. shamt occupies bits 25:20. */ 56 #define MATCH_ISHIFT(funct6, funct3, op) \ 57 (((u32)(funct6) << 26) | ((u32)(funct3) << 12) | (u32)(op)) 58 #define MASK_ISHIFT (0xfc00707fu) 59 60 /* I-type shift in 32-bit (W) form uses 7-bit funct7 + 5-bit shamt. */ 61 #define MATCH_ISHIFTW(funct7, funct3, op) \ 62 (((u32)(funct7) << 25) | ((u32)(funct3) << 12) | (u32)(op)) 63 #define MASK_ISHIFTW (0xfe00707fu) 64 65 /* AMO: aq/rl bits 26/25 vary, so mask must exclude them. funct5 is 66 * bits[31:27]. */ 67 #define MATCH_AMO(funct5, funct3, op) \ 68 (((u32)(funct5) << 27) | ((u32)(funct3) << 12) | (u32)(op)) 69 #define MASK_AMO (0xf800707fu) 70 #define MATCH_AMO_ORDER(funct5, aq, rl, funct3, op) \ 71 (((u32)(funct5) << 27) | ((u32)(aq) << 26) | ((u32)(rl) << 25) | \ 72 ((u32)(funct3) << 12) | (u32)(op)) 73 #define MASK_AMO_ORDER (MASK_AMO | (3u << 25)) 74 75 /* FP arithmetic with rm — rm field (funct3) is don't-care. funct7 76 * encodes op-major and format. */ 77 #define MATCH_FP_RM(funct7, op) (((u32)(funct7) << 25) | (u32)(op)) 78 #define MASK_FP_RM (0xfe00007fu) 79 80 /* FP R-type with fixed funct3 (compare or sign-injection variants). */ 81 #define MATCH_FP_R(funct7, funct3, op) MATCH_R((funct7), (funct3), (op)) 82 #define MASK_FP_R MASK_R 83 84 /* FP conversion: funct7 + rs2 (type selector) + funct3-as-rm don't-care 85 * + opcode. The rs2 field (bits 24:20) selects integer width / signedness. */ 86 #define MATCH_FP_CVT(funct7, rs2, op) \ 87 (((u32)(funct7) << 25) | ((u32)(rs2) << 20) | (u32)(op)) 88 #define MASK_FP_CVT (0xfff0007fu) 89 90 /* SYSTEM (ECALL/EBREAK) — full 32-bit value matches a single instruction. */ 91 #define MATCH_FULL(w) ((u32)(w)) 92 #define MASK_FULL (0xffffffffu) 93 94 /* CSR — Zicsr. csr (imm12) is don't-care, but funct3+opcode pin the op. */ 95 #define MATCH_CSR(funct3) (((u32)(funct3) << 12) | (u32)RV_SYSTEM) 96 #define MASK_CSR (0x0000707fu) 97 98 /* Compressed 16-bit instructions live in low 16 bits of the descriptor 99 * word; the mask zeroes bits 16+ to ensure a match against the C-decode 100 * path which presents the halfword in low 16 bits. */ 101 #define MATCH_C(w16) ((u32)(w16)) 102 103 /* Mnemonic Slice literal for a static table row (compile-time length). */ 104 #define MN(s) {{(s)}, sizeof(s) - 1} 105 106 const Rv64InsnDesc rv64_insn_table[] = { 107 /* ================================================================= 108 * RV64I base — integer register ops (R-type, OP=0x33) 109 * ================================================================= */ 110 {MN("add"), MATCH_R(0x00, 0x0, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 111 {MN("sub"), MATCH_R(0x20, 0x0, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 112 {MN("sll"), MATCH_R(0x00, 0x1, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 113 {MN("slt"), MATCH_R(0x00, 0x2, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 114 {MN("sltu"), MATCH_R(0x00, 0x3, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 115 {MN("xor"), MATCH_R(0x00, 0x4, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 116 {MN("srl"), MATCH_R(0x00, 0x5, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 117 {MN("sra"), MATCH_R(0x20, 0x5, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 118 {MN("or"), MATCH_R(0x00, 0x6, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 119 {MN("and"), MATCH_R(0x00, 0x7, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 120 121 /* 32-bit (W) variants — OP_32 = 0x3b */ 122 {MN("addw"), MATCH_R(0x00, 0x0, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, 123 {MN("subw"), MATCH_R(0x20, 0x0, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, 124 {MN("sllw"), MATCH_R(0x00, 0x1, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, 125 {MN("srlw"), MATCH_R(0x00, 0x5, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, 126 {MN("sraw"), MATCH_R(0x20, 0x5, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, 127 128 /* ---- I-type immediate ALU (OP_IMM=0x13) ---- 129 * Aliases: `li rd, imm` = ADDI rd, x0, imm (rs1=x0). 130 * `mv rd, rs1` = ADDI rd, rs1, 0 (imm=0). 131 * `nop` = ADDI x0, x0, 0 (full word fixed). */ 132 {MN("nop"), 133 0x00000013u, 134 0xffffffffu, 135 RV64_FMT_SYSTEM, 136 RV64_ASMFL_ALIAS, 137 {0, 0}}, 138 {MN("li"), 0x00000013u, 0x000f807fu, RV64_FMT_I, RV64_ASMFL_ALIAS, {0, 0}}, 139 /* mv: ADDI with imm=0. mask requires imm12=0 + funct3=0 + op. */ 140 {MN("mv"), 0x00000013u, 0xfff0707fu, RV64_FMT_I, RV64_ASMFL_ALIAS, {0, 0}}, 141 /* seqz: SLTIU rd, rs, 1 — funct3=3, imm12=1, op=OP_IMM. */ 142 {MN("seqz"), 143 0x00103013u, 144 0xfff0707fu, 145 RV64_FMT_I, 146 RV64_ASMFL_ALIAS, 147 {0, 0}}, 148 /* snez: SLTU rd, x0, rs2 — rs1=x0, funct3=3, op=OP. */ 149 {MN("snez"), 150 0x00003033u, 151 0xfe0ff07fu, 152 RV64_FMT_R, 153 RV64_ASMFL_ALIAS, 154 {0, 0}}, 155 /* not: XORI rd, rs, -1 — imm12=0xfff, funct3=4, op=OP_IMM. */ 156 {MN("not"), 0xfff04013u, 0xfff0707fu, RV64_FMT_I, RV64_ASMFL_ALIAS, {0, 0}}, 157 /* neg: SUB rd, x0, rs2 — rs1=x0, funct7=0x20, funct3=0. */ 158 {MN("neg"), 0x40000033u, 0xfe0ff07fu, RV64_FMT_R, RV64_ASMFL_ALIAS, {0, 0}}, 159 /* negw: SUBW rd, x0, rs2. */ 160 {MN("negw"), 161 0x4000003bu, 162 0xfe0ff07fu, 163 RV64_FMT_R, 164 RV64_ASMFL_ALIAS, 165 {0, 0}}, 166 {MN("addi"), MATCH_I(0x0, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, 167 {MN("slti"), MATCH_I(0x2, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, 168 {MN("sltiu"), MATCH_I(0x3, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, 169 {MN("xori"), MATCH_I(0x4, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, 170 {MN("ori"), MATCH_I(0x6, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, 171 {MN("andi"), MATCH_I(0x7, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, 172 173 /* RV64I shift-imm: funct6 in bits 31:26, shamt in 25:20. */ 174 {MN("slli"), 175 MATCH_ISHIFT(0x00, 0x1, RV_OP_IMM), 176 MASK_ISHIFT, 177 RV64_FMT_I_SHIFT, 178 0, 179 {0, 0}}, 180 {MN("srli"), 181 MATCH_ISHIFT(0x00, 0x5, RV_OP_IMM), 182 MASK_ISHIFT, 183 RV64_FMT_I_SHIFT, 184 0, 185 {0, 0}}, 186 {MN("srai"), 187 MATCH_ISHIFT(0x10, 0x5, RV_OP_IMM), 188 MASK_ISHIFT, 189 RV64_FMT_I_SHIFT, 190 0, 191 {0, 0}}, 192 193 /* OP_IMM_32: ADDIW + word shifts. sext.w alias = ADDIW rd, rs, 0. */ 194 {MN("sext.w"), 195 0x0000001bu, 196 0xfff0707fu, 197 RV64_FMT_I, 198 RV64_ASMFL_ALIAS, 199 {0, 0}}, 200 {MN("addiw"), MATCH_I(0x0, RV_OP_IMM_32), MASK_I, RV64_FMT_I, 0, {0, 0}}, 201 {MN("slliw"), 202 MATCH_ISHIFTW(0x00, 0x1, RV_OP_IMM_32), 203 MASK_ISHIFTW, 204 RV64_FMT_I_SHIFTW, 205 0, 206 {0, 0}}, 207 {MN("srliw"), 208 MATCH_ISHIFTW(0x00, 0x5, RV_OP_IMM_32), 209 MASK_ISHIFTW, 210 RV64_FMT_I_SHIFTW, 211 0, 212 {0, 0}}, 213 {MN("sraiw"), 214 MATCH_ISHIFTW(0x20, 0x5, RV_OP_IMM_32), 215 MASK_ISHIFTW, 216 RV64_FMT_I_SHIFTW, 217 0, 218 {0, 0}}, 219 220 /* ---- LUI / AUIPC ---- */ 221 {MN("lui"), MATCH_U(RV_LUI), MASK_U, RV64_FMT_U, 0, {0, 0}}, 222 {MN("auipc"), MATCH_U(RV_AUIPC), MASK_U, RV64_FMT_U, 0, {0, 0}}, 223 224 /* ---- Loads (I-type, op=LOAD=0x03) ---- */ 225 {MN("lb"), MATCH_I(0x0, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, 226 {MN("lh"), MATCH_I(0x1, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, 227 {MN("lw"), MATCH_I(0x2, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, 228 {MN("ld"), MATCH_I(0x3, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, 229 {MN("lbu"), MATCH_I(0x4, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, 230 {MN("lhu"), MATCH_I(0x5, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, 231 {MN("lwu"), MATCH_I(0x6, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, 232 233 /* ---- Stores (S-type, op=STORE=0x23) ---- */ 234 {MN("sb"), MATCH_S(0x0, RV_STORE), MASK_S, RV64_FMT_STORE, 0, {0, 0}}, 235 {MN("sh"), MATCH_S(0x1, RV_STORE), MASK_S, RV64_FMT_STORE, 0, {0, 0}}, 236 {MN("sw"), MATCH_S(0x2, RV_STORE), MASK_S, RV64_FMT_STORE, 0, {0, 0}}, 237 {MN("sd"), MATCH_S(0x3, RV_STORE), MASK_S, RV64_FMT_STORE, 0, {0, 0}}, 238 239 /* ---- Branches (B-type, op=BRANCH=0x63) ---- 240 * Aliases: `beqz rs, off` = BEQ rs, x0, off; `bnez rs, off` = BNE. */ 241 {MN("beqz"), 242 0x00000063u, 243 0x01f0707fu, 244 RV64_FMT_B, 245 RV64_ASMFL_ALIAS, 246 {0, 0}}, 247 {MN("bnez"), 248 0x00001063u, 249 0x01f0707fu, 250 RV64_FMT_B, 251 RV64_ASMFL_ALIAS, 252 {0, 0}}, 253 {MN("beq"), MATCH_B(0x0, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, 254 {MN("bne"), MATCH_B(0x1, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, 255 {MN("blt"), MATCH_B(0x4, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, 256 {MN("bge"), MATCH_B(0x5, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, 257 {MN("bltu"), MATCH_B(0x6, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, 258 {MN("bgeu"), MATCH_B(0x7, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, 259 260 /* ---- JAL / JALR ---- 261 * `j off` = JAL x0, off (rd=x0). 262 * `jal off` = JAL ra, off (rd=ra, single-operand form). 263 * `ret` = JALR x0, 0(ra) (rd=x0 + rs1=ra + imm=0). 264 * `jr rs` = JALR x0, 0(rs) (rd=x0, imm=0). 265 * `jalr rs` = JALR ra, 0(rs) (rd=ra, imm=0). */ 266 {MN("ret"), 267 0x00008067u, 268 0xffffffffu, 269 RV64_FMT_SYSTEM, 270 RV64_ASMFL_ALIAS, 271 {0, 0}}, 272 {MN("jr"), 273 0x00000067u, 274 0xfff07fffu, 275 RV64_FMT_JALR, 276 RV64_ASMFL_ALIAS, 277 {0, 0}}, 278 {MN("j"), 0x0000006fu, 0x00000fffu, RV64_FMT_J, RV64_ASMFL_ALIAS, {0, 0}}, 279 {MN("jal"), MATCH_J(RV_JAL), MASK_J, RV64_FMT_J, 0, {0, 0}}, 280 {MN("jalr"), MATCH_I(0x0, RV_JALR), MASK_I, RV64_FMT_JALR, 0, {0, 0}}, 281 282 /* ---- Multi-word pseudo-instructions ---- 283 * `call sym` = AUIPC ra, %pcrel_hi(sym); JALR ra, %pcrel_lo(ra) — one 284 * R_RV_CALL reloc at the AUIPC; the linker patches both. 285 * `tail sym` = AUIPC t1, ...; JALR zero, t1 — same R_RV_CALL reloc. 286 * `la rd,sym` / `lla rd,sym` = AUIPC rd, %pcrel_hi(sym); ADDI rd, rd, 287 * %pcrel_lo. kit's static Local-Exec model treats `la` 288 * and `lla` identically (no GOT indirection). The match 289 * column is unused: RV64_FMT_PSEUDO dispatches on the 290 * mnemonic and emits the expansion directly. */ 291 {MN("call"), 0u, 0u, RV64_FMT_PSEUDO, RV64_ASMFL_PSEUDO, {0, 0}}, 292 {MN("tail"), 0u, 0u, RV64_FMT_PSEUDO, RV64_ASMFL_PSEUDO, {0, 0}}, 293 {MN("la"), 0u, 0u, RV64_FMT_PSEUDO, RV64_ASMFL_PSEUDO, {0, 0}}, 294 {MN("lla"), 0u, 0u, RV64_FMT_PSEUDO, RV64_ASMFL_PSEUDO, {0, 0}}, 295 296 /* ---- FENCE ---- */ 297 {MN("fence"), MATCH_I(0x0, RV_FENCE), MASK_I, RV64_FMT_FENCE, 0, {0, 0}}, 298 {MN("fence.i"), 299 MATCH_FULL(0x0000100fu), 300 MASK_FULL, 301 RV64_FMT_SYSTEM, 302 0, 303 {0, 0}}, 304 305 /* ---- System (ECALL/EBREAK) ---- */ 306 {MN("ecall"), 307 MATCH_FULL(0x00000073u), 308 MASK_FULL, 309 RV64_FMT_SYSTEM, 310 0, 311 {0, 0}}, 312 {MN("ebreak"), 313 MATCH_FULL(0x00100073u), 314 MASK_FULL, 315 RV64_FMT_SYSTEM, 316 0, 317 {0, 0}}, 318 319 /* ================================================================= 320 * Zicsr (CSR access) — RV_SYSTEM with funct3 ∈ {1..3, 5..7}. 321 * ================================================================= */ 322 {MN("csrrw"), MATCH_CSR(0x1), MASK_CSR, RV64_FMT_CSR, 0, {0, 0}}, 323 {MN("csrrs"), MATCH_CSR(0x2), MASK_CSR, RV64_FMT_CSR, 0, {0, 0}}, 324 {MN("csrrc"), MATCH_CSR(0x3), MASK_CSR, RV64_FMT_CSR, 0, {0, 0}}, 325 {MN("csrrwi"), MATCH_CSR(0x5), MASK_CSR, RV64_FMT_CSRI, 0, {0, 0}}, 326 {MN("csrrsi"), MATCH_CSR(0x6), MASK_CSR, RV64_FMT_CSRI, 0, {0, 0}}, 327 {MN("csrrci"), MATCH_CSR(0x7), MASK_CSR, RV64_FMT_CSRI, 0, {0, 0}}, 328 329 /* ================================================================= 330 * RV64M (multiply / divide) — funct7 = 0x01 331 * ================================================================= */ 332 {MN("mul"), MATCH_R(0x01, 0x0, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 333 {MN("mulh"), MATCH_R(0x01, 0x1, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 334 {MN("mulhsu"), MATCH_R(0x01, 0x2, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 335 {MN("mulhu"), MATCH_R(0x01, 0x3, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 336 {MN("div"), MATCH_R(0x01, 0x4, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 337 {MN("divu"), MATCH_R(0x01, 0x5, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 338 {MN("rem"), MATCH_R(0x01, 0x6, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 339 {MN("remu"), MATCH_R(0x01, 0x7, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, 340 {MN("mulw"), MATCH_R(0x01, 0x0, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, 341 {MN("divw"), MATCH_R(0x01, 0x4, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, 342 {MN("divuw"), MATCH_R(0x01, 0x5, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, 343 {MN("remw"), MATCH_R(0x01, 0x6, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, 344 {MN("remuw"), MATCH_R(0x01, 0x7, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, 345 346 /* ================================================================= 347 * RV32F / RV32D — single and double precision FP 348 * ================================================================= */ 349 /* FP fused multiply-add/subtract — rm defaults to dyn in the assembler. */ 350 {MN("fmadd.s"), 351 MATCH_R4(RV_FMT_S, RV_MADD), 352 MASK_R4, 353 RV64_FMT_R4, 354 RV64_ASMFL_FP, 355 {0, 0}}, 356 {MN("fmsub.s"), 357 MATCH_R4(RV_FMT_S, RV_MSUB), 358 MASK_R4, 359 RV64_FMT_R4, 360 RV64_ASMFL_FP, 361 {0, 0}}, 362 {MN("fnmsub.s"), 363 MATCH_R4(RV_FMT_S, RV_NMSUB), 364 MASK_R4, 365 RV64_FMT_R4, 366 RV64_ASMFL_FP, 367 {0, 0}}, 368 {MN("fnmadd.s"), 369 MATCH_R4(RV_FMT_S, RV_NMADD), 370 MASK_R4, 371 RV64_FMT_R4, 372 RV64_ASMFL_FP, 373 {0, 0}}, 374 {MN("fmadd.d"), 375 MATCH_R4(RV_FMT_D, RV_MADD), 376 MASK_R4, 377 RV64_FMT_R4, 378 RV64_ASMFL_FP, 379 {0, 0}}, 380 {MN("fmsub.d"), 381 MATCH_R4(RV_FMT_D, RV_MSUB), 382 MASK_R4, 383 RV64_FMT_R4, 384 RV64_ASMFL_FP, 385 {0, 0}}, 386 {MN("fnmsub.d"), 387 MATCH_R4(RV_FMT_D, RV_NMSUB), 388 MASK_R4, 389 RV64_FMT_R4, 390 RV64_ASMFL_FP, 391 {0, 0}}, 392 {MN("fnmadd.d"), 393 MATCH_R4(RV_FMT_D, RV_NMADD), 394 MASK_R4, 395 RV64_FMT_R4, 396 RV64_ASMFL_FP, 397 {0, 0}}, 398 399 /* FP arithmetic — rm field (funct3) is the rounding mode and prints 400 * as the DYN(=7) default suppressed. funct7 low bits select fmt. */ 401 {MN("fadd.s"), 402 MATCH_FP_RM(0x00, RV_OP_FP), 403 MASK_FP_RM, 404 RV64_FMT_FP_RM, 405 RV64_ASMFL_FP, 406 {0, 0}}, 407 {MN("fsub.s"), 408 MATCH_FP_RM(0x04, RV_OP_FP), 409 MASK_FP_RM, 410 RV64_FMT_FP_RM, 411 RV64_ASMFL_FP, 412 {0, 0}}, 413 {MN("fmul.s"), 414 MATCH_FP_RM(0x08, RV_OP_FP), 415 MASK_FP_RM, 416 RV64_FMT_FP_RM, 417 RV64_ASMFL_FP, 418 {0, 0}}, 419 {MN("fdiv.s"), 420 MATCH_FP_RM(0x0c, RV_OP_FP), 421 MASK_FP_RM, 422 RV64_FMT_FP_RM, 423 RV64_ASMFL_FP, 424 {0, 0}}, 425 {MN("fadd.d"), 426 MATCH_FP_RM(0x01, RV_OP_FP), 427 MASK_FP_RM, 428 RV64_FMT_FP_RM, 429 RV64_ASMFL_FP, 430 {0, 0}}, 431 {MN("fsub.d"), 432 MATCH_FP_RM(0x05, RV_OP_FP), 433 MASK_FP_RM, 434 RV64_FMT_FP_RM, 435 RV64_ASMFL_FP, 436 {0, 0}}, 437 {MN("fmul.d"), 438 MATCH_FP_RM(0x09, RV_OP_FP), 439 MASK_FP_RM, 440 RV64_FMT_FP_RM, 441 RV64_ASMFL_FP, 442 {0, 0}}, 443 {MN("fdiv.d"), 444 MATCH_FP_RM(0x0d, RV_OP_FP), 445 MASK_FP_RM, 446 RV64_FMT_FP_RM, 447 RV64_ASMFL_FP, 448 {0, 0}}, 449 450 /* FP sqrt — funct7 = 0x2c (S) / 0x2d (D), rs2 must be 0. */ 451 {MN("fsqrt.s"), 452 MATCH_FP_CVT(0x2c, 0x0, RV_OP_FP), 453 MASK_FP_CVT, 454 RV64_FMT_FP_CVT, 455 RV64_ASMFL_FP, 456 {0, 0}}, 457 {MN("fsqrt.d"), 458 MATCH_FP_CVT(0x2d, 0x0, RV_OP_FP), 459 MASK_FP_CVT, 460 RV64_FMT_FP_CVT, 461 RV64_ASMFL_FP, 462 {0, 0}}, 463 464 /* FP min/max — funct7 = 0x14/0x15, funct3 = 0 (min) / 1 (max). */ 465 {MN("fmin.s"), 466 MATCH_FP_R(0x14, 0x0, RV_OP_FP), 467 MASK_FP_R, 468 RV64_FMT_FP_R, 469 RV64_ASMFL_FP | RV64_ASMFL_NORM, 470 {0, 0}}, 471 {MN("fmax.s"), 472 MATCH_FP_R(0x14, 0x1, RV_OP_FP), 473 MASK_FP_R, 474 RV64_FMT_FP_R, 475 RV64_ASMFL_FP | RV64_ASMFL_NORM, 476 {0, 0}}, 477 {MN("fmin.d"), 478 MATCH_FP_R(0x15, 0x0, RV_OP_FP), 479 MASK_FP_R, 480 RV64_FMT_FP_R, 481 RV64_ASMFL_FP | RV64_ASMFL_NORM, 482 {0, 0}}, 483 {MN("fmax.d"), 484 MATCH_FP_R(0x15, 0x1, RV_OP_FP), 485 MASK_FP_R, 486 RV64_FMT_FP_R, 487 RV64_ASMFL_FP | RV64_ASMFL_NORM, 488 {0, 0}}, 489 490 /* FP sign-injection — funct7 = 0x10/0x11, funct3 = 0/1/2 = J/JN/JX. */ 491 {MN("fsgnj.s"), 492 MATCH_FP_R(0x10, 0x0, RV_OP_FP), 493 MASK_FP_R, 494 RV64_FMT_FP_R, 495 RV64_ASMFL_FP | RV64_ASMFL_NORM, 496 {0, 0}}, 497 {MN("fsgnjn.s"), 498 MATCH_FP_R(0x10, 0x1, RV_OP_FP), 499 MASK_FP_R, 500 RV64_FMT_FP_R, 501 RV64_ASMFL_FP | RV64_ASMFL_NORM, 502 {0, 0}}, 503 {MN("fsgnjx.s"), 504 MATCH_FP_R(0x10, 0x2, RV_OP_FP), 505 MASK_FP_R, 506 RV64_FMT_FP_R, 507 RV64_ASMFL_FP | RV64_ASMFL_NORM, 508 {0, 0}}, 509 {MN("fsgnj.d"), 510 MATCH_FP_R(0x11, 0x0, RV_OP_FP), 511 MASK_FP_R, 512 RV64_FMT_FP_R, 513 RV64_ASMFL_FP | RV64_ASMFL_NORM, 514 {0, 0}}, 515 {MN("fsgnjn.d"), 516 MATCH_FP_R(0x11, 0x1, RV_OP_FP), 517 MASK_FP_R, 518 RV64_FMT_FP_R, 519 RV64_ASMFL_FP | RV64_ASMFL_NORM, 520 {0, 0}}, 521 {MN("fsgnjx.d"), 522 MATCH_FP_R(0x11, 0x2, RV_OP_FP), 523 MASK_FP_R, 524 RV64_FMT_FP_R, 525 RV64_ASMFL_FP | RV64_ASMFL_NORM, 526 {0, 0}}, 527 528 /* FP compare — funct7 = 0x50 (S) / 0x51 (D), funct3 = 0/1/2 = LE/LT/EQ. 529 * rd is integer GPR (not FP). */ 530 {MN("fle.s"), 531 MATCH_FP_R(0x50, 0x0, RV_OP_FP), 532 MASK_FP_R, 533 RV64_FMT_FP_R, 534 RV64_ASMFL_NORM, 535 {0, 0}}, 536 {MN("flt.s"), 537 MATCH_FP_R(0x50, 0x1, RV_OP_FP), 538 MASK_FP_R, 539 RV64_FMT_FP_R, 540 RV64_ASMFL_NORM, 541 {0, 0}}, 542 {MN("feq.s"), 543 MATCH_FP_R(0x50, 0x2, RV_OP_FP), 544 MASK_FP_R, 545 RV64_FMT_FP_R, 546 RV64_ASMFL_NORM, 547 {0, 0}}, 548 {MN("fle.d"), 549 MATCH_FP_R(0x51, 0x0, RV_OP_FP), 550 MASK_FP_R, 551 RV64_FMT_FP_R, 552 RV64_ASMFL_NORM, 553 {0, 0}}, 554 {MN("flt.d"), 555 MATCH_FP_R(0x51, 0x1, RV_OP_FP), 556 MASK_FP_R, 557 RV64_FMT_FP_R, 558 RV64_ASMFL_NORM, 559 {0, 0}}, 560 {MN("feq.d"), 561 MATCH_FP_R(0x51, 0x2, RV_OP_FP), 562 MASK_FP_R, 563 RV64_FMT_FP_R, 564 RV64_ASMFL_NORM, 565 {0, 0}}, 566 567 /* FP classification — rd is GPR, rs1 is FPR, rs2=0, rm/funct3=1. */ 568 {MN("fclass.s"), 569 MATCH_FP_R(0x70, 0x1, RV_OP_FP) | (0u << 20), 570 MASK_FP_CVT | (7u << 12), 571 RV64_FMT_FP_CVT, 572 0, 573 {0, 0}}, 574 {MN("fclass.d"), 575 MATCH_FP_R(0x71, 0x1, RV_OP_FP) | (0u << 20), 576 MASK_FP_CVT | (7u << 12), 577 RV64_FMT_FP_CVT, 578 0, 579 {0, 0}}, 580 581 /* FP conversions — funct7 selects {direction, fmt}, rs2 selects 582 * integer width/signedness. */ 583 {MN("fcvt.w.s"), 584 MATCH_FP_CVT(0x60, 0x0, RV_OP_FP), 585 MASK_FP_CVT, 586 RV64_FMT_FP_CVT, 587 0, 588 {0, 0}}, 589 {MN("fcvt.wu.s"), 590 MATCH_FP_CVT(0x60, 0x1, RV_OP_FP), 591 MASK_FP_CVT, 592 RV64_FMT_FP_CVT, 593 0, 594 {0, 0}}, 595 {MN("fcvt.l.s"), 596 MATCH_FP_CVT(0x60, 0x2, RV_OP_FP), 597 MASK_FP_CVT, 598 RV64_FMT_FP_CVT, 599 0, 600 {0, 0}}, 601 {MN("fcvt.lu.s"), 602 MATCH_FP_CVT(0x60, 0x3, RV_OP_FP), 603 MASK_FP_CVT, 604 RV64_FMT_FP_CVT, 605 0, 606 {0, 0}}, 607 {MN("fcvt.w.d"), 608 MATCH_FP_CVT(0x61, 0x0, RV_OP_FP), 609 MASK_FP_CVT, 610 RV64_FMT_FP_CVT, 611 0, 612 {0, 0}}, 613 {MN("fcvt.wu.d"), 614 MATCH_FP_CVT(0x61, 0x1, RV_OP_FP), 615 MASK_FP_CVT, 616 RV64_FMT_FP_CVT, 617 0, 618 {0, 0}}, 619 {MN("fcvt.l.d"), 620 MATCH_FP_CVT(0x61, 0x2, RV_OP_FP), 621 MASK_FP_CVT, 622 RV64_FMT_FP_CVT, 623 0, 624 {0, 0}}, 625 {MN("fcvt.lu.d"), 626 MATCH_FP_CVT(0x61, 0x3, RV_OP_FP), 627 MASK_FP_CVT, 628 RV64_FMT_FP_CVT, 629 0, 630 {0, 0}}, 631 {MN("fcvt.s.w"), 632 MATCH_FP_CVT(0x68, 0x0, RV_OP_FP), 633 MASK_FP_CVT, 634 RV64_FMT_FP_CVT, 635 RV64_ASMFL_FP, 636 {0, 0}}, 637 {MN("fcvt.s.wu"), 638 MATCH_FP_CVT(0x68, 0x1, RV_OP_FP), 639 MASK_FP_CVT, 640 RV64_FMT_FP_CVT, 641 RV64_ASMFL_FP, 642 {0, 0}}, 643 {MN("fcvt.s.l"), 644 MATCH_FP_CVT(0x68, 0x2, RV_OP_FP), 645 MASK_FP_CVT, 646 RV64_FMT_FP_CVT, 647 RV64_ASMFL_FP, 648 {0, 0}}, 649 {MN("fcvt.s.lu"), 650 MATCH_FP_CVT(0x68, 0x3, RV_OP_FP), 651 MASK_FP_CVT, 652 RV64_FMT_FP_CVT, 653 RV64_ASMFL_FP, 654 {0, 0}}, 655 {MN("fcvt.d.w"), 656 MATCH_FP_CVT(0x69, 0x0, RV_OP_FP), 657 MASK_FP_CVT, 658 RV64_FMT_FP_CVT, 659 RV64_ASMFL_FP, 660 {0, 0}}, 661 {MN("fcvt.d.wu"), 662 MATCH_FP_CVT(0x69, 0x1, RV_OP_FP), 663 MASK_FP_CVT, 664 RV64_FMT_FP_CVT, 665 RV64_ASMFL_FP, 666 {0, 0}}, 667 {MN("fcvt.d.l"), 668 MATCH_FP_CVT(0x69, 0x2, RV_OP_FP), 669 MASK_FP_CVT, 670 RV64_FMT_FP_CVT, 671 RV64_ASMFL_FP, 672 {0, 0}}, 673 {MN("fcvt.d.lu"), 674 MATCH_FP_CVT(0x69, 0x3, RV_OP_FP), 675 MASK_FP_CVT, 676 RV64_FMT_FP_CVT, 677 RV64_ASMFL_FP, 678 {0, 0}}, 679 {MN("fcvt.s.d"), 680 MATCH_FP_CVT(0x20, 0x1, RV_OP_FP), 681 MASK_FP_CVT, 682 RV64_FMT_FP_CVT, 683 RV64_ASMFL_FP, 684 {0, 0}}, 685 {MN("fcvt.d.s"), 686 MATCH_FP_CVT(0x21, 0x0, RV_OP_FP), 687 MASK_FP_CVT, 688 RV64_FMT_FP_CVT, 689 RV64_ASMFL_FP, 690 {0, 0}}, 691 692 /* FP bitcast moves — funct7 + rs2=0 + funct3=0 fixed. */ 693 {MN("fmv.x.w"), 694 MATCH_FP_CVT(0x70, 0x0, RV_OP_FP), 695 MASK_FP_CVT, 696 RV64_FMT_FP_CVT, 697 0, 698 {0, 0}}, 699 {MN("fmv.w.x"), 700 MATCH_FP_CVT(0x78, 0x0, RV_OP_FP), 701 MASK_FP_CVT, 702 RV64_FMT_FP_CVT, 703 RV64_ASMFL_FP, 704 {0, 0}}, 705 {MN("fmv.x.d"), 706 MATCH_FP_CVT(0x71, 0x0, RV_OP_FP), 707 MASK_FP_CVT, 708 RV64_FMT_FP_CVT, 709 0, 710 {0, 0}}, 711 {MN("fmv.d.x"), 712 MATCH_FP_CVT(0x79, 0x0, RV_OP_FP), 713 MASK_FP_CVT, 714 RV64_FMT_FP_CVT, 715 RV64_ASMFL_FP, 716 {0, 0}}, 717 718 /* FP load/store */ 719 {MN("flw"), 720 MATCH_I(0x2, RV_LOAD_FP), 721 MASK_I, 722 RV64_FMT_FP_LOAD, 723 RV64_ASMFL_FP, 724 {0, 0}}, 725 {MN("fld"), 726 MATCH_I(0x3, RV_LOAD_FP), 727 MASK_I, 728 RV64_FMT_FP_LOAD, 729 RV64_ASMFL_FP, 730 {0, 0}}, 731 {MN("fsw"), 732 MATCH_S(0x2, RV_STORE_FP), 733 MASK_S, 734 RV64_FMT_FP_STORE, 735 RV64_ASMFL_FP, 736 {0, 0}}, 737 {MN("fsd"), 738 MATCH_S(0x3, RV_STORE_FP), 739 MASK_S, 740 RV64_FMT_FP_STORE, 741 RV64_ASMFL_FP, 742 {0, 0}}, 743 744 /* ================================================================= 745 * RV64A (atomic) — AMO funct5 + funct3 (W=2, D=3). aq/rl vary, so 746 * mask leaves bits 26:25 free. We expose the .aq/.rl ordering 747 * suffixes via the disassembler's annotation, but the row mnemonic 748 * itself is the bare form (e.g. "amoadd.w"). 749 * ================================================================= */ 750 {MN("lr.w.aq"), 751 MATCH_AMO_ORDER(0x02, 1, 0, 0x2, RV_AMO), 752 MASK_AMO_ORDER | (0x1fu << 20), 753 RV64_FMT_LR, 754 0, 755 {0, 0}}, 756 {MN("lr.w.rl"), 757 MATCH_AMO_ORDER(0x02, 0, 1, 0x2, RV_AMO), 758 MASK_AMO_ORDER | (0x1fu << 20), 759 RV64_FMT_LR, 760 0, 761 {0, 0}}, 762 {MN("lr.w.aqrl"), 763 MATCH_AMO_ORDER(0x02, 1, 1, 0x2, RV_AMO), 764 MASK_AMO_ORDER | (0x1fu << 20), 765 RV64_FMT_LR, 766 0, 767 {0, 0}}, 768 {MN("lr.d.aq"), 769 MATCH_AMO_ORDER(0x02, 1, 0, 0x3, RV_AMO), 770 MASK_AMO_ORDER | (0x1fu << 20), 771 RV64_FMT_LR, 772 0, 773 {0, 0}}, 774 {MN("lr.d.rl"), 775 MATCH_AMO_ORDER(0x02, 0, 1, 0x3, RV_AMO), 776 MASK_AMO_ORDER | (0x1fu << 20), 777 RV64_FMT_LR, 778 0, 779 {0, 0}}, 780 {MN("lr.d.aqrl"), 781 MATCH_AMO_ORDER(0x02, 1, 1, 0x3, RV_AMO), 782 MASK_AMO_ORDER | (0x1fu << 20), 783 RV64_FMT_LR, 784 0, 785 {0, 0}}, 786 {MN("sc.w.aq"), 787 MATCH_AMO_ORDER(0x03, 1, 0, 0x2, RV_AMO), 788 MASK_AMO_ORDER, 789 RV64_FMT_AMO, 790 0, 791 {0, 0}}, 792 {MN("sc.w.rl"), 793 MATCH_AMO_ORDER(0x03, 0, 1, 0x2, RV_AMO), 794 MASK_AMO_ORDER, 795 RV64_FMT_AMO, 796 0, 797 {0, 0}}, 798 {MN("sc.w.aqrl"), 799 MATCH_AMO_ORDER(0x03, 1, 1, 0x2, RV_AMO), 800 MASK_AMO_ORDER, 801 RV64_FMT_AMO, 802 0, 803 {0, 0}}, 804 {MN("sc.d.aq"), 805 MATCH_AMO_ORDER(0x03, 1, 0, 0x3, RV_AMO), 806 MASK_AMO_ORDER, 807 RV64_FMT_AMO, 808 0, 809 {0, 0}}, 810 {MN("sc.d.rl"), 811 MATCH_AMO_ORDER(0x03, 0, 1, 0x3, RV_AMO), 812 MASK_AMO_ORDER, 813 RV64_FMT_AMO, 814 0, 815 {0, 0}}, 816 {MN("sc.d.aqrl"), 817 MATCH_AMO_ORDER(0x03, 1, 1, 0x3, RV_AMO), 818 MASK_AMO_ORDER, 819 RV64_FMT_AMO, 820 0, 821 {0, 0}}, 822 #define RV64_AMO_ORDER_ROWS(mn, f5, f3) \ 823 {MN(mn ".aq"), \ 824 MATCH_AMO_ORDER(f5, 1, 0, f3, RV_AMO), \ 825 MASK_AMO_ORDER, \ 826 RV64_FMT_AMO, \ 827 0, \ 828 {0, 0}}, \ 829 {MN(mn ".rl"), \ 830 MATCH_AMO_ORDER(f5, 0, 1, f3, RV_AMO), \ 831 MASK_AMO_ORDER, \ 832 RV64_FMT_AMO, \ 833 0, \ 834 {0, 0}}, \ 835 { \ 836 MN(mn ".aqrl"), MATCH_AMO_ORDER(f5, 1, 1, f3, RV_AMO), MASK_AMO_ORDER, \ 837 RV64_FMT_AMO, 0, {0, 0} \ 838 } 839 RV64_AMO_ORDER_ROWS("amoswap.w", RV_AMO_SWAP, 0x2), 840 RV64_AMO_ORDER_ROWS("amoadd.w", RV_AMO_ADD, 0x2), 841 RV64_AMO_ORDER_ROWS("amoxor.w", RV_AMO_XOR, 0x2), 842 RV64_AMO_ORDER_ROWS("amoand.w", RV_AMO_AND, 0x2), 843 RV64_AMO_ORDER_ROWS("amoor.w", RV_AMO_OR, 0x2), 844 RV64_AMO_ORDER_ROWS("amomin.w", RV_AMO_MIN, 0x2), 845 RV64_AMO_ORDER_ROWS("amomax.w", RV_AMO_MAX, 0x2), 846 RV64_AMO_ORDER_ROWS("amominu.w", RV_AMO_MINU, 0x2), 847 RV64_AMO_ORDER_ROWS("amomaxu.w", RV_AMO_MAXU, 0x2), 848 RV64_AMO_ORDER_ROWS("amoswap.d", RV_AMO_SWAP, 0x3), 849 RV64_AMO_ORDER_ROWS("amoadd.d", RV_AMO_ADD, 0x3), 850 RV64_AMO_ORDER_ROWS("amoxor.d", RV_AMO_XOR, 0x3), 851 RV64_AMO_ORDER_ROWS("amoand.d", RV_AMO_AND, 0x3), 852 RV64_AMO_ORDER_ROWS("amoor.d", RV_AMO_OR, 0x3), 853 RV64_AMO_ORDER_ROWS("amomin.d", RV_AMO_MIN, 0x3), 854 RV64_AMO_ORDER_ROWS("amomax.d", RV_AMO_MAX, 0x3), 855 RV64_AMO_ORDER_ROWS("amominu.d", RV_AMO_MINU, 0x3), 856 RV64_AMO_ORDER_ROWS("amomaxu.d", RV_AMO_MAXU, 0x3), 857 {MN("lr.w"), 858 MATCH_AMO(0x02, 0x2, RV_AMO), 859 MASK_AMO | (0x1fu << 20), 860 RV64_FMT_LR, 861 0, 862 {0, 0}}, 863 {MN("lr.d"), 864 MATCH_AMO(0x02, 0x3, RV_AMO), 865 MASK_AMO | (0x1fu << 20), 866 RV64_FMT_LR, 867 0, 868 {0, 0}}, 869 {MN("sc.w"), 870 MATCH_AMO(0x03, 0x2, RV_AMO), 871 MASK_AMO, 872 RV64_FMT_AMO, 873 0, 874 {0, 0}}, 875 {MN("sc.d"), 876 MATCH_AMO(0x03, 0x3, RV_AMO), 877 MASK_AMO, 878 RV64_FMT_AMO, 879 0, 880 {0, 0}}, 881 {MN("amoswap.w"), 882 MATCH_AMO(RV_AMO_SWAP, 0x2, RV_AMO), 883 MASK_AMO, 884 RV64_FMT_AMO, 885 0, 886 {0, 0}}, 887 {MN("amoadd.w"), 888 MATCH_AMO(RV_AMO_ADD, 0x2, RV_AMO), 889 MASK_AMO, 890 RV64_FMT_AMO, 891 0, 892 {0, 0}}, 893 {MN("amoxor.w"), 894 MATCH_AMO(RV_AMO_XOR, 0x2, RV_AMO), 895 MASK_AMO, 896 RV64_FMT_AMO, 897 0, 898 {0, 0}}, 899 {MN("amoand.w"), 900 MATCH_AMO(RV_AMO_AND, 0x2, RV_AMO), 901 MASK_AMO, 902 RV64_FMT_AMO, 903 0, 904 {0, 0}}, 905 {MN("amoor.w"), 906 MATCH_AMO(RV_AMO_OR, 0x2, RV_AMO), 907 MASK_AMO, 908 RV64_FMT_AMO, 909 0, 910 {0, 0}}, 911 {MN("amomin.w"), 912 MATCH_AMO(RV_AMO_MIN, 0x2, RV_AMO), 913 MASK_AMO, 914 RV64_FMT_AMO, 915 0, 916 {0, 0}}, 917 {MN("amomax.w"), 918 MATCH_AMO(RV_AMO_MAX, 0x2, RV_AMO), 919 MASK_AMO, 920 RV64_FMT_AMO, 921 0, 922 {0, 0}}, 923 {MN("amominu.w"), 924 MATCH_AMO(RV_AMO_MINU, 0x2, RV_AMO), 925 MASK_AMO, 926 RV64_FMT_AMO, 927 0, 928 {0, 0}}, 929 {MN("amomaxu.w"), 930 MATCH_AMO(RV_AMO_MAXU, 0x2, RV_AMO), 931 MASK_AMO, 932 RV64_FMT_AMO, 933 0, 934 {0, 0}}, 935 {MN("amoswap.d"), 936 MATCH_AMO(RV_AMO_SWAP, 0x3, RV_AMO), 937 MASK_AMO, 938 RV64_FMT_AMO, 939 0, 940 {0, 0}}, 941 {MN("amoadd.d"), 942 MATCH_AMO(RV_AMO_ADD, 0x3, RV_AMO), 943 MASK_AMO, 944 RV64_FMT_AMO, 945 0, 946 {0, 0}}, 947 {MN("amoxor.d"), 948 MATCH_AMO(RV_AMO_XOR, 0x3, RV_AMO), 949 MASK_AMO, 950 RV64_FMT_AMO, 951 0, 952 {0, 0}}, 953 {MN("amoand.d"), 954 MATCH_AMO(RV_AMO_AND, 0x3, RV_AMO), 955 MASK_AMO, 956 RV64_FMT_AMO, 957 0, 958 {0, 0}}, 959 {MN("amoor.d"), 960 MATCH_AMO(RV_AMO_OR, 0x3, RV_AMO), 961 MASK_AMO, 962 RV64_FMT_AMO, 963 0, 964 {0, 0}}, 965 {MN("amomin.d"), 966 MATCH_AMO(RV_AMO_MIN, 0x3, RV_AMO), 967 MASK_AMO, 968 RV64_FMT_AMO, 969 0, 970 {0, 0}}, 971 {MN("amomax.d"), 972 MATCH_AMO(RV_AMO_MAX, 0x3, RV_AMO), 973 MASK_AMO, 974 RV64_FMT_AMO, 975 0, 976 {0, 0}}, 977 {MN("amominu.d"), 978 MATCH_AMO(RV_AMO_MINU, 0x3, RV_AMO), 979 MASK_AMO, 980 RV64_FMT_AMO, 981 0, 982 {0, 0}}, 983 {MN("amomaxu.d"), 984 MATCH_AMO(RV_AMO_MAXU, 0x3, RV_AMO), 985 MASK_AMO, 986 RV64_FMT_AMO, 987 0, 988 {0, 0}}, 989 990 /* ================================================================= 991 * RV64C compressed — assembler rows. The disassembler uses the 992 * dynamic C decoder below, so 32-bit decode skips these rows. 993 * ================================================================= */ 994 {MN("c.nop"), 0x0001u, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, {0, 0}}, 995 {MN("c.ebreak"), 0x9002u, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, {0, 0}}, 996 {MN("c.jr"), 0x8002u, 0xf07fu, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}, 997 {MN("c.jalr"), 0x9002u, 0xf07fu, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}, 998 {MN("c.mv"), 0x8002u, 0xf003u, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}, 999 {MN("c.add"), 0x9002u, 0xf003u, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}, 1000 {MN("c.li"), 0x4001u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, 1001 {MN("c.addi"), 0x0001u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, 1002 {MN("c.addiw"), 0x2001u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, 1003 {MN("c.slli"), 0x0002u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, 1004 {MN("c.lui"), 0x6001u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, 1005 {MN("c.addi16sp"), 0x6101u, 0xef83u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, 1006 {MN("c.lwsp"), 0x4002u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, 1007 {MN("c.ldsp"), 0x6002u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, 1008 {MN("c.fldsp"), 1009 0x2002u, 1010 0xe003u, 1011 RV64_FMT_CI, 1012 RV64_ASMFL_C16 | RV64_ASMFL_FP, 1013 {0, 0}}, 1014 {MN("c.swsp"), 0xc002u, 0xe003u, RV64_FMT_CSS, RV64_ASMFL_C16, {0, 0}}, 1015 {MN("c.sdsp"), 0xe002u, 0xe003u, RV64_FMT_CSS, RV64_ASMFL_C16, {0, 0}}, 1016 {MN("c.fsdsp"), 1017 0xa002u, 1018 0xe003u, 1019 RV64_FMT_CSS, 1020 RV64_ASMFL_C16 | RV64_ASMFL_FP, 1021 {0, 0}}, 1022 {MN("c.addi4spn"), 0x0000u, 0xe003u, RV64_FMT_CIW, RV64_ASMFL_C16, {0, 0}}, 1023 {MN("c.lw"), 0x4000u, 0xe003u, RV64_FMT_CL, RV64_ASMFL_C16, {0, 0}}, 1024 {MN("c.ld"), 0x6000u, 0xe003u, RV64_FMT_CL, RV64_ASMFL_C16, {0, 0}}, 1025 {MN("c.fld"), 1026 0x2000u, 1027 0xe003u, 1028 RV64_FMT_CL, 1029 RV64_ASMFL_C16 | RV64_ASMFL_FP, 1030 {0, 0}}, 1031 {MN("c.sw"), 0xc000u, 0xe003u, RV64_FMT_CS, RV64_ASMFL_C16, {0, 0}}, 1032 {MN("c.sd"), 0xe000u, 0xe003u, RV64_FMT_CS, RV64_ASMFL_C16, {0, 0}}, 1033 {MN("c.fsd"), 1034 0xa000u, 1035 0xe003u, 1036 RV64_FMT_CS, 1037 RV64_ASMFL_C16 | RV64_ASMFL_FP, 1038 {0, 0}}, 1039 {MN("c.srli"), 0x8001u, 0xec03u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, 1040 {MN("c.srai"), 0x8401u, 0xec03u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, 1041 {MN("c.andi"), 0x8801u, 0xec03u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, 1042 {MN("c.sub"), 0x8c01u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, 1043 {MN("c.xor"), 0x8c21u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, 1044 {MN("c.or"), 0x8c41u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, 1045 {MN("c.and"), 0x8c61u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, 1046 {MN("c.subw"), 0x9c01u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, 1047 {MN("c.addw"), 0x9c21u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, 1048 {MN("c.j"), 0xa001u, 0xe003u, RV64_FMT_CJ, RV64_ASMFL_C16, {0, 0}}, 1049 {MN("c.beqz"), 0xc001u, 0xe003u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, 1050 {MN("c.bnez"), 0xe001u, 0xe003u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, 1051 }; 1052 #undef RV64_AMO_ORDER_ROWS 1053 1054 const u32 rv64_insn_table_n = 1055 (u32)(sizeof rv64_insn_table / sizeof rv64_insn_table[0]); 1056 1057 const Rv64InsnDesc* rv64_disasm_find(u32 word) { 1058 for (u32 i = 0; i < rv64_insn_table_n; ++i) { 1059 const Rv64InsnDesc* d = &rv64_insn_table[i]; 1060 if ((d->flags & RV64_ASMFL_C16)) continue; /* 32-bit decode path */ 1061 if ((d->flags & RV64_ASMFL_PSEUDO)) continue; /* assembler-only expansion */ 1062 if ((word & d->mask) == d->match) return d; 1063 } 1064 return NULL; 1065 } 1066 1067 const Rv64InsnDesc* rv64_asm_find(Slice mnemonic) { 1068 /* Prefer canonical (non-alias) rows when both spellings exist; the 1069 * caller can still write the alias and we'll match it on a second 1070 * pass. Aliases share encoding with the canonical row so the choice 1071 * is purely for diagnostics. */ 1072 if (!mnemonic.s) return NULL; 1073 for (u32 i = 0; i < rv64_insn_table_n; ++i) { 1074 const Rv64InsnDesc* d = &rv64_insn_table[i]; 1075 if ((d->flags & RV64_ASMFL_ALIAS)) continue; 1076 if (slice_eq(d->mnemonic, mnemonic)) return d; 1077 } 1078 for (u32 i = 0; i < rv64_insn_table_n; ++i) { 1079 const Rv64InsnDesc* d = &rv64_insn_table[i]; 1080 if (slice_eq(d->mnemonic, mnemonic)) return d; 1081 } 1082 return NULL; 1083 } 1084 1085 /* ===================================================================== 1086 * Compressed-instruction decode. 1087 * 1088 * RV64C instructions are 16 bits; bits[1:0] (op-quadrant) is 00/01/10 1089 * (11 means uncompressed/32-bit). bits[15:13] (funct3) further select. 1090 * 1091 * For the disassembler we expose a small set of the common encodings; 1092 * less common ones decode as .hword. */ 1093 1094 static u32 rv64c_lookup_simple(u32 w) { 1095 u32 op = w & 0x3u; 1096 u32 f3 = (w >> 13) & 0x7u; 1097 /* C.NOP: funct3=000, op=01, rd/rs1=x0, imm=0 → word=0x0001 */ 1098 if (w == 0x0001u) return 1; /* index in table-c below */ 1099 /* C.EBREAK: 0x9002 */ 1100 if (w == 0x9002u) return 2; 1101 (void)op; 1102 (void)f3; 1103 return 0; 1104 } 1105 1106 /* The C-extension descriptors are stored in a private table indexed by 1107 * an internal enum. They are minimal — most C-format instructions print 1108 * with custom operand printers. */ 1109 static const Rv64InsnDesc rv64_c_table[] = { 1110 /* index 0 reserved (no match). */ 1111 {MN("c.unknown"), 0, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, {0, 0}}, 1112 {MN("c.nop"), 0x0001u, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, {0, 0}}, 1113 {MN("c.ebreak"), 0x9002u, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, {0, 0}}, 1114 }; 1115 1116 #undef MN 1117 1118 const Rv64InsnDesc* rv64_disasm_find_c(u32 word) { 1119 u32 hw = word & 0xffffu; 1120 u32 idx = rv64c_lookup_simple(hw); 1121 if (idx) return &rv64_c_table[idx]; 1122 /* Pattern-match remaining common C-instructions. We use a tiny static 1123 * scratch descriptor that the printer interprets by funct3+op. */ 1124 static Rv64InsnDesc dyn; 1125 u32 op = hw & 0x3u; 1126 u32 f3 = (hw >> 13) & 0x7u; 1127 if (op == 3u) return NULL; /* uncompressed */ 1128 1129 /* C.JR / C.JALR / C.MV / C.ADD — quadrant 2, funct3=100 */ 1130 if (op == 2u && f3 == 4u) { 1131 u32 funct4 = (hw >> 12) & 0xfu; 1132 u32 rd_rs1 = (hw >> 7) & 0x1fu; 1133 u32 rs2 = (hw >> 2) & 0x1fu; 1134 if (funct4 == 0x8u) { 1135 dyn = (Rv64InsnDesc){slice_from_cstr(rs2 == 0 ? "c.jr" : "c.mv"), 1136 hw, 1137 0xffffu, 1138 RV64_FMT_CR, 1139 RV64_ASMFL_C16, 1140 {0, 0}}; 1141 return rd_rs1 == 0 ? NULL : &dyn; 1142 } 1143 if (funct4 == 0x9u) { 1144 if (rs2 == 0 && rd_rs1 == 0) { 1145 dyn = rv64_c_table[2]; /* c.ebreak */ 1146 return &dyn; 1147 } 1148 dyn = (Rv64InsnDesc){slice_from_cstr(rs2 == 0 ? "c.jalr" : "c.add"), 1149 hw, 1150 0xffffu, 1151 RV64_FMT_CR, 1152 RV64_ASMFL_C16, 1153 {0, 0}}; 1154 return &dyn; 1155 } 1156 } 1157 /* C.LI / C.ADDI / C.LUI — quadrant 1 */ 1158 if (op == 1u && f3 == 2u) { 1159 dyn = (Rv64InsnDesc){slice_from_cstr("c.li"), hw, 0xffffu, RV64_FMT_CI, 1160 RV64_ASMFL_C16, {0, 0}}; 1161 return &dyn; 1162 } 1163 if (op == 1u && f3 == 1u) { 1164 dyn = (Rv64InsnDesc){slice_from_cstr("c.addiw"), 1165 hw, 1166 0xffffu, 1167 RV64_FMT_CI, 1168 RV64_ASMFL_C16, 1169 {0, 0}}; 1170 return &dyn; 1171 } 1172 if (op == 1u && f3 == 0u) { 1173 dyn = (Rv64InsnDesc){slice_from_cstr("c.addi"), 1174 hw, 1175 0xffffu, 1176 RV64_FMT_CI, 1177 RV64_ASMFL_C16, 1178 {0, 0}}; 1179 return &dyn; 1180 } 1181 if (op == 1u && f3 == 3u) { 1182 u32 rd = (hw >> 7) & 0x1fu; 1183 dyn = (Rv64InsnDesc){slice_from_cstr(rd == 2u ? "c.addi16sp" : "c.lui"), 1184 hw, 1185 0xffffu, 1186 RV64_FMT_CI, 1187 RV64_ASMFL_C16, 1188 {0, 0}}; 1189 return &dyn; 1190 } 1191 if (op == 1u && f3 == 4u) { 1192 u32 top = (hw >> 10) & 0x3u; 1193 if (top == 0u || top == 1u || top == 2u) { 1194 static const char* const names[3] = {"c.srli", "c.srai", "c.andi"}; 1195 dyn = (Rv64InsnDesc){slice_from_cstr(names[top]), 1196 hw, 1197 0xffffu, 1198 RV64_FMT_CB, 1199 RV64_ASMFL_C16, 1200 {0, 0}}; 1201 return &dyn; 1202 } 1203 { 1204 u32 bit12 = (hw >> 12) & 1u; 1205 u32 subop = (hw >> 5) & 0x3u; 1206 static const char* const ca0[4] = {"c.sub", "c.xor", "c.or", "c.and"}; 1207 static const char* const ca1[4] = {"c.subw", "c.addw", NULL, NULL}; 1208 const char* name = bit12 ? ca1[subop] : ca0[subop]; 1209 if (!name) return NULL; 1210 dyn = (Rv64InsnDesc){slice_from_cstr(name), hw, 0xffffu, RV64_FMT_CA, 1211 RV64_ASMFL_C16, {0, 0}}; 1212 return &dyn; 1213 } 1214 } 1215 if (op == 1u && f3 == 5u) { 1216 dyn = (Rv64InsnDesc){slice_from_cstr("c.j"), hw, 0xffffu, RV64_FMT_CJ, 1217 RV64_ASMFL_C16, {0, 0}}; 1218 return &dyn; 1219 } 1220 if (op == 1u && f3 == 6u) { 1221 dyn = (Rv64InsnDesc){slice_from_cstr("c.beqz"), 1222 hw, 1223 0xffffu, 1224 RV64_FMT_CB, 1225 RV64_ASMFL_C16, 1226 {0, 0}}; 1227 return &dyn; 1228 } 1229 if (op == 1u && f3 == 7u) { 1230 dyn = (Rv64InsnDesc){slice_from_cstr("c.bnez"), 1231 hw, 1232 0xffffu, 1233 RV64_FMT_CB, 1234 RV64_ASMFL_C16, 1235 {0, 0}}; 1236 return &dyn; 1237 } 1238 /* C.LWSP / C.LDSP — quadrant 2, funct3=010/011 */ 1239 if (op == 2u && f3 == 2u) { 1240 dyn = (Rv64InsnDesc){slice_from_cstr("c.lwsp"), 1241 hw, 1242 0xffffu, 1243 RV64_FMT_CI, 1244 RV64_ASMFL_C16, 1245 {0, 0}}; 1246 return &dyn; 1247 } 1248 if (op == 2u && f3 == 3u) { 1249 dyn = (Rv64InsnDesc){slice_from_cstr("c.ldsp"), 1250 hw, 1251 0xffffu, 1252 RV64_FMT_CI, 1253 RV64_ASMFL_C16, 1254 {0, 0}}; 1255 return &dyn; 1256 } 1257 if (op == 2u && f3 == 0u) { 1258 dyn = (Rv64InsnDesc){slice_from_cstr("c.slli"), 1259 hw, 1260 0xffffu, 1261 RV64_FMT_CI, 1262 RV64_ASMFL_C16, 1263 {0, 0}}; 1264 return &dyn; 1265 } 1266 if (op == 2u && f3 == 1u) { 1267 dyn = (Rv64InsnDesc){ 1268 slice_from_cstr("c.fldsp"), hw, 0xffffu, RV64_FMT_CI, 1269 RV64_ASMFL_C16 | RV64_ASMFL_FP, {0, 0}}; 1270 return &dyn; 1271 } 1272 /* C.SWSP / C.SDSP — quadrant 2, funct3=110/111 */ 1273 if (op == 2u && f3 == 6u) { 1274 dyn = (Rv64InsnDesc){slice_from_cstr("c.swsp"), 1275 hw, 1276 0xffffu, 1277 RV64_FMT_CSS, 1278 RV64_ASMFL_C16, 1279 {0, 0}}; 1280 return &dyn; 1281 } 1282 if (op == 2u && f3 == 7u) { 1283 dyn = (Rv64InsnDesc){slice_from_cstr("c.sdsp"), 1284 hw, 1285 0xffffu, 1286 RV64_FMT_CSS, 1287 RV64_ASMFL_C16, 1288 {0, 0}}; 1289 return &dyn; 1290 } 1291 if (op == 2u && f3 == 5u) { 1292 dyn = (Rv64InsnDesc){ 1293 slice_from_cstr("c.fsdsp"), hw, 0xffffu, RV64_FMT_CSS, 1294 RV64_ASMFL_C16 | RV64_ASMFL_FP, {0, 0}}; 1295 return &dyn; 1296 } 1297 /* C.ADDI4SPN — quadrant 0, funct3=000 */ 1298 if (op == 0u && f3 == 0u) { 1299 dyn = (Rv64InsnDesc){slice_from_cstr("c.addi4spn"), 1300 hw, 1301 0xffffu, 1302 RV64_FMT_CIW, 1303 RV64_ASMFL_C16, 1304 {0, 0}}; 1305 return &dyn; 1306 } 1307 /* C.LW / C.LD — quadrant 0, funct3=010/011 */ 1308 if (op == 0u && f3 == 2u) { 1309 dyn = (Rv64InsnDesc){slice_from_cstr("c.lw"), hw, 0xffffu, RV64_FMT_CL, 1310 RV64_ASMFL_C16, {0, 0}}; 1311 return &dyn; 1312 } 1313 if (op == 0u && f3 == 3u) { 1314 dyn = (Rv64InsnDesc){slice_from_cstr("c.ld"), hw, 0xffffu, RV64_FMT_CL, 1315 RV64_ASMFL_C16, {0, 0}}; 1316 return &dyn; 1317 } 1318 if (op == 0u && f3 == 1u) { 1319 dyn = (Rv64InsnDesc){ 1320 slice_from_cstr("c.fld"), hw, 0xffffu, RV64_FMT_CL, 1321 RV64_ASMFL_C16 | RV64_ASMFL_FP, {0, 0}}; 1322 return &dyn; 1323 } 1324 if (op == 0u && f3 == 6u) { 1325 dyn = (Rv64InsnDesc){slice_from_cstr("c.sw"), hw, 0xffffu, RV64_FMT_CS, 1326 RV64_ASMFL_C16, {0, 0}}; 1327 return &dyn; 1328 } 1329 if (op == 0u && f3 == 7u) { 1330 dyn = (Rv64InsnDesc){slice_from_cstr("c.sd"), hw, 0xffffu, RV64_FMT_CS, 1331 RV64_ASMFL_C16, {0, 0}}; 1332 return &dyn; 1333 } 1334 if (op == 0u && f3 == 5u) { 1335 dyn = (Rv64InsnDesc){ 1336 slice_from_cstr("c.fsd"), hw, 0xffffu, RV64_FMT_CS, 1337 RV64_ASMFL_C16 | RV64_ASMFL_FP, {0, 0}}; 1338 return &dyn; 1339 } 1340 return NULL; 1341 } 1342 1343 /* ===================================================================== 1344 * Operand print — one helper per format. */ 1345 1346 static const char* const RV_XNAMES[32] = { 1347 "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", 1348 "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", 1349 "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", 1350 }; 1351 1352 static const char* const RV_FNAMES[32] = { 1353 "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", 1354 "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", 1355 "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", 1356 "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11", 1357 }; 1358 1359 static void p_xreg(StrBuf* sb, u32 r) { strbuf_puts(sb, RV_XNAMES[r & 31u]); } 1360 static void p_freg(StrBuf* sb, u32 r) { strbuf_puts(sb, RV_FNAMES[r & 31u]); } 1361 static void p_sep(StrBuf* sb) { strbuf_puts(sb, ", "); } 1362 static void p_mem(StrBuf* sb, i64 off, u32 base) { 1363 strbuf_put_i64(sb, off); 1364 strbuf_putc(sb, '('); 1365 p_xreg(sb, base); 1366 strbuf_putc(sb, ')'); 1367 } 1368 static void p_rel(StrBuf* sb, u64 vaddr, i64 off) { 1369 if (vaddr) 1370 strbuf_put_hex_u64(sb, vaddr + (u64)off); 1371 else { 1372 strbuf_putc(sb, '#'); 1373 strbuf_put_i64(sb, off); 1374 } 1375 } 1376 1377 static void print_r(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { 1378 Rv64R f = rv64_r_unpack(w); 1379 /* Two-operand aliases (snez/neg/negw) drop rs1=x0 from the print. */ 1380 if (d->flags & RV64_ASMFL_ALIAS) { 1381 p_xreg(sb, f.rd); 1382 p_sep(sb); 1383 p_xreg(sb, f.rs2); 1384 return; 1385 } 1386 p_xreg(sb, f.rd); 1387 p_sep(sb); 1388 p_xreg(sb, f.rs1); 1389 p_sep(sb); 1390 p_xreg(sb, f.rs2); 1391 } 1392 1393 static void print_r4(StrBuf* sb, u32 w) { 1394 u32 rd = (w >> 7) & 0x1fu; 1395 u32 rs1 = (w >> 15) & 0x1fu; 1396 u32 rs2 = (w >> 20) & 0x1fu; 1397 u32 rs3 = (w >> 27) & 0x1fu; 1398 p_freg(sb, rd); 1399 p_sep(sb); 1400 p_freg(sb, rs1); 1401 p_sep(sb); 1402 p_freg(sb, rs2); 1403 p_sep(sb); 1404 p_freg(sb, rs3); 1405 } 1406 1407 static void print_i(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { 1408 Rv64I f = rv64_i_unpack(w); 1409 i64 imm = rv64_sext((u64)f.imm12, 12); 1410 /* Alias: `li rd, imm` — print rd, imm. */ 1411 if ((d->flags & RV64_ASMFL_ALIAS) && slice_eq_cstr(d->mnemonic, "li")) { 1412 p_xreg(sb, f.rd); 1413 p_sep(sb); 1414 strbuf_put_i64(sb, imm); 1415 return; 1416 } 1417 /* Alias: `mv rd, rs1` — print rd, rs1. */ 1418 if ((d->flags & RV64_ASMFL_ALIAS) && slice_eq_cstr(d->mnemonic, "mv")) { 1419 p_xreg(sb, f.rd); 1420 p_sep(sb); 1421 p_xreg(sb, f.rs1); 1422 return; 1423 } 1424 /* Alias: `sext.w rd, rs1` — print rd, rs1. */ 1425 if ((d->flags & RV64_ASMFL_ALIAS) && slice_eq_cstr(d->mnemonic, "sext.w")) { 1426 p_xreg(sb, f.rd); 1427 p_sep(sb); 1428 p_xreg(sb, f.rs1); 1429 return; 1430 } 1431 /* Alias: `seqz rd, rs` / `not rd, rs` — print rd, rs (drop imm). */ 1432 if ((d->flags & RV64_ASMFL_ALIAS) && (slice_eq_cstr(d->mnemonic, "seqz") || 1433 slice_eq_cstr(d->mnemonic, "not"))) { 1434 p_xreg(sb, f.rd); 1435 p_sep(sb); 1436 p_xreg(sb, f.rs1); 1437 return; 1438 } 1439 p_xreg(sb, f.rd); 1440 p_sep(sb); 1441 p_xreg(sb, f.rs1); 1442 p_sep(sb); 1443 strbuf_put_i64(sb, imm); 1444 } 1445 1446 static void print_i_shift(StrBuf* sb, u32 w) { 1447 /* shamt is 6 bits for RV64 shift-imm. */ 1448 u32 rd = (w >> 7) & 0x1fu; 1449 u32 rs1 = (w >> 15) & 0x1fu; 1450 u32 shamt = (w >> 20) & 0x3fu; 1451 p_xreg(sb, rd); 1452 p_sep(sb); 1453 p_xreg(sb, rs1); 1454 p_sep(sb); 1455 strbuf_put_u64(sb, (u64)shamt); 1456 } 1457 1458 static void print_i_shiftw(StrBuf* sb, u32 w) { 1459 u32 rd = (w >> 7) & 0x1fu; 1460 u32 rs1 = (w >> 15) & 0x1fu; 1461 u32 shamt = (w >> 20) & 0x1fu; 1462 p_xreg(sb, rd); 1463 p_sep(sb); 1464 p_xreg(sb, rs1); 1465 p_sep(sb); 1466 strbuf_put_u64(sb, (u64)shamt); 1467 } 1468 1469 static void print_u(StrBuf* sb, u32 w) { 1470 Rv64U f = rv64_u_unpack(w); 1471 p_xreg(sb, f.rd); 1472 p_sep(sb); 1473 /* The immediate is the upper-20 already shifted into bits 31:12; print 1474 * the raw 20-bit value the assembler expects. */ 1475 strbuf_put_hex_u64(sb, (u64)(f.imm32_hi20 >> 12)); 1476 } 1477 1478 static void print_load(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { 1479 Rv64I f = rv64_i_unpack(w); 1480 i64 imm = rv64_sext((u64)f.imm12, 12); 1481 if (d->flags & RV64_ASMFL_FP) 1482 p_freg(sb, f.rd); 1483 else 1484 p_xreg(sb, f.rd); 1485 p_sep(sb); 1486 p_mem(sb, imm, f.rs1); 1487 } 1488 1489 static void print_store(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { 1490 Rv64S f = rv64_s_unpack(w); 1491 i64 imm = rv64_sext((u64)f.imm12, 12); 1492 if (d->flags & RV64_ASMFL_FP) 1493 p_freg(sb, f.rs2); 1494 else 1495 p_xreg(sb, f.rs2); 1496 p_sep(sb); 1497 p_mem(sb, imm, f.rs1); 1498 } 1499 1500 static void print_b(StrBuf* sb, u32 w, u64 vaddr, const Rv64InsnDesc* d) { 1501 Rv64B f = rv64_b_unpack(w); 1502 i64 off = rv64_sext((u64)f.imm13, 13); 1503 if ((d->flags & RV64_ASMFL_ALIAS) && (slice_eq_cstr(d->mnemonic, "beqz") || 1504 slice_eq_cstr(d->mnemonic, "bnez"))) { 1505 p_xreg(sb, f.rs1); 1506 p_sep(sb); 1507 p_rel(sb, vaddr, off); 1508 return; 1509 } 1510 p_xreg(sb, f.rs1); 1511 p_sep(sb); 1512 p_xreg(sb, f.rs2); 1513 p_sep(sb); 1514 p_rel(sb, vaddr, off); 1515 } 1516 1517 static void print_j(StrBuf* sb, u32 w, u64 vaddr, const Rv64InsnDesc* d) { 1518 Rv64J f = rv64_j_unpack(w); 1519 i64 off = rv64_sext((u64)f.imm21, 21); 1520 if ((d->flags & RV64_ASMFL_ALIAS) && slice_eq_cstr(d->mnemonic, "j")) { 1521 p_rel(sb, vaddr, off); 1522 return; 1523 } 1524 p_xreg(sb, f.rd); 1525 p_sep(sb); 1526 p_rel(sb, vaddr, off); 1527 } 1528 1529 static void print_jalr(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { 1530 Rv64I f = rv64_i_unpack(w); 1531 i64 imm = rv64_sext((u64)f.imm12, 12); 1532 if ((d->flags & RV64_ASMFL_ALIAS) && slice_eq_cstr(d->mnemonic, "jr")) { 1533 p_xreg(sb, f.rs1); 1534 return; 1535 } 1536 p_xreg(sb, f.rd); 1537 p_sep(sb); 1538 p_mem(sb, imm, f.rs1); 1539 } 1540 1541 static void print_fence(StrBuf* sb, u32 w) { 1542 u32 pred = (w >> 24) & 0xfu; 1543 u32 succ = (w >> 20) & 0xfu; 1544 static const char order_chars[5] = {'w', 'r', 'o', 'i', '\0'}; 1545 /* pred/succ: bit3=i, bit2=o, bit1=r, bit0=w; print iorw left-to-right. */ 1546 char buf[8]; 1547 u32 k = 0; 1548 if (pred & 8u) buf[k++] = 'i'; 1549 if (pred & 4u) buf[k++] = 'o'; 1550 if (pred & 2u) buf[k++] = 'r'; 1551 if (pred & 1u) buf[k++] = 'w'; 1552 if (!k) buf[k++] = '0'; 1553 buf[k] = '\0'; 1554 strbuf_puts(sb, buf); 1555 p_sep(sb); 1556 k = 0; 1557 if (succ & 8u) buf[k++] = 'i'; 1558 if (succ & 4u) buf[k++] = 'o'; 1559 if (succ & 2u) buf[k++] = 'r'; 1560 if (succ & 1u) buf[k++] = 'w'; 1561 if (!k) buf[k++] = '0'; 1562 buf[k] = '\0'; 1563 strbuf_puts(sb, buf); 1564 (void)order_chars; 1565 } 1566 1567 static void print_csr(StrBuf* sb, u32 w) { 1568 Rv64I f = rv64_i_unpack(w); 1569 p_xreg(sb, f.rd); 1570 p_sep(sb); 1571 strbuf_put_hex_u64(sb, (u64)f.imm12); 1572 p_sep(sb); 1573 p_xreg(sb, f.rs1); 1574 } 1575 1576 static void print_csri(StrBuf* sb, u32 w) { 1577 Rv64I f = rv64_i_unpack(w); 1578 p_xreg(sb, f.rd); 1579 p_sep(sb); 1580 strbuf_put_hex_u64(sb, (u64)f.imm12); 1581 p_sep(sb); 1582 strbuf_put_u64(sb, (u64)f.rs1); 1583 } 1584 1585 static void print_fp_rm(StrBuf* sb, u32 w) { 1586 Rv64R f = rv64_r_unpack(w); 1587 p_freg(sb, f.rd); 1588 p_sep(sb); 1589 p_freg(sb, f.rs1); 1590 p_sep(sb); 1591 p_freg(sb, f.rs2); 1592 } 1593 1594 static void print_fp_r(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { 1595 Rv64R f = rv64_r_unpack(w); 1596 if (d->flags & RV64_ASMFL_FP) { 1597 p_freg(sb, f.rd); 1598 p_sep(sb); 1599 p_freg(sb, f.rs1); 1600 p_sep(sb); 1601 p_freg(sb, f.rs2); 1602 } else { 1603 /* FP compare: rd is GPR. */ 1604 p_xreg(sb, f.rd); 1605 p_sep(sb); 1606 p_freg(sb, f.rs1); 1607 p_sep(sb); 1608 p_freg(sb, f.rs2); 1609 } 1610 } 1611 1612 static void print_fp_cvt(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { 1613 Rv64R f = rv64_r_unpack(w); 1614 /* rd is FP for: fcvt.s.*, fcvt.d.*, fmv.w.x, fmv.d.x, fsqrt.{s,d}. 1615 * GPR for: fcvt.w.*, fcvt.l.*, fmv.x.w, fmv.x.d. */ 1616 if (d->flags & RV64_ASMFL_FP) 1617 p_freg(sb, f.rd); 1618 else 1619 p_xreg(sb, f.rd); 1620 p_sep(sb); 1621 /* rs1: FP if mnemonic is fcvt.X.{S,D} or fsqrt or fmv.x.{w,d}; 1622 * GPR if mnemonic is fcvt.{S,D}.{w,wu,l,lu} or fmv.{w,d}.x. */ 1623 int rs1_is_fp = 1; 1624 if (slice_eq_cstr(d->mnemonic, "fmv.w.x") || 1625 slice_eq_cstr(d->mnemonic, "fmv.d.x") || 1626 slice_has_prefix_cstr(d->mnemonic, "fcvt.s.", 7) || 1627 slice_has_prefix_cstr(d->mnemonic, "fcvt.d.", 7)) { 1628 /* These have rs1 as integer GPR (source is integer). Exception: 1629 * fcvt.s.d / fcvt.d.s have rs1 as FP. */ 1630 if (slice_eq_cstr(d->mnemonic, "fcvt.s.d") || 1631 slice_eq_cstr(d->mnemonic, "fcvt.d.s")) 1632 rs1_is_fp = 1; 1633 else 1634 rs1_is_fp = 0; 1635 } 1636 if (rs1_is_fp) 1637 p_freg(sb, f.rs1); 1638 else 1639 p_xreg(sb, f.rs1); 1640 /* Explicit rounding mode for the rounding conversions (fcvt / fsqrt) when it 1641 * isn't the default `dyn` — fmv and fclass carry no rounding mode. Matches 1642 * the objdump/clang convention (an omitted suffix means dyn), so a third- 1643 * party assembler re-encodes our fp->int truncation (rtz) exactly rather 1644 * than substituting its own default. */ 1645 if (slice_has_prefix_cstr(d->mnemonic, "fcvt.", 5) || 1646 slice_has_prefix_cstr(d->mnemonic, "fsqrt.", 6)) { 1647 u32 rm = (w >> 12) & 7u; 1648 static const char* const RMN[8] = {"rne", "rtz", "rdn", "rup", 1649 "rmm", 0, 0, "dyn"}; 1650 if (rm != 7u && RMN[rm]) { 1651 p_sep(sb); 1652 strbuf_puts(sb, RMN[rm]); 1653 } 1654 } 1655 } 1656 1657 static void print_amo(StrBuf* sb, u32 w) { 1658 Rv64R f = rv64_r_unpack(w); 1659 p_xreg(sb, f.rd); 1660 p_sep(sb); 1661 p_xreg(sb, f.rs2); 1662 p_sep(sb); 1663 strbuf_putc(sb, '('); 1664 p_xreg(sb, f.rs1); 1665 strbuf_putc(sb, ')'); 1666 } 1667 1668 static void print_lr(StrBuf* sb, u32 w) { 1669 Rv64R f = rv64_r_unpack(w); 1670 p_xreg(sb, f.rd); 1671 p_sep(sb); 1672 strbuf_putc(sb, '('); 1673 p_xreg(sb, f.rs1); 1674 strbuf_putc(sb, ')'); 1675 } 1676 1677 /* ---- compressed printers ---- */ 1678 1679 static void print_cr(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { 1680 u32 hw = w & 0xffffu; 1681 u32 rd_rs1 = (hw >> 7) & 0x1fu; 1682 u32 rs2 = (hw >> 2) & 0x1fu; 1683 if (slice_eq_cstr(d->mnemonic, "c.jr") || 1684 slice_eq_cstr(d->mnemonic, "c.jalr")) { 1685 p_xreg(sb, rd_rs1); 1686 } else { 1687 /* c.mv / c.add */ 1688 p_xreg(sb, rd_rs1); 1689 p_sep(sb); 1690 p_xreg(sb, rs2); 1691 } 1692 } 1693 1694 static void print_ci(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { 1695 u32 hw = w & 0xffffu; 1696 u32 rd_rs1 = (hw >> 7) & 0x1fu; 1697 /* immediate is split across bits 12 and 6:2 (signed 6-bit for most). */ 1698 u32 imm5 = (hw >> 12) & 1u; 1699 u32 imm4_0 = (hw >> 2) & 0x1fu; 1700 i64 imm; 1701 if (slice_eq_cstr(d->mnemonic, "c.lui")) { 1702 /* nzimm[17:12] = bits 12, 6:2 — signed extended to 18 bits. */ 1703 u64 raw = (u64)((imm5 << 5) | imm4_0); 1704 imm = rv64_sext(raw, 6) << 12; 1705 p_xreg(sb, rd_rs1); 1706 p_sep(sb); 1707 strbuf_put_hex_u64(sb, (u64)imm); 1708 return; 1709 } 1710 if (slice_eq_cstr(d->mnemonic, "c.addi16sp")) { 1711 /* nzimm[9|4|6|8:7|5] (scrambled). Just decode for print. */ 1712 u32 b9 = (hw >> 12) & 1u; 1713 u32 b4 = (hw >> 6) & 1u; 1714 u32 b6 = (hw >> 5) & 1u; 1715 u32 b87 = (hw >> 3) & 3u; 1716 u32 b5 = (hw >> 2) & 1u; 1717 u64 raw = ((u64)b9 << 9) | ((u64)b87 << 7) | ((u64)b6 << 6) | 1718 ((u64)b5 << 5) | ((u64)b4 << 4); 1719 imm = rv64_sext(raw, 10); 1720 p_xreg(sb, rd_rs1); 1721 p_sep(sb); 1722 strbuf_put_i64(sb, imm); 1723 return; 1724 } 1725 if (slice_eq_cstr(d->mnemonic, "c.lwsp")) { 1726 /* offset[5|4:2|7:6] scaled by 4. */ 1727 u32 b5 = imm5; 1728 u32 b4_2 = (imm4_0 >> 2) & 7u; 1729 u32 b7_6 = imm4_0 & 3u; 1730 u32 off = (b7_6 << 6) | (b5 << 5) | (b4_2 << 2); 1731 p_xreg(sb, rd_rs1); 1732 p_sep(sb); 1733 p_mem(sb, (i64)off, 2u); 1734 return; 1735 } 1736 if (slice_eq_cstr(d->mnemonic, "c.ldsp") || 1737 slice_eq_cstr(d->mnemonic, "c.fldsp")) { 1738 /* offset[5|4:3|8:6] scaled by 8. */ 1739 u32 b5 = imm5; 1740 u32 b4_3 = (imm4_0 >> 3) & 3u; 1741 u32 b8_6 = imm4_0 & 7u; 1742 u32 off = (b8_6 << 6) | (b5 << 5) | (b4_3 << 3); 1743 if (d->flags & RV64_ASMFL_FP) 1744 p_freg(sb, rd_rs1); 1745 else 1746 p_xreg(sb, rd_rs1); 1747 p_sep(sb); 1748 p_mem(sb, (i64)off, 2u); 1749 return; 1750 } 1751 if (slice_eq_cstr(d->mnemonic, "c.slli")) { 1752 u32 shamt = (imm5 << 5) | imm4_0; 1753 p_xreg(sb, rd_rs1); 1754 p_sep(sb); 1755 strbuf_put_u64(sb, (u64)shamt); 1756 return; 1757 } 1758 /* c.li / c.addi — signed 6-bit immediate. */ 1759 imm = rv64_sext((u64)((imm5 << 5) | imm4_0), 6); 1760 p_xreg(sb, rd_rs1); 1761 p_sep(sb); 1762 strbuf_put_i64(sb, imm); 1763 } 1764 1765 static void print_css(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { 1766 u32 hw = w & 0xffffu; 1767 u32 rs2 = (hw >> 2) & 0x1fu; 1768 u32 imm6 = (hw >> 7) & 0x3fu; 1769 u32 off; 1770 if (slice_eq_cstr(d->mnemonic, "c.swsp")) { 1771 /* offset[5:2|7:6] scaled by 4. */ 1772 u32 b5_2 = (imm6 >> 2) & 0xfu; 1773 u32 b7_6 = imm6 & 3u; 1774 off = (b7_6 << 6) | (b5_2 << 2); 1775 p_xreg(sb, rs2); 1776 p_sep(sb); 1777 p_mem(sb, (i64)off, 2u); 1778 return; 1779 } 1780 /* c.sdsp / c.fsdsp — offset[5:3|8:6] scaled by 8. */ 1781 { 1782 u32 b5_3 = (imm6 >> 3) & 7u; 1783 u32 b8_6 = imm6 & 7u; 1784 off = (b8_6 << 6) | (b5_3 << 3); 1785 if (d->flags & RV64_ASMFL_FP) 1786 p_freg(sb, rs2); 1787 else 1788 p_xreg(sb, rs2); 1789 p_sep(sb); 1790 p_mem(sb, (i64)off, 2u); 1791 } 1792 } 1793 1794 static void print_ciw(StrBuf* sb, u32 w) { 1795 u32 hw = w & 0xffffu; 1796 u32 rd3 = (hw >> 2) & 7u; 1797 /* nzuimm[5:4|9:6|2|3] scaled by 4 — encoded into bits 12:5. */ 1798 u32 imm = (hw >> 5) & 0xffu; 1799 u32 b5_4 = (imm >> 6) & 3u; 1800 u32 b9_6 = (imm >> 2) & 0xfu; 1801 u32 b2 = (imm >> 1) & 1u; 1802 u32 b3 = imm & 1u; 1803 u32 off = (b9_6 << 6) | (b5_4 << 4) | (b3 << 3) | (b2 << 2); 1804 p_xreg(sb, RVC_REG3(rd3)); 1805 p_sep(sb); 1806 strbuf_puts(sb, "sp"); 1807 p_sep(sb); 1808 strbuf_put_u64(sb, (u64)off); 1809 } 1810 1811 static void print_cl(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { 1812 u32 hw = w & 0xffffu; 1813 u32 rd3 = (hw >> 2) & 7u; 1814 u32 rs1_3 = (hw >> 7) & 7u; 1815 u32 b5_3 = (hw >> 10) & 7u; 1816 u32 lo = (hw >> 5) & 3u; 1817 u32 off; 1818 if (slice_eq_cstr(d->mnemonic, "c.lw")) { 1819 /* offset[5:3|2|6] scaled by 4. */ 1820 u32 b2 = (lo >> 1) & 1u; 1821 u32 b6 = lo & 1u; 1822 off = (b6 << 6) | (b5_3 << 3) | (b2 << 2); 1823 } else { 1824 /* c.ld: offset[5:3|7:6] scaled by 8. */ 1825 off = (lo << 6) | (b5_3 << 3); 1826 } 1827 if (d->flags & RV64_ASMFL_FP) 1828 p_freg(sb, RVC_REG3(rd3)); 1829 else 1830 p_xreg(sb, RVC_REG3(rd3)); 1831 p_sep(sb); 1832 p_mem(sb, (i64)off, RVC_REG3(rs1_3)); 1833 } 1834 1835 static void print_cs(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { 1836 u32 hw = w & 0xffffu; 1837 u32 rs2_3 = (hw >> 2) & 7u; 1838 u32 rs1_3 = (hw >> 7) & 7u; 1839 u32 b5_3 = (hw >> 10) & 7u; 1840 u32 lo = (hw >> 5) & 3u; 1841 u32 off; 1842 if (slice_eq_cstr(d->mnemonic, "c.sw")) { 1843 u32 b2 = (lo >> 1) & 1u; 1844 u32 b6 = lo & 1u; 1845 off = (b6 << 6) | (b5_3 << 3) | (b2 << 2); 1846 } else { 1847 off = (lo << 6) | (b5_3 << 3); 1848 } 1849 if (d->flags & RV64_ASMFL_FP) 1850 p_freg(sb, RVC_REG3(rs2_3)); 1851 else 1852 p_xreg(sb, RVC_REG3(rs2_3)); 1853 p_sep(sb); 1854 p_mem(sb, (i64)off, RVC_REG3(rs1_3)); 1855 } 1856 1857 static void print_ca(StrBuf* sb, u32 w) { 1858 u32 hw = w & 0xffffu; 1859 u32 rd3 = (hw >> 7) & 7u; 1860 u32 rs2_3 = (hw >> 2) & 7u; 1861 p_xreg(sb, RVC_REG3(rd3)); 1862 p_sep(sb); 1863 p_xreg(sb, RVC_REG3(rs2_3)); 1864 } 1865 1866 static void print_cb(StrBuf* sb, u32 w, u64 vaddr, const Rv64InsnDesc* d) { 1867 u32 hw = w & 0xffffu; 1868 u32 rs1_3 = (hw >> 7) & 7u; 1869 if (slice_eq_cstr(d->mnemonic, "c.srli") || 1870 slice_eq_cstr(d->mnemonic, "c.srai") || 1871 slice_eq_cstr(d->mnemonic, "c.andi")) { 1872 u32 imm = (((hw >> 12) & 1u) << 5) | ((hw >> 2) & 0x1fu); 1873 p_xreg(sb, RVC_REG3(rs1_3)); 1874 p_sep(sb); 1875 if (slice_eq_cstr(d->mnemonic, "c.andi")) 1876 strbuf_put_i64(sb, rv64_sext((u64)imm, 6)); 1877 else 1878 strbuf_put_u64(sb, (u64)imm); 1879 return; 1880 } 1881 /* offset[8|4:3|7:6|2:1|5] scaled by 2. */ 1882 u32 b8 = (hw >> 12) & 1u; 1883 u32 b4_3 = (hw >> 10) & 3u; 1884 u32 b7_6 = (hw >> 5) & 3u; 1885 u32 b2_1 = (hw >> 3) & 3u; 1886 u32 b5 = (hw >> 2) & 1u; 1887 u64 raw = ((u64)b8 << 8) | ((u64)b7_6 << 6) | ((u64)b5 << 5) | 1888 ((u64)b4_3 << 3) | ((u64)b2_1 << 1); 1889 i64 off = rv64_sext(raw, 9); 1890 p_xreg(sb, RVC_REG3(rs1_3)); 1891 p_sep(sb); 1892 p_rel(sb, vaddr, off); 1893 } 1894 1895 static void print_cj(StrBuf* sb, u32 w, u64 vaddr) { 1896 u32 hw = w & 0xffffu; 1897 /* offset[11|4|9:8|10|6|7|3:1|5] scaled by 2. */ 1898 u32 b11 = (hw >> 12) & 1u; 1899 u32 b4 = (hw >> 11) & 1u; 1900 u32 b9_8 = (hw >> 9) & 3u; 1901 u32 b10 = (hw >> 8) & 1u; 1902 u32 b6 = (hw >> 7) & 1u; 1903 u32 b7 = (hw >> 6) & 1u; 1904 u32 b3_1 = (hw >> 3) & 7u; 1905 u32 b5 = (hw >> 2) & 1u; 1906 u64 raw = ((u64)b11 << 11) | ((u64)b10 << 10) | ((u64)b9_8 << 8) | 1907 ((u64)b7 << 7) | ((u64)b6 << 6) | ((u64)b5 << 5) | ((u64)b4 << 4) | 1908 ((u64)b3_1 << 1); 1909 i64 off = rv64_sext(raw, 12); 1910 p_rel(sb, vaddr, off); 1911 } 1912 1913 void rv64_print_operands(StrBuf* sb, const Rv64InsnDesc* desc, u32 word, 1914 u64 vaddr) { 1915 switch ((Rv64Format)desc->fmt) { 1916 case RV64_FMT_R: 1917 print_r(sb, word, desc); 1918 break; 1919 case RV64_FMT_R4: 1920 print_r4(sb, word); 1921 break; 1922 case RV64_FMT_I: 1923 print_i(sb, word, desc); 1924 break; 1925 case RV64_FMT_I_SHIFT: 1926 print_i_shift(sb, word); 1927 break; 1928 case RV64_FMT_I_SHIFTW: 1929 print_i_shiftw(sb, word); 1930 break; 1931 case RV64_FMT_S: 1932 print_store(sb, word, desc); 1933 break; 1934 case RV64_FMT_B: 1935 print_b(sb, word, vaddr, desc); 1936 break; 1937 case RV64_FMT_U: 1938 print_u(sb, word); 1939 break; 1940 case RV64_FMT_J: 1941 print_j(sb, word, vaddr, desc); 1942 break; 1943 case RV64_FMT_LOAD: 1944 print_load(sb, word, desc); 1945 break; 1946 case RV64_FMT_STORE: 1947 print_store(sb, word, desc); 1948 break; 1949 case RV64_FMT_JALR: 1950 print_jalr(sb, word, desc); 1951 break; 1952 case RV64_FMT_FENCE: 1953 print_fence(sb, word); 1954 break; 1955 case RV64_FMT_SYSTEM: 1956 break; /* no operands */ 1957 case RV64_FMT_FP_RM: 1958 print_fp_rm(sb, word); 1959 break; 1960 case RV64_FMT_FP_R: 1961 print_fp_r(sb, word, desc); 1962 break; 1963 case RV64_FMT_FP_CVT: 1964 print_fp_cvt(sb, word, desc); 1965 break; 1966 case RV64_FMT_FP_LOAD: 1967 print_load(sb, word, desc); 1968 break; 1969 case RV64_FMT_FP_STORE: 1970 print_store(sb, word, desc); 1971 break; 1972 case RV64_FMT_AMO: 1973 print_amo(sb, word); 1974 break; 1975 case RV64_FMT_LR: 1976 print_lr(sb, word); 1977 break; 1978 case RV64_FMT_CSR: 1979 print_csr(sb, word); 1980 break; 1981 case RV64_FMT_CSRI: 1982 print_csri(sb, word); 1983 break; 1984 case RV64_FMT_CR: 1985 print_cr(sb, word, desc); 1986 break; 1987 case RV64_FMT_CI: 1988 print_ci(sb, word, desc); 1989 break; 1990 case RV64_FMT_CSS: 1991 print_css(sb, word, desc); 1992 break; 1993 case RV64_FMT_CIW: 1994 print_ciw(sb, word); 1995 break; 1996 case RV64_FMT_CL: 1997 print_cl(sb, word, desc); 1998 break; 1999 case RV64_FMT_CS: 2000 print_cs(sb, word, desc); 2001 break; 2002 case RV64_FMT_CA: 2003 print_ca(sb, word); 2004 break; 2005 case RV64_FMT_CB: 2006 print_cb(sb, word, vaddr, desc); 2007 break; 2008 case RV64_FMT_CJ: 2009 print_cj(sb, word, vaddr); 2010 break; 2011 case RV64_FMT_C_NONE: 2012 break; 2013 case RV64_FMT_PSEUDO: 2014 /* Assembler-only multi-word pseudo; rv64_disasm_find never returns 2015 * these rows, so the printer is never reached for this format. */ 2016 break; 2017 } 2018 }