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