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