Fix seg fault in linker when performing garbage collection on COFF based targets.
[external/binutils.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 }