]> git.proxmox.com Git - mirror_qemu.git/blame - target/loongarch/disas.c
target/loongarch: Add disassembler
[mirror_qemu.git] / target / loongarch / disas.c
CommitLineData
aae1746c
SG
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
12typedef struct {
13 disassemble_info *info;
14 uint64_t pc;
15 uint32_t insn;
16} DisasContext;
17
18static inline int plus_1(DisasContext *ctx, int x)
19{
20 return x + 1;
21}
22
23static 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
36int 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
60static 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
65static 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
70static 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
75static 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
81static 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
86static 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
92static 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
98static void output_i(DisasContext *ctx, arg_i *a, const char *mnemonic)
99{
100 output(ctx, mnemonic, "%d", a->imm);
101}
102
103static 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
109static 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
114static 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
119static 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
124static 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
129static 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
134static 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
139static 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
145static 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
151static 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
156static 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
161static 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
166static 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
171static 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
176static 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
181static 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
188static 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
195static 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
201static 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) \
209static bool trans_##insn(DisasContext *ctx, arg_##type * a) \
210{ \
211 output_##type(ctx, a, #insn); \
212 return true; \
213}
214
215INSN(clo_w, rr)
216INSN(clz_w, rr)
217INSN(cto_w, rr)
218INSN(ctz_w, rr)
219INSN(clo_d, rr)
220INSN(clz_d, rr)
221INSN(cto_d, rr)
222INSN(ctz_d, rr)
223INSN(revb_2h, rr)
224INSN(revb_4h, rr)
225INSN(revb_2w, rr)
226INSN(revb_d, rr)
227INSN(revh_2w, rr)
228INSN(revh_d, rr)
229INSN(bitrev_4b, rr)
230INSN(bitrev_8b, rr)
231INSN(bitrev_w, rr)
232INSN(bitrev_d, rr)
233INSN(ext_w_h, rr)
234INSN(ext_w_b, rr)
235INSN(cpucfg, rr)
236INSN(asrtle_d, rr_jk)
237INSN(asrtgt_d, rr_jk)
238INSN(alsl_w, rrr_sa)
239INSN(alsl_wu, rrr_sa)
240INSN(bytepick_w, rrr_sa)
241INSN(bytepick_d, rrr_sa)
242INSN(add_w, rrr)
243INSN(add_d, rrr)
244INSN(sub_w, rrr)
245INSN(sub_d, rrr)
246INSN(slt, rrr)
247INSN(sltu, rrr)
248INSN(maskeqz, rrr)
249INSN(masknez, rrr)
250INSN(nor, rrr)
251INSN(and, rrr)
252INSN(or, rrr)
253INSN(xor, rrr)
254INSN(orn, rrr)
255INSN(andn, rrr)
256INSN(sll_w, rrr)
257INSN(srl_w, rrr)
258INSN(sra_w, rrr)
259INSN(sll_d, rrr)
260INSN(srl_d, rrr)
261INSN(sra_d, rrr)
262INSN(rotr_w, rrr)
263INSN(rotr_d, rrr)
264INSN(mul_w, rrr)
265INSN(mulh_w, rrr)
266INSN(mulh_wu, rrr)
267INSN(mul_d, rrr)
268INSN(mulh_d, rrr)
269INSN(mulh_du, rrr)
270INSN(mulw_d_w, rrr)
271INSN(mulw_d_wu, rrr)
272INSN(div_w, rrr)
273INSN(mod_w, rrr)
274INSN(div_wu, rrr)
275INSN(mod_wu, rrr)
276INSN(div_d, rrr)
277INSN(mod_d, rrr)
278INSN(div_du, rrr)
279INSN(mod_du, rrr)
280INSN(crc_w_b_w, rrr)
281INSN(crc_w_h_w, rrr)
282INSN(crc_w_w_w, rrr)
283INSN(crc_w_d_w, rrr)
284INSN(crcc_w_b_w, rrr)
285INSN(crcc_w_h_w, rrr)
286INSN(crcc_w_w_w, rrr)
287INSN(crcc_w_d_w, rrr)
288INSN(break, i)
289INSN(syscall, i)
290INSN(alsl_d, rrr_sa)
291INSN(slli_w, rr_i)
292INSN(slli_d, rr_i)
293INSN(srli_w, rr_i)
294INSN(srli_d, rr_i)
295INSN(srai_w, rr_i)
296INSN(srai_d, rr_i)
297INSN(rotri_w, rr_i)
298INSN(rotri_d, rr_i)
299INSN(bstrins_w, rr_ms_ls)
300INSN(bstrpick_w, rr_ms_ls)
301INSN(bstrins_d, rr_ms_ls)
302INSN(bstrpick_d, rr_ms_ls)
303INSN(fadd_s, fff)
304INSN(fadd_d, fff)
305INSN(fsub_s, fff)
306INSN(fsub_d, fff)
307INSN(fmul_s, fff)
308INSN(fmul_d, fff)
309INSN(fdiv_s, fff)
310INSN(fdiv_d, fff)
311INSN(fmax_s, fff)
312INSN(fmax_d, fff)
313INSN(fmin_s, fff)
314INSN(fmin_d, fff)
315INSN(fmaxa_s, fff)
316INSN(fmaxa_d, fff)
317INSN(fmina_s, fff)
318INSN(fmina_d, fff)
319INSN(fscaleb_s, fff)
320INSN(fscaleb_d, fff)
321INSN(fcopysign_s, fff)
322INSN(fcopysign_d, fff)
323INSN(fabs_s, ff)
324INSN(fabs_d, ff)
325INSN(fneg_s, ff)
326INSN(fneg_d, ff)
327INSN(flogb_s, ff)
328INSN(flogb_d, ff)
329INSN(fclass_s, ff)
330INSN(fclass_d, ff)
331INSN(fsqrt_s, ff)
332INSN(fsqrt_d, ff)
333INSN(frecip_s, ff)
334INSN(frecip_d, ff)
335INSN(frsqrt_s, ff)
336INSN(frsqrt_d, ff)
337INSN(fmov_s, ff)
338INSN(fmov_d, ff)
339INSN(movgr2fr_w, fr)
340INSN(movgr2fr_d, fr)
341INSN(movgr2frh_w, fr)
342INSN(movfr2gr_s, rf)
343INSN(movfr2gr_d, rf)
344INSN(movfrh2gr_s, rf)
345INSN(movgr2fcsr, fcsrd_r)
346INSN(movfcsr2gr, r_fcsrs)
347INSN(movfr2cf, cf)
348INSN(movcf2fr, fc)
349INSN(movgr2cf, cr)
350INSN(movcf2gr, rc)
351INSN(fcvt_s_d, ff)
352INSN(fcvt_d_s, ff)
353INSN(ftintrm_w_s, ff)
354INSN(ftintrm_w_d, ff)
355INSN(ftintrm_l_s, ff)
356INSN(ftintrm_l_d, ff)
357INSN(ftintrp_w_s, ff)
358INSN(ftintrp_w_d, ff)
359INSN(ftintrp_l_s, ff)
360INSN(ftintrp_l_d, ff)
361INSN(ftintrz_w_s, ff)
362INSN(ftintrz_w_d, ff)
363INSN(ftintrz_l_s, ff)
364INSN(ftintrz_l_d, ff)
365INSN(ftintrne_w_s, ff)
366INSN(ftintrne_w_d, ff)
367INSN(ftintrne_l_s, ff)
368INSN(ftintrne_l_d, ff)
369INSN(ftint_w_s, ff)
370INSN(ftint_w_d, ff)
371INSN(ftint_l_s, ff)
372INSN(ftint_l_d, ff)
373INSN(ffint_s_w, ff)
374INSN(ffint_s_l, ff)
375INSN(ffint_d_w, ff)
376INSN(ffint_d_l, ff)
377INSN(frint_s, ff)
378INSN(frint_d, ff)
379INSN(slti, rr_i)
380INSN(sltui, rr_i)
381INSN(addi_w, rr_i)
382INSN(addi_d, rr_i)
383INSN(lu52i_d, rr_i)
384INSN(andi, rr_i)
385INSN(ori, rr_i)
386INSN(xori, rr_i)
387INSN(fmadd_s, ffff)
388INSN(fmadd_d, ffff)
389INSN(fmsub_s, ffff)
390INSN(fmsub_d, ffff)
391INSN(fnmadd_s, ffff)
392INSN(fnmadd_d, ffff)
393INSN(fnmsub_s, ffff)
394INSN(fnmsub_d, ffff)
395INSN(fsel, fffc)
396INSN(addu16i_d, rr_i)
397INSN(lu12i_w, r_i)
398INSN(lu32i_d, r_i)
399INSN(pcaddi, r_i)
400INSN(pcalau12i, r_i)
401INSN(pcaddu12i, r_i)
402INSN(pcaddu18i, r_i)
403INSN(ll_w, rr_i)
404INSN(sc_w, rr_i)
405INSN(ll_d, rr_i)
406INSN(sc_d, rr_i)
407INSN(ldptr_w, rr_i)
408INSN(stptr_w, rr_i)
409INSN(ldptr_d, rr_i)
410INSN(stptr_d, rr_i)
411INSN(ld_b, rr_i)
412INSN(ld_h, rr_i)
413INSN(ld_w, rr_i)
414INSN(ld_d, rr_i)
415INSN(st_b, rr_i)
416INSN(st_h, rr_i)
417INSN(st_w, rr_i)
418INSN(st_d, rr_i)
419INSN(ld_bu, rr_i)
420INSN(ld_hu, rr_i)
421INSN(ld_wu, rr_i)
422INSN(preld, hint_r_i)
423INSN(fld_s, fr_i)
424INSN(fst_s, fr_i)
425INSN(fld_d, fr_i)
426INSN(fst_d, fr_i)
427INSN(ldx_b, rrr)
428INSN(ldx_h, rrr)
429INSN(ldx_w, rrr)
430INSN(ldx_d, rrr)
431INSN(stx_b, rrr)
432INSN(stx_h, rrr)
433INSN(stx_w, rrr)
434INSN(stx_d, rrr)
435INSN(ldx_bu, rrr)
436INSN(ldx_hu, rrr)
437INSN(ldx_wu, rrr)
438INSN(fldx_s, frr)
439INSN(fldx_d, frr)
440INSN(fstx_s, frr)
441INSN(fstx_d, frr)
442INSN(amswap_w, rrr)
443INSN(amswap_d, rrr)
444INSN(amadd_w, rrr)
445INSN(amadd_d, rrr)
446INSN(amand_w, rrr)
447INSN(amand_d, rrr)
448INSN(amor_w, rrr)
449INSN(amor_d, rrr)
450INSN(amxor_w, rrr)
451INSN(amxor_d, rrr)
452INSN(ammax_w, rrr)
453INSN(ammax_d, rrr)
454INSN(ammin_w, rrr)
455INSN(ammin_d, rrr)
456INSN(ammax_wu, rrr)
457INSN(ammax_du, rrr)
458INSN(ammin_wu, rrr)
459INSN(ammin_du, rrr)
460INSN(amswap_db_w, rrr)
461INSN(amswap_db_d, rrr)
462INSN(amadd_db_w, rrr)
463INSN(amadd_db_d, rrr)
464INSN(amand_db_w, rrr)
465INSN(amand_db_d, rrr)
466INSN(amor_db_w, rrr)
467INSN(amor_db_d, rrr)
468INSN(amxor_db_w, rrr)
469INSN(amxor_db_d, rrr)
470INSN(ammax_db_w, rrr)
471INSN(ammax_db_d, rrr)
472INSN(ammin_db_w, rrr)
473INSN(ammin_db_d, rrr)
474INSN(ammax_db_wu, rrr)
475INSN(ammax_db_du, rrr)
476INSN(ammin_db_wu, rrr)
477INSN(ammin_db_du, rrr)
478INSN(dbar, i)
479INSN(ibar, i)
480INSN(fldgt_s, frr)
481INSN(fldgt_d, frr)
482INSN(fldle_s, frr)
483INSN(fldle_d, frr)
484INSN(fstgt_s, frr)
485INSN(fstgt_d, frr)
486INSN(fstle_s, frr)
487INSN(fstle_d, frr)
488INSN(ldgt_b, rrr)
489INSN(ldgt_h, rrr)
490INSN(ldgt_w, rrr)
491INSN(ldgt_d, rrr)
492INSN(ldle_b, rrr)
493INSN(ldle_h, rrr)
494INSN(ldle_w, rrr)
495INSN(ldle_d, rrr)
496INSN(stgt_b, rrr)
497INSN(stgt_h, rrr)
498INSN(stgt_w, rrr)
499INSN(stgt_d, rrr)
500INSN(stle_b, rrr)
501INSN(stle_h, rrr)
502INSN(stle_w, rrr)
503INSN(stle_d, rrr)
504INSN(beqz, r_offs)
505INSN(bnez, r_offs)
506INSN(bceqz, c_offs)
507INSN(bcnez, c_offs)
508INSN(jirl, rr_offs)
509INSN(b, offs)
510INSN(bl, offs)
511INSN(beq, rr_offs)
512INSN(bne, rr_offs)
513INSN(blt, rr_offs)
514INSN(bge, rr_offs)
515INSN(bltu, rr_offs)
516INSN(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
525static 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) \
603static bool trans_fcmp_cond_##suffix(DisasContext *ctx, \
604 arg_cff_fcond * a) \
605{ \
606 return output_cff_fcond(ctx, a, #suffix); \
607}
608
609FCMP_INSN(s)
610FCMP_INSN(d)