PR binutils/15834
[deliverable/binutils-gdb.git] / opcodes / msp430-dis.c
1 /* Disassemble MSP430 instructions.
2 Copyright (C) 2002-2013 Free Software Foundation, Inc.
3
4 Contributed by Dmitry Diky <diwil@mail.ru>
5
6 This file is part of the GNU opcodes library.
7
8 This library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
12
13 It is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
22
23 #include "sysdep.h"
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <sys/types.h>
27
28 #include "dis-asm.h"
29 #include "opintl.h"
30 #include "libiberty.h"
31
32 #define DASM_SECTION
33 #include "opcode/msp430.h"
34 #undef DASM_SECTION
35
36
37 #define PS(x) (0xffff & (x))
38
39 static unsigned short
40 msp430dis_opcode (bfd_vma addr, disassemble_info *info)
41 {
42 bfd_byte buffer[2];
43 int status;
44
45 status = info->read_memory_func (addr, buffer, 2, info);
46 if (status != 0)
47 {
48 info->memory_error_func (status, addr, info);
49 return -1;
50 }
51 return bfd_getl16 (buffer);
52 }
53
54 static int
55 msp430_nooperands (struct msp430_opcode_s *opcode,
56 bfd_vma addr ATTRIBUTE_UNUSED,
57 unsigned short insn ATTRIBUTE_UNUSED,
58 char *comm,
59 int *cycles)
60 {
61 /* Pop with constant. */
62 if (insn == 0x43b2)
63 return 0;
64 if (insn == opcode->bin_opcode)
65 return 2;
66
67 if (opcode->fmt == 0)
68 {
69 if ((insn & 0x0f00) != 3 || (insn & 0x0f00) != 2)
70 return 0;
71
72 strcpy (comm, "emulated...");
73 *cycles = 1;
74 }
75 else
76 {
77 strcpy (comm, "return from interupt");
78 *cycles = 5;
79 }
80
81 return 2;
82 }
83
84 static int
85 print_as2_reg_name (int regno, char * op1, char * comm1,
86 int c2, int c3, int cd)
87 {
88 switch (regno)
89 {
90 case 2:
91 sprintf (op1, "#4");
92 sprintf (comm1, "r2 As==10");
93 return c2;
94
95 case 3:
96 sprintf (op1, "#2");
97 sprintf (comm1, "r3 As==10");
98 return c3;
99
100 default:
101 /* Indexed register mode @Rn. */
102 sprintf (op1, "@r%d", regno);
103 return cd;
104 }
105 }
106
107 static int
108 print_as3_reg_name (int regno, char * op1, char * comm1,
109 int c2, int c3, int cd)
110 {
111 switch (regno)
112 {
113 case 2:
114 sprintf (op1, "#8");
115 sprintf (comm1, "r2 As==11");
116 return c2;
117
118 case 3:
119 sprintf (op1, "#-1");
120 sprintf (comm1, "r3 As==11");
121 return c3;
122
123 default:
124 /* Post incremented @Rn+. */
125 sprintf (op1, "@r%d+", regno);
126 return cd;
127 }
128 }
129
130 static int
131 msp430_singleoperand (disassemble_info *info,
132 struct msp430_opcode_s *opcode,
133 bfd_vma addr,
134 unsigned short insn,
135 char *op,
136 char *comm,
137 unsigned short extension_word,
138 int *cycles)
139 {
140 int regs = 0, regd = 0;
141 int ad = 0, as = 0;
142 int where = 0;
143 int cmd_len = 2;
144 int dst = 0;
145 int fmt;
146 int extended_dst = extension_word & 0xf;
147
148 regd = insn & 0x0f;
149 regs = (insn & 0x0f00) >> 8;
150 as = (insn & 0x0030) >> 4;
151 ad = (insn & 0x0080) >> 7;
152
153 if (opcode->fmt < 0)
154 fmt = (- opcode->fmt) - 1;
155 else
156 fmt = opcode->fmt;
157
158 switch (fmt)
159 {
160 case 0: /* Emulated work with dst register. */
161 if (regs != 2 && regs != 3 && regs != 1)
162 return 0;
163
164 /* Check if not clr insn. */
165 if (opcode->bin_opcode == 0x4300 && (ad || as))
166 return 0;
167
168 /* Check if really inc, incd insns. */
169 if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3)
170 return 0;
171
172 if (ad == 0)
173 {
174 *cycles = 1;
175
176 /* Register. */
177 if (regd == 0)
178 {
179 *cycles += 1;
180 sprintf (op, "r0");
181 }
182 else if (regd == 1)
183 sprintf (op, "r1");
184
185 else if (regd == 2)
186 sprintf (op, "r2");
187
188 else
189 sprintf (op, "r%d", regd);
190 }
191 else /* ad == 1 msp430dis_opcode. */
192 {
193 if (regd == 0)
194 {
195 /* PC relative. */
196 dst = msp430dis_opcode (addr + 2, info);
197 cmd_len += 2;
198 *cycles = 4;
199 sprintf (op, "0x%04x", dst);
200 sprintf (comm, "PC rel. abs addr 0x%04x",
201 PS ((short) (addr + 2) + dst));
202 if (extended_dst)
203 {
204 dst |= extended_dst << 16;
205 sprintf (op, "0x%05x", dst);
206 sprintf (comm, "PC rel. abs addr 0x%05lx",
207 (long)((addr + 2 + dst) & 0xfffff));
208 }
209 }
210 else if (regd == 2)
211 {
212 /* Absolute. */
213 dst = msp430dis_opcode (addr + 2, info);
214 cmd_len += 2;
215 *cycles = 4;
216 sprintf (op, "&0x%04x", PS (dst));
217 if (extended_dst)
218 {
219 dst |= extended_dst << 16;
220 sprintf (op, "&0x%05x", dst & 0xfffff);
221 }
222 }
223 else
224 {
225 dst = msp430dis_opcode (addr + 2, info);
226 cmd_len += 2;
227 *cycles = 4;
228 if (extended_dst)
229 {
230 dst |= extended_dst << 16;
231 if (dst & 0x80000)
232 dst |= -1 << 20;
233 }
234 else if (dst & 0x8000)
235 dst |= -1 << 16;
236 sprintf (op, "%d(r%d)", dst, regd);
237 }
238 }
239 break;
240
241 case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
242 if (as == 0)
243 {
244 if (regd == 3)
245 {
246 /* Constsnts. */
247 sprintf (op, "#0");
248 sprintf (comm, "r3 As==00");
249 }
250 else
251 {
252 /* Register. */
253 sprintf (op, "r%d", regd);
254 }
255 *cycles = 1;
256 }
257 else if (as == 2)
258 {
259 * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3);
260 }
261 else if (as == 3)
262 {
263 if (regd == 0)
264 {
265 *cycles = 3;
266 /* absolute. @pc+ */
267 dst = msp430dis_opcode (addr + 2, info);
268 cmd_len += 2;
269 sprintf (op, "#%d", dst);
270 if (dst > 9 || dst < 0)
271 sprintf (comm, "#0x%04x", PS (dst));
272 if (extended_dst)
273 {
274 dst |= extended_dst << 16;
275 if (dst & 0x80000)
276 dst |= -1 << 20;
277 sprintf (op, "#%d", dst);
278 if (dst > 9 || dst < 0)
279 sprintf (comm, "#0x%05x", dst);
280 }
281 }
282 else
283 * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
284 }
285 else if (as == 1)
286 {
287 *cycles = 4;
288 if (regd == 0)
289 {
290 /* PC relative. */
291 dst = msp430dis_opcode (addr + 2, info);
292 cmd_len += 2;
293 sprintf (op, "0x%04x", PS (dst));
294 sprintf (comm, "PC rel. 0x%04x",
295 PS ((short) addr + 2 + dst));
296 if (extended_dst)
297 {
298 dst |= extended_dst << 16;
299 sprintf (op, "0x%05x", dst & 0xffff);
300 sprintf (comm, "PC rel. 0x%05lx",
301 (long)((addr + 2 + dst) & 0xfffff));
302 }
303 }
304 else if (regd == 2)
305 {
306 /* Absolute. */
307 dst = msp430dis_opcode (addr + 2, info);
308 cmd_len += 2;
309 sprintf (op, "&0x%04x", PS (dst));
310 if (extended_dst)
311 {
312 dst |= extended_dst << 16;
313 sprintf (op, "&0x%05x", dst & 0xfffff);
314 }
315 }
316 else if (regd == 3)
317 {
318 *cycles = 1;
319 sprintf (op, "#1");
320 sprintf (comm, "r3 As==01");
321 }
322 else
323 {
324 /* Indexed. */
325 dst = msp430dis_opcode (addr + 2, info);
326 cmd_len += 2;
327 if (extended_dst)
328 {
329 dst |= extended_dst << 16;
330 if (dst & 0x80000)
331 dst |= -1 << 20;
332 }
333 else if (dst & 0x8000)
334 dst |= -1 << 16;
335 sprintf (op, "%d(r%d)", dst, regd);
336 if (dst > 9 || dst < 0)
337 sprintf (comm, "%05x", dst);
338 }
339 }
340 break;
341
342 case 3: /* Jumps. */
343 where = insn & 0x03ff;
344 if (where & 0x200)
345 where |= ~0x03ff;
346 if (where > 512 || where < -511)
347 return 0;
348
349 where *= 2;
350 sprintf (op, "$%+-8d", where + 2);
351 sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where));
352 *cycles = 2;
353 return 2;
354 break;
355 default:
356 cmd_len = 0;
357 }
358
359 return cmd_len;
360 }
361
362 static int
363 msp430_doubleoperand (disassemble_info *info,
364 struct msp430_opcode_s *opcode,
365 bfd_vma addr,
366 unsigned short insn,
367 char *op1,
368 char *op2,
369 char *comm1,
370 char *comm2,
371 unsigned short extension_word,
372 int *cycles)
373 {
374 int regs = 0, regd = 0;
375 int ad = 0, as = 0;
376 int cmd_len = 2;
377 int dst = 0;
378 int fmt;
379 int extended_dst = extension_word & 0xf;
380 int extended_src = (extension_word >> 7) & 0xf;
381
382 regd = insn & 0x0f;
383 regs = (insn & 0x0f00) >> 8;
384 as = (insn & 0x0030) >> 4;
385 ad = (insn & 0x0080) >> 7;
386
387 if (opcode->fmt < 0)
388 fmt = (- opcode->fmt) - 1;
389 else
390 fmt = opcode->fmt;
391
392 if (fmt == 0)
393 {
394 /* Special case: rla and rlc are the only 2 emulated instructions that
395 fall into two operand instructions. */
396 /* With dst, there are only:
397 Rm Register,
398 x(Rm) Indexed,
399 0xXXXX Relative,
400 &0xXXXX Absolute
401 emulated_ins dst
402 basic_ins dst, dst. */
403
404 if (regd != regs || as != ad)
405 return 0; /* May be 'data' section. */
406
407 if (ad == 0)
408 {
409 /* Register mode. */
410 if (regd == 3)
411 {
412 strcpy (comm1, _("Illegal as emulation instr"));
413 return -1;
414 }
415
416 sprintf (op1, "r%d", regd);
417 *cycles = 1;
418 }
419 else /* ad == 1 */
420 {
421 if (regd == 0)
422 {
423 /* PC relative, Symbolic. */
424 dst = msp430dis_opcode (addr + 2, info);
425 cmd_len += 4;
426 *cycles = 6;
427 sprintf (op1, "0x%04x", PS (dst));
428 sprintf (comm1, "PC rel. 0x%04x",
429 PS ((short) addr + 2 + dst));
430 if (extended_dst)
431 {
432 dst |= extended_dst << 16;
433 if (dst & 0x80000)
434 dst |= -1 << 20;
435 sprintf (op1, "0x%05x", dst & 0xfffff);
436 sprintf (comm1, "PC rel. 0x%05lx",
437 (long)((addr + 2 + dst) & 0xfffff));
438 }
439 }
440 else if (regd == 2)
441 {
442 /* Absolute. */
443 dst = msp430dis_opcode (addr + 2, info);
444 /* If the 'src' field is not the same as the dst
445 then this is not an rla instruction. */
446 if (dst != msp430dis_opcode (addr + 4, info))
447 return 0;
448 cmd_len += 4;
449 *cycles = 6;
450 sprintf (op1, "&0x%04x", PS (dst));
451 if (extended_dst)
452 {
453 dst |= extended_dst << 16;
454 sprintf (op1, "&0x%05x", dst & 0xfffff);
455 }
456 }
457 else
458 {
459 /* Indexed. */
460 dst = msp430dis_opcode (addr + 2, info);
461 if (extended_dst)
462 {
463 dst |= extended_dst << 16;
464 if (dst & 0x80000)
465 dst |= -1 << 20;
466 }
467 else if (dst & 0x8000)
468 dst |= -1 << 16;
469 cmd_len += 4;
470 *cycles = 6;
471 sprintf (op1, "%d(r%d)", dst, regd);
472 if (dst > 9 || dst < -9)
473 sprintf (comm1, "#0x%05x", dst);
474 }
475 }
476
477 *op2 = 0;
478 *comm2 = 0;
479
480 return cmd_len;
481 }
482
483 /* Two operands exactly. */
484 if (ad == 0 && regd == 3)
485 {
486 /* R2/R3 are illegal as dest: may be data section. */
487 strcpy (comm1, _("Illegal as 2-op instr"));
488 return -1;
489 }
490
491 /* Source. */
492 if (as == 0)
493 {
494 *cycles = 1;
495 if (regs == 3)
496 {
497 /* Constants. */
498 sprintf (op1, "#0");
499 sprintf (comm1, "r3 As==00");
500 }
501 else
502 {
503 /* Register. */
504 sprintf (op1, "r%d", regs);
505 }
506 }
507 else if (as == 2)
508 {
509 * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2);
510 }
511 else if (as == 3)
512 {
513 if (regs == 0)
514 {
515 *cycles = 3;
516 /* Absolute. @pc+. */
517 dst = msp430dis_opcode (addr + 2, info);
518 cmd_len += 2;
519 sprintf (op1, "#%d", dst);
520 if (dst > 9 || dst < 0)
521 sprintf (comm1, "#0x%04x", PS (dst));
522 if (extended_src)
523 {
524 dst |= extended_src << 16;
525 if (dst & 0x80000)
526 dst |= -1 << 20;
527 sprintf (op1, "#%d", dst);
528 if (dst > 9 || dst < 0)
529 sprintf (comm1, "0x%05x", dst & 0xfffff);
530 }
531 }
532 else
533 * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
534 }
535 else if (as == 1)
536 {
537 if (regs == 0)
538 {
539 *cycles = 4;
540 /* PC relative. */
541 dst = msp430dis_opcode (addr + 2, info);
542 cmd_len += 2;
543 sprintf (op1, "0x%04x", PS (dst));
544 sprintf (comm1, "PC rel. 0x%04x",
545 PS ((short) addr + 2 + dst));
546 if (extended_src)
547 {
548 dst |= extended_src << 16;
549 if (dst & 0x80000)
550 dst |= -1 << 20;
551 sprintf (op1, "0x%05x", dst & 0xfffff);
552 sprintf (comm1, "PC rel. 0x%05lx",
553 (long) ((addr + 2 + dst) & 0xfffff));
554 }
555 }
556 else if (regs == 2)
557 {
558 *cycles = 2;
559 /* Absolute. */
560 dst = msp430dis_opcode (addr + 2, info);
561 cmd_len += 2;
562 sprintf (op1, "&0x%04x", PS (dst));
563 sprintf (comm1, "0x%04x", PS (dst));
564 if (extended_src)
565 {
566 dst |= extended_src << 16;
567 sprintf (op1, "&0x%05x", dst & 0xfffff);
568 * comm1 = 0;
569 }
570 }
571 else if (regs == 3)
572 {
573 *cycles = 1;
574 sprintf (op1, "#1");
575 sprintf (comm1, "r3 As==01");
576 }
577 else
578 {
579 *cycles = 3;
580 /* Indexed. */
581 dst = msp430dis_opcode (addr + 2, info);
582 cmd_len += 2;
583 if (extended_src)
584 {
585 dst |= extended_src << 16;
586 if (dst & 0x80000)
587 dst |= -1 << 20;
588 }
589 else if (dst & 0x8000)
590 dst |= -1 << 16;
591 sprintf (op1, "%d(r%d)", dst, regs);
592 if (dst > 9 || dst < -9)
593 sprintf (comm1, "0x%05x", dst);
594 }
595 }
596
597 /* Destination. Special care needed on addr + XXXX. */
598
599 if (ad == 0)
600 {
601 /* Register. */
602 if (regd == 0)
603 {
604 *cycles += 1;
605 sprintf (op2, "r0");
606 }
607 else if (regd == 1)
608 sprintf (op2, "r1");
609
610 else if (regd == 2)
611 sprintf (op2, "r2");
612
613 else
614 sprintf (op2, "r%d", regd);
615 }
616 else /* ad == 1. */
617 {
618 * cycles += 3;
619
620 if (regd == 0)
621 {
622 /* PC relative. */
623 *cycles += 1;
624 dst = msp430dis_opcode (addr + cmd_len, info);
625 sprintf (op2, "0x%04x", PS (dst));
626 sprintf (comm2, "PC rel. 0x%04x",
627 PS ((short) addr + cmd_len + dst));
628 if (extended_dst)
629 {
630 dst |= extended_dst << 16;
631 if (dst & 0x80000)
632 dst |= -1 << 20;
633 sprintf (op2, "0x%05x", dst & 0xfffff);
634 sprintf (comm2, "PC rel. 0x%05lx",
635 (long)((addr + cmd_len + dst) & 0xfffff));
636 }
637 cmd_len += 2;
638 }
639 else if (regd == 2)
640 {
641 /* Absolute. */
642 dst = msp430dis_opcode (addr + cmd_len, info);
643 cmd_len += 2;
644 sprintf (op2, "&0x%04x", PS (dst));
645 if (extended_dst)
646 {
647 dst |= extended_dst << 16;
648 sprintf (op2, "&0x%05x", dst & 0xfffff);
649 }
650 }
651 else
652 {
653 dst = msp430dis_opcode (addr + cmd_len, info);
654 cmd_len += 2;
655 if (dst & 0x8000)
656 dst |= -1 << 16;
657 if (dst > 9 || dst < 0)
658 sprintf (comm2, "0x%04x", PS (dst));
659 if (extended_dst)
660 {
661 dst |= extended_dst << 16;
662 if (dst & 0x80000)
663 dst |= -1 << 20;
664 if (dst > 9 || dst < 0)
665 sprintf (comm2, "0x%05x", dst & 0xfffff);
666 }
667 sprintf (op2, "%d(r%d)", dst, regd);
668 }
669 }
670
671 return cmd_len;
672 }
673
674 static int
675 msp430_branchinstr (disassemble_info *info,
676 struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
677 bfd_vma addr ATTRIBUTE_UNUSED,
678 unsigned short insn,
679 char *op1,
680 char *comm1,
681 int *cycles)
682 {
683 int regs = 0, regd = 0;
684 int as = 0;
685 int cmd_len = 2;
686 short dst = 0;
687
688 regd = insn & 0x0f;
689 regs = (insn & 0x0f00) >> 8;
690 as = (insn & 0x0030) >> 4;
691
692 if (regd != 0) /* Destination register is not a PC. */
693 return 0;
694
695 /* dst is a source register. */
696 if (as == 0)
697 {
698 /* Constants. */
699 if (regs == 3)
700 {
701 *cycles = 1;
702 sprintf (op1, "#0");
703 sprintf (comm1, "r3 As==00");
704 }
705 else
706 {
707 /* Register. */
708 *cycles = 1;
709 sprintf (op1, "r%d", regs);
710 }
711 }
712 else if (as == 2)
713 {
714 * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2);
715 }
716 else if (as == 3)
717 {
718 if (regs == 0)
719 {
720 /* Absolute. @pc+ */
721 *cycles = 3;
722 dst = msp430dis_opcode (addr + 2, info);
723 cmd_len += 2;
724 sprintf (op1, "#0x%04x", PS (dst));
725 }
726 else
727 * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
728 }
729 else if (as == 1)
730 {
731 * cycles = 3;
732
733 if (regs == 0)
734 {
735 /* PC relative. */
736 dst = msp430dis_opcode (addr + 2, info);
737 cmd_len += 2;
738 (*cycles)++;
739 sprintf (op1, "0x%04x", PS (dst));
740 sprintf (comm1, "PC rel. 0x%04x",
741 PS ((short) addr + 2 + dst));
742 }
743 else if (regs == 2)
744 {
745 /* Absolute. */
746 dst = msp430dis_opcode (addr + 2, info);
747 cmd_len += 2;
748 sprintf (op1, "&0x%04x", PS (dst));
749 }
750 else if (regs == 3)
751 {
752 (*cycles)--;
753 sprintf (op1, "#1");
754 sprintf (comm1, "r3 As==01");
755 }
756 else
757 {
758 /* Indexed. */
759 dst = msp430dis_opcode (addr + 2, info);
760 cmd_len += 2;
761 if (dst & 0x8000)
762 dst |= -1 << 16;
763 sprintf (op1, "%d(r%d)", dst, regs);
764 }
765 }
766
767 return cmd_len;
768 }
769
770 static int
771 msp430x_calla_instr (disassemble_info * info,
772 bfd_vma addr,
773 unsigned short insn,
774 char * op1,
775 char * comm1,
776 int * cycles)
777 {
778 unsigned int ureg = insn & 0xf;
779 int reg = insn & 0xf;
780 int am = (insn & 0xf0) >> 4;
781 int cmd_len = 2;
782 unsigned short udst = 0;
783 short dst = 0;
784
785 switch (am)
786 {
787 case 4: /* CALLA Rdst */
788 *cycles = 1;
789 sprintf (op1, "r%d", reg);
790 break;
791
792 case 5: /* CALLA x(Rdst) */
793 *cycles = 3;
794 dst = msp430dis_opcode (addr + 2, info);
795 cmd_len += 2;
796 sprintf (op1, "%d(r%d)", dst, reg);
797 if (reg == 0)
798 sprintf (comm1, "PC rel. 0x%05lx", (long) (addr + 2 + dst));
799 else
800 sprintf (comm1, "0x%05x", dst);
801 break;
802
803 case 6: /* CALLA @Rdst */
804 *cycles = 2;
805 sprintf (op1, "@r%d", reg);
806 break;
807
808 case 7: /* CALLA @Rdst+ */
809 *cycles = 2;
810 sprintf (op1, "@r%d+", reg);
811 break;
812
813 case 8: /* CALLA &abs20 */
814 udst = msp430dis_opcode (addr + 2, info);
815 cmd_len += 2;
816 *cycles = 4;
817 sprintf (op1, "&%d", (ureg << 16) + udst);
818 sprintf (comm1, "0x%05x", (ureg << 16) + udst);
819 break;
820
821 case 9: /* CALLA pcrel-sym */
822 dst = msp430dis_opcode (addr + 2, info);
823 cmd_len += 2;
824 *cycles = 4;
825 sprintf (op1, "%d(PC)", (reg << 16) + dst);
826 sprintf (comm1, "PC rel. 0x%05lx",
827 (long) (addr + 2 + dst + (reg << 16)));
828 break;
829
830 case 11: /* CALLA #imm20 */
831 udst = msp430dis_opcode (addr + 2, info);
832 cmd_len += 2;
833 *cycles = 4;
834 sprintf (op1, "#%d", (ureg << 16) + udst);
835 sprintf (comm1, "0x%05x", (ureg << 16) + udst);
836 break;
837
838 default:
839 strcpy (comm1, _("unrecognised CALLA addressing mode"));
840 return -1;
841 }
842
843 return cmd_len;
844 }
845
846 int
847 print_insn_msp430 (bfd_vma addr, disassemble_info *info)
848 {
849 void *stream = info->stream;
850 fprintf_ftype prin = info->fprintf_func;
851 struct msp430_opcode_s *opcode;
852 char op1[32], op2[32], comm1[64], comm2[64];
853 int cmd_len = 0;
854 unsigned short insn;
855 int cycles = 0;
856 char *bc = "";
857 unsigned short extension_word = 0;
858
859 insn = msp430dis_opcode (addr, info);
860 if (insn == (unsigned short) -1)
861 {
862 prin (stream, ".word 0xffff; ????");
863 return 2;
864 }
865
866 if (((int) addr & 0xffff) > 0xffdf)
867 {
868 (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn);
869 return 2;
870 }
871
872 *comm1 = 0;
873 *comm2 = 0;
874
875 /* Check for an extension word. */
876 if ((insn & 0xf800) == 0x1800)
877 {
878 extension_word = insn;
879 addr += 2;
880 insn = msp430dis_opcode (addr, info);
881 if (insn == (unsigned short) -1)
882 {
883 prin (stream, ".word 0x%04x, 0xffff; ????",
884 extension_word);
885 return 4;
886 }
887 }
888
889 for (opcode = msp430_opcodes; opcode->name; opcode++)
890 {
891 if ((insn & opcode->bin_mask) == opcode->bin_opcode
892 && opcode->bin_opcode != 0x9300)
893 {
894 *op1 = 0;
895 *op2 = 0;
896 *comm1 = 0;
897 *comm2 = 0;
898
899 /* r0 as destination. Ad should be zero. */
900 if (opcode->insn_opnumb == 3
901 && (insn & 0x000f) == 0
902 && (insn & 0x0080) == 0)
903 {
904 cmd_len +=
905 msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
906 &cycles);
907 if (cmd_len)
908 break;
909 }
910
911 switch (opcode->insn_opnumb)
912 {
913 int n;
914 int reg;
915
916 case 4:
917 cmd_len += msp430x_calla_instr (info, addr, insn,
918 op1, comm1, & cycles);
919 break;
920
921 case 5: /* PUSHM/POPM */
922 n = (insn & 0xf0) >> 4;
923 reg = (insn & 0xf);
924
925 sprintf (op1, "#%d", n + 1);
926 if (opcode->bin_opcode == 0x1400)
927 /* PUSHM */
928 sprintf (op2, "r%d", reg);
929 else
930 /* POPM */
931 sprintf (op2, "r%d", reg + n);
932 if (insn & 0x100)
933 sprintf (comm1, "16-bit words");
934 else
935 {
936 sprintf (comm1, "20-bit words");
937 bc =".a";
938 }
939
940 cycles = 2; /*FIXME*/
941 cmd_len = 2;
942 break;
943
944 case 6: /* RRAM, RRCM, RRUM, RLAM. */
945 n = ((insn >> 10) & 0x3) + 1;
946 reg = (insn & 0xf);
947 if ((insn & 0x10) == 0)
948 bc =".a";
949 sprintf (op1, "#%d", n);
950 sprintf (op2, "r%d", reg);
951 cycles = 2; /*FIXME*/
952 cmd_len = 2;
953 break;
954
955 case 8: /* ADDA, CMPA, SUBA. */
956 reg = (insn & 0xf);
957 n = (insn >> 8) & 0xf;
958 if (insn & 0x40)
959 {
960 sprintf (op1, "r%d", n);
961 cmd_len = 2;
962 }
963 else
964 {
965 n <<= 16;
966 n |= msp430dis_opcode (addr + 2, info);
967 sprintf (op1, "#%d", n);
968 if (n > 9 || n < 0)
969 sprintf (comm1, "0x%05x", n);
970 cmd_len = 4;
971 }
972 sprintf (op2, "r%d", reg);
973 cycles = 2; /*FIXME*/
974 break;
975
976 case 9: /* MOVA */
977 reg = (insn & 0xf);
978 n = (insn >> 8) & 0xf;
979 switch ((insn >> 4) & 0xf)
980 {
981 case 0: /* MOVA @Rsrc, Rdst */
982 cmd_len = 2;
983 sprintf (op1, "@r%d", n);
984 if (strcmp (opcode->name, "bra") != 0)
985 sprintf (op2, "r%d", reg);
986 break;
987
988 case 1: /* MOVA @Rsrc+, Rdst */
989 cmd_len = 2;
990 if (strcmp (opcode->name, "reta") != 0)
991 {
992 sprintf (op1, "@r%d+", n);
993 if (strcmp (opcode->name, "bra") != 0)
994 sprintf (op2, "r%d", reg);
995 }
996 break;
997
998 case 2: /* MOVA &abs20, Rdst */
999 cmd_len = 4;
1000 n <<= 16;
1001 n |= msp430dis_opcode (addr + 2, info);
1002 sprintf (op1, "&%d", n);
1003 if (n > 9 || n < 0)
1004 sprintf (comm1, "0x%05x", n);
1005 if (strcmp (opcode->name, "bra") != 0)
1006 sprintf (op2, "r%d", reg);
1007 break;
1008
1009 case 3: /* MOVA x(Rsrc), Rdst */
1010 cmd_len = 4;
1011 if (strcmp (opcode->name, "bra") != 0)
1012 sprintf (op2, "r%d", reg);
1013 reg = n;
1014 n = msp430dis_opcode (addr + 2, info);
1015 if (n & 0x8000)
1016 n |= -1 << 16;
1017 sprintf (op1, "%d(r%d)", n, reg);
1018 if (n > 9 || n < 0)
1019 {
1020 if (reg == 0)
1021 sprintf (comm1, "PC rel. 0x%05lx",
1022 (long) (addr + 2 + n));
1023 else
1024 sprintf (comm1, "0x%05x", n);
1025 }
1026 break;
1027
1028 case 6: /* MOVA Rsrc, &abs20 */
1029 cmd_len = 4;
1030 reg <<= 16;
1031 reg |= msp430dis_opcode (addr + 2, info);
1032 sprintf (op1, "r%d", n);
1033 sprintf (op2, "&%d", reg);
1034 if (reg > 9 || reg < 0)
1035 sprintf (comm2, "0x%05x", reg);
1036 break;
1037
1038 case 7: /* MOVA Rsrc, x(Rdst) */
1039 cmd_len = 4;
1040 sprintf (op1, "r%d", n);
1041 n = msp430dis_opcode (addr + 2, info);
1042 if (n & 0x8000)
1043 n |= -1 << 16;
1044 sprintf (op2, "%d(r%d)", n, reg);
1045 if (n > 9 || n < 0)
1046 {
1047 if (reg == 0)
1048 sprintf (comm2, "PC rel. 0x%05lx",
1049 (long) (addr + 2 + n));
1050 else
1051 sprintf (comm2, "0x%05x", n);
1052 }
1053 break;
1054
1055 case 8: /* MOVA #imm20, Rdst */
1056 cmd_len = 4;
1057 n <<= 16;
1058 n |= msp430dis_opcode (addr + 2, info);
1059 if (n & 0x80000)
1060 n |= -1 << 20;
1061 sprintf (op1, "#%d", n);
1062 if (n > 9 || n < 0)
1063 sprintf (comm1, "0x%05x", n);
1064 if (strcmp (opcode->name, "bra") != 0)
1065 sprintf (op2, "r%d", reg);
1066 break;
1067
1068 case 12: /* MOVA Rsrc, Rdst */
1069 cmd_len = 2;
1070 sprintf (op1, "r%d", n);
1071 if (strcmp (opcode->name, "bra") != 0)
1072 sprintf (op2, "r%d", reg);
1073 break;
1074
1075 default:
1076 break;
1077 }
1078 cycles = 2; /* FIXME */
1079 break;
1080 }
1081
1082 if (cmd_len)
1083 break;
1084
1085 switch (opcode->insn_opnumb)
1086 {
1087 case 0:
1088 cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles);
1089 break;
1090 case 2:
1091 cmd_len +=
1092 msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
1093 comm1, comm2,
1094 extension_word,
1095 &cycles);
1096 if (insn & BYTE_OPERATION)
1097 {
1098 if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
1099 bc = ".a";
1100 else
1101 bc = ".b";
1102 }
1103 else if (extension_word)
1104 {
1105 if (extension_word & (1 << 6))
1106 bc = ".w";
1107 else
1108 {
1109 bc = ".?";
1110 sprintf (comm2, _("Reserved use of A/L and B/W bits detected"));
1111 }
1112 }
1113
1114 break;
1115 case 1:
1116 cmd_len +=
1117 msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
1118 extension_word,
1119 &cycles);
1120 if (extension_word
1121 && (strcmp (opcode->name, "swpb") == 0
1122 || strcmp (opcode->name, "sxt") == 0))
1123 {
1124 if (insn & BYTE_OPERATION)
1125 {
1126 bc = ".?";
1127 sprintf (comm2, _("Reserved use of A/L and B/W bits detected"));
1128 }
1129 else if (extension_word & BYTE_OPERATION)
1130 bc = ".w";
1131 else
1132 bc = ".a";
1133 }
1134 else if (insn & BYTE_OPERATION && opcode->fmt != 3)
1135 {
1136 if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
1137 bc = ".a";
1138 else
1139 bc = ".b";
1140 }
1141 else if (extension_word)
1142 {
1143 if (extension_word & (1 << 6))
1144 bc = ".w";
1145 else
1146 {
1147 bc = ".?";
1148 sprintf (comm2, _("Reserved use of A/L and B/W bits detected"));
1149 }
1150 }
1151 break;
1152 default:
1153 break;
1154 }
1155 }
1156
1157 if (cmd_len)
1158 break;
1159 }
1160
1161 if (cmd_len < 1)
1162 {
1163 /* Unknown opcode, or invalid combination of operands. */
1164 if (extension_word)
1165 {
1166 prin (stream, ".word 0x%04x, 0x%04x; ????", extension_word, PS (insn));
1167 if (*comm1)
1168 prin (stream, "\t %s", comm1);
1169 return 4;
1170 }
1171 (*prin) (stream, ".word 0x%04x; ????", PS (insn));
1172 return 2;
1173 }
1174
1175 /* Display the repeat count (if set) for extended register mode. */
1176 if (cmd_len == 2 && ((extension_word & 0xf) != 0))
1177 {
1178 if (extension_word & (1 << 7))
1179 prin (stream, "rpt r%d { ", extension_word & 0xf);
1180 else
1181 prin (stream, "rpt #%d { ", (extension_word & 0xf) + 1);
1182 }
1183
1184 if (extension_word && opcode->name[strlen (opcode->name) - 1] != 'x')
1185 (*prin) (stream, "%sx%s", opcode->name, bc);
1186 else
1187 (*prin) (stream, "%s%s", opcode->name, bc);
1188
1189 if (*op1)
1190 (*prin) (stream, "\t%s", op1);
1191 if (*op2)
1192 (*prin) (stream, ",");
1193
1194 if (strlen (op1) < 7)
1195 (*prin) (stream, "\t");
1196 if (!strlen (op1))
1197 (*prin) (stream, "\t");
1198
1199 if (*op2)
1200 (*prin) (stream, "%s", op2);
1201 if (strlen (op2) < 8)
1202 (*prin) (stream, "\t");
1203
1204 if (*comm1 || *comm2)
1205 (*prin) (stream, ";");
1206 else if (cycles)
1207 {
1208 if (*op2)
1209 (*prin) (stream, ";");
1210 else
1211 {
1212 if (strlen (op1) < 7)
1213 (*prin) (stream, ";");
1214 else
1215 (*prin) (stream, "\t;");
1216 }
1217 }
1218 if (*comm1)
1219 (*prin) (stream, "%s", comm1);
1220 if (*comm1 && *comm2)
1221 (*prin) (stream, ",");
1222 if (*comm2)
1223 (*prin) (stream, " %s", comm2);
1224
1225 if (extension_word)
1226 cmd_len += 2;
1227
1228 return cmd_len;
1229 }
This page took 0.055667 seconds and 5 git commands to generate.