1 /* Disassemble MSP430 instructions.
2 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
4 Contributed by Dmitry Diky <diwil@mail.ru>
6 This program 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 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
24 #include <sys/types.h>
28 #include "libiberty.h"
31 #include "opcode/msp430.h"
35 #define PS(x) (0xffff & (x))
38 msp430dis_opcode (bfd_vma addr, disassemble_info *info)
43 status = info->read_memory_func (addr, buffer, 2, info);
46 info->memory_error_func (status, addr, info);
49 return bfd_getl16 (buffer);
53 msp430_nooperands (struct msp430_opcode_s *opcode,
54 bfd_vma addr ATTRIBUTE_UNUSED,
55 unsigned short insn ATTRIBUTE_UNUSED,
59 /* Pop with constant. */
62 if (insn == opcode->bin_opcode)
67 if ((insn & 0x0f00) != 3 || (insn & 0x0f00) != 2)
70 strcpy (comm, "emulated...");
75 strcpy (comm, "return from interupt");
83 msp430_singleoperand (disassemble_info *info,
84 struct msp430_opcode_s *opcode,
91 int regs = 0, regd = 0;
98 regs = (insn & 0x0f00) >> 8;
99 as = (insn & 0x0030) >> 4;
100 ad = (insn & 0x0080) >> 7;
104 case 0: /* Emulated work with dst register. */
105 if (regs != 2 && regs != 3 && regs != 1)
108 /* Check if not clr insn. */
109 if (opcode->bin_opcode == 0x4300 && (ad || as))
112 /* Check if really inc, incd insns. */
113 if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3)
133 sprintf (op, "r%d", regd);
135 else /* ad == 1 msp430dis_opcode. */
140 dst = msp430dis_opcode (addr + 2, info);
143 sprintf (op, "0x%04x", dst);
144 sprintf (comm, "PC rel. abs addr 0x%04x",
145 PS ((short) (addr + 2) + dst));
150 dst = msp430dis_opcode (addr + 2, info);
153 sprintf (op, "&0x%04x", PS (dst));
157 dst = msp430dis_opcode (addr + 2, info);
160 sprintf (op, "%d(r%d)", dst, regd);
165 case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
172 sprintf (comm, "r3 As==00");
177 sprintf (op, "r%d", regd);
187 sprintf (comm, "r2 As==10");
192 sprintf (comm, "r3 As==10");
197 /* Indexed register mode @Rn. */
198 sprintf (op, "@r%d", regd);
207 sprintf (comm, "r2 As==11");
212 sprintf (comm, "r3 As==11");
218 dst = msp430dis_opcode (addr + 2, info);
220 sprintf (op, "#%d", dst);
221 sprintf (comm, "#0x%04x", PS (dst));
226 sprintf (op, "@r%d+", regd);
235 dst = msp430dis_opcode (addr + 2, info);
237 sprintf (op, "0x%04x", PS (dst));
238 sprintf (comm, "PC rel. 0x%04x",
239 PS ((short) addr + 2 + dst));
244 dst = msp430dis_opcode (addr + 2, info);
246 sprintf (op, "&0x%04x", PS (dst));
252 sprintf (comm, "r3 As==01");
257 dst = msp430dis_opcode (addr + 2, info);
259 sprintf (op, "%d(r%d)", dst, regd);
265 where = insn & 0x03ff;
268 if (where > 512 || where < -511)
272 sprintf (op, "$%+-8d", where + 2);
273 sprintf (comm, "abs 0x%x", PS ((short) (addr) + 2 + where));
285 msp430_doubleoperand (disassemble_info *info,
286 struct msp430_opcode_s *opcode,
295 int regs = 0, regd = 0;
301 regs = (insn & 0x0f00) >> 8;
302 as = (insn & 0x0030) >> 4;
303 ad = (insn & 0x0080) >> 7;
305 if (opcode->fmt == 0)
307 /* Special case: rla and rlc are the only 2 emulated instructions that
308 fall into two operand instructions. */
309 /* With dst, there are only:
315 basic_ins dst, dst. */
317 if (regd != regs || as != ad)
318 return 0; /* May be 'data' section. */
325 strcpy (comm1, _("Illegal as emulation instr"));
329 sprintf (op1, "r%d", regd);
336 /* PC relative, Symbolic. */
337 dst = msp430dis_opcode (addr + 2, info);
340 sprintf (op1, "0x%04x", PS (dst));
341 sprintf (comm1, "PC rel. 0x%04x",
342 PS ((short) addr + 2 + dst));
348 dst = msp430dis_opcode (addr + 2, info);
349 /* If the 'src' field is not the same as the dst
350 then this is not an rla instruction. */
351 if (dst != msp430dis_opcode (addr + 4, info))
355 sprintf (op1, "&0x%04x", PS (dst));
360 dst = msp430dis_opcode (addr + 2, info);
363 sprintf (op1, "%d(r%d)", dst, regd);
372 /* Two operands exactly. */
373 if (ad == 0 && regd == 3)
375 /* R2/R3 are illegal as dest: may be data section. */
376 strcpy (comm1, _("Illegal as 2-op instr"));
388 sprintf (comm1, "r3 As==00");
393 sprintf (op1, "r%d", regs);
403 sprintf (comm1, "r2 As==10");
408 sprintf (comm1, "r3 As==10");
414 /* Indexed register mode @Rn. */
415 sprintf (op1, "@r%d", regs);
425 sprintf (comm1, "r2 As==11");
430 sprintf (op1, "#-1");
431 sprintf (comm1, "r3 As==11");
437 /* Absolute. @pc+. */
438 dst = msp430dis_opcode (addr + 2, info);
440 sprintf (op1, "#%d", dst);
441 sprintf (comm1, "#0x%04x", PS (dst));
446 sprintf (op1, "@r%d+", regs);
455 dst = msp430dis_opcode (addr + 2, info);
457 sprintf (op1, "0x%04x", PS (dst));
458 sprintf (comm1, "PC rel. 0x%04x",
459 PS ((short) addr + 2 + dst));
465 dst = msp430dis_opcode (addr + 2, info);
467 sprintf (op1, "&0x%04x", PS (dst));
468 sprintf (comm1, "0x%04x", PS (dst));
474 sprintf (comm1, "r3 As==01");
480 dst = msp430dis_opcode (addr + 2, info);
482 sprintf (op1, "%d(r%d)", dst, regs);
486 /* Destination. Special care needed on addr + XXXX. */
503 sprintf (op2, "r%d", regd);
513 dst = msp430dis_opcode (addr + cmd_len, info);
514 sprintf (op2, "0x%04x", PS (dst));
515 sprintf (comm2, "PC rel. 0x%04x",
516 PS ((short) addr + cmd_len + dst));
522 dst = msp430dis_opcode (addr + cmd_len, info);
524 sprintf (op2, "&0x%04x", PS (dst));
528 dst = msp430dis_opcode (addr + cmd_len, info);
530 sprintf (op2, "%d(r%d)", dst, regd);
538 msp430_branchinstr (disassemble_info *info,
539 struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
540 bfd_vma addr ATTRIBUTE_UNUSED,
546 int regs = 0, regd = 0;
552 regs = (insn & 0x0f00) >> 8;
553 as = (insn & 0x0030) >> 4;
554 ad = (insn & 0x0080) >> 7;
556 if (regd != 0) /* Destination register is not a PC. */
559 /* dst is a source register. */
567 sprintf (comm1, "r3 As==00");
573 sprintf (op1, "r%d", regs);
582 sprintf (comm1, "r2 As==10");
588 sprintf (comm1, "r3 As==10");
592 /* Indexed register mode @Rn. */
594 sprintf (op1, "@r%d", regs);
603 sprintf (comm1, "r2 As==11");
608 sprintf (op1, "#-1");
609 sprintf (comm1, "r3 As==11");
615 dst = msp430dis_opcode (addr + 2, info);
617 sprintf (op1, "#0x%04x", PS (dst));
622 sprintf (op1, "@r%d+", regs);
632 dst = msp430dis_opcode (addr + 2, info);
635 sprintf (op1, "0x%04x", PS (dst));
636 sprintf (comm1, "PC rel. 0x%04x",
637 PS ((short) addr + 2 + dst));
642 dst = msp430dis_opcode (addr + 2, info);
644 sprintf (op1, "&0x%04x", PS (dst));
650 sprintf (comm1, "r3 As==01");
655 dst = msp430dis_opcode (addr + 2, info);
657 sprintf (op1, "%d(r%d)", dst, regs);
665 print_insn_msp430 (bfd_vma addr, disassemble_info *info)
667 void *stream = info->stream;
668 fprintf_ftype prin = info->fprintf_func;
669 struct msp430_opcode_s *opcode;
670 char op1[32], op2[32], comm1[64], comm2[64];
675 char dinfo[32]; /* Debug purposes. */
677 insn = msp430dis_opcode (addr, info);
678 sprintf (dinfo, "0x%04x", insn);
680 if (((int) addr & 0xffff) > 0xffdf)
682 (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn);
689 for (opcode = msp430_opcodes; opcode->name; opcode++)
691 if ((insn & opcode->bin_mask) == opcode->bin_opcode
692 && opcode->bin_opcode != 0x9300)
699 /* r0 as destination. Ad should be zero. */
700 if (opcode->insn_opnumb == 3 && (insn & 0x000f) == 0
701 && (0x0080 & insn) == 0)
704 msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
710 switch (opcode->insn_opnumb)
713 cmd_len = msp430_nooperands (opcode, addr, insn, comm1, &cycles);
717 msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
718 comm1, comm2, &cycles);
719 if (insn & BYTE_OPERATION)
724 msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
726 if (insn & BYTE_OPERATION && opcode->fmt != 3)
742 /* Unknown opcode, or invalid combination of operands. */
743 (*prin) (stream, ".word 0x%04x; ????", PS (insn));
747 (*prin) (stream, "%s%s", opcode->name, bc);
750 (*prin) (stream, "\t%s", op1);
752 (*prin) (stream, ",");
754 if (strlen (op1) < 7)
755 (*prin) (stream, "\t");
757 (*prin) (stream, "\t");
760 (*prin) (stream, "%s", op2);
761 if (strlen (op2) < 8)
762 (*prin) (stream, "\t");
764 if (*comm1 || *comm2)
765 (*prin) (stream, ";");
769 (*prin) (stream, ";");
772 if (strlen (op1) < 7)
773 (*prin) (stream, ";");
775 (*prin) (stream, "\t;");
779 (*prin) (stream, "%s", comm1);
780 if (*comm1 && *comm2)
781 (*prin) (stream, ",");
783 (*prin) (stream, " %s", comm2);