1 /* Disassemble SH instructions.
2 Copyright (C) 1993-2021 Free Software Foundation, Inc.
4 This file is part of the GNU opcodes library.
6 This library is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 It is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this file; see the file COPYING. If not, write to the
18 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
28 #include "disassemble.h"
31 print_movxy (const sh_opcode_info
*op
,
34 fprintf_ftype fprintf_fn
,
39 fprintf_fn (stream
, "%s\t", op
->name
);
40 for (n
= 0; n
< 2; n
++)
49 fprintf_fn (stream
, "@r%d", rn
);
56 fprintf_fn (stream
, "@r%d+", rn
);
60 fprintf_fn (stream
, "@r%d+r8", rn
);
64 fprintf_fn (stream
, "@r%d+r9", rn
);
67 fprintf_fn (stream
, "a%c", '0' + rm
);
70 fprintf_fn (stream
, "x%c", '0' + rm
);
73 fprintf_fn (stream
, "y%c", '0' + rm
);
76 fprintf_fn (stream
, "%c%c",
78 (rm
& 2) ? '1' : '0');
81 fprintf_fn (stream
, "%c%c",
83 (rm
& 2) ? '1' : '0');
86 fprintf_fn (stream
, "%c%c",
88 (rm
& 1) ? '1' : '0');
91 fprintf_fn (stream
, "%c%c",
93 (rm
& 1) ? '1' : '0');
99 fprintf_fn (stream
, ",");
103 /* Print a double data transfer insn. INSN is just the lower three
104 nibbles of the insn, i.e. field a and the bit that indicates if
105 a parallel processing insn follows. */
108 print_insn_ddt (int insn
, struct disassemble_info
*info
)
110 fprintf_ftype fprintf_fn
= info
->fprintf_func
;
111 void *stream
= info
->stream
;
113 /* If this is just a nop, make sure to emit something. */
116 fprintf_fn (stream
, "nopx\tnopy");
120 /* If a parallel processing insn was printed before,
121 and we got a non-nop, emit a tab. */
122 if ((insn
& 0x800) && (insn
& 0x3ff))
123 fprintf_fn (stream
, "\t");
125 /* Check if either the x or y part is invalid. */
126 if (((insn
& 3) != 0 && (insn
& 0xc) == 0 && (insn
& 0x2a0))
127 || ((insn
& 3) == 0 && (insn
& 0xc) != 0 && (insn
& 0x150)))
128 if (info
->mach
!= bfd_mach_sh_dsp
129 && info
->mach
!= bfd_mach_sh3_dsp
)
131 static const sh_opcode_info
*first_movx
, *first_movy
;
132 const sh_opcode_info
*op
;
137 for (first_movx
= sh_table
; first_movx
->nibbles
[1] != MOVX_NOPY
;)
139 for (first_movy
= first_movx
; first_movy
->nibbles
[1] != MOVY_NOPX
;)
143 is_movy
= ((insn
& 3) != 0);
150 while (op
->nibbles
[2] != (unsigned) ((insn
>> 4) & 3)
151 || op
->nibbles
[3] != (unsigned) (insn
& 0xf))
155 (4 * ((insn
& (is_movy
? 0x200 : 0x100)) == 0)
157 + 1 * ((insn
& (is_movy
? 0x100 : 0x200)) != 0)),
162 fprintf_fn (stream
, ".word 0x%x", insn
| 0xf000);
165 static const sh_opcode_info
*first_movx
, *first_movy
;
166 const sh_opcode_info
*opx
, *opy
;
167 unsigned int insn_x
, insn_y
;
171 for (first_movx
= sh_table
; first_movx
->nibbles
[1] != MOVX
;)
173 for (first_movy
= first_movx
; first_movy
->nibbles
[1] != MOVY
;)
176 insn_x
= (insn
>> 2) & 0xb;
179 for (opx
= first_movx
; opx
->nibbles
[2] != insn_x
;)
181 print_movxy (opx
, ((insn
>> 9) & 1) + 4, (insn
>> 7) & 1,
184 insn_y
= (insn
& 3) | ((insn
>> 1) & 8);
188 fprintf_fn (stream
, "\t");
189 for (opy
= first_movy
; opy
->nibbles
[2] != insn_y
;)
191 print_movxy (opy
, ((insn
>> 8) & 1) + 6, (insn
>> 6) & 1,
194 if (!insn_x
&& !insn_y
&& ((insn
& 0x3ff) != 0 || (insn
& 0x800) == 0))
195 fprintf_fn (stream
, ".word 0x%x", insn
| 0xf000);
200 print_dsp_reg (int rm
, fprintf_ftype fprintf_fn
, void *stream
)
205 fprintf_fn (stream
, "a1");
208 fprintf_fn (stream
, "a0");
211 fprintf_fn (stream
, "x0");
214 fprintf_fn (stream
, "x1");
217 fprintf_fn (stream
, "y0");
220 fprintf_fn (stream
, "y1");
223 fprintf_fn (stream
, "m0");
226 fprintf_fn (stream
, "a1g");
229 fprintf_fn (stream
, "m1");
232 fprintf_fn (stream
, "a0g");
235 fprintf_fn (stream
, "0x%x", rm
);
241 print_insn_ppi (int field_b
, struct disassemble_info
*info
)
243 static char *sx_tab
[] = { "x0", "x1", "a0", "a1" };
244 static char *sy_tab
[] = { "y0", "y1", "m0", "m1" };
245 fprintf_ftype fprintf_fn
= info
->fprintf_func
;
246 void *stream
= info
->stream
;
247 unsigned int nib1
, nib2
, nib3
;
248 unsigned int altnib1
, nib4
;
250 const sh_opcode_info
*op
;
252 if ((field_b
& 0xe800) == 0)
254 fprintf_fn (stream
, "psh%c\t#%d,",
255 field_b
& 0x1000 ? 'a' : 'l',
256 (field_b
>> 4) & 127);
257 print_dsp_reg (field_b
& 0xf, fprintf_fn
, stream
);
260 if ((field_b
& 0xc000) == 0x4000 && (field_b
& 0x3000) != 0x1000)
262 static char *du_tab
[] = { "x0", "y0", "a0", "a1" };
263 static char *se_tab
[] = { "x0", "x1", "y0", "a1" };
264 static char *sf_tab
[] = { "y0", "y1", "x0", "a1" };
265 static char *sg_tab
[] = { "m0", "m1", "a0", "a1" };
267 if (field_b
& 0x2000)
268 fprintf_fn (stream
, "p%s %s,%s,%s\t",
269 (field_b
& 0x1000) ? "add" : "sub",
270 sx_tab
[(field_b
>> 6) & 3],
271 sy_tab
[(field_b
>> 4) & 3],
272 du_tab
[(field_b
>> 0) & 3]);
274 else if ((field_b
& 0xf0) == 0x10
275 && info
->mach
!= bfd_mach_sh_dsp
276 && info
->mach
!= bfd_mach_sh3_dsp
)
277 fprintf_fn (stream
, "pclr %s \t", du_tab
[(field_b
>> 0) & 3]);
279 else if ((field_b
& 0xf3) != 0)
280 fprintf_fn (stream
, ".word 0x%x\t", field_b
);
282 fprintf_fn (stream
, "pmuls%c%s,%s,%s",
283 field_b
& 0x2000 ? ' ' : '\t',
284 se_tab
[(field_b
>> 10) & 3],
285 sf_tab
[(field_b
>> 8) & 3],
286 sg_tab
[(field_b
>> 2) & 3]);
291 nib2
= field_b
>> 12 & 0xf;
292 nib3
= field_b
>> 8 & 0xf;
293 nib4
= field_b
>> 4 & 0xf;
316 for (op
= sh_table
; op
->name
; op
++)
318 if ((op
->nibbles
[1] == nib1
|| op
->nibbles
[1] == altnib1
)
319 && op
->nibbles
[2] == nib2
320 && op
->nibbles
[3] == nib3
)
324 switch (op
->nibbles
[4])
337 if ((nib4
& 0xc) != 0)
341 if ((nib4
& 0xc) != 4)
347 fprintf_fn (stream
, "%s%s\t", dc
, op
->name
);
348 for (n
= 0; n
< 3 && op
->arg
[n
] != A_END
; n
++)
350 if (n
&& op
->arg
[1] != A_END
)
351 fprintf_fn (stream
, ",");
355 print_dsp_reg (field_b
& 0xf, fprintf_fn
, stream
);
358 fprintf_fn (stream
, "%s", sx_tab
[(field_b
>> 6) & 3]);
361 fprintf_fn (stream
, "%s", sy_tab
[(field_b
>> 4) & 3]);
364 fprintf_fn (stream
, "mach");
367 fprintf_fn (stream
, "macl");
377 fprintf_fn (stream
, ".word 0x%x", field_b
);
380 /* FIXME mvs: movx insns print as ".word 0x%03x", insn & 0xfff
381 (ie. the upper nibble is missing). */
384 print_insn_sh (bfd_vma memaddr
, struct disassemble_info
*info
)
386 fprintf_ftype fprintf_fn
= info
->fprintf_func
;
387 void *stream
= info
->stream
;
388 unsigned char insn
[4];
389 unsigned char nibs
[8];
391 bfd_vma relmask
= ~(bfd_vma
) 0;
392 const sh_opcode_info
*op
;
393 unsigned int target_arch
;
399 target_arch
= arch_sh1
;
400 /* SH coff object files lack information about the machine type, so
401 we end up with bfd_mach_sh unless it was set explicitly (which
402 could have happended if this is a call from gdb or the simulator.) */
404 && bfd_asymbol_flavour(*info
->symbols
) == bfd_target_coff_flavour
)
405 target_arch
= arch_sh4
;
408 target_arch
= sh_get_arch_from_bfd_mach (info
->mach
);
411 status
= info
->read_memory_func (memaddr
, insn
, 2, info
);
415 info
->memory_error_func (status
, memaddr
, info
);
419 if (info
->endian
== BFD_ENDIAN_LITTLE
)
421 nibs
[0] = (insn
[1] >> 4) & 0xf;
422 nibs
[1] = insn
[1] & 0xf;
424 nibs
[2] = (insn
[0] >> 4) & 0xf;
425 nibs
[3] = insn
[0] & 0xf;
429 nibs
[0] = (insn
[0] >> 4) & 0xf;
430 nibs
[1] = insn
[0] & 0xf;
432 nibs
[2] = (insn
[1] >> 4) & 0xf;
433 nibs
[3] = insn
[1] & 0xf;
435 status
= info
->read_memory_func (memaddr
+ 2, insn
+ 2, 2, info
);
442 if (info
->endian
== BFD_ENDIAN_LITTLE
)
444 nibs
[4] = (insn
[3] >> 4) & 0xf;
445 nibs
[5] = insn
[3] & 0xf;
447 nibs
[6] = (insn
[2] >> 4) & 0xf;
448 nibs
[7] = insn
[2] & 0xf;
452 nibs
[4] = (insn
[2] >> 4) & 0xf;
453 nibs
[5] = insn
[2] & 0xf;
455 nibs
[6] = (insn
[3] >> 4) & 0xf;
456 nibs
[7] = insn
[3] & 0xf;
460 if (nibs
[0] == 0xf && (nibs
[1] & 4) == 0
461 && SH_MERGE_ARCH_SET_VALID (target_arch
, arch_sh_dsp_up
))
467 status
= info
->read_memory_func (memaddr
+ 2, insn
, 2, info
);
471 info
->memory_error_func (status
, memaddr
+ 2, info
);
475 if (info
->endian
== BFD_ENDIAN_LITTLE
)
476 field_b
= insn
[1] << 8 | insn
[0];
478 field_b
= insn
[0] << 8 | insn
[1];
480 print_insn_ppi (field_b
, info
);
481 print_insn_ddt ((nibs
[1] << 8) | (nibs
[2] << 4) | nibs
[3], info
);
484 print_insn_ddt ((nibs
[1] << 8) | (nibs
[2] << 4) | nibs
[3], info
);
487 for (op
= sh_table
; op
->name
; op
++)
495 bfd_vma disp_pc_addr
= 0;
498 int max_n
= SH_MERGE_ARCH_SET (op
->arch
, arch_op32
) ? 8 : 4;
501 && SH_MERGE_ARCH_SET (op
->arch
, arch_op32
))
504 if (!SH_MERGE_ARCH_SET_VALID (op
->arch
, target_arch
))
506 for (n
= 0; n
< max_n
; n
++)
508 int i
= op
->nibbles
[n
];
519 imm
= (nibs
[2] << 4) | (nibs
[3]);
522 imm
= ((char) imm
) * 2 + 4;
525 imm
= ((nibs
[1]) << 8) | (nibs
[2] << 4) | (nibs
[3]);
536 if (!(nibs
[3] & 0x8))
546 if (!(nibs
[2] & 0x8))
552 disp
= (nibs
[5] << 8) | (nibs
[6] << 4) | nibs
[7];
557 disp
= ((nibs
[5] << 8) | (nibs
[6] << 4) | nibs
[7]) << 1;
558 relmask
= ~(bfd_vma
) 1;
563 disp
= ((nibs
[5] << 8) | (nibs
[6] << 4) | nibs
[7]) << 2;
564 relmask
= ~(bfd_vma
) 3;
569 disp
= ((nibs
[5] << 8) | (nibs
[6] << 4) | nibs
[7]) << 3;
570 relmask
= ~(bfd_vma
) 7;
576 imm
= ((nibs
[2] << 16) | (nibs
[4] << 12) | (nibs
[5] << 8)
577 | (nibs
[6] << 4) | nibs
[7]);
582 imm
= ((nibs
[2] << 16) | (nibs
[4] << 12) | (nibs
[5] << 8)
583 | (nibs
[6] << 4) | nibs
[7]);
602 imm
= (nibs
[2] << 4) | nibs
[3];
609 disp
= imm
= (nibs
[2] << 4) | nibs
[3];
613 imm
= ((nibs
[2] << 4) | nibs
[3]) << 1;
614 relmask
= ~(bfd_vma
) 1;
617 imm
= ((nibs
[2] << 4) | nibs
[3]) << 2;
618 relmask
= ~(bfd_vma
) 3;
622 imm
= ((nibs
[2] << 4) | nibs
[3]) << 1;
626 imm
= ((nibs
[2] << 4) | nibs
[3]) << 2;
629 if ((nibs
[n
] & 1) != 0)
639 if ((nibs
[n
] & 0x3) != 1 /* binary 01 */)
641 rn
= (nibs
[n
] & 0xc) >> 2;
644 rn
= (nibs
[n
] & 0xc) >> 2;
645 rm
= (nibs
[n
] & 0x3);
651 /* sh-dsp: single data transfer. */
656 rn
|= (!(rn
& 2)) << 2;
667 /* sh2a has D_REG but not X_REG. We don't know the pattern
668 doesn't match unless we check the output args to see if they
670 if (target_arch
== arch_sh2a
671 && ((op
->arg
[0] == DX_REG_M
&& (rm
& 1) != 0)
672 || (op
->arg
[1] == DX_REG_N
&& (rn
& 1) != 0)))
675 fprintf_fn (stream
, "%s\t", op
->name
);
677 for (n
= 0; n
< 3 && op
->arg
[n
] != A_END
; n
++)
679 if (n
&& op
->arg
[1] != A_END
)
680 fprintf_fn (stream
, ",");
684 fprintf_fn (stream
, "#%d", imm
);
687 fprintf_fn (stream
, "r0");
690 fprintf_fn (stream
, "r%d", rn
);
694 fprintf_fn (stream
, "@r%d+", rn
);
698 fprintf_fn (stream
, "@-r%d", rn
);
702 fprintf_fn (stream
, "@r%d", rn
);
705 fprintf_fn (stream
, "@(%d,r%d)", has_disp
?disp
:imm
, rn
);
708 fprintf_fn (stream
, "@r%d+r8", rn
);
711 fprintf_fn (stream
, "r%d", rm
);
714 fprintf_fn (stream
, "@r%d+", rm
);
717 fprintf_fn (stream
, "@-r%d", rm
);
720 fprintf_fn (stream
, "@r%d", rm
);
723 fprintf_fn (stream
, "@(%d,r%d)", has_disp
?disp
:imm
, rm
);
726 fprintf_fn (stream
, "r%d_bank", rb
);
730 disp_pc_addr
= imm
+ 4 + (memaddr
& relmask
);
731 (*info
->print_address_func
) (disp_pc_addr
, info
);
734 fprintf_fn (stream
, "@(r0,r%d)", rn
);
737 fprintf_fn (stream
, "@(r0,r%d)", rm
);
740 fprintf_fn (stream
, "@(%d,gbr)", has_disp
?disp
:imm
);
743 fprintf_fn (stream
, "tbr");
746 fprintf_fn (stream
, "@@(%d,tbr)", has_disp
?disp
:imm
);
749 fprintf_fn (stream
, "@r15+");
752 fprintf_fn (stream
, "@-r15");
755 fprintf_fn (stream
, "@(r0,gbr)");
759 (*info
->print_address_func
) (imm
+ memaddr
, info
);
762 fprintf_fn (stream
, "sr");
765 fprintf_fn (stream
, "gbr");
768 fprintf_fn (stream
, "vbr");
771 fprintf_fn (stream
, "dsr");
774 fprintf_fn (stream
, "mod");
777 fprintf_fn (stream
, "re");
780 fprintf_fn (stream
, "rs");
783 fprintf_fn (stream
, "a0");
786 fprintf_fn (stream
, "x0");
789 fprintf_fn (stream
, "x1");
792 fprintf_fn (stream
, "y0");
795 fprintf_fn (stream
, "y1");
798 print_dsp_reg (rm
, fprintf_fn
, stream
);
801 fprintf_fn (stream
, "ssr");
804 fprintf_fn (stream
, "spc");
807 fprintf_fn (stream
, "mach");
810 fprintf_fn (stream
, "macl");
813 fprintf_fn (stream
, "pr");
816 fprintf_fn (stream
, "sgr");
819 fprintf_fn (stream
, "dbr");
822 fprintf_fn (stream
, "fr%d", rn
);
825 fprintf_fn (stream
, "fr%d", rm
);
830 fprintf_fn (stream
, "xd%d", rn
& ~1);
835 fprintf_fn (stream
, "dr%d", rn
);
840 fprintf_fn (stream
, "xd%d", rm
& ~1);
845 fprintf_fn (stream
, "dr%d", rm
);
849 fprintf_fn (stream
, "fpscr");
853 fprintf_fn (stream
, "fpul");
856 fprintf_fn (stream
, "fr0");
859 fprintf_fn (stream
, "fv%d", rn
* 4);
862 fprintf_fn (stream
, "fv%d", rm
* 4);
865 fprintf_fn (stream
, "xmtrx");
873 /* This code prints instructions in delay slots on the same line
874 as the instruction which needs the delay slots. This can be
875 confusing, since other disassembler don't work this way, and
876 it means that the instructions are not all in a line. So I
878 if (!(info
->flags
& 1)
879 && (op
->name
[0] == 'j'
880 || (op
->name
[0] == 'b'
881 && (op
->name
[1] == 'r'
882 || op
->name
[1] == 's'))
883 || (op
->name
[0] == 'r' && op
->name
[1] == 't')
884 || (op
->name
[0] == 'b' && op
->name
[2] == '.')))
887 fprintf_fn (stream
, "\t(slot ");
888 print_insn_sh (memaddr
+ 2, info
);
890 fprintf_fn (stream
, ")");
895 if (disp_pc
&& strcmp (op
->name
, "mova") != 0)
900 if (relmask
== ~(bfd_vma
) 1)
904 /* Not reading an instruction - disable stop_vma. */
906 status
= info
->read_memory_func (disp_pc_addr
, bytes
, size
, info
);
913 if (info
->endian
== BFD_ENDIAN_LITTLE
)
914 val
= bfd_getl16 (bytes
);
916 val
= bfd_getb16 (bytes
);
920 if (info
->endian
== BFD_ENDIAN_LITTLE
)
921 val
= bfd_getl32 (bytes
);
923 val
= bfd_getb32 (bytes
);
925 if ((*info
->symbol_at_address_func
) (val
, info
))
927 fprintf_fn (stream
, "\t! ");
928 (*info
->print_address_func
) (val
, info
);
931 fprintf_fn (stream
, "\t! %x", val
);
935 return SH_MERGE_ARCH_SET (op
->arch
, arch_op32
) ? 4 : 2;
940 fprintf_fn (stream
, ".word 0x%x%x%x%x", nibs
[0], nibs
[1], nibs
[2], nibs
[3]);
This page took 0.055085 seconds and 4 git commands to generate.