1 /* Disassemble MSP430 instructions.
2 Copyright (C) 2002, 2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23 #include <sys/types.h>
27 #include "libiberty.h"
30 #include "opcode/msp430.h"
34 static unsigned short msp430dis_opcode
35 PARAMS ((bfd_vma, disassemble_info *));
37 PARAMS ((bfd_vma, disassemble_info *));
39 PARAMS ((struct msp430_opcode_s *, bfd_vma, unsigned short, char *, int *));
40 int msp430_singleoperand
41 PARAMS ((disassemble_info *, struct msp430_opcode_s *, bfd_vma, unsigned short,
42 char *, char *, int *));
43 int msp430_doubleoperand
44 PARAMS ((disassemble_info *, struct msp430_opcode_s *, bfd_vma, unsigned short,
45 char *, char *, char *, char *, int *));
46 int msp430_branchinstr
47 PARAMS ((disassemble_info *, struct msp430_opcode_s *, bfd_vma, unsigned short,
48 char *, char *, int *));
50 #define PS(x) (0xffff & (x))
53 msp430dis_opcode (addr, info)
55 disassemble_info *info;
60 status = info->read_memory_func (addr, buffer, 2, info);
63 info->memory_error_func (status, addr, info);
66 return bfd_getl16 (buffer);
70 print_insn_msp430 (addr, info)
72 disassemble_info *info;
74 void *stream = info->stream;
75 fprintf_ftype prin = info->fprintf_func;
76 struct msp430_opcode_s *opcode;
77 char op1[32], op2[32], comm1[64], comm2[64];
82 char dinfo[32]; /* Debug purposes. */
84 insn = msp430dis_opcode (addr, info);
85 sprintf (dinfo, "0x%04x", insn);
87 if (((int) addr & 0xffff) > 0xffdf)
89 (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn);
96 for (opcode = msp430_opcodes; opcode->name; opcode++)
98 if ((insn & opcode->bin_mask) == opcode->bin_opcode
99 && opcode->bin_opcode != 0x9300)
106 /* r0 as destination. Ad should be zero. */
107 if (opcode->insn_opnumb == 3 && (insn & 0x000f) == 0
108 && (0x0080 & insn) == 0)
111 msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
117 switch (opcode->insn_opnumb)
120 cmd_len = msp430_nooperands (opcode, addr, insn, comm1, &cycles);
124 msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
125 comm1, comm2, &cycles);
126 if (insn & BYTE_OPERATION)
131 msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
133 if (insn & BYTE_OPERATION && opcode->fmt != 3)
149 /* Unknown opcode, or invalid combination of operands. */
150 (*prin) (stream, ".word 0x%04x; ????", PS (insn));
154 (*prin) (stream, "%s%s", opcode->name, bc);
157 (*prin) (stream, "\t%s", op1);
159 (*prin) (stream, ",");
161 if (strlen (op1) < 7)
162 (*prin) (stream, "\t");
164 (*prin) (stream, "\t");
167 (*prin) (stream, "%s", op2);
168 if (strlen (op2) < 8)
169 (*prin) (stream, "\t");
171 if (*comm1 || *comm2)
172 (*prin) (stream, ";");
176 (*prin) (stream, ";");
179 if (strlen (op1) < 7)
180 (*prin) (stream, ";");
182 (*prin) (stream, "\t;");
186 (*prin) (stream, "%s", comm1);
187 if (*comm1 && *comm2)
188 (*prin) (stream, ",");
190 (*prin) (stream, " %s", comm2);
195 msp430_nooperands (opcode, addr, insn, comm, cycles)
196 struct msp430_opcode_s *opcode;
197 bfd_vma addr ATTRIBUTE_UNUSED;
198 unsigned short insn ATTRIBUTE_UNUSED;
202 /* Pop with constant. */
205 if (insn == opcode->bin_opcode)
208 if (opcode->fmt == 0)
210 if ((insn & 0x0f00) != 3 || (insn & 0x0f00) != 2)
213 strcpy (comm, "emulated...");
218 strcpy (comm, "return from interupt");
227 msp430_singleoperand (info, opcode, addr, insn, op, comm, cycles)
228 disassemble_info *info;
229 struct msp430_opcode_s *opcode;
236 int regs = 0, regd = 0;
243 regs = (insn & 0x0f00) >> 8;
244 as = (insn & 0x0030) >> 4;
245 ad = (insn & 0x0080) >> 7;
249 case 0: /* Emulated work with dst register. */
250 if (regs != 2 && regs != 3 && regs != 1)
253 /* Check if not clr insn. */
254 if (opcode->bin_opcode == 0x4300 && (ad || as))
257 /* Check if really inc, incd insns. */
258 if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3)
278 sprintf (op, "r%d", regd);
280 else /* ad == 1 msp430dis_opcode. */
285 dst = msp430dis_opcode (addr + 2, info);
288 sprintf (op, "0x%04x", dst);
289 sprintf (comm, "PC rel. abs addr 0x%04x",
290 PS ((short) (addr + 2) + dst));
295 dst = msp430dis_opcode (addr + 2, info);
298 sprintf (op, "&0x%04x", PS (dst));
302 dst = msp430dis_opcode (addr + 2, info);
305 sprintf (op, "%d(r%d)", dst, regd);
310 case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
318 sprintf (comm, "r3 As==00");
323 sprintf (op, "r%d", regd);
333 sprintf (comm, "r2 As==10");
338 sprintf (comm, "r3 As==10");
343 /* Indexed register mode @Rn. */
344 sprintf (op, "@r%d", regd);
353 sprintf (comm, "r2 As==11");
358 sprintf (comm, "r3 As==11");
364 dst = msp430dis_opcode (addr + 2, info);
366 sprintf (op, "#%d", dst);
367 sprintf (comm, "#0x%04x", PS (dst));
372 sprintf (op, "@r%d+", regd);
381 dst = msp430dis_opcode (addr + 2, info);
383 sprintf (op, "0x%04x", PS (dst));
384 sprintf (comm, "PC rel. 0x%04x",
385 PS ((short) addr + 2 + dst));
390 dst = msp430dis_opcode (addr + 2, info);
392 sprintf (op, "&0x%04x", PS (dst));
398 sprintf (comm, "r3 As==01");
403 dst = msp430dis_opcode (addr + 2, info);
405 sprintf (op, "%d(r%d)", dst, regd);
411 where = insn & 0x03ff;
414 if (where > 512 || where < -511)
418 sprintf (op, "$%+-8d", where + 2);
419 sprintf (comm, "abs 0x%x", PS ((short) (addr) + 2 + where));
431 msp430_doubleoperand (info, opcode, addr, insn, op1, op2, comm1, comm2, cycles)
432 disassemble_info *info;
433 struct msp430_opcode_s *opcode;
440 int regs = 0, regd = 0;
446 regs = (insn & 0x0f00) >> 8;
447 as = (insn & 0x0030) >> 4;
448 ad = (insn & 0x0080) >> 7;
450 if (opcode->fmt == 0)
452 /* Special case: rla and rlc are the only 2 emulated instructions that
453 fall into two operand instructions. */
454 /* With dst, there are only:
460 basic_ins dst, dst. */
462 if (regd != regs || as != ad)
463 return 0; /* May be 'data' section. */
470 strcpy (comm1, "Illegal as emulation instr");
474 sprintf (op1, "r%d", regd);
481 /* PC relative, Symbolic. */
482 dst = msp430dis_opcode (addr + 2, info);
485 sprintf (op1, "0x%04x", PS (dst));
486 sprintf (comm1, "PC rel. 0x%04x",
487 PS ((short) addr + 2 + dst));
493 dst = msp430dis_opcode (addr + 2, info);
494 /* If the 'src' field is not the same as the dst
495 then this is not an rla instruction. */
496 if (dst != msp430dis_opcode (addr + 4, info))
500 sprintf (op1, "&0x%04x", PS (dst));
505 dst = msp430dis_opcode (addr + 2, info);
508 sprintf (op1, "%d(r%d)", dst, regd);
517 /* Two operands exactly. */
518 if (ad == 0 && regd == 3)
520 /* R2/R3 are illegal as dest: may be data section. */
521 strcpy (comm1, "Illegal as 2-op instr");
533 sprintf (comm1, "r3 As==00");
538 sprintf (op1, "r%d", regs);
548 sprintf (comm1, "r2 As==10");
553 sprintf (comm1, "r3 As==10");
559 /* Indexed register mode @Rn. */
560 sprintf (op1, "@r%d", regs);
570 sprintf (comm1, "r2 As==11");
575 sprintf (op1, "#-1");
576 sprintf (comm1, "r3 As==11");
583 dst = msp430dis_opcode (addr + 2, info);
585 sprintf (op1, "#%d", dst);
586 sprintf (comm1, "#0x%04x", PS (dst));
591 sprintf (op1, "@r%d+", regs);
600 dst = msp430dis_opcode (addr + 2, info);
602 sprintf (op1, "0x%04x", PS (dst));
603 sprintf (comm1, "PC rel. 0x%04x",
604 PS ((short) addr + 2 + dst));
610 dst = msp430dis_opcode (addr + 2, info);
612 sprintf (op1, "&0x%04x", PS (dst));
613 sprintf (comm1, "0x%04x", PS (dst));
619 sprintf (comm1, "r3 As==01");
625 dst = msp430dis_opcode (addr + 2, info);
627 sprintf (op1, "%d(r%d)", dst, regs);
631 /* Destination. Special care needed on addr + XXXX. */
648 sprintf (op2, "r%d", regd);
658 dst = msp430dis_opcode (addr + cmd_len, info);
659 sprintf (op2, "0x%04x", PS (dst));
660 sprintf (comm2, "PC rel. 0x%04x",
661 PS ((short) addr + cmd_len + dst));
667 dst = msp430dis_opcode (addr + cmd_len, info);
669 sprintf (op2, "&0x%04x", PS (dst));
673 dst = msp430dis_opcode (addr + cmd_len, info);
675 sprintf (op2, "%d(r%d)", dst, regd);
684 msp430_branchinstr (info, opcode, addr, insn, op1, comm1, cycles)
685 disassemble_info *info;
686 struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED;
687 bfd_vma addr ATTRIBUTE_UNUSED;
693 int regs = 0, regd = 0;
699 regs = (insn & 0x0f00) >> 8;
700 as = (insn & 0x0030) >> 4;
701 ad = (insn & 0x0080) >> 7;
703 if (regd != 0) /* Destination register is not a PC. */
706 /* dst is a source register. */
714 sprintf (comm1, "r3 As==00");
720 sprintf (op1, "r%d", regs);
729 sprintf (comm1, "r2 As==10");
735 sprintf (comm1, "r3 As==10");
739 /* Indexed register mode @Rn. */
741 sprintf (op1, "@r%d", regs);
750 sprintf (comm1, "r2 As==11");
755 sprintf (op1, "#-1");
756 sprintf (comm1, "r3 As==11");
762 dst = msp430dis_opcode (addr + 2, info);
764 sprintf (op1, "#0x%04x", PS (dst));
769 sprintf (op1, "@r%d+", regs);
779 dst = msp430dis_opcode (addr + 2, info);
782 sprintf (op1, "0x%04x", PS (dst));
783 sprintf (comm1, "PC rel. 0x%04x",
784 PS ((short) addr + 2 + dst));
789 dst = msp430dis_opcode (addr + 2, info);
791 sprintf (op1, "&0x%04x", PS (dst));
797 sprintf (comm1, "r3 As==01");
802 dst = msp430dis_opcode (addr + 2, info);
804 sprintf (op1, "%d(r%d)", dst, regs);