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
);