1 /* Disassemble MSP430 instructions.
2 Copyright (C) 2002-2015 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);