xref: /openbmc/qemu/target/rx/disas.c (revision fa6289e2)
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 operand(DisasContext *ctx, int ld, int mi, int rs, int rd)
139 {
140     static const char sizes[][4] = {".b", ".w", ".l", ".uw", ".ub"};
141     char dsp[8];
142 
143     if (ld < 3) {
144         rx_index_addr(ctx, dsp, ld, mi);
145         prt("%s[r%d]%s", dsp, rs, sizes[mi]);
146     } else {
147         prt("r%d", rs);
148     }
149     prt(", r%d", rd);
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     static const char msize[][4] = {
370         "b", "w", "l", "ub", "uw",
371     };
372     char dsp[8];
373 
374     rx_index_addr(ctx, dsp, a->ld, a->mi);
375     prt("xchg\t%s[r%d].%s, r%d", dsp, a->rs, msize[a->mi], a->rd);
376     return true;
377 }
378 
379 /* stz #imm,rd */
380 static bool trans_STZ(DisasContext *ctx, arg_STZ *a)
381 {
382     prt_ir(ctx, "stz", a->imm, a->rd);
383     return true;
384 }
385 
386 /* stnz #imm,rd */
387 static bool trans_STNZ(DisasContext *ctx, arg_STNZ *a)
388 {
389     prt_ir(ctx, "stnz", a->imm, a->rd);
390     return true;
391 }
392 
393 /* rtsd #imm */
394 static bool trans_RTSD_i(DisasContext *ctx, arg_RTSD_i *a)
395 {
396     prt("rtsd\t#%d", a->imm << 2);
397     return true;
398 }
399 
400 /* rtsd #imm, rd-rd2 */
401 static bool trans_RTSD_irr(DisasContext *ctx, arg_RTSD_irr *a)
402 {
403     prt("rtsd\t#%d, r%d - r%d", a->imm << 2, a->rd, a->rd2);
404     return true;
405 }
406 
407 /* and #uimm:4, rd */
408 /* and #imm, rd */
409 static bool trans_AND_ir(DisasContext *ctx, arg_AND_ir *a)
410 {
411     prt_ir(ctx, "and", a->imm, a->rd);
412     return true;
413 }
414 
415 /* and dsp[rs], rd */
416 /* and rs,rd */
417 static bool trans_AND_mr(DisasContext *ctx, arg_AND_mr *a)
418 {
419     prt("and\t");
420     operand(ctx, a->ld, a->mi, a->rs, a->rd);
421     return true;
422 }
423 
424 /* and rs,rs2,rd */
425 static bool trans_AND_rrr(DisasContext *ctx, arg_AND_rrr *a)
426 {
427     prt("and\tr%d,r%d, r%d", a->rs, a->rs2, a->rd);
428     return true;
429 }
430 
431 /* or #uimm:4, rd */
432 /* or #imm, rd */
433 static bool trans_OR_ir(DisasContext *ctx, arg_OR_ir *a)
434 {
435     prt_ir(ctx, "or", a->imm, a->rd);
436     return true;
437 }
438 
439 /* or dsp[rs], rd */
440 /* or rs,rd */
441 static bool trans_OR_mr(DisasContext *ctx, arg_OR_mr *a)
442 {
443     prt("or\t");
444     operand(ctx, a->ld, a->mi, a->rs, a->rd);
445     return true;
446 }
447 
448 /* or rs,rs2,rd */
449 static bool trans_OR_rrr(DisasContext *ctx, arg_OR_rrr *a)
450 {
451     prt("or\tr%d, r%d, r%d", a->rs, a->rs2, a->rd);
452     return true;
453 }
454 
455 /* xor #imm, rd */
456 static bool trans_XOR_ir(DisasContext *ctx, arg_XOR_ir *a)
457 {
458     prt_ir(ctx, "xor", a->imm, a->rd);
459     return true;
460 }
461 
462 /* xor dsp[rs], rd */
463 /* xor rs,rd */
464 static bool trans_XOR_mr(DisasContext *ctx, arg_XOR_mr *a)
465 {
466     prt("xor\t");
467     operand(ctx, a->ld, a->mi, a->rs, a->rd);
468     return true;
469 }
470 
471 /* tst #imm, rd */
472 static bool trans_TST_ir(DisasContext *ctx, arg_TST_ir *a)
473 {
474     prt_ir(ctx, "tst", a->imm, a->rd);
475     return true;
476 }
477 
478 /* tst dsp[rs], rd */
479 /* tst rs, rd */
480 static bool trans_TST_mr(DisasContext *ctx, arg_TST_mr *a)
481 {
482     prt("tst\t");
483     operand(ctx, a->ld, a->mi, a->rs, a->rd);
484     return true;
485 }
486 
487 /* not rd */
488 /* not rs, rd */
489 static bool trans_NOT_rr(DisasContext *ctx, arg_NOT_rr *a)
490 {
491     prt("not\t");
492     if (a->rs != a->rd) {
493         prt("r%d, ", a->rs);
494     }
495     prt("r%d", a->rd);
496     return true;
497 }
498 
499 /* neg rd */
500 /* neg rs, rd */
501 static bool trans_NEG_rr(DisasContext *ctx, arg_NEG_rr *a)
502 {
503     prt("neg\t");
504     if (a->rs != a->rd) {
505         prt("r%d, ", a->rs);
506     }
507     prt("r%d", a->rd);
508     return true;
509 }
510 
511 /* adc #imm, rd */
512 static bool trans_ADC_ir(DisasContext *ctx, arg_ADC_ir *a)
513 {
514     prt_ir(ctx, "adc", a->imm, a->rd);
515     return true;
516 }
517 
518 /* adc rs, rd */
519 static bool trans_ADC_rr(DisasContext *ctx, arg_ADC_rr *a)
520 {
521     prt("adc\tr%d, r%d", a->rs, a->rd);
522     return true;
523 }
524 
525 /* adc dsp[rs], rd */
526 static bool trans_ADC_mr(DisasContext *ctx, arg_ADC_mr *a)
527 {
528     char dsp[8];
529 
530     rx_index_addr(ctx, dsp, a->ld, 2);
531     prt("adc\t%s[r%d], r%d", dsp, a->rs, a->rd);
532     return true;
533 }
534 
535 /* add #uimm4, rd */
536 /* add #imm, rs, rd */
537 static bool trans_ADD_irr(DisasContext *ctx, arg_ADD_irr *a)
538 {
539     if (a->imm < 0x10 && a->rs2 == a->rd) {
540         prt("add\t#%d, r%d", a->imm, a->rd);
541     } else {
542         prt("add\t#0x%08x, r%d, r%d", a->imm, a->rs2, a->rd);
543     }
544     return true;
545 }
546 
547 /* add rs, rd */
548 /* add dsp[rs], rd */
549 static bool trans_ADD_mr(DisasContext *ctx, arg_ADD_mr *a)
550 {
551     prt("add\t");
552     operand(ctx, a->ld, a->mi, a->rs, a->rd);
553     return true;
554 }
555 
556 /* add rs, rs2, rd */
557 static bool trans_ADD_rrr(DisasContext *ctx, arg_ADD_rrr *a)
558 {
559     prt("add\tr%d, r%d, r%d", a->rs, a->rs2, a->rd);
560     return true;
561 }
562 
563 /* cmp #imm4, rd */
564 /* cmp #imm8, rd */
565 /* cmp #imm, rs2 */
566 static bool trans_CMP_ir(DisasContext *ctx, arg_CMP_ir *a)
567 {
568     prt_ir(ctx, "cmp", a->imm, a->rs2);
569     return true;
570 }
571 
572 /* cmp rs, rs2 */
573 /* cmp dsp[rs], rs2 */
574 static bool trans_CMP_mr(DisasContext *ctx, arg_CMP_mr *a)
575 {
576     prt("cmp\t");
577     operand(ctx, a->ld, a->mi, a->rs, a->rd);
578     return true;
579 }
580 
581 /* sub #imm4, rd */
582 static bool trans_SUB_ir(DisasContext *ctx, arg_SUB_ir *a)
583 {
584     prt("sub\t#%d, r%d", a->imm, a->rd);
585     return true;
586 }
587 
588 /* sub rs, rd */
589 /* sub dsp[rs], rd */
590 static bool trans_SUB_mr(DisasContext *ctx, arg_SUB_mr *a)
591 {
592     prt("sub\t");
593     operand(ctx, a->ld, a->mi, a->rs, a->rd);
594     return true;
595 }
596 
597 /* sub rs, rs2, rd */
598 static bool trans_SUB_rrr(DisasContext *ctx, arg_SUB_rrr *a)
599 {
600     prt("sub\tr%d, r%d, r%d", a->rs, a->rs2, a->rd);
601     return true;
602 }
603 
604 /* sbb rs, rd */
605 static bool trans_SBB_rr(DisasContext *ctx, arg_SBB_rr *a)
606 {
607     prt("sbb\tr%d, r%d", a->rs, a->rd);
608     return true;
609 }
610 
611 /* sbb dsp[rs], rd */
612 static bool trans_SBB_mr(DisasContext *ctx, arg_SBB_mr *a)
613 {
614     prt("sbb\t");
615     operand(ctx, a->ld, RX_IM_LONG, a->rs, a->rd);
616     return true;
617 }
618 
619 /* abs rd */
620 /* abs rs, rd */
621 static bool trans_ABS_rr(DisasContext *ctx, arg_ABS_rr *a)
622 {
623     prt("abs\t");
624     if (a->rs == a->rd) {
625         prt("r%d", a->rd);
626     } else {
627         prt("r%d, r%d", a->rs, a->rd);
628     }
629     return true;
630 }
631 
632 /* max #imm, rd */
633 static bool trans_MAX_ir(DisasContext *ctx, arg_MAX_ir *a)
634 {
635     prt_ir(ctx, "max", a->imm, a->rd);
636     return true;
637 }
638 
639 /* max rs, rd */
640 /* max dsp[rs], rd */
641 static bool trans_MAX_mr(DisasContext *ctx, arg_MAX_mr *a)
642 {
643     prt("max\t");
644     operand(ctx, a->ld, a->mi, a->rs, a->rd);
645     return true;
646 }
647 
648 /* min #imm, rd */
649 static bool trans_MIN_ir(DisasContext *ctx, arg_MIN_ir *a)
650 {
651     prt_ir(ctx, "min", a->imm, a->rd);
652     return true;
653 }
654 
655 /* min rs, rd */
656 /* min dsp[rs], rd */
657 static bool trans_MIN_mr(DisasContext *ctx, arg_MIN_mr *a)
658 {
659     prt("max\t");
660     operand(ctx, a->ld, a->mi, a->rs, a->rd);
661     return true;
662 }
663 
664 /* mul #uimm4, rd */
665 /* mul #imm, rd */
666 static bool trans_MUL_ir(DisasContext *ctx, arg_MUL_ir *a)
667 {
668     prt_ir(ctx, "mul", a->imm, a->rd);
669     return true;
670 }
671 
672 /* mul rs, rd */
673 /* mul dsp[rs], rd */
674 static bool trans_MUL_mr(DisasContext *ctx, arg_MUL_mr *a)
675 {
676     prt("mul\t");
677     operand(ctx, a->ld, a->mi, a->rs, a->rd);
678     return true;
679 }
680 
681 /* mul rs, rs2, rd */
682 static bool trans_MUL_rrr(DisasContext *ctx, arg_MUL_rrr *a)
683 {
684     prt("mul\tr%d,r%d,r%d", a->rs, a->rs2, a->rd);
685     return true;
686 }
687 
688 /* emul #imm, rd */
689 static bool trans_EMUL_ir(DisasContext *ctx, arg_EMUL_ir *a)
690 {
691     prt_ir(ctx, "emul", a->imm, a->rd);
692     return true;
693 }
694 
695 /* emul rs, rd */
696 /* emul dsp[rs], rd */
697 static bool trans_EMUL_mr(DisasContext *ctx, arg_EMUL_mr *a)
698 {
699     prt("emul\t");
700     operand(ctx, a->ld, a->mi, a->rs, a->rd);
701     return true;
702 }
703 
704 /* emulu #imm, rd */
705 static bool trans_EMULU_ir(DisasContext *ctx, arg_EMULU_ir *a)
706 {
707     prt_ir(ctx, "emulu", a->imm, a->rd);
708     return true;
709 }
710 
711 /* emulu rs, rd */
712 /* emulu dsp[rs], rd */
713 static bool trans_EMULU_mr(DisasContext *ctx, arg_EMULU_mr *a)
714 {
715     prt("emulu\t");
716     operand(ctx, a->ld, a->mi, a->rs, a->rd);
717     return true;
718 }
719 
720 /* div #imm, rd */
721 static bool trans_DIV_ir(DisasContext *ctx, arg_DIV_ir *a)
722 {
723     prt_ir(ctx, "div", a->imm, a->rd);
724     return true;
725 }
726 
727 /* div rs, rd */
728 /* div dsp[rs], rd */
729 static bool trans_DIV_mr(DisasContext *ctx, arg_DIV_mr *a)
730 {
731     prt("div\t");
732     operand(ctx, a->ld, a->mi, a->rs, a->rd);
733     return true;
734 }
735 
736 /* divu #imm, rd */
737 static bool trans_DIVU_ir(DisasContext *ctx, arg_DIVU_ir *a)
738 {
739     prt_ir(ctx, "divu", a->imm, a->rd);
740     return true;
741 }
742 
743 /* divu rs, rd */
744 /* divu dsp[rs], rd */
745 static bool trans_DIVU_mr(DisasContext *ctx, arg_DIVU_mr *a)
746 {
747     prt("divu\t");
748     operand(ctx, a->ld, a->mi, a->rs, a->rd);
749     return true;
750 }
751 
752 
753 /* shll #imm:5, rd */
754 /* shll #imm:5, rs, rd */
755 static bool trans_SHLL_irr(DisasContext *ctx, arg_SHLL_irr *a)
756 {
757     prt("shll\t#%d, ", a->imm);
758     if (a->rs2 != a->rd) {
759         prt("r%d, ", a->rs2);
760     }
761     prt("r%d", a->rd);
762     return true;
763 }
764 
765 /* shll rs, rd */
766 static bool trans_SHLL_rr(DisasContext *ctx, arg_SHLL_rr *a)
767 {
768     prt("shll\tr%d, r%d", a->rs, a->rd);
769     return true;
770 }
771 
772 /* shar #imm:5, rd */
773 /* shar #imm:5, rs, rd */
774 static bool trans_SHAR_irr(DisasContext *ctx, arg_SHAR_irr *a)
775 {
776     prt("shar\t#%d,", a->imm);
777     if (a->rs2 != a->rd) {
778         prt("r%d, ", a->rs2);
779     }
780     prt("r%d", a->rd);
781     return true;
782 }
783 
784 /* shar rs, rd */
785 static bool trans_SHAR_rr(DisasContext *ctx, arg_SHAR_rr *a)
786 {
787     prt("shar\tr%d, r%d", a->rs, a->rd);
788     return true;
789 }
790 
791 /* shlr #imm:5, rd */
792 /* shlr #imm:5, rs, rd */
793 static bool trans_SHLR_irr(DisasContext *ctx, arg_SHLR_irr *a)
794 {
795     prt("shlr\t#%d, ", a->imm);
796     if (a->rs2 != a->rd) {
797         prt("r%d, ", a->rs2);
798     }
799     prt("r%d", a->rd);
800     return true;
801 }
802 
803 /* shlr rs, rd */
804 static bool trans_SHLR_rr(DisasContext *ctx, arg_SHLR_rr *a)
805 {
806     prt("shlr\tr%d, r%d", a->rs, a->rd);
807     return true;
808 }
809 
810 /* rolc rd */
811 static bool trans_ROLC(DisasContext *ctx, arg_ROLC *a)
812 {
813     prt("rorc\tr%d", a->rd);
814     return true;
815 }
816 
817 /* rorc rd */
818 static bool trans_RORC(DisasContext *ctx, arg_RORC *a)
819 {
820     prt("rorc\tr%d", a->rd);
821     return true;
822 }
823 
824 /* rotl #imm, rd */
825 static bool trans_ROTL_ir(DisasContext *ctx, arg_ROTL_ir *a)
826 {
827     prt("rotl\t#%d, r%d", a->imm, a->rd);
828     return true;
829 }
830 
831 /* rotl rs, rd */
832 static bool trans_ROTL_rr(DisasContext *ctx, arg_ROTL_rr *a)
833 {
834     prt("rotl\tr%d, r%d", a->rs, a->rd);
835     return true;
836 }
837 
838 /* rotr #imm, rd */
839 static bool trans_ROTR_ir(DisasContext *ctx, arg_ROTR_ir *a)
840 {
841     prt("rotr\t#%d, r%d", a->imm, a->rd);
842     return true;
843 }
844 
845 /* rotr rs, rd */
846 static bool trans_ROTR_rr(DisasContext *ctx, arg_ROTR_rr *a)
847 {
848     prt("rotr\tr%d, r%d", a->rs, a->rd);
849     return true;
850 }
851 
852 /* revl rs, rd */
853 static bool trans_REVL(DisasContext *ctx, arg_REVL *a)
854 {
855     prt("revl\tr%d, r%d", a->rs, a->rd);
856     return true;
857 }
858 
859 /* revw rs, rd */
860 static bool trans_REVW(DisasContext *ctx, arg_REVW *a)
861 {
862     prt("revw\tr%d, r%d", a->rs, a->rd);
863     return true;
864 }
865 
866 /* conditional branch helper */
867 static void rx_bcnd_main(DisasContext *ctx, int cd, int len, int dst)
868 {
869     static const char sz[] = {'s', 'b', 'w', 'a'};
870     prt("b%s.%c\t%08x", cond[cd], sz[len - 1], ctx->pc + dst);
871 }
872 
873 /* beq dsp:3 / bne dsp:3 */
874 /* beq dsp:8 / bne dsp:8 */
875 /* bc dsp:8 / bnc dsp:8 */
876 /* bgtu dsp:8 / bleu dsp:8 */
877 /* bpz dsp:8 / bn dsp:8 */
878 /* bge dsp:8 / blt dsp:8 */
879 /* bgt dsp:8 / ble dsp:8 */
880 /* bo dsp:8 / bno dsp:8 */
881 /* beq dsp:16 / bne dsp:16 */
882 static bool trans_BCnd(DisasContext *ctx, arg_BCnd *a)
883 {
884     rx_bcnd_main(ctx, a->cd, a->sz, a->dsp);
885     return true;
886 }
887 
888 /* bra dsp:3 */
889 /* bra dsp:8 */
890 /* bra dsp:16 */
891 /* bra dsp:24 */
892 static bool trans_BRA(DisasContext *ctx, arg_BRA *a)
893 {
894     rx_bcnd_main(ctx, 14, a->sz, a->dsp);
895     return true;
896 }
897 
898 /* bra rs */
899 static bool trans_BRA_l(DisasContext *ctx, arg_BRA_l *a)
900 {
901     prt("bra.l\tr%d", a->rd);
902     return true;
903 }
904 
905 /* jmp rs */
906 static bool trans_JMP(DisasContext *ctx, arg_JMP *a)
907 {
908     prt("jmp\tr%d", a->rs);
909     return true;
910 }
911 
912 /* jsr rs */
913 static bool trans_JSR(DisasContext *ctx, arg_JSR *a)
914 {
915     prt("jsr\tr%d", a->rs);
916     return true;
917 }
918 
919 /* bsr dsp:16 */
920 /* bsr dsp:24 */
921 static bool trans_BSR(DisasContext *ctx, arg_BSR *a)
922 {
923     static const char sz[] = {'w', 'a'};
924     prt("bsr.%c\t%08x", sz[a->sz - 3], ctx->pc + a->dsp);
925     return true;
926 }
927 
928 /* bsr rs */
929 static bool trans_BSR_l(DisasContext *ctx, arg_BSR_l *a)
930 {
931     prt("bsr.l\tr%d", a->rd);
932     return true;
933 }
934 
935 /* rts */
936 static bool trans_RTS(DisasContext *ctx, arg_RTS *a)
937 {
938     prt("rts");
939     return true;
940 }
941 
942 /* nop */
943 static bool trans_NOP(DisasContext *ctx, arg_NOP *a)
944 {
945     prt("nop");
946     return true;
947 }
948 
949 /* scmpu */
950 static bool trans_SCMPU(DisasContext *ctx, arg_SCMPU *a)
951 {
952     prt("scmpu");
953     return true;
954 }
955 
956 /* smovu */
957 static bool trans_SMOVU(DisasContext *ctx, arg_SMOVU *a)
958 {
959     prt("smovu");
960     return true;
961 }
962 
963 /* smovf */
964 static bool trans_SMOVF(DisasContext *ctx, arg_SMOVF *a)
965 {
966     prt("smovf");
967     return true;
968 }
969 
970 /* smovb */
971 static bool trans_SMOVB(DisasContext *ctx, arg_SMOVB *a)
972 {
973     prt("smovb");
974     return true;
975 }
976 
977 /* suntile */
978 static bool trans_SUNTIL(DisasContext *ctx, arg_SUNTIL *a)
979 {
980     prt("suntil.%c", size[a->sz]);
981     return true;
982 }
983 
984 /* swhile */
985 static bool trans_SWHILE(DisasContext *ctx, arg_SWHILE *a)
986 {
987     prt("swhile.%c", size[a->sz]);
988     return true;
989 }
990 /* sstr */
991 static bool trans_SSTR(DisasContext *ctx, arg_SSTR *a)
992 {
993     prt("sstr.%c", size[a->sz]);
994     return true;
995 }
996 
997 /* rmpa */
998 static bool trans_RMPA(DisasContext *ctx, arg_RMPA *a)
999 {
1000     prt("rmpa.%c", size[a->sz]);
1001     return true;
1002 }
1003 
1004 /* mulhi rs,rs2 */
1005 static bool trans_MULHI(DisasContext *ctx, arg_MULHI *a)
1006 {
1007     prt("mulhi\tr%d,r%d", a->rs, a->rs2);
1008     return true;
1009 }
1010 
1011 /* mullo rs,rs2 */
1012 static bool trans_MULLO(DisasContext *ctx, arg_MULLO *a)
1013 {
1014     prt("mullo\tr%d, r%d", a->rs, a->rs2);
1015     return true;
1016 }
1017 
1018 /* machi rs,rs2 */
1019 static bool trans_MACHI(DisasContext *ctx, arg_MACHI *a)
1020 {
1021     prt("machi\tr%d, r%d", a->rs, a->rs2);
1022     return true;
1023 }
1024 
1025 /* maclo rs,rs2 */
1026 static bool trans_MACLO(DisasContext *ctx, arg_MACLO *a)
1027 {
1028     prt("maclo\tr%d, r%d", a->rs, a->rs2);
1029     return true;
1030 }
1031 
1032 /* mvfachi rd */
1033 static bool trans_MVFACHI(DisasContext *ctx, arg_MVFACHI *a)
1034 {
1035     prt("mvfachi\tr%d", a->rd);
1036     return true;
1037 }
1038 
1039 /* mvfacmi rd */
1040 static bool trans_MVFACMI(DisasContext *ctx, arg_MVFACMI *a)
1041 {
1042     prt("mvfacmi\tr%d", a->rd);
1043     return true;
1044 }
1045 
1046 /* mvtachi rs */
1047 static bool trans_MVTACHI(DisasContext *ctx, arg_MVTACHI *a)
1048 {
1049     prt("mvtachi\tr%d", a->rs);
1050     return true;
1051 }
1052 
1053 /* mvtaclo rs */
1054 static bool trans_MVTACLO(DisasContext *ctx, arg_MVTACLO *a)
1055 {
1056     prt("mvtaclo\tr%d", a->rs);
1057     return true;
1058 }
1059 
1060 /* racw #imm */
1061 static bool trans_RACW(DisasContext *ctx, arg_RACW *a)
1062 {
1063     prt("racw\t#%d", a->imm + 1);
1064     return true;
1065 }
1066 
1067 /* sat rd */
1068 static bool trans_SAT(DisasContext *ctx, arg_SAT *a)
1069 {
1070     prt("sat\tr%d", a->rd);
1071     return true;
1072 }
1073 
1074 /* satr */
1075 static bool trans_SATR(DisasContext *ctx, arg_SATR *a)
1076 {
1077     prt("satr");
1078     return true;
1079 }
1080 
1081 /* fadd #imm, rd */
1082 static bool trans_FADD_ir(DisasContext *ctx, arg_FADD_ir *a)
1083 {
1084     prt("fadd\t#%d,r%d", li(ctx, 0), a->rd);
1085     return true;
1086 }
1087 
1088 /* fadd dsp[rs], rd */
1089 /* fadd rs, rd */
1090 static bool trans_FADD_mr(DisasContext *ctx, arg_FADD_mr *a)
1091 {
1092     prt("fadd\t");
1093     operand(ctx, a->ld, RX_IM_LONG, a->rs, a->rd);
1094     return true;
1095 }
1096 
1097 /* fcmp #imm, rd */
1098 static bool trans_FCMP_ir(DisasContext *ctx, arg_FCMP_ir *a)
1099 {
1100     prt("fadd\t#%d,r%d", li(ctx, 0), a->rd);
1101     return true;
1102 }
1103 
1104 /* fcmp dsp[rs], rd */
1105 /* fcmp rs, rd */
1106 static bool trans_FCMP_mr(DisasContext *ctx, arg_FCMP_mr *a)
1107 {
1108     prt("fcmp\t");
1109     operand(ctx, a->ld, RX_IM_LONG, a->rs, a->rd);
1110     return true;
1111 }
1112 
1113 /* fsub #imm, rd */
1114 static bool trans_FSUB_ir(DisasContext *ctx, arg_FSUB_ir *a)
1115 {
1116     prt("fsub\t#%d,r%d", li(ctx, 0), a->rd);
1117     return true;
1118 }
1119 
1120 /* fsub dsp[rs], rd */
1121 /* fsub rs, rd */
1122 static bool trans_FSUB_mr(DisasContext *ctx, arg_FSUB_mr *a)
1123 {
1124     prt("fsub\t");
1125     operand(ctx, a->ld, RX_IM_LONG, a->rs, a->rd);
1126     return true;
1127 }
1128 
1129 /* ftoi dsp[rs], rd */
1130 /* ftoi rs, rd */
1131 static bool trans_FTOI(DisasContext *ctx, arg_FTOI *a)
1132 {
1133     prt("ftoi\t");
1134     operand(ctx, a->ld, RX_IM_LONG, a->rs, a->rd);
1135     return true;
1136 }
1137 
1138 /* fmul #imm, rd */
1139 static bool trans_FMUL_ir(DisasContext *ctx, arg_FMUL_ir *a)
1140 {
1141     prt("fmul\t#%d,r%d", li(ctx, 0), a->rd);
1142     return true;
1143 }
1144 
1145 /* fmul dsp[rs], rd */
1146 /* fmul rs, rd */
1147 static bool trans_FMUL_mr(DisasContext *ctx, arg_FMUL_mr *a)
1148 {
1149     prt("fmul\t");
1150     operand(ctx, a->ld, RX_IM_LONG, a->rs, a->rd);
1151     return true;
1152 }
1153 
1154 /* fdiv #imm, rd */
1155 static bool trans_FDIV_ir(DisasContext *ctx, arg_FDIV_ir *a)
1156 {
1157     prt("fdiv\t#%d,r%d", li(ctx, 0), a->rd);
1158     return true;
1159 }
1160 
1161 /* fdiv dsp[rs], rd */
1162 /* fdiv rs, rd */
1163 static bool trans_FDIV_mr(DisasContext *ctx, arg_FDIV_mr *a)
1164 {
1165     prt("fdiv\t");
1166     operand(ctx, a->ld, RX_IM_LONG, a->rs, a->rd);
1167     return true;
1168 }
1169 
1170 /* round dsp[rs], rd */
1171 /* round rs, rd */
1172 static bool trans_ROUND(DisasContext *ctx, arg_ROUND *a)
1173 {
1174     prt("round\t");
1175     operand(ctx, a->ld, RX_IM_LONG, a->rs, a->rd);
1176     return true;
1177 }
1178 
1179 /* itof rs, rd */
1180 /* itof dsp[rs], rd */
1181 static bool trans_ITOF(DisasContext *ctx, arg_ITOF *a)
1182 {
1183     prt("itof\t");
1184     operand(ctx, a->ld, RX_IM_LONG, a->rs, a->rd);
1185     return true;
1186 }
1187 
1188 #define BOP_IM(name, reg)                                       \
1189     do {                                                        \
1190         char dsp[8];                                            \
1191         rx_index_addr(ctx, dsp, a->ld, RX_MEMORY_BYTE);         \
1192         prt("b%s\t#%d, %s[r%d]", #name, a->imm, dsp, reg);      \
1193         return true;                                            \
1194     } while (0)
1195 
1196 #define BOP_RM(name)                                            \
1197     do {                                                        \
1198         char dsp[8];                                            \
1199         rx_index_addr(ctx, dsp, a->ld, RX_MEMORY_BYTE);         \
1200         prt("b%s\tr%d, %s[r%d]", #name, a->rd, dsp, a->rs);     \
1201         return true;                                            \
1202     } while (0)
1203 
1204 /* bset #imm, dsp[rd] */
1205 static bool trans_BSET_im(DisasContext *ctx, arg_BSET_im *a)
1206 {
1207     BOP_IM(bset, a->rs);
1208 }
1209 
1210 /* bset rs, dsp[rd] */
1211 static bool trans_BSET_rm(DisasContext *ctx, arg_BSET_rm *a)
1212 {
1213     BOP_RM(set);
1214 }
1215 
1216 /* bset rs, rd */
1217 static bool trans_BSET_rr(DisasContext *ctx, arg_BSET_rr *a)
1218 {
1219     prt("bset\tr%d,r%d", a->rs, a->rd);
1220     return true;
1221 }
1222 
1223 /* bset #imm, rd */
1224 static bool trans_BSET_ir(DisasContext *ctx, arg_BSET_ir *a)
1225 {
1226     prt("bset\t#%d, r%d", a->imm, a->rd);
1227     return true;
1228 }
1229 
1230 /* bclr #imm, dsp[rd] */
1231 static bool trans_BCLR_im(DisasContext *ctx, arg_BCLR_im *a)
1232 {
1233     BOP_IM(clr, a->rs);
1234 }
1235 
1236 /* bclr rs, dsp[rd] */
1237 static bool trans_BCLR_rm(DisasContext *ctx, arg_BCLR_rm *a)
1238 {
1239     BOP_RM(clr);
1240 }
1241 
1242 /* bclr rs, rd */
1243 static bool trans_BCLR_rr(DisasContext *ctx, arg_BCLR_rr *a)
1244 {
1245     prt("bclr\tr%d, r%d", a->rs, a->rd);
1246     return true;
1247 }
1248 
1249 /* bclr #imm, rd */
1250 static bool trans_BCLR_ir(DisasContext *ctx, arg_BCLR_ir *a)
1251 {
1252     prt("bclr\t#%d,r%d", a->imm, a->rd);
1253     return true;
1254 }
1255 
1256 /* btst #imm, dsp[rd] */
1257 static bool trans_BTST_im(DisasContext *ctx, arg_BTST_im *a)
1258 {
1259     BOP_IM(tst, a->rs);
1260 }
1261 
1262 /* btst rs, dsp[rd] */
1263 static bool trans_BTST_rm(DisasContext *ctx, arg_BTST_rm *a)
1264 {
1265     BOP_RM(tst);
1266 }
1267 
1268 /* btst rs, rd */
1269 static bool trans_BTST_rr(DisasContext *ctx, arg_BTST_rr *a)
1270 {
1271     prt("btst\tr%d, r%d", a->rs, a->rd);
1272     return true;
1273 }
1274 
1275 /* btst #imm, rd */
1276 static bool trans_BTST_ir(DisasContext *ctx, arg_BTST_ir *a)
1277 {
1278     prt("btst\t#%d, r%d", a->imm, a->rd);
1279     return true;
1280 }
1281 
1282 /* bnot rs, dsp[rd] */
1283 static bool trans_BNOT_rm(DisasContext *ctx, arg_BNOT_rm *a)
1284 {
1285     BOP_RM(not);
1286 }
1287 
1288 /* bnot rs, rd */
1289 static bool trans_BNOT_rr(DisasContext *ctx, arg_BNOT_rr *a)
1290 {
1291     prt("bnot\tr%d, r%d", a->rs, a->rd);
1292     return true;
1293 }
1294 
1295 /* bnot #imm, dsp[rd] */
1296 static bool trans_BNOT_im(DisasContext *ctx, arg_BNOT_im *a)
1297 {
1298     BOP_IM(not, a->rs);
1299 }
1300 
1301 /* bnot #imm, rd */
1302 static bool trans_BNOT_ir(DisasContext *ctx, arg_BNOT_ir *a)
1303 {
1304     prt("bnot\t#%d, r%d", a->imm, a->rd);
1305     return true;
1306 }
1307 
1308 /* bmcond #imm, dsp[rd] */
1309 static bool trans_BMCnd_im(DisasContext *ctx, arg_BMCnd_im *a)
1310 {
1311     char dsp[8];
1312 
1313     rx_index_addr(ctx, dsp, a->ld, RX_MEMORY_BYTE);
1314     prt("bm%s\t#%d, %s[r%d]", cond[a->cd], a->imm, dsp, a->rd);
1315     return true;
1316 }
1317 
1318 /* bmcond #imm, rd */
1319 static bool trans_BMCnd_ir(DisasContext *ctx, arg_BMCnd_ir *a)
1320 {
1321     prt("bm%s\t#%d, r%d", cond[a->cd], a->imm, a->rd);
1322     return true;
1323 }
1324 
1325 /* clrpsw psw */
1326 static bool trans_CLRPSW(DisasContext *ctx, arg_CLRPSW *a)
1327 {
1328     prt("clrpsw\t%c", psw[a->cb]);
1329     return true;
1330 }
1331 
1332 /* setpsw psw */
1333 static bool trans_SETPSW(DisasContext *ctx, arg_SETPSW *a)
1334 {
1335     prt("setpsw\t%c", psw[a->cb]);
1336     return true;
1337 }
1338 
1339 /* mvtipl #imm */
1340 static bool trans_MVTIPL(DisasContext *ctx, arg_MVTIPL *a)
1341 {
1342     prt("movtipl\t#%d", a->imm);
1343     return true;
1344 }
1345 
1346 /* mvtc #imm, rd */
1347 static bool trans_MVTC_i(DisasContext *ctx, arg_MVTC_i *a)
1348 {
1349     prt("mvtc\t#0x%08x, %s", a->imm, rx_crname(a->cr));
1350     return true;
1351 }
1352 
1353 /* mvtc rs, rd */
1354 static bool trans_MVTC_r(DisasContext *ctx, arg_MVTC_r *a)
1355 {
1356     prt("mvtc\tr%d, %s", a->rs, rx_crname(a->cr));
1357     return true;
1358 }
1359 
1360 /* mvfc rs, rd */
1361 static bool trans_MVFC(DisasContext *ctx, arg_MVFC *a)
1362 {
1363     prt("mvfc\t%s, r%d", rx_crname(a->cr), a->rd);
1364     return true;
1365 }
1366 
1367 /* rtfi */
1368 static bool trans_RTFI(DisasContext *ctx, arg_RTFI *a)
1369 {
1370     prt("rtfi");
1371     return true;
1372 }
1373 
1374 /* rte */
1375 static bool trans_RTE(DisasContext *ctx, arg_RTE *a)
1376 {
1377     prt("rte");
1378     return true;
1379 }
1380 
1381 /* brk */
1382 static bool trans_BRK(DisasContext *ctx, arg_BRK *a)
1383 {
1384     prt("brk");
1385     return true;
1386 }
1387 
1388 /* int #imm */
1389 static bool trans_INT(DisasContext *ctx, arg_INT *a)
1390 {
1391     prt("int\t#%d", a->imm);
1392     return true;
1393 }
1394 
1395 /* wait */
1396 static bool trans_WAIT(DisasContext *ctx, arg_WAIT *a)
1397 {
1398     prt("wait");
1399     return true;
1400 }
1401 
1402 /* sccnd.[bwl] rd */
1403 /* sccnd.[bwl] dsp:[rd] */
1404 static bool trans_SCCnd(DisasContext *ctx, arg_SCCnd *a)
1405 {
1406     if (a->ld < 3) {
1407         char dsp[8];
1408         rx_index_addr(ctx, dsp, a->sz, a->ld);
1409         prt("sc%s.%c\t%s[r%d]", cond[a->cd], size[a->sz], dsp, a->rd);
1410     } else {
1411         prt("sc%s.%c\tr%d", cond[a->cd], size[a->sz], a->rd);
1412     }
1413     return true;
1414 }
1415 
1416 int print_insn_rx(bfd_vma addr, disassemble_info *dis)
1417 {
1418     DisasContext ctx;
1419     uint32_t insn;
1420     int i;
1421     ctx.dis = dis;
1422     ctx.pc = ctx.addr = addr;
1423 
1424     insn = decode_load(&ctx);
1425     if (!decode(&ctx, insn)) {
1426         ctx.dis->fprintf_func(ctx.dis->stream, ".byte\t");
1427         for (i = 0; i < ctx.addr - addr; i++) {
1428             if (i > 0) {
1429                 ctx.dis->fprintf_func(ctx.dis->stream, ",");
1430             }
1431             ctx.dis->fprintf_func(ctx.dis->stream, "0x%02x", insn >> 24);
1432             insn <<= 8;
1433         }
1434     }
1435     return ctx.addr - addr;
1436 }
1437