1 /* Disassemble MSP430 instructions.
2 Copyright (C) 2002, 2004, 2005, 2007, 2009, 2010
3 Free Software Foundation, Inc.
5 Contributed by Dmitry Diky <diwil@mail.ru>
7 This file is part of the GNU opcodes library.
9 This library is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3, or (at your option)
14 It is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
17 License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
22 MA 02110-1301, USA. */
27 #include <sys/types.h>
31 #include "libiberty.h"
34 #include "opcode/msp430.h"
38 #define PS(x) (0xffff & (x))
41 msp430dis_opcode (bfd_vma addr, disassemble_info *info)
46 status = info->read_memory_func (addr, buffer, 2, info);
49 info->memory_error_func (status, addr, info);
52 return bfd_getl16 (buffer);
56 msp430_nooperands (struct msp430_opcode_s *opcode,
57 bfd_vma addr ATTRIBUTE_UNUSED,
58 unsigned short insn ATTRIBUTE_UNUSED,
62 /* Pop with constant. */
65 if (insn == opcode->bin_opcode)
70 if ((insn & 0x0f00) != 3 || (insn & 0x0f00) != 2)
73 strcpy (comm, "emulated...");
78 strcpy (comm, "return from interupt");
86 msp430_singleoperand (disassemble_info *info,
87 struct msp430_opcode_s *opcode,
94 int regs = 0, regd = 0;
101 regs = (insn & 0x0f00) >> 8;
102 as = (insn & 0x0030) >> 4;
103 ad = (insn & 0x0080) >> 7;
107 case 0: /* Emulated work with dst register. */
108 if (regs != 2 && regs != 3 && regs != 1)
111 /* Check if not clr insn. */
112 if (opcode->bin_opcode == 0x4300 && (ad || as))
115 /* Check if really inc, incd insns. */
116 if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3)
136 sprintf (op, "r%d", regd);
138 else /* ad == 1 msp430dis_opcode. */
143 dst = msp430dis_opcode (addr + 2, info);
146 sprintf (op, "0x%04x", dst);
147 sprintf (comm, "PC rel. abs addr 0x%04x",
148 PS ((short) (addr + 2) + dst));
153 dst = msp430dis_opcode (addr + 2, info);
156 sprintf (op, "&0x%04x", PS (dst));
160 dst = msp430dis_opcode (addr + 2, info);
163 sprintf (op, "%d(r%d)", dst, regd);
168 case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
175 sprintf (comm, "r3 As==00");
180 sprintf (op, "r%d", regd);
190 sprintf (comm, "r2 As==10");
195 sprintf (comm, "r3 As==10");
200 /* Indexed register mode @Rn. */
201 sprintf (op, "@r%d", regd);
210 sprintf (comm, "r2 As==11");
215 sprintf (comm, "r3 As==11");
221 dst = msp430dis_opcode (addr + 2, info);
223 sprintf (op, "#%d", dst);
224 sprintf (comm, "#0x%04x", PS (dst));
229 sprintf (op, "@r%d+", regd);
238 dst = msp430dis_opcode (addr + 2, info);
240 sprintf (op, "0x%04x", PS (dst));
241 sprintf (comm, "PC rel. 0x%04x",
242 PS ((short) addr + 2 + dst));
247 dst = msp430dis_opcode (addr + 2, info);
249 sprintf (op, "&0x%04x", PS (dst));
255 sprintf (comm, "r3 As==01");
260 dst = msp430dis_opcode (addr + 2, info);
262 sprintf (op, "%d(r%d)", dst, regd);
268 where = insn & 0x03ff;
271 if (where > 512 || where < -511)
275 sprintf (op, "$%+-8d", where + 2);
276 sprintf (comm, "abs 0x%x", PS ((short) (addr) + 2 + where));
288 msp430_doubleoperand (disassemble_info *info,
289 struct msp430_opcode_s *opcode,
298 int regs = 0, regd = 0;
304 regs = (insn & 0x0f00) >> 8;
305 as = (insn & 0x0030) >> 4;
306 ad = (insn & 0x0080) >> 7;
308 if (opcode->fmt == 0)
310 /* Special case: rla and rlc are the only 2 emulated instructions that
311 fall into two operand instructions. */
312 /* With dst, there are only:
318 basic_ins dst, dst. */
320 if (regd != regs || as != ad)
321 return 0; /* May be 'data' section. */
328 strcpy (comm1, _("Illegal as emulation instr"));
332 sprintf (op1, "r%d", regd);
339 /* PC relative, Symbolic. */
340 dst = msp430dis_opcode (addr + 2, info);
343 sprintf (op1, "0x%04x", PS (dst));
344 sprintf (comm1, "PC rel. 0x%04x",
345 PS ((short) addr + 2 + dst));
351 dst = msp430dis_opcode (addr + 2, info);
352 /* If the 'src' field is not the same as the dst
353 then this is not an rla instruction. */
354 if (dst != msp430dis_opcode (addr + 4, info))
358 sprintf (op1, "&0x%04x", PS (dst));
363 dst = msp430dis_opcode (addr + 2, info);
366 sprintf (op1, "%d(r%d)", dst, regd);
375 /* Two operands exactly. */
376 if (ad == 0 && regd == 3)
378 /* R2/R3 are illegal as dest: may be data section. */
379 strcpy (comm1, _("Illegal as 2-op instr"));
391 sprintf (comm1, "r3 As==00");
396 sprintf (op1, "r%d", regs);
406 sprintf (comm1, "r2 As==10");
411 sprintf (comm1, "r3 As==10");
417 /* Indexed register mode @Rn. */
418 sprintf (op1, "@r%d", regs);
428 sprintf (comm1, "r2 As==11");
433 sprintf (op1, "#-1");
434 sprintf (comm1, "r3 As==11");
440 /* Absolute. @pc+. */
441 dst = msp430dis_opcode (addr + 2, info);
443 sprintf (op1, "#%d", dst);
444 sprintf (comm1, "#0x%04x", PS (dst));
449 sprintf (op1, "@r%d+", regs);
458 dst = msp430dis_opcode (addr + 2, info);
460 sprintf (op1, "0x%04x", PS (dst));
461 sprintf (comm1, "PC rel. 0x%04x",
462 PS ((short) addr + 2 + dst));
468 dst = msp430dis_opcode (addr + 2, info);
470 sprintf (op1, "&0x%04x", PS (dst));
471 sprintf (comm1, "0x%04x", PS (dst));
477 sprintf (comm1, "r3 As==01");
483 dst = msp430dis_opcode (addr + 2, info);
485 sprintf (op1, "%d(r%d)", dst, regs);
489 /* Destination. Special care needed on addr + XXXX. */
506 sprintf (op2, "r%d", regd);
516 dst = msp430dis_opcode (addr + cmd_len, info);
517 sprintf (op2, "0x%04x", PS (dst));
518 sprintf (comm2, "PC rel. 0x%04x",
519 PS ((short) addr + cmd_len + dst));
525 dst = msp430dis_opcode (addr + cmd_len, info);
527 sprintf (op2, "&0x%04x", PS (dst));
531 dst = msp430dis_opcode (addr + cmd_len, info);
533 sprintf (op2, "%d(r%d)", dst, regd);
541 msp430_branchinstr (disassemble_info *info,
542 struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
543 bfd_vma addr ATTRIBUTE_UNUSED,
549 int regs = 0, regd = 0;
555 regs = (insn & 0x0f00) >> 8;
556 as = (insn & 0x0030) >> 4;
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);