Convert to C90
[binutils.git] / opcodes / msp430-dis.c
blob767ffa472c14961057e75383d721f061e5ccfb7f
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. */
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 cmd_len += 4;
495 *cycles = 6;
496 sprintf (op1, "&0x%04x", PS (dst));
498 else
500 /* Indexed. */
501 dst = msp430dis_opcode (addr + 2, info);
502 cmd_len += 4;
503 *cycles = 6;
504 sprintf (op1, "%d(r%d)", dst, regd);
508 *op2 = 0;
509 *comm2 = 0;
510 return cmd_len;
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");
518 return -1;
521 /* Source. */
522 if (as == 0)
524 *cycles = 1;
525 if (regs == 3)
527 /* Constsnts. */
528 sprintf (op1, "#0");
529 sprintf (comm1, "r3 As==00");
531 else
533 /* Register. */
534 sprintf (op1, "r%d", regs);
537 else if (as == 2)
539 *cycles = 1;
541 if (regs == 2)
543 sprintf (op1, "#4");
544 sprintf (comm1, "r2 As==10");
546 else if (regs == 3)
548 sprintf (op1, "#2");
549 sprintf (comm1, "r3 As==10");
551 else
553 *cycles = 2;
555 /* Indexed register mode @Rn. */
556 sprintf (op1, "@r%d", regs);
558 if (!regs)
559 *cycles = 3;
561 else if (as == 3)
563 if (regs == 2)
565 sprintf (op1, "#8");
566 sprintf (comm1, "r2 As==11");
567 *cycles = 1;
569 else if (regs == 3)
571 sprintf (op1, "#-1");
572 sprintf (comm1, "r3 As==11");
573 *cycles = 1;
575 else if (regs == 0)
577 *cycles = 3;
578 /* Absolute. @pc+ */
579 dst = msp430dis_opcode (addr + 2, info);
580 cmd_len += 2;
581 sprintf (op1, "#%d", dst);
582 sprintf (comm1, "#0x%04x", PS (dst));
584 else
586 *cycles = 2;
587 sprintf (op1, "@r%d+", regs);
590 else if (as == 1)
592 if (regs == 0)
594 *cycles = 4;
595 /* PC relative. */
596 dst = msp430dis_opcode (addr + 2, info);
597 cmd_len += 2;
598 sprintf (op1, "0x%04x", PS (dst));
599 sprintf (comm1, "PC rel. 0x%04x",
600 PS ((short) addr + 2 + dst));
602 else if (regs == 2)
604 *cycles = 2;
605 /* Absolute. */
606 dst = msp430dis_opcode (addr + 2, info);
607 cmd_len += 2;
608 sprintf (op1, "&0x%04x", PS (dst));
609 sprintf (comm1, "0x%04x", PS (dst));
611 else if (regs == 3)
613 *cycles = 1;
614 sprintf (op1, "#1");
615 sprintf (comm1, "r3 As==01");
617 else
619 *cycles = 3;
620 /* Indexed. */
621 dst = msp430dis_opcode (addr + 2, info);
622 cmd_len += 2;
623 sprintf (op1, "%d(r%d)", dst, regs);
627 /* Destination. Special care needed on addr + XXXX. */
629 if (ad == 0)
631 /* Register. */
632 if (regd == 0)
634 *cycles += 1;
635 sprintf (op2, "r0");
637 else if (regd == 1)
638 sprintf (op2, "r1");
640 else if (regd == 2)
641 sprintf (op2, "r2");
643 else
644 sprintf (op2, "r%d", regd);
646 else /* ad == 1. */
648 * cycles += 3;
650 if (regd == 0)
652 /* PC relative. */
653 *cycles += 1;
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));
658 cmd_len += 2;
660 else if (regd == 2)
662 /* Absolute. */
663 dst = msp430dis_opcode (addr + cmd_len, info);
664 cmd_len += 2;
665 sprintf (op2, "&0x%04x", PS (dst));
667 else
669 dst = msp430dis_opcode (addr + cmd_len, info);
670 cmd_len += 2;
671 sprintf (op2, "%d(r%d)", dst, regd);
675 return cmd_len;
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;
684 unsigned short insn;
685 char *op1;
686 char *comm1;
687 int *cycles;
689 int regs = 0, regd = 0;
690 int ad = 0, as = 0;
691 int cmd_len = 2;
692 short dst = 0;
694 regd = insn & 0x0f;
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. */
700 return 0;
702 /* dst is a source register. */
703 if (as == 0)
705 /* Constants. */
706 if (regs == 3)
708 *cycles = 1;
709 sprintf (op1, "#0");
710 sprintf (comm1, "r3 As==00");
712 else
714 /* Register. */
715 *cycles = 1;
716 sprintf (op1, "r%d", regs);
719 else if (as == 2)
721 if (regs == 2)
723 *cycles = 2;
724 sprintf (op1, "#4");
725 sprintf (comm1, "r2 As==10");
727 else if (regs == 3)
729 *cycles = 1;
730 sprintf (op1, "#2");
731 sprintf (comm1, "r3 As==10");
733 else
735 /* Indexed register mode @Rn. */
736 *cycles = 2;
737 sprintf (op1, "@r%d", regs);
740 else if (as == 3)
742 if (regs == 2)
744 *cycles = 1;
745 sprintf (op1, "#8");
746 sprintf (comm1, "r2 As==11");
748 else if (regs == 3)
750 *cycles = 1;
751 sprintf (op1, "#-1");
752 sprintf (comm1, "r3 As==11");
754 else if (regs == 0)
756 /* Absolute. @pc+ */
757 *cycles = 3;
758 dst = msp430dis_opcode (addr + 2, info);
759 cmd_len += 2;
760 sprintf (op1, "#0x%04x", PS (dst));
762 else
764 *cycles = 2;
765 sprintf (op1, "@r%d+", regs);
768 else if (as == 1)
770 * cycles = 3;
772 if (regs == 0)
774 /* PC relative. */
775 dst = msp430dis_opcode (addr + 2, info);
776 cmd_len += 2;
777 (*cycles)++;
778 sprintf (op1, "0x%04x", PS (dst));
779 sprintf (comm1, "PC rel. 0x%04x",
780 PS ((short) addr + 2 + dst));
782 else if (regs == 2)
784 /* Absolute. */
785 dst = msp430dis_opcode (addr + 2, info);
786 cmd_len += 2;
787 sprintf (op1, "&0x%04x", PS (dst));
789 else if (regs == 3)
791 (*cycles)--;
792 sprintf (op1, "#1");
793 sprintf (comm1, "r3 As==01");
795 else
797 /* Indexd. */
798 dst = msp430dis_opcode (addr + 2, info);
799 cmd_len += 2;
800 sprintf (op1, "%d(r%d)", dst, regs);
804 return cmd_len;