target/rx: Use prt_ldmi for XCHG_mr disassembly
[qemu.git] / target / rx / disas.c
1 /*
2 * Renesas RX Disassembler
3 *
4 * Copyright (c) 2019 Yoshinori Sato <ysato@users.sourceforge.jp>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2 or later, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "qemu/osdep.h"
20 #include "disas/dis-asm.h"
21 #include "qemu/bitops.h"
22 #include "cpu.h"
23
24 typedef struct DisasContext {
25 disassemble_info *dis;
26 uint32_t addr;
27 uint32_t pc;
28 } DisasContext;
29
30
31 static uint32_t decode_load_bytes(DisasContext *ctx, uint32_t insn,
32 int i, int n)
33 {
34 bfd_byte buf;
35 while (++i <= n) {
36 ctx->dis->read_memory_func(ctx->addr++, &buf, 1, ctx->dis);
37 insn |= buf << (32 - i * 8);
38 }
39 return insn;
40 }
41
42 static int32_t li(DisasContext *ctx, int sz)
43 {
44 int32_t addr;
45 bfd_byte buf[4];
46 addr = ctx->addr;
47
48 switch (sz) {
49 case 1:
50 ctx->addr += 1;
51 ctx->dis->read_memory_func(addr, buf, 1, ctx->dis);
52 return (int8_t)buf[0];
53 case 2:
54 ctx->addr += 2;
55 ctx->dis->read_memory_func(addr, buf, 2, ctx->dis);
56 return ldsw_le_p(buf);
57 case 3:
58 ctx->addr += 3;
59 ctx->dis->read_memory_func(addr, buf, 3, ctx->dis);
60 return (int8_t)buf[2] << 16 | lduw_le_p(buf);
61 case 0:
62 ctx->addr += 4;
63 ctx->dis->read_memory_func(addr, buf, 4, ctx->dis);
64 return ldl_le_p(buf);
65 default:
66 g_assert_not_reached();
67 }
68 }
69
70 static int bdsp_s(DisasContext *ctx, int d)
71 {
72 /*
73 * 0 -> 8
74 * 1 -> 9
75 * 2 -> 10
76 * 3 -> 3
77 * :
78 * 7 -> 7
79 */
80 if (d < 3) {
81 d += 8;
82 }
83 return d;
84 }
85
86 /* Include the auto-generated decoder. */
87 #include "decode.inc.c"
88
89 #define prt(...) (ctx->dis->fprintf_func)((ctx->dis->stream), __VA_ARGS__)
90
91 #define RX_MEMORY_BYTE 0
92 #define RX_MEMORY_WORD 1
93 #define RX_MEMORY_LONG 2
94
95 #define RX_IM_BYTE 0
96 #define RX_IM_WORD 1
97 #define RX_IM_LONG 2
98 #define RX_IM_UWORD 3
99
100 static const char size[] = {'b', 'w', 'l'};
101 static const char cond[][4] = {
102 "eq", "ne", "c", "nc", "gtu", "leu", "pz", "n",
103 "ge", "lt", "gt", "le", "o", "no", "ra", "f"
104 };
105 static const char psw[] = {
106 'c', 'z', 's', 'o', 0, 0, 0, 0,
107 'i', 'u', 0, 0, 0, 0, 0, 0,
108 };
109
110 static void rx_index_addr(DisasContext *ctx, char out[8], int ld, int mi)
111 {
112 uint32_t addr = ctx->addr;
113 uint8_t buf[2];
114 uint16_t dsp;
115
116 switch (ld) {
117 case 0:
118 /* No index; return empty string. */
119 out[0] = '\0';
120 return;
121 case 1:
122 ctx->addr += 1;
123 ctx->dis->read_memory_func(addr, buf, 1, ctx->dis);
124 dsp = buf[0];
125 break;
126 case 2:
127 ctx->addr += 2;
128 ctx->dis->read_memory_func(addr, buf, 2, ctx->dis);
129 dsp = lduw_le_p(buf);
130 break;
131 default:
132 g_assert_not_reached();
133 }
134
135 sprintf(out, "%u", dsp << (mi < 3 ? mi : 4 - mi));
136 }
137
138 static void prt_ldmi(DisasContext *ctx, const char *insn,
139 int ld, int mi, int rs, int rd)
140 {
141 static const char sizes[][4] = {".b", ".w", ".l", ".uw", ".ub"};
142 char dsp[8];
143
144 if (ld < 3) {
145 rx_index_addr(ctx, dsp, ld, mi);
146 prt("%s\t%s[r%d]%s, r%d", insn, dsp, rs, sizes[mi], rd);
147 } else {
148 prt("%s\tr%d, r%d", insn, rs, rd);
149 }
150 }
151
152 static void prt_ir(DisasContext *ctx, const char *insn, int imm, int rd)
153 {
154 if (imm < 0x100) {
155 prt("%s\t#%d, r%d", insn, imm, rd);
156 } else {
157 prt("%s\t#0x%08x, r%d", insn, imm, rd);
158 }
159 }
160
161 /* mov.[bwl] rs,dsp:[rd] */
162 static bool trans_MOV_rm(DisasContext *ctx, arg_MOV_rm *a)
163 {
164 if (a->dsp > 0) {
165 prt("mov.%c\tr%d,%d[r%d]",
166 size[a->sz], a->rs, a->dsp << a->sz, a->rd);
167 } else {
168 prt("mov.%c\tr%d,[r%d]",
169 size[a->sz], a->rs, a->rd);
170 }
171 return true;
172 }
173
174 /* mov.[bwl] dsp:[rs],rd */
175 static bool trans_MOV_mr(DisasContext *ctx, arg_MOV_mr *a)
176 {
177 if (a->dsp > 0) {
178 prt("mov.%c\t%d[r%d], r%d",
179 size[a->sz], a->dsp << a->sz, a->rs, a->rd);
180 } else {
181 prt("mov.%c\t[r%d], r%d",
182 size[a->sz], a->rs, a->rd);
183 }
184 return true;
185 }
186
187 /* mov.l #uimm4,rd */
188 /* mov.l #uimm8,rd */
189 /* mov.l #imm,rd */
190 static bool trans_MOV_ir(DisasContext *ctx, arg_MOV_ir *a)
191 {
192 prt_ir(ctx, "mov.l", a->imm, a->rd);
193 return true;
194 }
195
196 /* mov.[bwl] #uimm8,dsp:[rd] */
197 /* mov #imm, dsp:[rd] */
198 static bool trans_MOV_im(DisasContext *ctx, arg_MOV_im *a)
199 {
200 if (a->dsp > 0) {
201 prt("mov.%c\t#%d,%d[r%d]",
202 size[a->sz], a->imm, a->dsp << a->sz, a->rd);
203 } else {
204 prt("mov.%c\t#%d,[r%d]",
205 size[a->sz], a->imm, a->rd);
206 }
207 return true;
208 }
209
210 /* mov.[bwl] [ri,rb],rd */
211 static bool trans_MOV_ar(DisasContext *ctx, arg_MOV_ar *a)
212 {
213 prt("mov.%c\t[r%d,r%d], r%d", size[a->sz], a->ri, a->rb, a->rd);
214 return true;
215 }
216
217 /* mov.[bwl] rd,[ri,rb] */
218 static bool trans_MOV_ra(DisasContext *ctx, arg_MOV_ra *a)
219 {
220 prt("mov.%c\tr%d, [r%d, r%d]", size[a->sz], a->rs, a->ri, a->rb);
221 return true;
222 }
223
224
225 /* mov.[bwl] dsp:[rs],dsp:[rd] */
226 /* mov.[bwl] rs,dsp:[rd] */
227 /* mov.[bwl] dsp:[rs],rd */
228 /* mov.[bwl] rs,rd */
229 static bool trans_MOV_mm(DisasContext *ctx, arg_MOV_mm *a)
230 {
231 char dspd[8], dsps[8];
232
233 prt("mov.%c\t", size[a->sz]);
234 if (a->lds == 3 && a->ldd == 3) {
235 /* mov.[bwl] rs,rd */
236 prt("r%d, r%d", a->rs, a->rd);
237 return true;
238 }
239 if (a->lds == 3) {
240 rx_index_addr(ctx, dspd, a->ldd, a->sz);
241 prt("r%d, %s[r%d]", a->rs, dspd, a->rd);
242 } else if (a->ldd == 3) {
243 rx_index_addr(ctx, dsps, a->lds, a->sz);
244 prt("%s[r%d], r%d", dsps, a->rs, a->rd);
245 } else {
246 rx_index_addr(ctx, dsps, a->lds, a->sz);
247 rx_index_addr(ctx, dspd, a->ldd, a->sz);
248 prt("%s[r%d], %s[r%d]", dsps, a->rs, dspd, a->rd);
249 }
250 return true;
251 }
252
253 /* mov.[bwl] rs,[rd+] */
254 /* mov.[bwl] rs,[-rd] */
255 static bool trans_MOV_rp(DisasContext *ctx, arg_MOV_rp *a)
256 {
257 prt("mov.%c\tr%d, ", size[a->sz], a->rs);
258 prt((a->ad == 0) ? "[r%d+]" : "[-r%d]", a->rd);
259 return true;
260 }
261
262 /* mov.[bwl] [rd+],rs */
263 /* mov.[bwl] [-rd],rs */
264 static bool trans_MOV_pr(DisasContext *ctx, arg_MOV_pr *a)
265 {
266 prt("mov.%c\t", size[a->sz]);
267 prt((a->ad == 0) ? "[r%d+]" : "[-r%d]", a->rd);
268 prt(", r%d", a->rs);
269 return true;
270 }
271
272 /* movu.[bw] dsp5:[rs],rd */
273 static bool trans_MOVU_mr(DisasContext *ctx, arg_MOVU_mr *a)
274 {
275 if (a->dsp > 0) {
276 prt("movu.%c\t%d[r%d], r%d", size[a->sz],
277 a->dsp << a->sz, a->rs, a->rd);
278 } else {
279 prt("movu.%c\t[r%d], r%d", size[a->sz], a->rs, a->rd);
280 }
281 return true;
282 }
283
284 /* movu.[bw] rs,rd */
285 static bool trans_MOVU_rr(DisasContext *ctx, arg_MOVU_rr *a)
286 {
287 prt("movu.%c\tr%d, r%d", size[a->sz], a->rs, a->rd);
288 return true;
289 }
290
291 /* movu.[bw] [ri,rb],rd */
292 static bool trans_MOVU_ar(DisasContext *ctx, arg_MOVU_ar *a)
293 {
294 prt("mov.%c\t[r%d,r%d], r%d", size[a->sz], a->ri, a->rb, a->rd);
295 return true;
296 }
297
298 /* movu.[bw] [rs+],rd */
299 /* movu.[bw] [-rs],rd */
300 static bool trans_MOVU_pr(DisasContext *ctx, arg_MOVU_pr *a)
301 {
302 prt("movu.%c\t", size[a->sz]);
303 prt((a->ad == 0) ? "[r%d+]" : "[-r%d]", a->rd);
304 prt(", r%d", a->rs);
305 return true;
306 }
307
308 /* pop rd */
309 static bool trans_POP(DisasContext *ctx, arg_POP *a)
310 {
311 prt("pop\tr%d", a->rd);
312 return true;
313 }
314
315 /* popc rx */
316 static bool trans_POPC(DisasContext *ctx, arg_POPC *a)
317 {
318 prt("pop\tr%s", rx_crname(a->cr));
319 return true;
320 }
321
322 /* popm rd-rd2 */
323 static bool trans_POPM(DisasContext *ctx, arg_POPM *a)
324 {
325 prt("popm\tr%d-r%d", a->rd, a->rd2);
326 return true;
327 }
328
329 /* push rs */
330 static bool trans_PUSH_r(DisasContext *ctx, arg_PUSH_r *a)
331 {
332 prt("push\tr%d", a->rs);
333 return true;
334 }
335
336 /* push dsp[rs] */
337 static bool trans_PUSH_m(DisasContext *ctx, arg_PUSH_m *a)
338 {
339 char dsp[8];
340
341 rx_index_addr(ctx, dsp, a->ld, a->sz);
342 prt("push\t%s[r%d]", dsp, a->rs);
343 return true;
344 }
345
346 /* pushc rx */
347 static bool trans_PUSHC(DisasContext *ctx, arg_PUSHC *a)
348 {
349 prt("push\t%s", rx_crname(a->cr));
350 return true;
351 }
352
353 /* pushm rs-rs2*/
354 static bool trans_PUSHM(DisasContext *ctx, arg_PUSHM *a)
355 {
356 prt("pushm\tr%d-r%d", a->rs, a->rs2);
357 return true;
358 }
359
360 /* xchg rs,rd */
361 static bool trans_XCHG_rr(DisasContext *ctx, arg_XCHG_rr *a)
362 {
363 prt("xchg\tr%d, r%d", a->rs, a->rd);
364 return true;
365 }
366 /* xchg dsp[rs].<mi>,rd */
367 static bool trans_XCHG_mr(DisasContext *ctx, arg_XCHG_mr *a)
368 {
369 prt_ldmi(ctx, "xchg", a->ld, a->mi, a->rs, a->rd);
370 return true;
371 }
372
373 /* stz #imm,rd */
374 static bool trans_STZ(DisasContext *ctx, arg_STZ *a)
375 {
376 prt_ir(ctx, "stz", a->imm, a->rd);
377 return true;
378 }
379
380 /* stnz #imm,rd */
381 static bool trans_STNZ(DisasContext *ctx, arg_STNZ *a)
382 {
383 prt_ir(ctx, "stnz", a->imm, a->rd);
384 return true;
385 }
386
387 /* rtsd #imm */
388 static bool trans_RTSD_i(DisasContext *ctx, arg_RTSD_i *a)
389 {
390 prt("rtsd\t#%d", a->imm << 2);
391 return true;
392 }
393
394 /* rtsd #imm, rd-rd2 */
395 static bool trans_RTSD_irr(DisasContext *ctx, arg_RTSD_irr *a)
396 {
397 prt("rtsd\t#%d, r%d - r%d", a->imm << 2, a->rd, a->rd2);
398 return true;
399 }
400
401 /* and #uimm:4, rd */
402 /* and #imm, rd */
403 static bool trans_AND_ir(DisasContext *ctx, arg_AND_ir *a)
404 {
405 prt_ir(ctx, "and", a->imm, a->rd);
406 return true;
407 }
408
409 /* and dsp[rs], rd */
410 /* and rs,rd */
411 static bool trans_AND_mr(DisasContext *ctx, arg_AND_mr *a)
412 {
413 prt_ldmi(ctx, "and", a->ld, a->mi, a->rs, a->rd);
414 return true;
415 }
416
417 /* and rs,rs2,rd */
418 static bool trans_AND_rrr(DisasContext *ctx, arg_AND_rrr *a)
419 {
420 prt("and\tr%d,r%d, r%d", a->rs, a->rs2, a->rd);
421 return true;
422 }
423
424 /* or #uimm:4, rd */
425 /* or #imm, rd */
426 static bool trans_OR_ir(DisasContext *ctx, arg_OR_ir *a)
427 {
428 prt_ir(ctx, "or", a->imm, a->rd);
429 return true;
430 }
431
432 /* or dsp[rs], rd */
433 /* or rs,rd */
434 static bool trans_OR_mr(DisasContext *ctx, arg_OR_mr *a)
435 {
436 prt_ldmi(ctx, "or", a->ld, a->mi, a->rs, a->rd);
437 return true;
438 }
439
440 /* or rs,rs2,rd */
441 static bool trans_OR_rrr(DisasContext *ctx, arg_OR_rrr *a)
442 {
443 prt("or\tr%d, r%d, r%d", a->rs, a->rs2, a->rd);
444 return true;
445 }
446
447 /* xor #imm, rd */
448 static bool trans_XOR_ir(DisasContext *ctx, arg_XOR_ir *a)
449 {
450 prt_ir(ctx, "xor", a->imm, a->rd);
451 return true;
452 }
453
454 /* xor dsp[rs], rd */
455 /* xor rs,rd */
456 static bool trans_XOR_mr(DisasContext *ctx, arg_XOR_mr *a)
457 {
458 prt_ldmi(ctx, "xor", a->ld, a->mi, a->rs, a->rd);
459 return true;
460 }
461
462 /* tst #imm, rd */
463 static bool trans_TST_ir(DisasContext *ctx, arg_TST_ir *a)
464 {
465 prt_ir(ctx, "tst", a->imm, a->rd);
466 return true;
467 }
468
469 /* tst dsp[rs], rd */
470 /* tst rs, rd */
471 static bool trans_TST_mr(DisasContext *ctx, arg_TST_mr *a)
472 {
473 prt_ldmi(ctx, "tst", a->ld, a->mi, a->rs, a->rd);
474 return true;
475 }
476
477 /* not rd */
478 /* not rs, rd */
479 static bool trans_NOT_rr(DisasContext *ctx, arg_NOT_rr *a)
480 {
481 prt("not\t");
482 if (a->rs != a->rd) {
483 prt("r%d, ", a->rs);
484 }
485 prt("r%d", a->rd);
486 return true;
487 }
488
489 /* neg rd */
490 /* neg rs, rd */
491 static bool trans_NEG_rr(DisasContext *ctx, arg_NEG_rr *a)
492 {
493 prt("neg\t");
494 if (a->rs != a->rd) {
495 prt("r%d, ", a->rs);
496 }
497 prt("r%d", a->rd);
498 return true;
499 }
500
501 /* adc #imm, rd */
502 static bool trans_ADC_ir(DisasContext *ctx, arg_ADC_ir *a)
503 {
504 prt_ir(ctx, "adc", a->imm, a->rd);
505 return true;
506 }
507
508 /* adc rs, rd */
509 static bool trans_ADC_rr(DisasContext *ctx, arg_ADC_rr *a)
510 {
511 prt("adc\tr%d, r%d", a->rs, a->rd);
512 return true;
513 }
514
515 /* adc dsp[rs], rd */
516 static bool trans_ADC_mr(DisasContext *ctx, arg_ADC_mr *a)
517 {
518 char dsp[8];
519
520 rx_index_addr(ctx, dsp, a->ld, 2);
521 prt("adc\t%s[r%d], r%d", dsp, a->rs, a->rd);
522 return true;
523 }
524
525 /* add #uimm4, rd */
526 /* add #imm, rs, rd */
527 static bool trans_ADD_irr(DisasContext *ctx, arg_ADD_irr *a)
528 {
529 if (a->imm < 0x10 && a->rs2 == a->rd) {
530 prt("add\t#%d, r%d", a->imm, a->rd);
531 } else {
532 prt("add\t#0x%08x, r%d, r%d", a->imm, a->rs2, a->rd);
533 }
534 return true;
535 }
536
537 /* add rs, rd */
538 /* add dsp[rs], rd */
539 static bool trans_ADD_mr(DisasContext *ctx, arg_ADD_mr *a)
540 {
541 prt_ldmi(ctx, "add", a->ld, a->mi, a->rs, a->rd);
542 return true;
543 }
544
545 /* add rs, rs2, rd */
546 static bool trans_ADD_rrr(DisasContext *ctx, arg_ADD_rrr *a)
547 {
548 prt("add\tr%d, r%d, r%d", a->rs, a->rs2, a->rd);
549 return true;
550 }
551
552 /* cmp #imm4, rd */
553 /* cmp #imm8, rd */
554 /* cmp #imm, rs2 */
555 static bool trans_CMP_ir(DisasContext *ctx, arg_CMP_ir *a)
556 {
557 prt_ir(ctx, "cmp", a->imm, a->rs2);
558 return true;
559 }
560
561 /* cmp rs, rs2 */
562 /* cmp dsp[rs], rs2 */
563 static bool trans_CMP_mr(DisasContext *ctx, arg_CMP_mr *a)
564 {
565 prt_ldmi(ctx, "cmp", a->ld, a->mi, a->rs, a->rd);
566 return true;
567 }
568
569 /* sub #imm4, rd */
570 static bool trans_SUB_ir(DisasContext *ctx, arg_SUB_ir *a)
571 {
572 prt("sub\t#%d, r%d", a->imm, a->rd);
573 return true;
574 }
575
576 /* sub rs, rd */
577 /* sub dsp[rs], rd */
578 static bool trans_SUB_mr(DisasContext *ctx, arg_SUB_mr *a)
579 {
580 prt_ldmi(ctx, "sub", a->ld, a->mi, a->rs, a->rd);
581 return true;
582 }
583
584 /* sub rs, rs2, rd */
585 static bool trans_SUB_rrr(DisasContext *ctx, arg_SUB_rrr *a)
586 {
587 prt("sub\tr%d, r%d, r%d", a->rs, a->rs2, a->rd);
588 return true;
589 }
590
591 /* sbb rs, rd */
592 static bool trans_SBB_rr(DisasContext *ctx, arg_SBB_rr *a)
593 {
594 prt("sbb\tr%d, r%d", a->rs, a->rd);
595 return true;
596 }
597
598 /* sbb dsp[rs], rd */
599 static bool trans_SBB_mr(DisasContext *ctx, arg_SBB_mr *a)
600 {
601 prt_ldmi(ctx, "sbb", a->ld, RX_IM_LONG, a->rs, a->rd);
602 return true;
603 }
604
605 /* abs rd */
606 /* abs rs, rd */
607 static bool trans_ABS_rr(DisasContext *ctx, arg_ABS_rr *a)
608 {
609 prt("abs\t");
610 if (a->rs == a->rd) {
611 prt("r%d", a->rd);
612 } else {
613 prt("r%d, r%d", a->rs, a->rd);
614 }
615 return true;
616 }
617
618 /* max #imm, rd */
619 static bool trans_MAX_ir(DisasContext *ctx, arg_MAX_ir *a)
620 {
621 prt_ir(ctx, "max", a->imm, a->rd);
622 return true;
623 }
624
625 /* max rs, rd */
626 /* max dsp[rs], rd */
627 static bool trans_MAX_mr(DisasContext *ctx, arg_MAX_mr *a)
628 {
629 prt_ldmi(ctx, "max", a->ld, a->mi, a->rs, a->rd);
630 return true;
631 }
632
633 /* min #imm, rd */
634 static bool trans_MIN_ir(DisasContext *ctx, arg_MIN_ir *a)
635 {
636 prt_ir(ctx, "min", a->imm, a->rd);
637 return true;
638 }
639
640 /* min rs, rd */
641 /* min dsp[rs], rd */
642 static bool trans_MIN_mr(DisasContext *ctx, arg_MIN_mr *a)
643 {
644 prt_ldmi(ctx, "min", a->ld, a->mi, a->rs, a->rd);
645 return true;
646 }
647
648 /* mul #uimm4, rd */
649 /* mul #imm, rd */
650 static bool trans_MUL_ir(DisasContext *ctx, arg_MUL_ir *a)
651 {
652 prt_ir(ctx, "mul", a->imm, a->rd);
653 return true;
654 }
655
656 /* mul rs, rd */
657 /* mul dsp[rs], rd */
658 static bool trans_MUL_mr(DisasContext *ctx, arg_MUL_mr *a)
659 {
660 prt_ldmi(ctx, "mul", a->ld, a->mi, a->rs, a->rd);
661 return true;
662 }
663
664 /* mul rs, rs2, rd */
665 static bool trans_MUL_rrr(DisasContext *ctx, arg_MUL_rrr *a)
666 {
667 prt("mul\tr%d,r%d,r%d", a->rs, a->rs2, a->rd);
668 return true;
669 }
670
671 /* emul #imm, rd */
672 static bool trans_EMUL_ir(DisasContext *ctx, arg_EMUL_ir *a)
673 {
674 prt_ir(ctx, "emul", a->imm, a->rd);
675 return true;
676 }
677
678 /* emul rs, rd */
679 /* emul dsp[rs], rd */
680 static bool trans_EMUL_mr(DisasContext *ctx, arg_EMUL_mr *a)
681 {
682 prt_ldmi(ctx, "emul", a->ld, a->mi, a->rs, a->rd);
683 return true;
684 }
685
686 /* emulu #imm, rd */
687 static bool trans_EMULU_ir(DisasContext *ctx, arg_EMULU_ir *a)
688 {
689 prt_ir(ctx, "emulu", a->imm, a->rd);
690 return true;
691 }
692
693 /* emulu rs, rd */
694 /* emulu dsp[rs], rd */
695 static bool trans_EMULU_mr(DisasContext *ctx, arg_EMULU_mr *a)
696 {
697 prt_ldmi(ctx, "emulu", a->ld, a->mi, a->rs, a->rd);
698 return true;
699 }
700
701 /* div #imm, rd */
702 static bool trans_DIV_ir(DisasContext *ctx, arg_DIV_ir *a)
703 {
704 prt_ir(ctx, "div", a->imm, a->rd);
705 return true;
706 }
707
708 /* div rs, rd */
709 /* div dsp[rs], rd */
710 static bool trans_DIV_mr(DisasContext *ctx, arg_DIV_mr *a)
711 {
712 prt_ldmi(ctx, "div", a->ld, a->mi, a->rs, a->rd);
713 return true;
714 }
715
716 /* divu #imm, rd */
717 static bool trans_DIVU_ir(DisasContext *ctx, arg_DIVU_ir *a)
718 {
719 prt_ir(ctx, "divu", a->imm, a->rd);
720 return true;
721 }
722
723 /* divu rs, rd */
724 /* divu dsp[rs], rd */
725 static bool trans_DIVU_mr(DisasContext *ctx, arg_DIVU_mr *a)
726 {
727 prt_ldmi(ctx, "divu", a->ld, a->mi, a->rs, a->rd);
728 return true;
729 }
730
731
732 /* shll #imm:5, rd */
733 /* shll #imm:5, rs, rd */
734 static bool trans_SHLL_irr(DisasContext *ctx, arg_SHLL_irr *a)
735 {
736 prt("shll\t#%d, ", a->imm);
737 if (a->rs2 != a->rd) {
738 prt("r%d, ", a->rs2);
739 }
740 prt("r%d", a->rd);
741 return true;
742 }
743
744 /* shll rs, rd */
745 static bool trans_SHLL_rr(DisasContext *ctx, arg_SHLL_rr *a)
746 {
747 prt("shll\tr%d, r%d", a->rs, a->rd);
748 return true;
749 }
750
751 /* shar #imm:5, rd */
752 /* shar #imm:5, rs, rd */
753 static bool trans_SHAR_irr(DisasContext *ctx, arg_SHAR_irr *a)
754 {
755 prt("shar\t#%d,", a->imm);
756 if (a->rs2 != a->rd) {
757 prt("r%d, ", a->rs2);
758 }
759 prt("r%d", a->rd);
760 return true;
761 }
762
763 /* shar rs, rd */
764 static bool trans_SHAR_rr(DisasContext *ctx, arg_SHAR_rr *a)
765 {
766 prt("shar\tr%d, r%d", a->rs, a->rd);
767 return true;
768 }
769
770 /* shlr #imm:5, rd */
771 /* shlr #imm:5, rs, rd */
772 static bool trans_SHLR_irr(DisasContext *ctx, arg_SHLR_irr *a)
773 {
774 prt("shlr\t#%d, ", a->imm);
775 if (a->rs2 != a->rd) {
776 prt("r%d, ", a->rs2);
777 }
778 prt("r%d", a->rd);
779 return true;
780 }
781
782 /* shlr rs, rd */
783 static bool trans_SHLR_rr(DisasContext *ctx, arg_SHLR_rr *a)
784 {
785 prt("shlr\tr%d, r%d", a->rs, a->rd);
786 return true;
787 }
788
789 /* rolc rd */
790 static bool trans_ROLC(DisasContext *ctx, arg_ROLC *a)
791 {
792 prt("rorc\tr%d", a->rd);
793 return true;
794 }
795
796 /* rorc rd */
797 static bool trans_RORC(DisasContext *ctx, arg_RORC *a)
798 {
799 prt("rorc\tr%d", a->rd);
800 return true;
801 }
802
803 /* rotl #imm, rd */
804 static bool trans_ROTL_ir(DisasContext *ctx, arg_ROTL_ir *a)
805 {
806 prt("rotl\t#%d, r%d", a->imm, a->rd);
807 return true;
808 }
809
810 /* rotl rs, rd */
811 static bool trans_ROTL_rr(DisasContext *ctx, arg_ROTL_rr *a)
812 {
813 prt("rotl\tr%d, r%d", a->rs, a->rd);
814 return true;
815 }
816
817 /* rotr #imm, rd */
818 static bool trans_ROTR_ir(DisasContext *ctx, arg_ROTR_ir *a)
819 {
820 prt("rotr\t#%d, r%d", a->imm, a->rd);
821 return true;
822 }
823
824 /* rotr rs, rd */
825 static bool trans_ROTR_rr(DisasContext *ctx, arg_ROTR_rr *a)
826 {
827 prt("rotr\tr%d, r%d", a->rs, a->rd);
828 return true;
829 }
830
831 /* revl rs, rd */
832 static bool trans_REVL(DisasContext *ctx, arg_REVL *a)
833 {
834 prt("revl\tr%d, r%d", a->rs, a->rd);
835 return true;
836 }
837
838 /* revw rs, rd */
839 static bool trans_REVW(DisasContext *ctx, arg_REVW *a)
840 {
841 prt("revw\tr%d, r%d", a->rs, a->rd);
842 return true;
843 }
844
845 /* conditional branch helper */
846 static void rx_bcnd_main(DisasContext *ctx, int cd, int len, int dst)
847 {
848 static const char sz[] = {'s', 'b', 'w', 'a'};
849 prt("b%s.%c\t%08x", cond[cd], sz[len - 1], ctx->pc + dst);
850 }
851
852 /* beq dsp:3 / bne dsp:3 */
853 /* beq dsp:8 / bne dsp:8 */
854 /* bc dsp:8 / bnc dsp:8 */
855 /* bgtu dsp:8 / bleu dsp:8 */
856 /* bpz dsp:8 / bn dsp:8 */
857 /* bge dsp:8 / blt dsp:8 */
858 /* bgt dsp:8 / ble dsp:8 */
859 /* bo dsp:8 / bno dsp:8 */
860 /* beq dsp:16 / bne dsp:16 */
861 static bool trans_BCnd(DisasContext *ctx, arg_BCnd *a)
862 {
863 rx_bcnd_main(ctx, a->cd, a->sz, a->dsp);
864 return true;
865 }
866
867 /* bra dsp:3 */
868 /* bra dsp:8 */
869 /* bra dsp:16 */
870 /* bra dsp:24 */
871 static bool trans_BRA(DisasContext *ctx, arg_BRA *a)
872 {
873 rx_bcnd_main(ctx, 14, a->sz, a->dsp);
874 return true;
875 }
876
877 /* bra rs */
878 static bool trans_BRA_l(DisasContext *ctx, arg_BRA_l *a)
879 {
880 prt("bra.l\tr%d", a->rd);
881 return true;
882 }
883
884 /* jmp rs */
885 static bool trans_JMP(DisasContext *ctx, arg_JMP *a)
886 {
887 prt("jmp\tr%d", a->rs);
888 return true;
889 }
890
891 /* jsr rs */
892 static bool trans_JSR(DisasContext *ctx, arg_JSR *a)
893 {
894 prt("jsr\tr%d", a->rs);
895 return true;
896 }
897
898 /* bsr dsp:16 */
899 /* bsr dsp:24 */
900 static bool trans_BSR(DisasContext *ctx, arg_BSR *a)
901 {
902 static const char sz[] = {'w', 'a'};
903 prt("bsr.%c\t%08x", sz[a->sz - 3], ctx->pc + a->dsp);
904 return true;
905 }
906
907 /* bsr rs */
908 static bool trans_BSR_l(DisasContext *ctx, arg_BSR_l *a)
909 {
910 prt("bsr.l\tr%d", a->rd);
911 return true;
912 }
913
914 /* rts */
915 static bool trans_RTS(DisasContext *ctx, arg_RTS *a)
916 {
917 prt("rts");
918 return true;
919 }
920
921 /* nop */
922 static bool trans_NOP(DisasContext *ctx, arg_NOP *a)
923 {
924 prt("nop");
925 return true;
926 }
927
928 /* scmpu */
929 static bool trans_SCMPU(DisasContext *ctx, arg_SCMPU *a)
930 {
931 prt("scmpu");
932 return true;
933 }
934
935 /* smovu */
936 static bool trans_SMOVU(DisasContext *ctx, arg_SMOVU *a)
937 {
938 prt("smovu");
939 return true;
940 }
941
942 /* smovf */
943 static bool trans_SMOVF(DisasContext *ctx, arg_SMOVF *a)
944 {
945 prt("smovf");
946 return true;
947 }
948
949 /* smovb */
950 static bool trans_SMOVB(DisasContext *ctx, arg_SMOVB *a)
951 {
952 prt("smovb");
953 return true;
954 }
955
956 /* suntile */
957 static bool trans_SUNTIL(DisasContext *ctx, arg_SUNTIL *a)
958 {
959 prt("suntil.%c", size[a->sz]);
960 return true;
961 }
962
963 /* swhile */
964 static bool trans_SWHILE(DisasContext *ctx, arg_SWHILE *a)
965 {
966 prt("swhile.%c", size[a->sz]);
967 return true;
968 }
969 /* sstr */
970 static bool trans_SSTR(DisasContext *ctx, arg_SSTR *a)
971 {
972 prt("sstr.%c", size[a->sz]);
973 return true;
974 }
975
976 /* rmpa */
977 static bool trans_RMPA(DisasContext *ctx, arg_RMPA *a)
978 {
979 prt("rmpa.%c", size[a->sz]);
980 return true;
981 }
982
983 /* mulhi rs,rs2 */
984 static bool trans_MULHI(DisasContext *ctx, arg_MULHI *a)
985 {
986 prt("mulhi\tr%d,r%d", a->rs, a->rs2);
987 return true;
988 }
989
990 /* mullo rs,rs2 */
991 static bool trans_MULLO(DisasContext *ctx, arg_MULLO *a)
992 {
993 prt("mullo\tr%d, r%d", a->rs, a->rs2);
994 return true;
995 }
996
997 /* machi rs,rs2 */
998 static bool trans_MACHI(DisasContext *ctx, arg_MACHI *a)
999 {
1000 prt("machi\tr%d, r%d", a->rs, a->rs2);
1001 return true;
1002 }
1003
1004 /* maclo rs,rs2 */
1005 static bool trans_MACLO(DisasContext *ctx, arg_MACLO *a)
1006 {
1007 prt("maclo\tr%d, r%d", a->rs, a->rs2);
1008 return true;
1009 }
1010
1011 /* mvfachi rd */
1012 static bool trans_MVFACHI(DisasContext *ctx, arg_MVFACHI *a)
1013 {
1014 prt("mvfachi\tr%d", a->rd);
1015 return true;
1016 }
1017
1018 /* mvfacmi rd */
1019 static bool trans_MVFACMI(DisasContext *ctx, arg_MVFACMI *a)
1020 {
1021 prt("mvfacmi\tr%d", a->rd);
1022 return true;
1023 }
1024
1025 /* mvtachi rs */
1026 static bool trans_MVTACHI(DisasContext *ctx, arg_MVTACHI *a)
1027 {
1028 prt("mvtachi\tr%d", a->rs);
1029 return true;
1030 }
1031
1032 /* mvtaclo rs */
1033 static bool trans_MVTACLO(DisasContext *ctx, arg_MVTACLO *a)
1034 {
1035 prt("mvtaclo\tr%d", a->rs);
1036 return true;
1037 }
1038
1039 /* racw #imm */
1040 static bool trans_RACW(DisasContext *ctx, arg_RACW *a)
1041 {
1042 prt("racw\t#%d", a->imm + 1);
1043 return true;
1044 }
1045
1046 /* sat rd */
1047 static bool trans_SAT(DisasContext *ctx, arg_SAT *a)
1048 {
1049 prt("sat\tr%d", a->rd);
1050 return true;
1051 }
1052
1053 /* satr */
1054 static bool trans_SATR(DisasContext *ctx, arg_SATR *a)
1055 {
1056 prt("satr");
1057 return true;
1058 }
1059
1060 /* fadd #imm, rd */
1061 static bool trans_FADD_ir(DisasContext *ctx, arg_FADD_ir *a)
1062 {
1063 prt("fadd\t#%d,r%d", li(ctx, 0), a->rd);
1064 return true;
1065 }
1066
1067 /* fadd dsp[rs], rd */
1068 /* fadd rs, rd */
1069 static bool trans_FADD_mr(DisasContext *ctx, arg_FADD_mr *a)
1070 {
1071 prt_ldmi(ctx, "fadd", a->ld, RX_IM_LONG, a->rs, a->rd);
1072 return true;
1073 }
1074
1075 /* fcmp #imm, rd */
1076 static bool trans_FCMP_ir(DisasContext *ctx, arg_FCMP_ir *a)
1077 {
1078 prt("fadd\t#%d,r%d", li(ctx, 0), a->rd);
1079 return true;
1080 }
1081
1082 /* fcmp dsp[rs], rd */
1083 /* fcmp rs, rd */
1084 static bool trans_FCMP_mr(DisasContext *ctx, arg_FCMP_mr *a)
1085 {
1086 prt_ldmi(ctx, "fcmp", a->ld, RX_IM_LONG, a->rs, a->rd);
1087 return true;
1088 }
1089
1090 /* fsub #imm, rd */
1091 static bool trans_FSUB_ir(DisasContext *ctx, arg_FSUB_ir *a)
1092 {
1093 prt("fsub\t#%d,r%d", li(ctx, 0), a->rd);
1094 return true;
1095 }
1096
1097 /* fsub dsp[rs], rd */
1098 /* fsub rs, rd */
1099 static bool trans_FSUB_mr(DisasContext *ctx, arg_FSUB_mr *a)
1100 {
1101 prt_ldmi(ctx, "fsub", a->ld, RX_IM_LONG, a->rs, a->rd);
1102 return true;
1103 }
1104
1105 /* ftoi dsp[rs], rd */
1106 /* ftoi rs, rd */
1107 static bool trans_FTOI(DisasContext *ctx, arg_FTOI *a)
1108 {
1109 prt_ldmi(ctx, "ftoi", a->ld, RX_IM_LONG, a->rs, a->rd);
1110 return true;
1111 }
1112
1113 /* fmul #imm, rd */
1114 static bool trans_FMUL_ir(DisasContext *ctx, arg_FMUL_ir *a)
1115 {
1116 prt("fmul\t#%d,r%d", li(ctx, 0), a->rd);
1117 return true;
1118 }
1119
1120 /* fmul dsp[rs], rd */
1121 /* fmul rs, rd */
1122 static bool trans_FMUL_mr(DisasContext *ctx, arg_FMUL_mr *a)
1123 {
1124 prt_ldmi(ctx, "fmul", a->ld, RX_IM_LONG, a->rs, a->rd);
1125 return true;
1126 }
1127
1128 /* fdiv #imm, rd */
1129 static bool trans_FDIV_ir(DisasContext *ctx, arg_FDIV_ir *a)
1130 {
1131 prt("fdiv\t#%d,r%d", li(ctx, 0), a->rd);
1132 return true;
1133 }
1134
1135 /* fdiv dsp[rs], rd */
1136 /* fdiv rs, rd */
1137 static bool trans_FDIV_mr(DisasContext *ctx, arg_FDIV_mr *a)
1138 {
1139 prt_ldmi(ctx, "fdiv", a->ld, RX_IM_LONG, a->rs, a->rd);
1140 return true;
1141 }
1142
1143 /* round dsp[rs], rd */
1144 /* round rs, rd */
1145 static bool trans_ROUND(DisasContext *ctx, arg_ROUND *a)
1146 {
1147 prt_ldmi(ctx, "round", a->ld, RX_IM_LONG, a->rs, a->rd);
1148 return true;
1149 }
1150
1151 /* itof rs, rd */
1152 /* itof dsp[rs], rd */
1153 static bool trans_ITOF(DisasContext *ctx, arg_ITOF *a)
1154 {
1155 prt_ldmi(ctx, "itof", a->ld, RX_IM_LONG, a->rs, a->rd);
1156 return true;
1157 }
1158
1159 #define BOP_IM(name, reg) \
1160 do { \
1161 char dsp[8]; \
1162 rx_index_addr(ctx, dsp, a->ld, RX_MEMORY_BYTE); \
1163 prt("b%s\t#%d, %s[r%d]", #name, a->imm, dsp, reg); \
1164 return true; \
1165 } while (0)
1166
1167 #define BOP_RM(name) \
1168 do { \
1169 char dsp[8]; \
1170 rx_index_addr(ctx, dsp, a->ld, RX_MEMORY_BYTE); \
1171 prt("b%s\tr%d, %s[r%d]", #name, a->rd, dsp, a->rs); \
1172 return true; \
1173 } while (0)
1174
1175 /* bset #imm, dsp[rd] */
1176 static bool trans_BSET_im(DisasContext *ctx, arg_BSET_im *a)
1177 {
1178 BOP_IM(bset, a->rs);
1179 }
1180
1181 /* bset rs, dsp[rd] */
1182 static bool trans_BSET_rm(DisasContext *ctx, arg_BSET_rm *a)
1183 {
1184 BOP_RM(set);
1185 }
1186
1187 /* bset rs, rd */
1188 static bool trans_BSET_rr(DisasContext *ctx, arg_BSET_rr *a)
1189 {
1190 prt("bset\tr%d,r%d", a->rs, a->rd);
1191 return true;
1192 }
1193
1194 /* bset #imm, rd */
1195 static bool trans_BSET_ir(DisasContext *ctx, arg_BSET_ir *a)
1196 {
1197 prt("bset\t#%d, r%d", a->imm, a->rd);
1198 return true;
1199 }
1200
1201 /* bclr #imm, dsp[rd] */
1202 static bool trans_BCLR_im(DisasContext *ctx, arg_BCLR_im *a)
1203 {
1204 BOP_IM(clr, a->rs);
1205 }
1206
1207 /* bclr rs, dsp[rd] */
1208 static bool trans_BCLR_rm(DisasContext *ctx, arg_BCLR_rm *a)
1209 {
1210 BOP_RM(clr);
1211 }
1212
1213 /* bclr rs, rd */
1214 static bool trans_BCLR_rr(DisasContext *ctx, arg_BCLR_rr *a)
1215 {
1216 prt("bclr\tr%d, r%d", a->rs, a->rd);
1217 return true;
1218 }
1219
1220 /* bclr #imm, rd */
1221 static bool trans_BCLR_ir(DisasContext *ctx, arg_BCLR_ir *a)
1222 {
1223 prt("bclr\t#%d,r%d", a->imm, a->rd);
1224 return true;
1225 }
1226
1227 /* btst #imm, dsp[rd] */
1228 static bool trans_BTST_im(DisasContext *ctx, arg_BTST_im *a)
1229 {
1230 BOP_IM(tst, a->rs);
1231 }
1232
1233 /* btst rs, dsp[rd] */
1234 static bool trans_BTST_rm(DisasContext *ctx, arg_BTST_rm *a)
1235 {
1236 BOP_RM(tst);
1237 }
1238
1239 /* btst rs, rd */
1240 static bool trans_BTST_rr(DisasContext *ctx, arg_BTST_rr *a)
1241 {
1242 prt("btst\tr%d, r%d", a->rs, a->rd);
1243 return true;
1244 }
1245
1246 /* btst #imm, rd */
1247 static bool trans_BTST_ir(DisasContext *ctx, arg_BTST_ir *a)
1248 {
1249 prt("btst\t#%d, r%d", a->imm, a->rd);
1250 return true;
1251 }
1252
1253 /* bnot rs, dsp[rd] */
1254 static bool trans_BNOT_rm(DisasContext *ctx, arg_BNOT_rm *a)
1255 {
1256 BOP_RM(not);
1257 }
1258
1259 /* bnot rs, rd */
1260 static bool trans_BNOT_rr(DisasContext *ctx, arg_BNOT_rr *a)
1261 {
1262 prt("bnot\tr%d, r%d", a->rs, a->rd);
1263 return true;
1264 }
1265
1266 /* bnot #imm, dsp[rd] */
1267 static bool trans_BNOT_im(DisasContext *ctx, arg_BNOT_im *a)
1268 {
1269 BOP_IM(not, a->rs);
1270 }
1271
1272 /* bnot #imm, rd */
1273 static bool trans_BNOT_ir(DisasContext *ctx, arg_BNOT_ir *a)
1274 {
1275 prt("bnot\t#%d, r%d", a->imm, a->rd);
1276 return true;
1277 }
1278
1279 /* bmcond #imm, dsp[rd] */
1280 static bool trans_BMCnd_im(DisasContext *ctx, arg_BMCnd_im *a)
1281 {
1282 char dsp[8];
1283
1284 rx_index_addr(ctx, dsp, a->ld, RX_MEMORY_BYTE);
1285 prt("bm%s\t#%d, %s[r%d]", cond[a->cd], a->imm, dsp, a->rd);
1286 return true;
1287 }
1288
1289 /* bmcond #imm, rd */
1290 static bool trans_BMCnd_ir(DisasContext *ctx, arg_BMCnd_ir *a)
1291 {
1292 prt("bm%s\t#%d, r%d", cond[a->cd], a->imm, a->rd);
1293 return true;
1294 }
1295
1296 /* clrpsw psw */
1297 static bool trans_CLRPSW(DisasContext *ctx, arg_CLRPSW *a)
1298 {
1299 prt("clrpsw\t%c", psw[a->cb]);
1300 return true;
1301 }
1302
1303 /* setpsw psw */
1304 static bool trans_SETPSW(DisasContext *ctx, arg_SETPSW *a)
1305 {
1306 prt("setpsw\t%c", psw[a->cb]);
1307 return true;
1308 }
1309
1310 /* mvtipl #imm */
1311 static bool trans_MVTIPL(DisasContext *ctx, arg_MVTIPL *a)
1312 {
1313 prt("movtipl\t#%d", a->imm);
1314 return true;
1315 }
1316
1317 /* mvtc #imm, rd */
1318 static bool trans_MVTC_i(DisasContext *ctx, arg_MVTC_i *a)
1319 {
1320 prt("mvtc\t#0x%08x, %s", a->imm, rx_crname(a->cr));
1321 return true;
1322 }
1323
1324 /* mvtc rs, rd */
1325 static bool trans_MVTC_r(DisasContext *ctx, arg_MVTC_r *a)
1326 {
1327 prt("mvtc\tr%d, %s", a->rs, rx_crname(a->cr));
1328 return true;
1329 }
1330
1331 /* mvfc rs, rd */
1332 static bool trans_MVFC(DisasContext *ctx, arg_MVFC *a)
1333 {
1334 prt("mvfc\t%s, r%d", rx_crname(a->cr), a->rd);
1335 return true;
1336 }
1337
1338 /* rtfi */
1339 static bool trans_RTFI(DisasContext *ctx, arg_RTFI *a)
1340 {
1341 prt("rtfi");
1342 return true;
1343 }
1344
1345 /* rte */
1346 static bool trans_RTE(DisasContext *ctx, arg_RTE *a)
1347 {
1348 prt("rte");
1349 return true;
1350 }
1351
1352 /* brk */
1353 static bool trans_BRK(DisasContext *ctx, arg_BRK *a)
1354 {
1355 prt("brk");
1356 return true;
1357 }
1358
1359 /* int #imm */
1360 static bool trans_INT(DisasContext *ctx, arg_INT *a)
1361 {
1362 prt("int\t#%d", a->imm);
1363 return true;
1364 }
1365
1366 /* wait */
1367 static bool trans_WAIT(DisasContext *ctx, arg_WAIT *a)
1368 {
1369 prt("wait");
1370 return true;
1371 }
1372
1373 /* sccnd.[bwl] rd */
1374 /* sccnd.[bwl] dsp:[rd] */
1375 static bool trans_SCCnd(DisasContext *ctx, arg_SCCnd *a)
1376 {
1377 if (a->ld < 3) {
1378 char dsp[8];
1379 rx_index_addr(ctx, dsp, a->sz, a->ld);
1380 prt("sc%s.%c\t%s[r%d]", cond[a->cd], size[a->sz], dsp, a->rd);
1381 } else {
1382 prt("sc%s.%c\tr%d", cond[a->cd], size[a->sz], a->rd);
1383 }
1384 return true;
1385 }
1386
1387 int print_insn_rx(bfd_vma addr, disassemble_info *dis)
1388 {
1389 DisasContext ctx;
1390 uint32_t insn;
1391 int i;
1392 ctx.dis = dis;
1393 ctx.pc = ctx.addr = addr;
1394
1395 insn = decode_load(&ctx);
1396 if (!decode(&ctx, insn)) {
1397 ctx.dis->fprintf_func(ctx.dis->stream, ".byte\t");
1398 for (i = 0; i < ctx.addr - addr; i++) {
1399 if (i > 0) {
1400 ctx.dis->fprintf_func(ctx.dis->stream, ",");
1401 }
1402 ctx.dis->fprintf_func(ctx.dis->stream, "0x%02x", insn >> 24);
1403 insn <<= 8;
1404 }
1405 }
1406 return ctx.addr - addr;
1407 }