merge from gcc
[binutils.git] / opcodes / msp430-dis.c
blob0f61665e163125c4392f5a92a3f9cde30eae4c0a
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. */
21 #include <stdio.h>
22 #include <ctype.h>
23 #include <string.h>
24 #include <sys/types.h>
26 #include "dis-asm.h"
27 #include "opintl.h"
28 #include "libiberty.h"
30 #define DASM_SECTION
31 #include "opcode/msp430.h"
32 #undef DASM_SECTION
35 #define PS(x) (0xffff & (x))
37 static unsigned short
38 msp430dis_opcode (bfd_vma addr, disassemble_info *info)
40 bfd_byte buffer[2];
41 int status;
43 status = info->read_memory_func (addr, buffer, 2, info);
44 if (status != 0)
46 info->memory_error_func (status, addr, info);
47 return -1;
49 return bfd_getl16 (buffer);
52 static int
53 msp430_nooperands (struct msp430_opcode_s *opcode,
54 bfd_vma addr ATTRIBUTE_UNUSED,
55 unsigned short insn ATTRIBUTE_UNUSED,
56 char *comm,
57 int *cycles)
59 /* Pop with constant. */
60 if (insn == 0x43b2)
61 return 0;
62 if (insn == opcode->bin_opcode)
63 return 2;
65 if (opcode->fmt == 0)
67 if ((insn & 0x0f00) != 3 || (insn & 0x0f00) != 2)
68 return 0;
70 strcpy (comm, "emulated...");
71 *cycles = 1;
73 else
75 strcpy (comm, "return from interupt");
76 *cycles = 5;
79 return 2;
82 static int
83 msp430_singleoperand (disassemble_info *info,
84 struct msp430_opcode_s *opcode,
85 bfd_vma addr,
86 unsigned short insn,
87 char *op,
88 char *comm,
89 int *cycles)
91 int regs = 0, regd = 0;
92 int ad = 0, as = 0;
93 int where = 0;
94 int cmd_len = 2;
95 short dst = 0;
97 regd = insn & 0x0f;
98 regs = (insn & 0x0f00) >> 8;
99 as = (insn & 0x0030) >> 4;
100 ad = (insn & 0x0080) >> 7;
102 switch (opcode->fmt)
104 case 0: /* Emulated work with dst register. */
105 if (regs != 2 && regs != 3 && regs != 1)
106 return 0;
108 /* Check if not clr insn. */
109 if (opcode->bin_opcode == 0x4300 && (ad || as))
110 return 0;
112 /* Check if really inc, incd insns. */
113 if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3)
114 return 0;
116 if (ad == 0)
118 *cycles = 1;
120 /* Register. */
121 if (regd == 0)
123 *cycles += 1;
124 sprintf (op, "r0");
126 else if (regd == 1)
127 sprintf (op, "r1");
129 else if (regd == 2)
130 sprintf (op, "r2");
132 else
133 sprintf (op, "r%d", regd);
135 else /* ad == 1 msp430dis_opcode. */
137 if (regd == 0)
139 /* PC relative. */
140 dst = msp430dis_opcode (addr + 2, info);
141 cmd_len += 2;
142 *cycles = 4;
143 sprintf (op, "0x%04x", dst);
144 sprintf (comm, "PC rel. abs addr 0x%04x",
145 PS ((short) (addr + 2) + dst));
147 else if (regd == 2)
149 /* Absolute. */
150 dst = msp430dis_opcode (addr + 2, info);
151 cmd_len += 2;
152 *cycles = 4;
153 sprintf (op, "&0x%04x", PS (dst));
155 else
157 dst = msp430dis_opcode (addr + 2, info);
158 cmd_len += 2;
159 *cycles = 4;
160 sprintf (op, "%d(r%d)", dst, regd);
163 break;
165 case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
166 if (as == 0)
168 if (regd == 3)
170 /* Constsnts. */
171 sprintf (op, "#0");
172 sprintf (comm, "r3 As==00");
174 else
176 /* Register. */
177 sprintf (op, "r%d", regd);
179 *cycles = 1;
181 else if (as == 2)
183 *cycles = 1;
184 if (regd == 2)
186 sprintf (op, "#4");
187 sprintf (comm, "r2 As==10");
189 else if (regd == 3)
191 sprintf (op, "#2");
192 sprintf (comm, "r3 As==10");
194 else
196 *cycles = 3;
197 /* Indexed register mode @Rn. */
198 sprintf (op, "@r%d", regd);
201 else if (as == 3)
203 *cycles = 1;
204 if (regd == 2)
206 sprintf (op, "#8");
207 sprintf (comm, "r2 As==11");
209 else if (regd == 3)
211 sprintf (op, "#-1");
212 sprintf (comm, "r3 As==11");
214 else if (regd == 0)
216 *cycles = 3;
217 /* absolute. @pc+ */
218 dst = msp430dis_opcode (addr + 2, info);
219 cmd_len += 2;
220 sprintf (op, "#%d", dst);
221 sprintf (comm, "#0x%04x", PS (dst));
223 else
225 *cycles = 3;
226 sprintf (op, "@r%d+", regd);
229 else if (as == 1)
231 *cycles = 4;
232 if (regd == 0)
234 /* PC relative. */
235 dst = msp430dis_opcode (addr + 2, info);
236 cmd_len += 2;
237 sprintf (op, "0x%04x", PS (dst));
238 sprintf (comm, "PC rel. 0x%04x",
239 PS ((short) addr + 2 + dst));
241 else if (regd == 2)
243 /* Absolute. */
244 dst = msp430dis_opcode (addr + 2, info);
245 cmd_len += 2;
246 sprintf (op, "&0x%04x", PS (dst));
248 else if (regd == 3)
250 *cycles = 1;
251 sprintf (op, "#1");
252 sprintf (comm, "r3 As==01");
254 else
256 /* Indexd. */
257 dst = msp430dis_opcode (addr + 2, info);
258 cmd_len += 2;
259 sprintf (op, "%d(r%d)", dst, regd);
262 break;
264 case 3: /* Jumps. */
265 where = insn & 0x03ff;
266 if (where & 0x200)
267 where |= ~0x03ff;
268 if (where > 512 || where < -511)
269 return 0;
271 where *= 2;
272 sprintf (op, "$%+-8d", where + 2);
273 sprintf (comm, "abs 0x%x", PS ((short) (addr) + 2 + where));
274 *cycles = 2;
275 return 2;
276 break;
277 default:
278 cmd_len = 0;
281 return cmd_len;
284 static int
285 msp430_doubleoperand (disassemble_info *info,
286 struct msp430_opcode_s *opcode,
287 bfd_vma addr,
288 unsigned short insn,
289 char *op1,
290 char *op2,
291 char *comm1,
292 char *comm2,
293 int *cycles)
295 int regs = 0, regd = 0;
296 int ad = 0, as = 0;
297 int cmd_len = 2;
298 short dst = 0;
300 regd = insn & 0x0f;
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:
310 Rm Register,
311 x(Rm) Indexed,
312 0xXXXX Relative,
313 &0xXXXX Absolute
314 emulated_ins dst
315 basic_ins dst, dst. */
317 if (regd != regs || as != ad)
318 return 0; /* May be 'data' section. */
320 if (ad == 0)
322 /* Register mode. */
323 if (regd == 3)
325 strcpy (comm1, _("Illegal as emulation instr"));
326 return -1;
329 sprintf (op1, "r%d", regd);
330 *cycles = 1;
332 else /* ad == 1 */
334 if (regd == 0)
336 /* PC relative, Symbolic. */
337 dst = msp430dis_opcode (addr + 2, info);
338 cmd_len += 4;
339 *cycles = 6;
340 sprintf (op1, "0x%04x", PS (dst));
341 sprintf (comm1, "PC rel. 0x%04x",
342 PS ((short) addr + 2 + dst));
345 else if (regd == 2)
347 /* Absolute. */
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))
352 return 0;
353 cmd_len += 4;
354 *cycles = 6;
355 sprintf (op1, "&0x%04x", PS (dst));
357 else
359 /* Indexed. */
360 dst = msp430dis_opcode (addr + 2, info);
361 cmd_len += 4;
362 *cycles = 6;
363 sprintf (op1, "%d(r%d)", dst, regd);
367 *op2 = 0;
368 *comm2 = 0;
369 return cmd_len;
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"));
377 return -1;
380 /* Source. */
381 if (as == 0)
383 *cycles = 1;
384 if (regs == 3)
386 /* Constsnts. */
387 sprintf (op1, "#0");
388 sprintf (comm1, "r3 As==00");
390 else
392 /* Register. */
393 sprintf (op1, "r%d", regs);
396 else if (as == 2)
398 *cycles = 1;
400 if (regs == 2)
402 sprintf (op1, "#4");
403 sprintf (comm1, "r2 As==10");
405 else if (regs == 3)
407 sprintf (op1, "#2");
408 sprintf (comm1, "r3 As==10");
410 else
412 *cycles = 2;
414 /* Indexed register mode @Rn. */
415 sprintf (op1, "@r%d", regs);
417 if (!regs)
418 *cycles = 3;
420 else if (as == 3)
422 if (regs == 2)
424 sprintf (op1, "#8");
425 sprintf (comm1, "r2 As==11");
426 *cycles = 1;
428 else if (regs == 3)
430 sprintf (op1, "#-1");
431 sprintf (comm1, "r3 As==11");
432 *cycles = 1;
434 else if (regs == 0)
436 *cycles = 3;
437 /* Absolute. @pc+. */
438 dst = msp430dis_opcode (addr + 2, info);
439 cmd_len += 2;
440 sprintf (op1, "#%d", dst);
441 sprintf (comm1, "#0x%04x", PS (dst));
443 else
445 *cycles = 2;
446 sprintf (op1, "@r%d+", regs);
449 else if (as == 1)
451 if (regs == 0)
453 *cycles = 4;
454 /* PC relative. */
455 dst = msp430dis_opcode (addr + 2, info);
456 cmd_len += 2;
457 sprintf (op1, "0x%04x", PS (dst));
458 sprintf (comm1, "PC rel. 0x%04x",
459 PS ((short) addr + 2 + dst));
461 else if (regs == 2)
463 *cycles = 2;
464 /* Absolute. */
465 dst = msp430dis_opcode (addr + 2, info);
466 cmd_len += 2;
467 sprintf (op1, "&0x%04x", PS (dst));
468 sprintf (comm1, "0x%04x", PS (dst));
470 else if (regs == 3)
472 *cycles = 1;
473 sprintf (op1, "#1");
474 sprintf (comm1, "r3 As==01");
476 else
478 *cycles = 3;
479 /* Indexed. */
480 dst = msp430dis_opcode (addr + 2, info);
481 cmd_len += 2;
482 sprintf (op1, "%d(r%d)", dst, regs);
486 /* Destination. Special care needed on addr + XXXX. */
488 if (ad == 0)
490 /* Register. */
491 if (regd == 0)
493 *cycles += 1;
494 sprintf (op2, "r0");
496 else if (regd == 1)
497 sprintf (op2, "r1");
499 else if (regd == 2)
500 sprintf (op2, "r2");
502 else
503 sprintf (op2, "r%d", regd);
505 else /* ad == 1. */
507 * cycles += 3;
509 if (regd == 0)
511 /* PC relative. */
512 *cycles += 1;
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));
517 cmd_len += 2;
519 else if (regd == 2)
521 /* Absolute. */
522 dst = msp430dis_opcode (addr + cmd_len, info);
523 cmd_len += 2;
524 sprintf (op2, "&0x%04x", PS (dst));
526 else
528 dst = msp430dis_opcode (addr + cmd_len, info);
529 cmd_len += 2;
530 sprintf (op2, "%d(r%d)", dst, regd);
534 return cmd_len;
537 static int
538 msp430_branchinstr (disassemble_info *info,
539 struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
540 bfd_vma addr ATTRIBUTE_UNUSED,
541 unsigned short insn,
542 char *op1,
543 char *comm1,
544 int *cycles)
546 int regs = 0, regd = 0;
547 int ad = 0, as = 0;
548 int cmd_len = 2;
549 short dst = 0;
551 regd = insn & 0x0f;
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. */
557 return 0;
559 /* dst is a source register. */
560 if (as == 0)
562 /* Constants. */
563 if (regs == 3)
565 *cycles = 1;
566 sprintf (op1, "#0");
567 sprintf (comm1, "r3 As==00");
569 else
571 /* Register. */
572 *cycles = 1;
573 sprintf (op1, "r%d", regs);
576 else if (as == 2)
578 if (regs == 2)
580 *cycles = 2;
581 sprintf (op1, "#4");
582 sprintf (comm1, "r2 As==10");
584 else if (regs == 3)
586 *cycles = 1;
587 sprintf (op1, "#2");
588 sprintf (comm1, "r3 As==10");
590 else
592 /* Indexed register mode @Rn. */
593 *cycles = 2;
594 sprintf (op1, "@r%d", regs);
597 else if (as == 3)
599 if (regs == 2)
601 *cycles = 1;
602 sprintf (op1, "#8");
603 sprintf (comm1, "r2 As==11");
605 else if (regs == 3)
607 *cycles = 1;
608 sprintf (op1, "#-1");
609 sprintf (comm1, "r3 As==11");
611 else if (regs == 0)
613 /* Absolute. @pc+ */
614 *cycles = 3;
615 dst = msp430dis_opcode (addr + 2, info);
616 cmd_len += 2;
617 sprintf (op1, "#0x%04x", PS (dst));
619 else
621 *cycles = 2;
622 sprintf (op1, "@r%d+", regs);
625 else if (as == 1)
627 * cycles = 3;
629 if (regs == 0)
631 /* PC relative. */
632 dst = msp430dis_opcode (addr + 2, info);
633 cmd_len += 2;
634 (*cycles)++;
635 sprintf (op1, "0x%04x", PS (dst));
636 sprintf (comm1, "PC rel. 0x%04x",
637 PS ((short) addr + 2 + dst));
639 else if (regs == 2)
641 /* Absolute. */
642 dst = msp430dis_opcode (addr + 2, info);
643 cmd_len += 2;
644 sprintf (op1, "&0x%04x", PS (dst));
646 else if (regs == 3)
648 (*cycles)--;
649 sprintf (op1, "#1");
650 sprintf (comm1, "r3 As==01");
652 else
654 /* Indexd. */
655 dst = msp430dis_opcode (addr + 2, info);
656 cmd_len += 2;
657 sprintf (op1, "%d(r%d)", dst, regs);
661 return cmd_len;
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];
671 int cmd_len = 0;
672 unsigned short insn;
673 int cycles = 0;
674 char *bc = "";
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);
683 return 2;
686 *comm1 = 0;
687 *comm2 = 0;
689 for (opcode = msp430_opcodes; opcode->name; opcode++)
691 if ((insn & opcode->bin_mask) == opcode->bin_opcode
692 && opcode->bin_opcode != 0x9300)
694 *op1 = 0;
695 *op2 = 0;
696 *comm1 = 0;
697 *comm2 = 0;
699 /* r0 as destination. Ad should be zero. */
700 if (opcode->insn_opnumb == 3 && (insn & 0x000f) == 0
701 && (0x0080 & insn) == 0)
703 cmd_len =
704 msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
705 &cycles);
706 if (cmd_len)
707 break;
710 switch (opcode->insn_opnumb)
712 case 0:
713 cmd_len = msp430_nooperands (opcode, addr, insn, comm1, &cycles);
714 break;
715 case 2:
716 cmd_len =
717 msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
718 comm1, comm2, &cycles);
719 if (insn & BYTE_OPERATION)
720 bc = ".b";
721 break;
722 case 1:
723 cmd_len =
724 msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
725 &cycles);
726 if (insn & BYTE_OPERATION && opcode->fmt != 3)
727 bc = ".b";
728 break;
729 default:
730 break;
734 if (cmd_len)
735 break;
738 dinfo[5] = 0;
740 if (cmd_len < 1)
742 /* Unknown opcode, or invalid combination of operands. */
743 (*prin) (stream, ".word 0x%04x; ????", PS (insn));
744 return 2;
747 (*prin) (stream, "%s%s", opcode->name, bc);
749 if (*op1)
750 (*prin) (stream, "\t%s", op1);
751 if (*op2)
752 (*prin) (stream, ",");
754 if (strlen (op1) < 7)
755 (*prin) (stream, "\t");
756 if (!strlen (op1))
757 (*prin) (stream, "\t");
759 if (*op2)
760 (*prin) (stream, "%s", op2);
761 if (strlen (op2) < 8)
762 (*prin) (stream, "\t");
764 if (*comm1 || *comm2)
765 (*prin) (stream, ";");
766 else if (cycles)
768 if (*op2)
769 (*prin) (stream, ";");
770 else
772 if (strlen (op1) < 7)
773 (*prin) (stream, ";");
774 else
775 (*prin) (stream, "\t;");
778 if (*comm1)
779 (*prin) (stream, "%s", comm1);
780 if (*comm1 && *comm2)
781 (*prin) (stream, ",");
782 if (*comm2)
783 (*prin) (stream, " %s", comm2);
784 return cmd_len;