1 /* Disassemble MSP430 instructions.
2 Copyright (C) 2002-2016 Free Software Foundation, Inc.
4 Contributed by Dmitry Diky <diwil@mail.ru>
6 This file is part of the GNU opcodes library.
8 This library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 It is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
26 #include <sys/types.h>
30 #include "libiberty.h"
33 #include "opcode/msp430.h"
37 #define PS(x) (0xffff & (x))
40 msp430dis_opcode (bfd_vma addr
, disassemble_info
*info
)
45 status
= info
->read_memory_func (addr
, buffer
, 2, info
);
48 info
->memory_error_func (status
, addr
, info
);
51 return bfd_getl16 (buffer
);
55 msp430_nooperands (struct msp430_opcode_s
*opcode
,
56 bfd_vma addr ATTRIBUTE_UNUSED
,
57 unsigned short insn ATTRIBUTE_UNUSED
,
61 /* Pop with constant. */
64 if (insn
== opcode
->bin_opcode
)
69 if ((insn
& 0x0f00) != 0x0300 || (insn
& 0x0f00) != 0x0200)
72 strcpy (comm
, "emulated...");
77 strcpy (comm
, "return from interupt");
85 print_as2_reg_name (int regno
, char * op1
, char * comm1
,
86 int c2
, int c3
, int cd
)
92 sprintf (comm1
, "r2 As==10");
97 sprintf (comm1
, "r3 As==10");
101 /* Indexed register mode @Rn. */
102 sprintf (op1
, "@r%d", regno
);
108 print_as3_reg_name (int regno
, char * op1
, char * comm1
,
109 int c2
, int c3
, int cd
)
115 sprintf (comm1
, "r2 As==11");
119 sprintf (op1
, "#-1");
120 sprintf (comm1
, "r3 As==11");
124 /* Post incremented @Rn+. */
125 sprintf (op1
, "@r%d+", regno
);
131 msp430_singleoperand (disassemble_info
*info
,
132 struct msp430_opcode_s
*opcode
,
137 unsigned short extension_word
,
140 int regs
= 0, regd
= 0;
146 int extended_dst
= extension_word
& 0xf;
149 regs
= (insn
& 0x0f00) >> 8;
150 as
= (insn
& 0x0030) >> 4;
151 ad
= (insn
& 0x0080) >> 7;
154 fmt
= (- opcode
->fmt
) - 1;
160 case 0: /* Emulated work with dst register. */
161 if (regs
!= 2 && regs
!= 3 && regs
!= 1)
164 /* Check if not clr insn. */
165 if (opcode
->bin_opcode
== 0x4300 && (ad
|| as
))
168 /* Check if really inc, incd insns. */
169 if ((opcode
->bin_opcode
& 0xff00) == 0x5300 && as
== 3)
189 sprintf (op
, "r%d", regd
);
191 else /* ad == 1 msp430dis_opcode. */
196 dst
= msp430dis_opcode (addr
+ 2, info
);
199 sprintf (op
, "0x%04x", dst
);
200 sprintf (comm
, "PC rel. abs addr 0x%04x",
201 PS ((short) (addr
+ 2) + dst
));
204 dst
|= extended_dst
<< 16;
205 sprintf (op
, "0x%05x", dst
);
206 sprintf (comm
, "PC rel. abs addr 0x%05lx",
207 (long)((addr
+ 2 + dst
) & 0xfffff));
213 dst
= msp430dis_opcode (addr
+ 2, info
);
216 sprintf (op
, "&0x%04x", PS (dst
));
219 dst
|= extended_dst
<< 16;
220 sprintf (op
, "&0x%05x", dst
& 0xfffff);
225 dst
= msp430dis_opcode (addr
+ 2, info
);
230 dst
|= extended_dst
<< 16;
234 else if (dst
& 0x8000)
236 sprintf (op
, "%d(r%d)", dst
, regd
);
241 case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
248 sprintf (comm
, "r3 As==00");
253 sprintf (op
, "r%d", regd
);
259 * cycles
= print_as2_reg_name (regd
, op
, comm
, 1, 1, 3);
267 dst
= msp430dis_opcode (addr
+ 2, info
);
269 sprintf (op
, "#%d", dst
);
270 if (dst
> 9 || dst
< 0)
271 sprintf (comm
, "#0x%04x", PS (dst
));
274 dst
|= extended_dst
<< 16;
277 sprintf (op
, "#%d", dst
);
278 if (dst
> 9 || dst
< 0)
279 sprintf (comm
, "#0x%05x", dst
);
283 * cycles
= print_as3_reg_name (regd
, op
, comm
, 1, 1, 3);
291 dst
= msp430dis_opcode (addr
+ 2, info
);
293 sprintf (op
, "0x%04x", PS (dst
));
294 sprintf (comm
, "PC rel. 0x%04x",
295 PS ((short) addr
+ 2 + dst
));
298 dst
|= extended_dst
<< 16;
299 sprintf (op
, "0x%05x", dst
& 0xffff);
300 sprintf (comm
, "PC rel. 0x%05lx",
301 (long)((addr
+ 2 + dst
) & 0xfffff));
307 dst
= msp430dis_opcode (addr
+ 2, info
);
309 sprintf (op
, "&0x%04x", PS (dst
));
312 dst
|= extended_dst
<< 16;
313 sprintf (op
, "&0x%05x", dst
& 0xfffff);
320 sprintf (comm
, "r3 As==01");
325 dst
= msp430dis_opcode (addr
+ 2, info
);
329 dst
|= extended_dst
<< 16;
333 else if (dst
& 0x8000)
335 sprintf (op
, "%d(r%d)", dst
, regd
);
336 if (dst
> 9 || dst
< 0)
337 sprintf (comm
, "%05x", dst
);
343 where
= insn
& 0x03ff;
346 if (where
> 512 || where
< -511)
350 sprintf (op
, "$%+-8d", where
+ 2);
351 sprintf (comm
, "abs 0x%lx", (long) (addr
+ 2 + where
));
363 msp430_doubleoperand (disassemble_info
*info
,
364 struct msp430_opcode_s
*opcode
,
371 unsigned short extension_word
,
374 int regs
= 0, regd
= 0;
379 int extended_dst
= extension_word
& 0xf;
380 int extended_src
= (extension_word
>> 7) & 0xf;
383 regs
= (insn
& 0x0f00) >> 8;
384 as
= (insn
& 0x0030) >> 4;
385 ad
= (insn
& 0x0080) >> 7;
388 fmt
= (- opcode
->fmt
) - 1;
394 /* Special case: rla and rlc are the only 2 emulated instructions that
395 fall into two operand instructions. */
396 /* With dst, there are only:
402 basic_ins dst, dst. */
404 if (regd
!= regs
|| as
!= ad
)
405 return 0; /* May be 'data' section. */
412 strcpy (comm1
, _("Illegal as emulation instr"));
416 sprintf (op1
, "r%d", regd
);
423 /* PC relative, Symbolic. */
424 dst
= msp430dis_opcode (addr
+ 2, info
);
427 sprintf (op1
, "0x%04x", PS (dst
));
428 sprintf (comm1
, "PC rel. 0x%04x",
429 PS ((short) addr
+ 2 + dst
));
432 dst
|= extended_dst
<< 16;
435 sprintf (op1
, "0x%05x", dst
& 0xfffff);
436 sprintf (comm1
, "PC rel. 0x%05lx",
437 (long)((addr
+ 2 + dst
) & 0xfffff));
443 dst
= msp430dis_opcode (addr
+ 2, info
);
444 /* If the 'src' field is not the same as the dst
445 then this is not an rla instruction. */
446 if (dst
!= msp430dis_opcode (addr
+ 4, info
))
450 sprintf (op1
, "&0x%04x", PS (dst
));
453 dst
|= extended_dst
<< 16;
454 sprintf (op1
, "&0x%05x", dst
& 0xfffff);
460 dst
= msp430dis_opcode (addr
+ 2, info
);
463 dst
|= extended_dst
<< 16;
467 else if (dst
& 0x8000)
471 sprintf (op1
, "%d(r%d)", dst
, regd
);
472 if (dst
> 9 || dst
< -9)
473 sprintf (comm1
, "#0x%05x", dst
);
483 /* Two operands exactly. */
484 if (ad
== 0 && regd
== 3)
486 /* R2/R3 are illegal as dest: may be data section. */
487 strcpy (comm1
, _("Illegal as 2-op instr"));
499 sprintf (comm1
, "r3 As==00");
504 sprintf (op1
, "r%d", regs
);
509 * cycles
= print_as2_reg_name (regs
, op1
, comm1
, 1, 1, regs
== 0 ? 3 : 2);
516 /* Absolute. @pc+. */
517 dst
= msp430dis_opcode (addr
+ 2, info
);
519 sprintf (op1
, "#%d", dst
);
520 if (dst
> 9 || dst
< 0)
521 sprintf (comm1
, "#0x%04x", PS (dst
));
524 dst
|= extended_src
<< 16;
527 sprintf (op1
, "#%d", dst
);
528 if (dst
> 9 || dst
< 0)
529 sprintf (comm1
, "0x%05x", dst
& 0xfffff);
533 * cycles
= print_as3_reg_name (regs
, op1
, comm1
, 1, 1, 2);
541 dst
= msp430dis_opcode (addr
+ 2, info
);
543 sprintf (op1
, "0x%04x", PS (dst
));
544 sprintf (comm1
, "PC rel. 0x%04x",
545 PS ((short) addr
+ 2 + dst
));
548 dst
|= extended_src
<< 16;
551 sprintf (op1
, "0x%05x", dst
& 0xfffff);
552 sprintf (comm1
, "PC rel. 0x%05lx",
553 (long) ((addr
+ 2 + dst
) & 0xfffff));
560 dst
= msp430dis_opcode (addr
+ 2, info
);
562 sprintf (op1
, "&0x%04x", PS (dst
));
563 sprintf (comm1
, "0x%04x", PS (dst
));
566 dst
|= extended_src
<< 16;
567 sprintf (op1
, "&0x%05x", dst
& 0xfffff);
575 sprintf (comm1
, "r3 As==01");
581 dst
= msp430dis_opcode (addr
+ 2, info
);
585 dst
|= extended_src
<< 16;
589 else if (dst
& 0x8000)
591 sprintf (op1
, "%d(r%d)", dst
, regs
);
592 if (dst
> 9 || dst
< -9)
593 sprintf (comm1
, "0x%05x", dst
);
597 /* Destination. Special care needed on addr + XXXX. */
614 sprintf (op2
, "r%d", regd
);
624 dst
= msp430dis_opcode (addr
+ cmd_len
, info
);
625 sprintf (op2
, "0x%04x", PS (dst
));
626 sprintf (comm2
, "PC rel. 0x%04x",
627 PS ((short) addr
+ cmd_len
+ dst
));
630 dst
|= extended_dst
<< 16;
633 sprintf (op2
, "0x%05x", dst
& 0xfffff);
634 sprintf (comm2
, "PC rel. 0x%05lx",
635 (long)((addr
+ cmd_len
+ dst
) & 0xfffff));
642 dst
= msp430dis_opcode (addr
+ cmd_len
, info
);
644 sprintf (op2
, "&0x%04x", PS (dst
));
647 dst
|= extended_dst
<< 16;
648 sprintf (op2
, "&0x%05x", dst
& 0xfffff);
653 dst
= msp430dis_opcode (addr
+ cmd_len
, info
);
657 if (dst
> 9 || dst
< 0)
658 sprintf (comm2
, "0x%04x", PS (dst
));
661 dst
|= extended_dst
<< 16;
664 if (dst
> 9 || dst
< 0)
665 sprintf (comm2
, "0x%05x", dst
& 0xfffff);
667 sprintf (op2
, "%d(r%d)", dst
, regd
);
675 msp430_branchinstr (disassemble_info
*info
,
676 struct msp430_opcode_s
*opcode ATTRIBUTE_UNUSED
,
677 bfd_vma addr ATTRIBUTE_UNUSED
,
683 int regs
= 0, regd
= 0;
689 regs
= (insn
& 0x0f00) >> 8;
690 as
= (insn
& 0x0030) >> 4;
692 if (regd
!= 0) /* Destination register is not a PC. */
695 /* dst is a source register. */
703 sprintf (comm1
, "r3 As==00");
709 sprintf (op1
, "r%d", regs
);
714 * cycles
= print_as2_reg_name (regs
, op1
, comm1
, 2, 1, 2);
722 dst
= msp430dis_opcode (addr
+ 2, info
);
724 sprintf (op1
, "#0x%04x", PS (dst
));
727 * cycles
= print_as3_reg_name (regs
, op1
, comm1
, 1, 1, 2);
736 dst
= msp430dis_opcode (addr
+ 2, info
);
739 sprintf (op1
, "0x%04x", PS (dst
));
740 sprintf (comm1
, "PC rel. 0x%04x",
741 PS ((short) addr
+ 2 + dst
));
746 dst
= msp430dis_opcode (addr
+ 2, info
);
748 sprintf (op1
, "&0x%04x", PS (dst
));
754 sprintf (comm1
, "r3 As==01");
759 dst
= msp430dis_opcode (addr
+ 2, info
);
763 sprintf (op1
, "%d(r%d)", dst
, regs
);
771 msp430x_calla_instr (disassemble_info
* info
,
778 unsigned int ureg
= insn
& 0xf;
779 int reg
= insn
& 0xf;
780 int am
= (insn
& 0xf0) >> 4;
782 unsigned short udst
= 0;
787 case 4: /* CALLA Rdst */
789 sprintf (op1
, "r%d", reg
);
792 case 5: /* CALLA x(Rdst) */
794 dst
= msp430dis_opcode (addr
+ 2, info
);
796 sprintf (op1
, "%d(r%d)", dst
, reg
);
798 sprintf (comm1
, "PC rel. 0x%05lx", (long) (addr
+ 2 + dst
));
800 sprintf (comm1
, "0x%05x", dst
);
803 case 6: /* CALLA @Rdst */
805 sprintf (op1
, "@r%d", reg
);
808 case 7: /* CALLA @Rdst+ */
810 sprintf (op1
, "@r%d+", reg
);
813 case 8: /* CALLA &abs20 */
814 udst
= msp430dis_opcode (addr
+ 2, info
);
817 sprintf (op1
, "&%d", (ureg
<< 16) + udst
);
818 sprintf (comm1
, "0x%05x", (ureg
<< 16) + udst
);
821 case 9: /* CALLA pcrel-sym */
822 dst
= msp430dis_opcode (addr
+ 2, info
);
825 sprintf (op1
, "%d(PC)", (reg
<< 16) + dst
);
826 sprintf (comm1
, "PC rel. 0x%05lx",
827 (long) (addr
+ 2 + dst
+ (reg
<< 16)));
830 case 11: /* CALLA #imm20 */
831 udst
= msp430dis_opcode (addr
+ 2, info
);
834 sprintf (op1
, "#%d", (ureg
<< 16) + udst
);
835 sprintf (comm1
, "0x%05x", (ureg
<< 16) + udst
);
839 strcpy (comm1
, _("unrecognised CALLA addressing mode"));
847 print_insn_msp430 (bfd_vma addr
, disassemble_info
*info
)
849 void *stream
= info
->stream
;
850 fprintf_ftype prin
= info
->fprintf_func
;
851 struct msp430_opcode_s
*opcode
;
852 char op1
[32], op2
[32], comm1
[64], comm2
[64];
857 unsigned short extension_word
= 0;
859 insn
= msp430dis_opcode (addr
, info
);
860 if (insn
== (unsigned short) -1)
862 prin (stream
, ".word 0xffff; ????");
866 if (((int) addr
& 0xffff) > 0xffdf)
868 (*prin
) (stream
, "interrupt service routine at 0x%04x", 0xffff & insn
);
875 /* Check for an extension word. */
876 if ((insn
& 0xf800) == 0x1800)
878 extension_word
= insn
;
880 insn
= msp430dis_opcode (addr
, info
);
881 if (insn
== (unsigned short) -1)
883 prin (stream
, ".word 0x%04x, 0xffff; ????",
889 for (opcode
= msp430_opcodes
; opcode
->name
; opcode
++)
891 if ((insn
& opcode
->bin_mask
) == opcode
->bin_opcode
892 && opcode
->bin_opcode
!= 0x9300)
899 /* r0 as destination. Ad should be zero. */
900 if (opcode
->insn_opnumb
== 3
901 && (insn
& 0x000f) == 0
902 && (insn
& 0x0080) == 0)
905 msp430_branchinstr (info
, opcode
, addr
, insn
, op1
, comm1
,
911 switch (opcode
->insn_opnumb
)
917 cmd_len
+= msp430x_calla_instr (info
, addr
, insn
,
918 op1
, comm1
, & cycles
);
921 case 5: /* PUSHM/POPM */
922 n
= (insn
& 0xf0) >> 4;
925 sprintf (op1
, "#%d", n
+ 1);
926 if (opcode
->bin_opcode
== 0x1400)
928 sprintf (op2
, "r%d", reg
);
931 sprintf (op2
, "r%d", reg
+ n
);
933 sprintf (comm1
, "16-bit words");
936 sprintf (comm1
, "20-bit words");
940 cycles
= 2; /*FIXME*/
944 case 6: /* RRAM, RRCM, RRUM, RLAM. */
945 n
= ((insn
>> 10) & 0x3) + 1;
947 if ((insn
& 0x10) == 0)
949 sprintf (op1
, "#%d", n
);
950 sprintf (op2
, "r%d", reg
);
951 cycles
= 2; /*FIXME*/
955 case 8: /* ADDA, CMPA, SUBA. */
957 n
= (insn
>> 8) & 0xf;
960 sprintf (op1
, "r%d", n
);
966 n
|= msp430dis_opcode (addr
+ 2, info
);
967 sprintf (op1
, "#%d", n
);
969 sprintf (comm1
, "0x%05x", n
);
972 sprintf (op2
, "r%d", reg
);
973 cycles
= 2; /*FIXME*/
978 n
= (insn
>> 8) & 0xf;
979 switch ((insn
>> 4) & 0xf)
981 case 0: /* MOVA @Rsrc, Rdst */
983 sprintf (op1
, "@r%d", n
);
984 if (strcmp (opcode
->name
, "bra") != 0)
985 sprintf (op2
, "r%d", reg
);
988 case 1: /* MOVA @Rsrc+, Rdst */
990 if (strcmp (opcode
->name
, "reta") != 0)
992 sprintf (op1
, "@r%d+", n
);
993 if (strcmp (opcode
->name
, "bra") != 0)
994 sprintf (op2
, "r%d", reg
);
998 case 2: /* MOVA &abs20, Rdst */
1001 n
|= msp430dis_opcode (addr
+ 2, info
);
1002 sprintf (op1
, "&%d", n
);
1004 sprintf (comm1
, "0x%05x", n
);
1005 if (strcmp (opcode
->name
, "bra") != 0)
1006 sprintf (op2
, "r%d", reg
);
1009 case 3: /* MOVA x(Rsrc), Rdst */
1011 if (strcmp (opcode
->name
, "bra") != 0)
1012 sprintf (op2
, "r%d", reg
);
1014 n
= msp430dis_opcode (addr
+ 2, info
);
1017 sprintf (op1
, "%d(r%d)", n
, reg
);
1021 sprintf (comm1
, "PC rel. 0x%05lx",
1022 (long) (addr
+ 2 + n
));
1024 sprintf (comm1
, "0x%05x", n
);
1028 case 6: /* MOVA Rsrc, &abs20 */
1031 reg
|= msp430dis_opcode (addr
+ 2, info
);
1032 sprintf (op1
, "r%d", n
);
1033 sprintf (op2
, "&%d", reg
);
1034 if (reg
> 9 || reg
< 0)
1035 sprintf (comm2
, "0x%05x", reg
);
1038 case 7: /* MOVA Rsrc, x(Rdst) */
1040 sprintf (op1
, "r%d", n
);
1041 n
= msp430dis_opcode (addr
+ 2, info
);
1044 sprintf (op2
, "%d(r%d)", n
, reg
);
1048 sprintf (comm2
, "PC rel. 0x%05lx",
1049 (long) (addr
+ 2 + n
));
1051 sprintf (comm2
, "0x%05x", n
);
1055 case 8: /* MOVA #imm20, Rdst */
1058 n
|= msp430dis_opcode (addr
+ 2, info
);
1061 sprintf (op1
, "#%d", n
);
1063 sprintf (comm1
, "0x%05x", n
);
1064 if (strcmp (opcode
->name
, "bra") != 0)
1065 sprintf (op2
, "r%d", reg
);
1068 case 12: /* MOVA Rsrc, Rdst */
1070 sprintf (op1
, "r%d", n
);
1071 if (strcmp (opcode
->name
, "bra") != 0)
1072 sprintf (op2
, "r%d", reg
);
1078 cycles
= 2; /* FIXME */
1085 switch (opcode
->insn_opnumb
)
1088 cmd_len
+= msp430_nooperands (opcode
, addr
, insn
, comm1
, &cycles
);
1092 msp430_doubleoperand (info
, opcode
, addr
, insn
, op1
, op2
,
1096 if (insn
& BYTE_OPERATION
)
1098 if (extension_word
!= 0 && ((extension_word
& BYTE_OPERATION
) == 0))
1103 else if (extension_word
)
1105 if (extension_word
& (1 << 6))
1110 sprintf (comm2
, _("Reserved use of A/L and B/W bits detected"));
1117 msp430_singleoperand (info
, opcode
, addr
, insn
, op1
, comm1
,
1121 && (strcmp (opcode
->name
, "swpb") == 0
1122 || strcmp (opcode
->name
, "sxt") == 0))
1124 if (insn
& BYTE_OPERATION
)
1127 sprintf (comm2
, _("Reserved use of A/L and B/W bits detected"));
1129 else if (extension_word
& BYTE_OPERATION
)
1134 else if (insn
& BYTE_OPERATION
&& opcode
->fmt
!= 3)
1136 if (extension_word
!= 0 && ((extension_word
& BYTE_OPERATION
) == 0))
1141 else if (extension_word
)
1143 if (extension_word
& (1 << 6))
1148 sprintf (comm2
, _("Reserved use of A/L and B/W bits detected"));
1163 /* Unknown opcode, or invalid combination of operands. */
1166 prin (stream
, ".word 0x%04x, 0x%04x; ????", extension_word
, PS (insn
));
1168 prin (stream
, "\t %s", comm1
);
1171 (*prin
) (stream
, ".word 0x%04x; ????", PS (insn
));
1175 /* Display the repeat count (if set) for extended register mode. */
1176 if (cmd_len
== 2 && ((extension_word
& 0xf) != 0))
1178 if (extension_word
& (1 << 7))
1179 prin (stream
, "rpt r%d { ", extension_word
& 0xf);
1181 prin (stream
, "rpt #%d { ", (extension_word
& 0xf) + 1);
1184 if (extension_word
&& opcode
->name
[strlen (opcode
->name
) - 1] != 'x')
1185 (*prin
) (stream
, "%sx%s", opcode
->name
, bc
);
1187 (*prin
) (stream
, "%s%s", opcode
->name
, bc
);
1190 (*prin
) (stream
, "\t%s", op1
);
1192 (*prin
) (stream
, ",");
1194 if (strlen (op1
) < 7)
1195 (*prin
) (stream
, "\t");
1197 (*prin
) (stream
, "\t");
1200 (*prin
) (stream
, "%s", op2
);
1201 if (strlen (op2
) < 8)
1202 (*prin
) (stream
, "\t");
1204 if (*comm1
|| *comm2
)
1205 (*prin
) (stream
, ";");
1209 (*prin
) (stream
, ";");
1212 if (strlen (op1
) < 7)
1213 (*prin
) (stream
, ";");
1215 (*prin
) (stream
, "\t;");
1219 (*prin
) (stream
, "%s", comm1
);
1220 if (*comm1
&& *comm2
)
1221 (*prin
) (stream
, ",");
1223 (*prin
) (stream
, " %s", comm2
);