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