1 /* Disassemble SH instructions.
2 Copyright (C) 1993-2020 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 imm
= ((nibs
[2] << 4) | nibs
[3]) << 1;
610 relmask
= ~(bfd_vma
) 1;
613 imm
= ((nibs
[2] << 4) | nibs
[3]) << 2;
614 relmask
= ~(bfd_vma
) 3;
618 imm
= ((nibs
[2] << 4) | nibs
[3]) << 1;
622 imm
= ((nibs
[2] << 4) | nibs
[3]) << 2;
625 if ((nibs
[n
] & 1) != 0)
635 if ((nibs
[n
] & 0x3) != 1 /* binary 01 */)
637 rn
= (nibs
[n
] & 0xc) >> 2;
640 rn
= (nibs
[n
] & 0xc) >> 2;
641 rm
= (nibs
[n
] & 0x3);
647 /* sh-dsp: single data transfer. */
652 rn
|= (!(rn
& 2)) << 2;
663 /* sh2a has D_REG but not X_REG. We don't know the pattern
664 doesn't match unless we check the output args to see if they
666 if (target_arch
== arch_sh2a
667 && ((op
->arg
[0] == DX_REG_M
&& (rm
& 1) != 0)
668 || (op
->arg
[1] == DX_REG_N
&& (rn
& 1) != 0)))
671 fprintf_fn (stream
, "%s\t", op
->name
);
673 for (n
= 0; n
< 3 && op
->arg
[n
] != A_END
; n
++)
675 if (n
&& op
->arg
[1] != A_END
)
676 fprintf_fn (stream
, ",");
680 fprintf_fn (stream
, "#%d", imm
);
683 fprintf_fn (stream
, "r0");
686 fprintf_fn (stream
, "r%d", rn
);
690 fprintf_fn (stream
, "@r%d+", rn
);
694 fprintf_fn (stream
, "@-r%d", rn
);
698 fprintf_fn (stream
, "@r%d", rn
);
701 fprintf_fn (stream
, "@(%d,r%d)", has_disp
?disp
:imm
, rn
);
704 fprintf_fn (stream
, "@r%d+r8", rn
);
707 fprintf_fn (stream
, "r%d", rm
);
710 fprintf_fn (stream
, "@r%d+", rm
);
713 fprintf_fn (stream
, "@-r%d", rm
);
716 fprintf_fn (stream
, "@r%d", rm
);
719 fprintf_fn (stream
, "@(%d,r%d)", has_disp
?disp
:imm
, rm
);
722 fprintf_fn (stream
, "r%d_bank", rb
);
726 disp_pc_addr
= imm
+ 4 + (memaddr
& relmask
);
727 (*info
->print_address_func
) (disp_pc_addr
, info
);
730 fprintf_fn (stream
, "@(r0,r%d)", rn
);
733 fprintf_fn (stream
, "@(r0,r%d)", rm
);
736 fprintf_fn (stream
, "@(%d,gbr)", has_disp
?disp
:imm
);
739 fprintf_fn (stream
, "tbr");
742 fprintf_fn (stream
, "@@(%d,tbr)", has_disp
?disp
:imm
);
745 fprintf_fn (stream
, "@r15+");
748 fprintf_fn (stream
, "@-r15");
751 fprintf_fn (stream
, "@(r0,gbr)");
755 (*info
->print_address_func
) (imm
+ memaddr
, info
);
758 fprintf_fn (stream
, "sr");
761 fprintf_fn (stream
, "gbr");
764 fprintf_fn (stream
, "vbr");
767 fprintf_fn (stream
, "dsr");
770 fprintf_fn (stream
, "mod");
773 fprintf_fn (stream
, "re");
776 fprintf_fn (stream
, "rs");
779 fprintf_fn (stream
, "a0");
782 fprintf_fn (stream
, "x0");
785 fprintf_fn (stream
, "x1");
788 fprintf_fn (stream
, "y0");
791 fprintf_fn (stream
, "y1");
794 print_dsp_reg (rm
, fprintf_fn
, stream
);
797 fprintf_fn (stream
, "ssr");
800 fprintf_fn (stream
, "spc");
803 fprintf_fn (stream
, "mach");
806 fprintf_fn (stream
, "macl");
809 fprintf_fn (stream
, "pr");
812 fprintf_fn (stream
, "sgr");
815 fprintf_fn (stream
, "dbr");
818 fprintf_fn (stream
, "fr%d", rn
);
821 fprintf_fn (stream
, "fr%d", rm
);
826 fprintf_fn (stream
, "xd%d", rn
& ~1);
831 fprintf_fn (stream
, "dr%d", rn
);
836 fprintf_fn (stream
, "xd%d", rm
& ~1);
841 fprintf_fn (stream
, "dr%d", rm
);
845 fprintf_fn (stream
, "fpscr");
849 fprintf_fn (stream
, "fpul");
852 fprintf_fn (stream
, "fr0");
855 fprintf_fn (stream
, "fv%d", rn
* 4);
858 fprintf_fn (stream
, "fv%d", rm
* 4);
861 fprintf_fn (stream
, "xmtrx");
869 /* This code prints instructions in delay slots on the same line
870 as the instruction which needs the delay slots. This can be
871 confusing, since other disassembler don't work this way, and
872 it means that the instructions are not all in a line. So I
874 if (!(info
->flags
& 1)
875 && (op
->name
[0] == 'j'
876 || (op
->name
[0] == 'b'
877 && (op
->name
[1] == 'r'
878 || op
->name
[1] == 's'))
879 || (op
->name
[0] == 'r' && op
->name
[1] == 't')
880 || (op
->name
[0] == 'b' && op
->name
[2] == '.')))
883 fprintf_fn (stream
, "\t(slot ");
884 print_insn_sh (memaddr
+ 2, info
);
886 fprintf_fn (stream
, ")");
891 if (disp_pc
&& strcmp (op
->name
, "mova") != 0)
896 if (relmask
== ~(bfd_vma
) 1)
900 /* Not reading an instruction - disable stop_vma. */
902 status
= info
->read_memory_func (disp_pc_addr
, bytes
, size
, info
);
909 if (info
->endian
== BFD_ENDIAN_LITTLE
)
910 val
= bfd_getl16 (bytes
);
912 val
= bfd_getb16 (bytes
);
916 if (info
->endian
== BFD_ENDIAN_LITTLE
)
917 val
= bfd_getl32 (bytes
);
919 val
= bfd_getb32 (bytes
);
921 if ((*info
->symbol_at_address_func
) (val
, info
))
923 fprintf_fn (stream
, "\t! ");
924 (*info
->print_address_func
) (val
, info
);
927 fprintf_fn (stream
, "\t! %x", val
);
931 return SH_MERGE_ARCH_SET (op
->arch
, arch_op32
) ? 4 : 2;
936 fprintf_fn (stream
, ".word 0x%x%x%x%x", nibs
[0], nibs
[1], nibs
[2], nibs
[3]);
This page took 0.078865 seconds and 4 git commands to generate.