1 /* Disassemble MSP430 instructions.
2 Copyright (C) 2002 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
);
496 sprintf (op1
, "&0x%04x", PS (dst
));
501 dst
= msp430dis_opcode (addr
+ 2, info
);
504 sprintf (op1
, "%d(r%d)", dst
, regd
);
513 /* Two operands exactly. */
514 if (ad
== 0 && regd
== 3)
516 /* R2/R3 are illegal as dest: may be data section. */
517 strcpy (comm1
, "Illegal as 2-op instr");
529 sprintf (comm1
, "r3 As==00");
534 sprintf (op1
, "r%d", regs
);
544 sprintf (comm1
, "r2 As==10");
549 sprintf (comm1
, "r3 As==10");
555 /* Indexed register mode @Rn. */
556 sprintf (op1
, "@r%d", regs
);
566 sprintf (comm1
, "r2 As==11");
571 sprintf (op1
, "#-1");
572 sprintf (comm1
, "r3 As==11");
579 dst
= msp430dis_opcode (addr
+ 2, info
);
581 sprintf (op1
, "#%d", dst
);
582 sprintf (comm1
, "#0x%04x", PS (dst
));
587 sprintf (op1
, "@r%d+", regs
);
596 dst
= msp430dis_opcode (addr
+ 2, info
);
598 sprintf (op1
, "0x%04x", PS (dst
));
599 sprintf (comm1
, "PC rel. 0x%04x",
600 PS ((short) addr
+ 2 + dst
));
606 dst
= msp430dis_opcode (addr
+ 2, info
);
608 sprintf (op1
, "&0x%04x", PS (dst
));
609 sprintf (comm1
, "0x%04x", PS (dst
));
615 sprintf (comm1
, "r3 As==01");
621 dst
= msp430dis_opcode (addr
+ 2, info
);
623 sprintf (op1
, "%d(r%d)", dst
, regs
);
627 /* Destination. Special care needed on addr + XXXX. */
644 sprintf (op2
, "r%d", regd
);
654 dst
= msp430dis_opcode (addr
+ cmd_len
, info
);
655 sprintf (op2
, "0x%04x", PS (dst
));
656 sprintf (comm2
, "PC rel. 0x%04x",
657 PS ((short) addr
+ cmd_len
+ dst
));
663 dst
= msp430dis_opcode (addr
+ cmd_len
, info
);
665 sprintf (op2
, "&0x%04x", PS (dst
));
669 dst
= msp430dis_opcode (addr
+ cmd_len
, info
);
671 sprintf (op2
, "%d(r%d)", dst
, regd
);
680 msp430_branchinstr (info
, opcode
, addr
, insn
, op1
, comm1
, cycles
)
681 disassemble_info
*info
;
682 struct msp430_opcode_s
*opcode ATTRIBUTE_UNUSED
;
683 bfd_vma addr ATTRIBUTE_UNUSED
;
689 int regs
= 0, regd
= 0;
695 regs
= (insn
& 0x0f00) >> 8;
696 as
= (insn
& 0x0030) >> 4;
697 ad
= (insn
& 0x0080) >> 7;
699 if (regd
!= 0) /* Destination register is not a PC. */
702 /* dst is a source register. */
710 sprintf (comm1
, "r3 As==00");
716 sprintf (op1
, "r%d", regs
);
725 sprintf (comm1
, "r2 As==10");
731 sprintf (comm1
, "r3 As==10");
735 /* Indexed register mode @Rn. */
737 sprintf (op1
, "@r%d", regs
);
746 sprintf (comm1
, "r2 As==11");
751 sprintf (op1
, "#-1");
752 sprintf (comm1
, "r3 As==11");
758 dst
= msp430dis_opcode (addr
+ 2, info
);
760 sprintf (op1
, "#0x%04x", PS (dst
));
765 sprintf (op1
, "@r%d+", regs
);
775 dst
= msp430dis_opcode (addr
+ 2, info
);
778 sprintf (op1
, "0x%04x", PS (dst
));
779 sprintf (comm1
, "PC rel. 0x%04x",
780 PS ((short) addr
+ 2 + dst
));
785 dst
= msp430dis_opcode (addr
+ 2, info
);
787 sprintf (op1
, "&0x%04x", PS (dst
));
793 sprintf (comm1
, "r3 As==01");
798 dst
= msp430dis_opcode (addr
+ 2, info
);
800 sprintf (op1
, "%d(r%d)", dst
, regs
);