1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * QEMU LoongArch Disassembler 4 * 5 * Copyright (c) 2021 Loongson Technology Corporation Limited. 6 */ 7 8 #include "qemu/osdep.h" 9 #include "disas/dis-asm.h" 10 #include "qemu/bitops.h" 11 12 typedef struct { 13 disassemble_info *info; 14 uint64_t pc; 15 uint32_t insn; 16 } DisasContext; 17 18 static inline int plus_1(DisasContext *ctx, int x) 19 { 20 return x + 1; 21 } 22 23 static inline int shl_2(DisasContext *ctx, int x) 24 { 25 return x << 2; 26 } 27 28 #define output(C, INSN, FMT, ...) \ 29 { \ 30 (C)->info->fprintf_func((C)->info->stream, "%08x %-9s\t" FMT, \ 31 (C)->insn, INSN, ##__VA_ARGS__); \ 32 } 33 34 #include "decode-insns.c.inc" 35 36 int print_insn_loongarch(bfd_vma memaddr, struct disassemble_info *info) 37 { 38 bfd_byte buffer[4]; 39 uint32_t insn; 40 int status; 41 42 status = (*info->read_memory_func)(memaddr, buffer, 4, info); 43 if (status != 0) { 44 (*info->memory_error_func)(status, memaddr, info); 45 return -1; 46 } 47 insn = bfd_getl32(buffer); 48 DisasContext ctx = { 49 .info = info, 50 .pc = memaddr, 51 .insn = insn 52 }; 53 54 if (!decode(&ctx, insn)) { 55 output(&ctx, "illegal", ""); 56 } 57 return 4; 58 } 59 60 static void output_r_i(DisasContext *ctx, arg_r_i *a, const char *mnemonic) 61 { 62 output(ctx, mnemonic, "r%d, %d", a->rd, a->imm); 63 } 64 65 static void output_rrr(DisasContext *ctx, arg_rrr *a, const char *mnemonic) 66 { 67 output(ctx, mnemonic, "r%d, r%d, r%d", a->rd, a->rj, a->rk); 68 } 69 70 static void output_rr_i(DisasContext *ctx, arg_rr_i *a, const char *mnemonic) 71 { 72 output(ctx, mnemonic, "r%d, r%d, %d", a->rd, a->rj, a->imm); 73 } 74 75 static void output_rrr_sa(DisasContext *ctx, arg_rrr_sa *a, 76 const char *mnemonic) 77 { 78 output(ctx, mnemonic, "r%d, r%d, r%d, %d", a->rd, a->rj, a->rk, a->sa); 79 } 80 81 static void output_rr(DisasContext *ctx, arg_rr *a, const char *mnemonic) 82 { 83 output(ctx, mnemonic, "r%d, r%d", a->rd, a->rj); 84 } 85 86 static void output_rr_ms_ls(DisasContext *ctx, arg_rr_ms_ls *a, 87 const char *mnemonic) 88 { 89 output(ctx, mnemonic, "r%d, r%d, %d, %d", a->rd, a->rj, a->ms, a->ls); 90 } 91 92 static void output_hint_r_i(DisasContext *ctx, arg_hint_r_i *a, 93 const char *mnemonic) 94 { 95 output(ctx, mnemonic, "%d, r%d, %d", a->hint, a->rj, a->imm); 96 } 97 98 static void output_i(DisasContext *ctx, arg_i *a, const char *mnemonic) 99 { 100 output(ctx, mnemonic, "%d", a->imm); 101 } 102 103 static void output_rr_jk(DisasContext *ctx, arg_rr_jk *a, 104 const char *mnemonic) 105 { 106 output(ctx, mnemonic, "r%d, r%d", a->rj, a->rk); 107 } 108 109 static void output_ff(DisasContext *ctx, arg_ff *a, const char *mnemonic) 110 { 111 output(ctx, mnemonic, "f%d, f%d", a->fd, a->fj); 112 } 113 114 static void output_fff(DisasContext *ctx, arg_fff *a, const char *mnemonic) 115 { 116 output(ctx, mnemonic, "f%d, f%d, f%d", a->fd, a->fj, a->fk); 117 } 118 119 static void output_ffff(DisasContext *ctx, arg_ffff *a, const char *mnemonic) 120 { 121 output(ctx, mnemonic, "f%d, f%d, f%d, f%d", a->fd, a->fj, a->fk, a->fa); 122 } 123 124 static void output_fffc(DisasContext *ctx, arg_fffc *a, const char *mnemonic) 125 { 126 output(ctx, mnemonic, "f%d, f%d, f%d, %d", a->fd, a->fj, a->fk, a->ca); 127 } 128 129 static void output_fr(DisasContext *ctx, arg_fr *a, const char *mnemonic) 130 { 131 output(ctx, mnemonic, "f%d, r%d", a->fd, a->rj); 132 } 133 134 static void output_rf(DisasContext *ctx, arg_rf *a, const char *mnemonic) 135 { 136 output(ctx, mnemonic, "r%d, f%d", a->rd, a->fj); 137 } 138 139 static void output_fcsrd_r(DisasContext *ctx, arg_fcsrd_r *a, 140 const char *mnemonic) 141 { 142 output(ctx, mnemonic, "fcsr%d, r%d", a->fcsrd, a->rj); 143 } 144 145 static void output_r_fcsrs(DisasContext *ctx, arg_r_fcsrs *a, 146 const char *mnemonic) 147 { 148 output(ctx, mnemonic, "r%d, fcsr%d", a->rd, a->fcsrs); 149 } 150 151 static void output_cf(DisasContext *ctx, arg_cf *a, const char *mnemonic) 152 { 153 output(ctx, mnemonic, "fcc%d, f%d", a->cd, a->fj); 154 } 155 156 static void output_fc(DisasContext *ctx, arg_fc *a, const char *mnemonic) 157 { 158 output(ctx, mnemonic, "f%d, fcc%d", a->fd, a->cj); 159 } 160 161 static void output_cr(DisasContext *ctx, arg_cr *a, const char *mnemonic) 162 { 163 output(ctx, mnemonic, "fcc%d, r%d", a->cd, a->rj); 164 } 165 166 static void output_rc(DisasContext *ctx, arg_rc *a, const char *mnemonic) 167 { 168 output(ctx, mnemonic, "r%d, fcc%d", a->rd, a->cj); 169 } 170 171 static void output_frr(DisasContext *ctx, arg_frr *a, const char *mnemonic) 172 { 173 output(ctx, mnemonic, "f%d, r%d, r%d", a->fd, a->rj, a->rk); 174 } 175 176 static void output_fr_i(DisasContext *ctx, arg_fr_i *a, const char *mnemonic) 177 { 178 output(ctx, mnemonic, "f%d, r%d, %d", a->fd, a->rj, a->imm); 179 } 180 181 static void output_r_offs(DisasContext *ctx, arg_r_offs *a, 182 const char *mnemonic) 183 { 184 output(ctx, mnemonic, "r%d, %d # 0x%" PRIx64, a->rj, a->offs, 185 ctx->pc + a->offs); 186 } 187 188 static void output_c_offs(DisasContext *ctx, arg_c_offs *a, 189 const char *mnemonic) 190 { 191 output(ctx, mnemonic, "fcc%d, %d # 0x%" PRIx64, a->cj, a->offs, 192 ctx->pc + a->offs); 193 } 194 195 static void output_offs(DisasContext *ctx, arg_offs *a, 196 const char *mnemonic) 197 { 198 output(ctx, mnemonic, "%d # 0x%" PRIx64, a->offs, ctx->pc + a->offs); 199 } 200 201 static void output_rr_offs(DisasContext *ctx, arg_rr_offs *a, 202 const char *mnemonic) 203 { 204 output(ctx, mnemonic, "r%d, r%d, %d # 0x%" PRIx64, a->rj, 205 a->rd, a->offs, ctx->pc + a->offs); 206 } 207 208 #define INSN(insn, type) \ 209 static bool trans_##insn(DisasContext *ctx, arg_##type * a) \ 210 { \ 211 output_##type(ctx, a, #insn); \ 212 return true; \ 213 } 214 215 INSN(clo_w, rr) 216 INSN(clz_w, rr) 217 INSN(cto_w, rr) 218 INSN(ctz_w, rr) 219 INSN(clo_d, rr) 220 INSN(clz_d, rr) 221 INSN(cto_d, rr) 222 INSN(ctz_d, rr) 223 INSN(revb_2h, rr) 224 INSN(revb_4h, rr) 225 INSN(revb_2w, rr) 226 INSN(revb_d, rr) 227 INSN(revh_2w, rr) 228 INSN(revh_d, rr) 229 INSN(bitrev_4b, rr) 230 INSN(bitrev_8b, rr) 231 INSN(bitrev_w, rr) 232 INSN(bitrev_d, rr) 233 INSN(ext_w_h, rr) 234 INSN(ext_w_b, rr) 235 INSN(cpucfg, rr) 236 INSN(asrtle_d, rr_jk) 237 INSN(asrtgt_d, rr_jk) 238 INSN(alsl_w, rrr_sa) 239 INSN(alsl_wu, rrr_sa) 240 INSN(bytepick_w, rrr_sa) 241 INSN(bytepick_d, rrr_sa) 242 INSN(add_w, rrr) 243 INSN(add_d, rrr) 244 INSN(sub_w, rrr) 245 INSN(sub_d, rrr) 246 INSN(slt, rrr) 247 INSN(sltu, rrr) 248 INSN(maskeqz, rrr) 249 INSN(masknez, rrr) 250 INSN(nor, rrr) 251 INSN(and, rrr) 252 INSN(or, rrr) 253 INSN(xor, rrr) 254 INSN(orn, rrr) 255 INSN(andn, rrr) 256 INSN(sll_w, rrr) 257 INSN(srl_w, rrr) 258 INSN(sra_w, rrr) 259 INSN(sll_d, rrr) 260 INSN(srl_d, rrr) 261 INSN(sra_d, rrr) 262 INSN(rotr_w, rrr) 263 INSN(rotr_d, rrr) 264 INSN(mul_w, rrr) 265 INSN(mulh_w, rrr) 266 INSN(mulh_wu, rrr) 267 INSN(mul_d, rrr) 268 INSN(mulh_d, rrr) 269 INSN(mulh_du, rrr) 270 INSN(mulw_d_w, rrr) 271 INSN(mulw_d_wu, rrr) 272 INSN(div_w, rrr) 273 INSN(mod_w, rrr) 274 INSN(div_wu, rrr) 275 INSN(mod_wu, rrr) 276 INSN(div_d, rrr) 277 INSN(mod_d, rrr) 278 INSN(div_du, rrr) 279 INSN(mod_du, rrr) 280 INSN(crc_w_b_w, rrr) 281 INSN(crc_w_h_w, rrr) 282 INSN(crc_w_w_w, rrr) 283 INSN(crc_w_d_w, rrr) 284 INSN(crcc_w_b_w, rrr) 285 INSN(crcc_w_h_w, rrr) 286 INSN(crcc_w_w_w, rrr) 287 INSN(crcc_w_d_w, rrr) 288 INSN(break, i) 289 INSN(syscall, i) 290 INSN(alsl_d, rrr_sa) 291 INSN(slli_w, rr_i) 292 INSN(slli_d, rr_i) 293 INSN(srli_w, rr_i) 294 INSN(srli_d, rr_i) 295 INSN(srai_w, rr_i) 296 INSN(srai_d, rr_i) 297 INSN(rotri_w, rr_i) 298 INSN(rotri_d, rr_i) 299 INSN(bstrins_w, rr_ms_ls) 300 INSN(bstrpick_w, rr_ms_ls) 301 INSN(bstrins_d, rr_ms_ls) 302 INSN(bstrpick_d, rr_ms_ls) 303 INSN(fadd_s, fff) 304 INSN(fadd_d, fff) 305 INSN(fsub_s, fff) 306 INSN(fsub_d, fff) 307 INSN(fmul_s, fff) 308 INSN(fmul_d, fff) 309 INSN(fdiv_s, fff) 310 INSN(fdiv_d, fff) 311 INSN(fmax_s, fff) 312 INSN(fmax_d, fff) 313 INSN(fmin_s, fff) 314 INSN(fmin_d, fff) 315 INSN(fmaxa_s, fff) 316 INSN(fmaxa_d, fff) 317 INSN(fmina_s, fff) 318 INSN(fmina_d, fff) 319 INSN(fscaleb_s, fff) 320 INSN(fscaleb_d, fff) 321 INSN(fcopysign_s, fff) 322 INSN(fcopysign_d, fff) 323 INSN(fabs_s, ff) 324 INSN(fabs_d, ff) 325 INSN(fneg_s, ff) 326 INSN(fneg_d, ff) 327 INSN(flogb_s, ff) 328 INSN(flogb_d, ff) 329 INSN(fclass_s, ff) 330 INSN(fclass_d, ff) 331 INSN(fsqrt_s, ff) 332 INSN(fsqrt_d, ff) 333 INSN(frecip_s, ff) 334 INSN(frecip_d, ff) 335 INSN(frsqrt_s, ff) 336 INSN(frsqrt_d, ff) 337 INSN(fmov_s, ff) 338 INSN(fmov_d, ff) 339 INSN(movgr2fr_w, fr) 340 INSN(movgr2fr_d, fr) 341 INSN(movgr2frh_w, fr) 342 INSN(movfr2gr_s, rf) 343 INSN(movfr2gr_d, rf) 344 INSN(movfrh2gr_s, rf) 345 INSN(movgr2fcsr, fcsrd_r) 346 INSN(movfcsr2gr, r_fcsrs) 347 INSN(movfr2cf, cf) 348 INSN(movcf2fr, fc) 349 INSN(movgr2cf, cr) 350 INSN(movcf2gr, rc) 351 INSN(fcvt_s_d, ff) 352 INSN(fcvt_d_s, ff) 353 INSN(ftintrm_w_s, ff) 354 INSN(ftintrm_w_d, ff) 355 INSN(ftintrm_l_s, ff) 356 INSN(ftintrm_l_d, ff) 357 INSN(ftintrp_w_s, ff) 358 INSN(ftintrp_w_d, ff) 359 INSN(ftintrp_l_s, ff) 360 INSN(ftintrp_l_d, ff) 361 INSN(ftintrz_w_s, ff) 362 INSN(ftintrz_w_d, ff) 363 INSN(ftintrz_l_s, ff) 364 INSN(ftintrz_l_d, ff) 365 INSN(ftintrne_w_s, ff) 366 INSN(ftintrne_w_d, ff) 367 INSN(ftintrne_l_s, ff) 368 INSN(ftintrne_l_d, ff) 369 INSN(ftint_w_s, ff) 370 INSN(ftint_w_d, ff) 371 INSN(ftint_l_s, ff) 372 INSN(ftint_l_d, ff) 373 INSN(ffint_s_w, ff) 374 INSN(ffint_s_l, ff) 375 INSN(ffint_d_w, ff) 376 INSN(ffint_d_l, ff) 377 INSN(frint_s, ff) 378 INSN(frint_d, ff) 379 INSN(slti, rr_i) 380 INSN(sltui, rr_i) 381 INSN(addi_w, rr_i) 382 INSN(addi_d, rr_i) 383 INSN(lu52i_d, rr_i) 384 INSN(andi, rr_i) 385 INSN(ori, rr_i) 386 INSN(xori, rr_i) 387 INSN(fmadd_s, ffff) 388 INSN(fmadd_d, ffff) 389 INSN(fmsub_s, ffff) 390 INSN(fmsub_d, ffff) 391 INSN(fnmadd_s, ffff) 392 INSN(fnmadd_d, ffff) 393 INSN(fnmsub_s, ffff) 394 INSN(fnmsub_d, ffff) 395 INSN(fsel, fffc) 396 INSN(addu16i_d, rr_i) 397 INSN(lu12i_w, r_i) 398 INSN(lu32i_d, r_i) 399 INSN(pcaddi, r_i) 400 INSN(pcalau12i, r_i) 401 INSN(pcaddu12i, r_i) 402 INSN(pcaddu18i, r_i) 403 INSN(ll_w, rr_i) 404 INSN(sc_w, rr_i) 405 INSN(ll_d, rr_i) 406 INSN(sc_d, rr_i) 407 INSN(ldptr_w, rr_i) 408 INSN(stptr_w, rr_i) 409 INSN(ldptr_d, rr_i) 410 INSN(stptr_d, rr_i) 411 INSN(ld_b, rr_i) 412 INSN(ld_h, rr_i) 413 INSN(ld_w, rr_i) 414 INSN(ld_d, rr_i) 415 INSN(st_b, rr_i) 416 INSN(st_h, rr_i) 417 INSN(st_w, rr_i) 418 INSN(st_d, rr_i) 419 INSN(ld_bu, rr_i) 420 INSN(ld_hu, rr_i) 421 INSN(ld_wu, rr_i) 422 INSN(preld, hint_r_i) 423 INSN(fld_s, fr_i) 424 INSN(fst_s, fr_i) 425 INSN(fld_d, fr_i) 426 INSN(fst_d, fr_i) 427 INSN(ldx_b, rrr) 428 INSN(ldx_h, rrr) 429 INSN(ldx_w, rrr) 430 INSN(ldx_d, rrr) 431 INSN(stx_b, rrr) 432 INSN(stx_h, rrr) 433 INSN(stx_w, rrr) 434 INSN(stx_d, rrr) 435 INSN(ldx_bu, rrr) 436 INSN(ldx_hu, rrr) 437 INSN(ldx_wu, rrr) 438 INSN(fldx_s, frr) 439 INSN(fldx_d, frr) 440 INSN(fstx_s, frr) 441 INSN(fstx_d, frr) 442 INSN(amswap_w, rrr) 443 INSN(amswap_d, rrr) 444 INSN(amadd_w, rrr) 445 INSN(amadd_d, rrr) 446 INSN(amand_w, rrr) 447 INSN(amand_d, rrr) 448 INSN(amor_w, rrr) 449 INSN(amor_d, rrr) 450 INSN(amxor_w, rrr) 451 INSN(amxor_d, rrr) 452 INSN(ammax_w, rrr) 453 INSN(ammax_d, rrr) 454 INSN(ammin_w, rrr) 455 INSN(ammin_d, rrr) 456 INSN(ammax_wu, rrr) 457 INSN(ammax_du, rrr) 458 INSN(ammin_wu, rrr) 459 INSN(ammin_du, rrr) 460 INSN(amswap_db_w, rrr) 461 INSN(amswap_db_d, rrr) 462 INSN(amadd_db_w, rrr) 463 INSN(amadd_db_d, rrr) 464 INSN(amand_db_w, rrr) 465 INSN(amand_db_d, rrr) 466 INSN(amor_db_w, rrr) 467 INSN(amor_db_d, rrr) 468 INSN(amxor_db_w, rrr) 469 INSN(amxor_db_d, rrr) 470 INSN(ammax_db_w, rrr) 471 INSN(ammax_db_d, rrr) 472 INSN(ammin_db_w, rrr) 473 INSN(ammin_db_d, rrr) 474 INSN(ammax_db_wu, rrr) 475 INSN(ammax_db_du, rrr) 476 INSN(ammin_db_wu, rrr) 477 INSN(ammin_db_du, rrr) 478 INSN(dbar, i) 479 INSN(ibar, i) 480 INSN(fldgt_s, frr) 481 INSN(fldgt_d, frr) 482 INSN(fldle_s, frr) 483 INSN(fldle_d, frr) 484 INSN(fstgt_s, frr) 485 INSN(fstgt_d, frr) 486 INSN(fstle_s, frr) 487 INSN(fstle_d, frr) 488 INSN(ldgt_b, rrr) 489 INSN(ldgt_h, rrr) 490 INSN(ldgt_w, rrr) 491 INSN(ldgt_d, rrr) 492 INSN(ldle_b, rrr) 493 INSN(ldle_h, rrr) 494 INSN(ldle_w, rrr) 495 INSN(ldle_d, rrr) 496 INSN(stgt_b, rrr) 497 INSN(stgt_h, rrr) 498 INSN(stgt_w, rrr) 499 INSN(stgt_d, rrr) 500 INSN(stle_b, rrr) 501 INSN(stle_h, rrr) 502 INSN(stle_w, rrr) 503 INSN(stle_d, rrr) 504 INSN(beqz, r_offs) 505 INSN(bnez, r_offs) 506 INSN(bceqz, c_offs) 507 INSN(bcnez, c_offs) 508 INSN(jirl, rr_offs) 509 INSN(b, offs) 510 INSN(bl, offs) 511 INSN(beq, rr_offs) 512 INSN(bne, rr_offs) 513 INSN(blt, rr_offs) 514 INSN(bge, rr_offs) 515 INSN(bltu, rr_offs) 516 INSN(bgeu, rr_offs) 517 518 #define output_fcmp(C, PREFIX, SUFFIX) \ 519 { \ 520 (C)->info->fprintf_func((C)->info->stream, "%08x %s%s\tfcc%d, f%d, f%d", \ 521 (C)->insn, PREFIX, SUFFIX, a->cd, \ 522 a->fj, a->fk); \ 523 } 524 525 static bool output_cff_fcond(DisasContext *ctx, arg_cff_fcond * a, 526 const char *suffix) 527 { 528 bool ret = true; 529 switch (a->fcond) { 530 case 0x0: 531 output_fcmp(ctx, "fcmp_caf_", suffix); 532 break; 533 case 0x1: 534 output_fcmp(ctx, "fcmp_saf_", suffix); 535 break; 536 case 0x2: 537 output_fcmp(ctx, "fcmp_clt_", suffix); 538 break; 539 case 0x3: 540 output_fcmp(ctx, "fcmp_slt_", suffix); 541 break; 542 case 0x4: 543 output_fcmp(ctx, "fcmp_ceq_", suffix); 544 break; 545 case 0x5: 546 output_fcmp(ctx, "fcmp_seq_", suffix); 547 break; 548 case 0x6: 549 output_fcmp(ctx, "fcmp_cle_", suffix); 550 break; 551 case 0x7: 552 output_fcmp(ctx, "fcmp_sle_", suffix); 553 break; 554 case 0x8: 555 output_fcmp(ctx, "fcmp_cun_", suffix); 556 break; 557 case 0x9: 558 output_fcmp(ctx, "fcmp_sun_", suffix); 559 break; 560 case 0xA: 561 output_fcmp(ctx, "fcmp_cult_", suffix); 562 break; 563 case 0xB: 564 output_fcmp(ctx, "fcmp_sult_", suffix); 565 break; 566 case 0xC: 567 output_fcmp(ctx, "fcmp_cueq_", suffix); 568 break; 569 case 0xD: 570 output_fcmp(ctx, "fcmp_sueq_", suffix); 571 break; 572 case 0xE: 573 output_fcmp(ctx, "fcmp_cule_", suffix); 574 break; 575 case 0xF: 576 output_fcmp(ctx, "fcmp_sule_", suffix); 577 break; 578 case 0x10: 579 output_fcmp(ctx, "fcmp_cne_", suffix); 580 break; 581 case 0x11: 582 output_fcmp(ctx, "fcmp_sne_", suffix); 583 break; 584 case 0x14: 585 output_fcmp(ctx, "fcmp_cor_", suffix); 586 break; 587 case 0x15: 588 output_fcmp(ctx, "fcmp_sor_", suffix); 589 break; 590 case 0x18: 591 output_fcmp(ctx, "fcmp_cune_", suffix); 592 break; 593 case 0x19: 594 output_fcmp(ctx, "fcmp_sune_", suffix); 595 break; 596 default: 597 ret = false; 598 } 599 return ret; 600 } 601 602 #define FCMP_INSN(suffix) \ 603 static bool trans_fcmp_cond_##suffix(DisasContext *ctx, \ 604 arg_cff_fcond * a) \ 605 { \ 606 return output_cff_fcond(ctx, a, #suffix); \ 607 } 608 609 FCMP_INSN(s) 610 FCMP_INSN(d) 611