2004-04-21 Andrew Cagney <cagney@redhat.com>
[binutils.git] / opcodes / msp430-dis.c
blob1b5ffb1ec1229b23cbf8dec88c54a60ba08510e1
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. */
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <string.h>
23 #include <sys/types.h>
25 #include "dis-asm.h"
26 #include "opintl.h"
27 #include "libiberty.h"
29 #define DASM_SECTION
30 #include "opcode/msp430.h"
31 #undef DASM_SECTION
34 static unsigned short msp430dis_opcode
35 PARAMS ((bfd_vma, disassemble_info *));
36 int print_insn_msp430
37 PARAMS ((bfd_vma, disassemble_info *));
38 int msp430_nooperands
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))
52 static unsigned short
53 msp430dis_opcode (addr, info)
54 bfd_vma addr;
55 disassemble_info *info;
57 bfd_byte buffer[2];
58 int status;
60 status = info->read_memory_func (addr, buffer, 2, info);
61 if (status != 0)
63 info->memory_error_func (status, addr, info);
64 return -1;
66 return bfd_getl16 (buffer);
69 int
70 print_insn_msp430 (addr, info)
71 bfd_vma addr;
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];
78 int cmd_len = 0;
79 unsigned short insn;
80 int cycles = 0;
81 char *bc = "";
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);
90 return 2;
93 *comm1 = 0;
94 *comm2 = 0;
96 for (opcode = msp430_opcodes; opcode->name; opcode++)
98 if ((insn & opcode->bin_mask) == opcode->bin_opcode
99 && opcode->bin_opcode != 0x9300)
101 *op1 = 0;
102 *op2 = 0;
103 *comm1 = 0;
104 *comm2 = 0;
106 /* r0 as destination. Ad should be zero. */
107 if (opcode->insn_opnumb == 3 && (insn & 0x000f) == 0
108 && (0x0080 & insn) == 0)
110 cmd_len =
111 msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
112 &cycles);
113 if (cmd_len)
114 break;
117 switch (opcode->insn_opnumb)
119 case 0:
120 cmd_len = msp430_nooperands (opcode, addr, insn, comm1, &cycles);
121 break;
122 case 2:
123 cmd_len =
124 msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
125 comm1, comm2, &cycles);
126 if (insn & BYTE_OPERATION)
127 bc = ".b";
128 break;
129 case 1:
130 cmd_len =
131 msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
132 &cycles);
133 if (insn & BYTE_OPERATION && opcode->fmt != 3)
134 bc = ".b";
135 break;
136 default:
137 break;
141 if (cmd_len)
142 break;
145 dinfo[5] = 0;
147 if (cmd_len < 1)
149 /* Unknown opcode, or invalid combination of operands. */
150 (*prin) (stream, ".word 0x%04x; ????", PS (insn));
151 return 2;
154 (*prin) (stream, "%s%s", opcode->name, bc);
156 if (*op1)
157 (*prin) (stream, "\t%s", op1);
158 if (*op2)
159 (*prin) (stream, ",");
161 if (strlen (op1) < 7)
162 (*prin) (stream, "\t");
163 if (!strlen (op1))
164 (*prin) (stream, "\t");
166 if (*op2)
167 (*prin) (stream, "%s", op2);
168 if (strlen (op2) < 8)
169 (*prin) (stream, "\t");
171 if (*comm1 || *comm2)
172 (*prin) (stream, ";");
173 else if (cycles)
175 if (*op2)
176 (*prin) (stream, ";");
177 else
179 if (strlen (op1) < 7)
180 (*prin) (stream, ";");
181 else
182 (*prin) (stream, "\t;");
185 if (*comm1)
186 (*prin) (stream, "%s", comm1);
187 if (*comm1 && *comm2)
188 (*prin) (stream, ",");
189 if (*comm2)
190 (*prin) (stream, " %s", comm2);
191 return cmd_len;
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;
199 char *comm;
200 int *cycles;
202 /* Pop with constant. */
203 if (insn == 0x43b2)
204 return 0;
205 if (insn == opcode->bin_opcode)
206 return 2;
208 if (opcode->fmt == 0)
210 if ((insn & 0x0f00) != 3 || (insn & 0x0f00) != 2)
211 return 0;
213 strcpy (comm, "emulated...");
214 *cycles = 1;
216 else
218 strcpy (comm, "return from interupt");
219 *cycles = 5;
222 return 2;
227 msp430_singleoperand (info, opcode, addr, insn, op, comm, cycles)
228 disassemble_info *info;
229 struct msp430_opcode_s *opcode;
230 bfd_vma addr;
231 unsigned short insn;
232 char *op;
233 char *comm;
234 int *cycles;
236 int regs = 0, regd = 0;
237 int ad = 0, as = 0;
238 int where = 0;
239 int cmd_len = 2;
240 short dst = 0;
242 regd = insn & 0x0f;
243 regs = (insn & 0x0f00) >> 8;
244 as = (insn & 0x0030) >> 4;
245 ad = (insn & 0x0080) >> 7;
247 switch (opcode->fmt)
249 case 0: /* Emulated work with dst register. */
250 if (regs != 2 && regs != 3 && regs != 1)
251 return 0;
253 /* Check if not clr insn. */
254 if (opcode->bin_opcode == 0x4300 && (ad || as))
255 return 0;
257 /* Check if really inc, incd insns. */
258 if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3)
259 return 0;
261 if (ad == 0)
263 *cycles = 1;
265 /* Register. */
266 if (regd == 0)
268 *cycles += 1;
269 sprintf (op, "r0");
271 else if (regd == 1)
272 sprintf (op, "r1");
274 else if (regd == 2)
275 sprintf (op, "r2");
277 else
278 sprintf (op, "r%d", regd);
280 else /* ad == 1 msp430dis_opcode. */
282 if (regd == 0)
284 /* PC relative. */
285 dst = msp430dis_opcode (addr + 2, info);
286 cmd_len += 2;
287 *cycles = 4;
288 sprintf (op, "0x%04x", dst);
289 sprintf (comm, "PC rel. abs addr 0x%04x",
290 PS ((short) (addr + 2) + dst));
292 else if (regd == 2)
294 /* Absolute. */
295 dst = msp430dis_opcode (addr + 2, info);
296 cmd_len += 2;
297 *cycles = 4;
298 sprintf (op, "&0x%04x", PS (dst));
300 else
302 dst = msp430dis_opcode (addr + 2, info);
303 cmd_len += 2;
304 *cycles = 4;
305 sprintf (op, "%d(r%d)", dst, regd);
308 break;
310 case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
312 if (as == 0)
314 if (regd == 3)
316 /* Constsnts. */
317 sprintf (op, "#0");
318 sprintf (comm, "r3 As==00");
320 else
322 /* Register. */
323 sprintf (op, "r%d", regd);
325 *cycles = 1;
327 else if (as == 2)
329 *cycles = 1;
330 if (regd == 2)
332 sprintf (op, "#4");
333 sprintf (comm, "r2 As==10");
335 else if (regd == 3)
337 sprintf (op, "#2");
338 sprintf (comm, "r3 As==10");
340 else
342 *cycles = 3;
343 /* Indexed register mode @Rn. */
344 sprintf (op, "@r%d", regd);
347 else if (as == 3)
349 *cycles = 1;
350 if (regd == 2)
352 sprintf (op, "#8");
353 sprintf (comm, "r2 As==11");
355 else if (regd == 3)
357 sprintf (op, "#-1");
358 sprintf (comm, "r3 As==11");
360 else if (regd == 0)
362 *cycles = 3;
363 /* absolute. @pc+ */
364 dst = msp430dis_opcode (addr + 2, info);
365 cmd_len += 2;
366 sprintf (op, "#%d", dst);
367 sprintf (comm, "#0x%04x", PS (dst));
369 else
371 *cycles = 3;
372 sprintf (op, "@r%d+", regd);
375 else if (as == 1)
377 *cycles = 4;
378 if (regd == 0)
380 /* PC relative. */
381 dst = msp430dis_opcode (addr + 2, info);
382 cmd_len += 2;
383 sprintf (op, "0x%04x", PS (dst));
384 sprintf (comm, "PC rel. 0x%04x",
385 PS ((short) addr + 2 + dst));
387 else if (regd == 2)
389 /* Absolute. */
390 dst = msp430dis_opcode (addr + 2, info);
391 cmd_len += 2;
392 sprintf (op, "&0x%04x", PS (dst));
394 else if (regd == 3)
396 *cycles = 1;
397 sprintf (op, "#1");
398 sprintf (comm, "r3 As==01");
400 else
402 /* Indexd. */
403 dst = msp430dis_opcode (addr + 2, info);
404 cmd_len += 2;
405 sprintf (op, "%d(r%d)", dst, regd);
408 break;
410 case 3: /* Jumps. */
411 where = insn & 0x03ff;
412 if (where & 0x200)
413 where |= ~0x03ff;
414 if (where > 512 || where < -511)
415 return 0;
417 where *= 2;
418 sprintf (op, "$%+-8d", where + 2);
419 sprintf (comm, "abs 0x%x", PS ((short) (addr) + 2 + where));
420 *cycles = 2;
421 return 2;
422 break;
423 default:
424 cmd_len = 0;
427 return cmd_len;
431 msp430_doubleoperand (info, opcode, addr, insn, op1, op2, comm1, comm2, cycles)
432 disassemble_info *info;
433 struct msp430_opcode_s *opcode;
434 bfd_vma addr;
435 unsigned short insn;
436 char *op1, *op2;
437 char *comm1, *comm2;
438 int *cycles;
440 int regs = 0, regd = 0;
441 int ad = 0, as = 0;
442 int cmd_len = 2;
443 short dst = 0;
445 regd = insn & 0x0f;
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:
455 Rm Register,
456 x(Rm) Indexed,
457 0xXXXX Relative,
458 &0xXXXX Absolute
459 emulated_ins dst
460 basic_ins dst, dst. */
462 if (regd != regs || as != ad)
463 return 0; /* May be 'data' section. */
465 if (ad == 0)
467 /* Register mode. */
468 if (regd == 3)
470 strcpy (comm1, "Illegal as emulation instr");
471 return -1;
474 sprintf (op1, "r%d", regd);
475 *cycles = 1;
477 else /* ad == 1 */
479 if (regd == 0)
481 /* PC relative, Symbolic. */
482 dst = msp430dis_opcode (addr + 2, info);
483 cmd_len += 4;
484 *cycles = 6;
485 sprintf (op1, "0x%04x", PS (dst));
486 sprintf (comm1, "PC rel. 0x%04x",
487 PS ((short) addr + 2 + dst));
490 else if (regd == 2)
492 /* Absolute. */
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))
497 return 0;
498 cmd_len += 4;
499 *cycles = 6;
500 sprintf (op1, "&0x%04x", PS (dst));
502 else
504 /* Indexed. */
505 dst = msp430dis_opcode (addr + 2, info);
506 cmd_len += 4;
507 *cycles = 6;
508 sprintf (op1, "%d(r%d)", dst, regd);
512 *op2 = 0;
513 *comm2 = 0;
514 return cmd_len;
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");
522 return -1;
525 /* Source. */
526 if (as == 0)
528 *cycles = 1;
529 if (regs == 3)
531 /* Constsnts. */
532 sprintf (op1, "#0");
533 sprintf (comm1, "r3 As==00");
535 else
537 /* Register. */
538 sprintf (op1, "r%d", regs);
541 else if (as == 2)
543 *cycles = 1;
545 if (regs == 2)
547 sprintf (op1, "#4");
548 sprintf (comm1, "r2 As==10");
550 else if (regs == 3)
552 sprintf (op1, "#2");
553 sprintf (comm1, "r3 As==10");
555 else
557 *cycles = 2;
559 /* Indexed register mode @Rn. */
560 sprintf (op1, "@r%d", regs);
562 if (!regs)
563 *cycles = 3;
565 else if (as == 3)
567 if (regs == 2)
569 sprintf (op1, "#8");
570 sprintf (comm1, "r2 As==11");
571 *cycles = 1;
573 else if (regs == 3)
575 sprintf (op1, "#-1");
576 sprintf (comm1, "r3 As==11");
577 *cycles = 1;
579 else if (regs == 0)
581 *cycles = 3;
582 /* Absolute. @pc+ */
583 dst = msp430dis_opcode (addr + 2, info);
584 cmd_len += 2;
585 sprintf (op1, "#%d", dst);
586 sprintf (comm1, "#0x%04x", PS (dst));
588 else
590 *cycles = 2;
591 sprintf (op1, "@r%d+", regs);
594 else if (as == 1)
596 if (regs == 0)
598 *cycles = 4;
599 /* PC relative. */
600 dst = msp430dis_opcode (addr + 2, info);
601 cmd_len += 2;
602 sprintf (op1, "0x%04x", PS (dst));
603 sprintf (comm1, "PC rel. 0x%04x",
604 PS ((short) addr + 2 + dst));
606 else if (regs == 2)
608 *cycles = 2;
609 /* Absolute. */
610 dst = msp430dis_opcode (addr + 2, info);
611 cmd_len += 2;
612 sprintf (op1, "&0x%04x", PS (dst));
613 sprintf (comm1, "0x%04x", PS (dst));
615 else if (regs == 3)
617 *cycles = 1;
618 sprintf (op1, "#1");
619 sprintf (comm1, "r3 As==01");
621 else
623 *cycles = 3;
624 /* Indexed. */
625 dst = msp430dis_opcode (addr + 2, info);
626 cmd_len += 2;
627 sprintf (op1, "%d(r%d)", dst, regs);
631 /* Destination. Special care needed on addr + XXXX. */
633 if (ad == 0)
635 /* Register. */
636 if (regd == 0)
638 *cycles += 1;
639 sprintf (op2, "r0");
641 else if (regd == 1)
642 sprintf (op2, "r1");
644 else if (regd == 2)
645 sprintf (op2, "r2");
647 else
648 sprintf (op2, "r%d", regd);
650 else /* ad == 1. */
652 * cycles += 3;
654 if (regd == 0)
656 /* PC relative. */
657 *cycles += 1;
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));
662 cmd_len += 2;
664 else if (regd == 2)
666 /* Absolute. */
667 dst = msp430dis_opcode (addr + cmd_len, info);
668 cmd_len += 2;
669 sprintf (op2, "&0x%04x", PS (dst));
671 else
673 dst = msp430dis_opcode (addr + cmd_len, info);
674 cmd_len += 2;
675 sprintf (op2, "%d(r%d)", dst, regd);
679 return cmd_len;
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;
688 unsigned short insn;
689 char *op1;
690 char *comm1;
691 int *cycles;
693 int regs = 0, regd = 0;
694 int ad = 0, as = 0;
695 int cmd_len = 2;
696 short dst = 0;
698 regd = insn & 0x0f;
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. */
704 return 0;
706 /* dst is a source register. */
707 if (as == 0)
709 /* Constants. */
710 if (regs == 3)
712 *cycles = 1;
713 sprintf (op1, "#0");
714 sprintf (comm1, "r3 As==00");
716 else
718 /* Register. */
719 *cycles = 1;
720 sprintf (op1, "r%d", regs);
723 else if (as == 2)
725 if (regs == 2)
727 *cycles = 2;
728 sprintf (op1, "#4");
729 sprintf (comm1, "r2 As==10");
731 else if (regs == 3)
733 *cycles = 1;
734 sprintf (op1, "#2");
735 sprintf (comm1, "r3 As==10");
737 else
739 /* Indexed register mode @Rn. */
740 *cycles = 2;
741 sprintf (op1, "@r%d", regs);
744 else if (as == 3)
746 if (regs == 2)
748 *cycles = 1;
749 sprintf (op1, "#8");
750 sprintf (comm1, "r2 As==11");
752 else if (regs == 3)
754 *cycles = 1;
755 sprintf (op1, "#-1");
756 sprintf (comm1, "r3 As==11");
758 else if (regs == 0)
760 /* Absolute. @pc+ */
761 *cycles = 3;
762 dst = msp430dis_opcode (addr + 2, info);
763 cmd_len += 2;
764 sprintf (op1, "#0x%04x", PS (dst));
766 else
768 *cycles = 2;
769 sprintf (op1, "@r%d+", regs);
772 else if (as == 1)
774 * cycles = 3;
776 if (regs == 0)
778 /* PC relative. */
779 dst = msp430dis_opcode (addr + 2, info);
780 cmd_len += 2;
781 (*cycles)++;
782 sprintf (op1, "0x%04x", PS (dst));
783 sprintf (comm1, "PC rel. 0x%04x",
784 PS ((short) addr + 2 + dst));
786 else if (regs == 2)
788 /* Absolute. */
789 dst = msp430dis_opcode (addr + 2, info);
790 cmd_len += 2;
791 sprintf (op1, "&0x%04x", PS (dst));
793 else if (regs == 3)
795 (*cycles)--;
796 sprintf (op1, "#1");
797 sprintf (comm1, "r3 As==01");
799 else
801 /* Indexd. */
802 dst = msp430dis_opcode (addr + 2, info);
803 cmd_len += 2;
804 sprintf (op1, "%d(r%d)", dst, regs);
808 return cmd_len;