xref: /openbmc/qemu/target/loongarch/disas.c (revision 425876f5)
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