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