1 /* Disassemble MSP430 instructions.
2 Copyright (C) 2002, 2004, 2005, 2007, 2009 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) != 3 || (insn & 0x0f00) != 2)
72 strcpy (comm, "emulated...");
77 strcpy (comm, "return from interupt");
85 msp430_singleoperand (disassemble_info *info,
86 struct msp430_opcode_s *opcode,
93 int regs = 0, regd = 0;
100 regs = (insn & 0x0f00) >> 8;
101 as = (insn & 0x0030) >> 4;
102 ad = (insn & 0x0080) >> 7;
106 case 0: /* Emulated work with dst register. */
107 if (regs != 2 && regs != 3 && regs != 1)
110 /* Check if not clr insn. */
111 if (opcode->bin_opcode == 0x4300 && (ad || as))
114 /* Check if really inc, incd insns. */
115 if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3)
135 sprintf (op, "r%d", regd);
137 else /* ad == 1 msp430dis_opcode. */
142 dst = msp430dis_opcode (addr + 2, info);
145 sprintf (op, "0x%04x", dst);
146 sprintf (comm, "PC rel. abs addr 0x%04x",
147 PS ((short) (addr + 2) + dst));
152 dst = msp430dis_opcode (addr + 2, info);
155 sprintf (op, "&0x%04x", PS (dst));
159 dst = msp430dis_opcode (addr + 2, info);
162 sprintf (op, "%d(r%d)", dst, regd);
167 case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
174 sprintf (comm, "r3 As==00");
179 sprintf (op, "r%d", regd);
189 sprintf (comm, "r2 As==10");
194 sprintf (comm, "r3 As==10");
199 /* Indexed register mode @Rn. */
200 sprintf (op, "@r%d", regd);
209 sprintf (comm, "r2 As==11");
214 sprintf (comm, "r3 As==11");
220 dst = msp430dis_opcode (addr + 2, info);
222 sprintf (op, "#%d", dst);
223 sprintf (comm, "#0x%04x", PS (dst));
228 sprintf (op, "@r%d+", regd);
237 dst = msp430dis_opcode (addr + 2, info);
239 sprintf (op, "0x%04x", PS (dst));
240 sprintf (comm, "PC rel. 0x%04x",
241 PS ((short) addr + 2 + dst));
246 dst = msp430dis_opcode (addr + 2, info);
248 sprintf (op, "&0x%04x", PS (dst));
254 sprintf (comm, "r3 As==01");
259 dst = msp430dis_opcode (addr + 2, info);
261 sprintf (op, "%d(r%d)", dst, regd);
267 where = insn & 0x03ff;
270 if (where > 512 || where < -511)
274 sprintf (op, "$%+-8d", where + 2);
275 sprintf (comm, "abs 0x%x", PS ((short) (addr) + 2 + where));
287 msp430_doubleoperand (disassemble_info *info,
288 struct msp430_opcode_s *opcode,
297 int regs = 0, regd = 0;
303 regs = (insn & 0x0f00) >> 8;
304 as = (insn & 0x0030) >> 4;
305 ad = (insn & 0x0080) >> 7;
307 if (opcode->fmt == 0)
309 /* Special case: rla and rlc are the only 2 emulated instructions that
310 fall into two operand instructions. */
311 /* With dst, there are only:
317 basic_ins dst, dst. */
319 if (regd != regs || as != ad)
320 return 0; /* May be 'data' section. */
327 strcpy (comm1, _("Illegal as emulation instr"));
331 sprintf (op1, "r%d", regd);
338 /* PC relative, Symbolic. */
339 dst = msp430dis_opcode (addr + 2, info);
342 sprintf (op1, "0x%04x", PS (dst));
343 sprintf (comm1, "PC rel. 0x%04x",
344 PS ((short) addr + 2 + dst));
350 dst = msp430dis_opcode (addr + 2, info);
351 /* If the 'src' field is not the same as the dst
352 then this is not an rla instruction. */
353 if (dst != msp430dis_opcode (addr + 4, info))
357 sprintf (op1, "&0x%04x", PS (dst));
362 dst = msp430dis_opcode (addr + 2, info);
365 sprintf (op1, "%d(r%d)", dst, regd);
374 /* Two operands exactly. */
375 if (ad == 0 && regd == 3)
377 /* R2/R3 are illegal as dest: may be data section. */
378 strcpy (comm1, _("Illegal as 2-op instr"));
390 sprintf (comm1, "r3 As==00");
395 sprintf (op1, "r%d", regs);
405 sprintf (comm1, "r2 As==10");
410 sprintf (comm1, "r3 As==10");
416 /* Indexed register mode @Rn. */
417 sprintf (op1, "@r%d", regs);
427 sprintf (comm1, "r2 As==11");
432 sprintf (op1, "#-1");
433 sprintf (comm1, "r3 As==11");
439 /* Absolute. @pc+. */
440 dst = msp430dis_opcode (addr + 2, info);
442 sprintf (op1, "#%d", dst);
443 sprintf (comm1, "#0x%04x", PS (dst));
448 sprintf (op1, "@r%d+", regs);
457 dst = msp430dis_opcode (addr + 2, info);
459 sprintf (op1, "0x%04x", PS (dst));
460 sprintf (comm1, "PC rel. 0x%04x",
461 PS ((short) addr + 2 + dst));
467 dst = msp430dis_opcode (addr + 2, info);
469 sprintf (op1, "&0x%04x", PS (dst));
470 sprintf (comm1, "0x%04x", PS (dst));
476 sprintf (comm1, "r3 As==01");
482 dst = msp430dis_opcode (addr + 2, info);
484 sprintf (op1, "%d(r%d)", dst, regs);
488 /* Destination. Special care needed on addr + XXXX. */
505 sprintf (op2, "r%d", regd);
515 dst = msp430dis_opcode (addr + cmd_len, info);
516 sprintf (op2, "0x%04x", PS (dst));
517 sprintf (comm2, "PC rel. 0x%04x",
518 PS ((short) addr + cmd_len + dst));
524 dst = msp430dis_opcode (addr + cmd_len, info);
526 sprintf (op2, "&0x%04x", PS (dst));
530 dst = msp430dis_opcode (addr + cmd_len, info);
532 sprintf (op2, "%d(r%d)", dst, regd);
540 msp430_branchinstr (disassemble_info *info,
541 struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
542 bfd_vma addr ATTRIBUTE_UNUSED,
548 int regs = 0, regd = 0;
554 regs = (insn & 0x0f00) >> 8;
555 as = (insn & 0x0030) >> 4;
556 ad = (insn & 0x0080) >> 7;
558 if (regd != 0) /* Destination register is not a PC. */
561 /* dst is a source register. */
569 sprintf (comm1, "r3 As==00");
575 sprintf (op1, "r%d", regs);
584 sprintf (comm1, "r2 As==10");
590 sprintf (comm1, "r3 As==10");
594 /* Indexed register mode @Rn. */
596 sprintf (op1, "@r%d", regs);
605 sprintf (comm1, "r2 As==11");
610 sprintf (op1, "#-1");
611 sprintf (comm1, "r3 As==11");
617 dst = msp430dis_opcode (addr + 2, info);
619 sprintf (op1, "#0x%04x", PS (dst));
624 sprintf (op1, "@r%d+", regs);
634 dst = msp430dis_opcode (addr + 2, info);
637 sprintf (op1, "0x%04x", PS (dst));
638 sprintf (comm1, "PC rel. 0x%04x",
639 PS ((short) addr + 2 + dst));
644 dst = msp430dis_opcode (addr + 2, info);
646 sprintf (op1, "&0x%04x", PS (dst));
652 sprintf (comm1, "r3 As==01");
657 dst = msp430dis_opcode (addr + 2, info);
659 sprintf (op1, "%d(r%d)", dst, regs);
667 print_insn_msp430 (bfd_vma addr, disassemble_info *info)
669 void *stream = info->stream;
670 fprintf_ftype prin = info->fprintf_func;
671 struct msp430_opcode_s *opcode;
672 char op1[32], op2[32], comm1[64], comm2[64];
677 char dinfo[32]; /* Debug purposes. */
679 insn = msp430dis_opcode (addr, info);
680 sprintf (dinfo, "0x%04x", insn);
682 if (((int) addr & 0xffff) > 0xffdf)
684 (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn);
691 for (opcode = msp430_opcodes; opcode->name; opcode++)
693 if ((insn & opcode->bin_mask) == opcode->bin_opcode
694 && opcode->bin_opcode != 0x9300)
701 /* r0 as destination. Ad should be zero. */
702 if (opcode->insn_opnumb == 3 && (insn & 0x000f) == 0
703 && (0x0080 & insn) == 0)
706 msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
712 switch (opcode->insn_opnumb)
715 cmd_len = msp430_nooperands (opcode, addr, insn, comm1, &cycles);
719 msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
720 comm1, comm2, &cycles);
721 if (insn & BYTE_OPERATION)
726 msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
728 if (insn & BYTE_OPERATION && opcode->fmt != 3)
744 /* Unknown opcode, or invalid combination of operands. */
745 (*prin) (stream, ".word 0x%04x; ????", PS (insn));
749 (*prin) (stream, "%s%s", opcode->name, bc);
752 (*prin) (stream, "\t%s", op1);
754 (*prin) (stream, ",");
756 if (strlen (op1) < 7)
757 (*prin) (stream, "\t");
759 (*prin) (stream, "\t");
762 (*prin) (stream, "%s", op2);
763 if (strlen (op2) < 8)
764 (*prin) (stream, "\t");
766 if (*comm1 || *comm2)
767 (*prin) (stream, ";");
771 (*prin) (stream, ";");
774 if (strlen (op1) < 7)
775 (*prin) (stream, ";");
777 (*prin) (stream, "\t;");
781 (*prin) (stream, "%s", comm1);
782 if (*comm1 && *comm2)
783 (*prin) (stream, ",");
785 (*prin) (stream, " %s", comm2);