Release 2.33.1
[external/binutils.git] / opcodes / msp430-dis.c
1 /* Disassemble MSP430 instructions.
2    Copyright (C) 2002-2019 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 "disassemble.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               else
274                 return -1;
275             }
276           else if (regd == 2)
277             {
278               /* Absolute.  */
279               if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
280                 {
281                   cmd_len += 2;
282                   *cycles = 4;
283                   sprintf (op, "&0x%04x", PS (dst));
284                   if (extended_dst)
285                     {
286                       dst |= extended_dst << 16;
287                       sprintf (op, "&0x%05x", dst & 0xfffff);
288                     }
289                 }
290               else
291                 return -1;
292             }
293           else
294             {
295               if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
296                 {
297                   cmd_len += 2;
298                   *cycles = 4;
299                   if (extended_dst)
300                     {
301                       dst |= extended_dst << 16;
302                       if (dst & 0x80000)
303                         dst |= -1U << 20;
304                     }
305                   sprintf (op, "%d(r%d)", dst, regd);
306                 }
307               else
308                 return -1;
309             }
310         }
311       break;
312
313     case 2:     /* rrc, push, call, swpb, rra, sxt, push, call, reti etc...  */
314       if (as == 0)
315         {
316           if (regd == 3)
317             {
318               /* Constsnts.  */
319               sprintf (op, "#0");
320               sprintf (comm, "r3 As==00");
321             }
322           else
323             {
324               /* Register.  */
325               sprintf (op, "r%d", regd);
326             }
327           *cycles = 1;
328         }
329       else if (as == 2)
330         {
331           * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3);
332         }
333       else if (as == 3)
334         {
335           if (regd == 0)
336             {
337               *cycles = 3;
338               /* absolute. @pc+ */
339               if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
340                 {
341                   cmd_len += 2;
342                   sprintf (op, "#%d", dst);
343                   if (dst > 9 || dst < 0)
344                     sprintf (comm, "#0x%04x", PS (dst));
345                   if (extended_dst)
346                     {
347                       dst |= extended_dst << 16;
348                       if (dst & 0x80000)
349                         dst |= -1U << 20;
350                       sprintf (op, "#%d", dst);
351                       if (dst > 9 || dst < 0)
352                         sprintf (comm, "#0x%05x", dst);
353                     }
354                 }
355               else
356                 return -1;
357             }
358           else
359             * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
360         }
361       else if (as == 1)
362         {
363           *cycles = 4;
364           if (regd == 0)
365             {
366               /* PC relative.  */
367               if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
368                 {
369                   cmd_len += 2;
370                   sprintf (op, "0x%04x", PS (dst));
371                   sprintf (comm, "PC rel. 0x%04x",
372                            PS ((short) addr + 2 + dst));
373                   if (extended_dst)
374                     {
375                       dst |= extended_dst << 16;
376                       sprintf (op, "0x%05x", dst & 0xffff);
377                       sprintf (comm, "PC rel. 0x%05lx",
378                                (long)((addr + 2 + dst) & 0xfffff));
379                     }
380                 }
381               else
382                 return -1;
383             }
384           else if (regd == 2)
385             {
386               /* Absolute.  */
387               if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
388                 {
389                   cmd_len += 2;
390                   sprintf (op, "&0x%04x", PS (dst));
391                   if (extended_dst)
392                     {
393                       dst |= extended_dst << 16;
394                       sprintf (op, "&0x%05x", dst & 0xfffff);
395                     }
396                 }
397               else
398                 return -1;
399             }
400           else if (regd == 3)
401             {
402               *cycles = 1;
403               sprintf (op, "#1");
404               sprintf (comm, "r3 As==01");
405             }
406           else
407             {
408               /* Indexed.  */
409               if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
410                 {
411                   cmd_len += 2;
412                   if (extended_dst)
413                     {
414                       dst |= extended_dst << 16;
415                       if (dst & 0x80000)
416                         dst |= -1U << 20;
417                     }
418                   sprintf (op, "%d(r%d)", dst, regd);
419                   if (dst > 9 || dst < 0)
420                     sprintf (comm, "%05x", dst);
421                 }
422               else
423                 return -1;
424             }
425         }
426       break;
427
428     case 3:                     /* Jumps.  */
429       where = insn & 0x03ff;
430       if (where & 0x200)
431         where |= ~0x03ff;
432       if (where > 512 || where < -511)
433         return 0;
434
435       where *= 2;
436       sprintf (op, "$%+-8d", where + 2);
437       sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where));
438       *cycles = 2;
439       return 2;
440       break;
441
442     default:
443       cmd_len = 0;
444     }
445
446   return cmd_len;
447 }
448
449 static int
450 msp430_doubleoperand (disassemble_info *info,
451                       struct msp430_opcode_s *opcode,
452                       bfd_vma addr,
453                       unsigned short insn,
454                       char *op1,
455                       char *op2,
456                       char *comm1,
457                       char *comm2,
458                       unsigned short extension_word,
459                       int *cycles)
460 {
461   int regs = 0, regd = 0;
462   int ad = 0, as = 0;
463   int cmd_len = 2;
464   int dst = 0;
465   int fmt;
466   int extended_dst = extension_word & 0xf;
467   int extended_src = (extension_word >> 7) & 0xf;
468
469   regd = insn & 0x0f;
470   regs = (insn & 0x0f00) >> 8;
471   as = (insn & 0x0030) >> 4;
472   ad = (insn & 0x0080) >> 7;
473
474   if (opcode->fmt < 0)
475     fmt = (- opcode->fmt) - 1;
476   else
477     fmt = opcode->fmt;
478
479   if (fmt == 0)
480     {
481       /* Special case: rla and rlc are the only 2 emulated instructions that
482          fall into two operand instructions.  */
483       /* With dst, there are only:
484          Rm             Register,
485          x(Rm)          Indexed,
486          0xXXXX         Relative,
487          &0xXXXX        Absolute
488          emulated_ins   dst
489          basic_ins      dst, dst.  */
490
491       if (regd != regs || as != ad)
492         return 0;               /* May be 'data' section.  */
493
494       if (ad == 0)
495         {
496           /* Register mode.  */
497           if (regd == 3)
498             {
499               strcpy (comm1, _("Warning: illegal as emulation instr"));
500               return -1;
501             }
502
503           sprintf (op1, "r%d", regd);
504           *cycles = 1;
505         }
506       else                      /* ad == 1 */
507         {
508           if (regd == 0)
509             {
510               /* PC relative, Symbolic.  */
511               if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
512                 {
513                   cmd_len += 4;
514                   *cycles = 6;
515                   sprintf (op1, "0x%04x", PS (dst));
516                   sprintf (comm1, "PC rel. 0x%04x",
517                            PS ((short) addr + 2 + dst));
518                   if (extension_word)
519                     {
520                       dst |= extended_dst << 16;
521                       if (dst & 0x80000)
522                         dst |= -1U << 20;
523                       sprintf (op1, "0x%05x", dst & 0xfffff);
524                       sprintf (comm1, "PC rel. 0x%05lx",
525                                (long)((addr + 2 + dst) & 0xfffff));
526                     }
527                 }
528               else
529                 return -1;
530             }
531           else if (regd == 2)
532             {
533               /* Absolute.  */
534               if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
535                 {
536                   int src;
537
538                   /* If the 'src' field is not the same as the dst
539                      then this is not an rla instruction.  */
540                   if (msp430dis_opcode_signed (addr + 4, info, &src, comm2))
541                     {
542                       if (src != dst)
543                         return 0;
544                     }
545                   else
546                     return -1;
547                   cmd_len += 4;
548                   *cycles = 6;
549                   sprintf (op1, "&0x%04x", PS (dst));
550                   if (extension_word)
551                     {
552                       dst |= extended_dst << 16;
553                       sprintf (op1, "&0x%05x", dst & 0xfffff);
554                     }
555                 }
556               else
557                 return -1;
558             }
559           else
560             {
561               /* Indexed.  */
562               if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
563                 {
564                   if (extension_word)
565                     {
566                       dst |= extended_dst << 16;
567                       if (dst & 0x80000)
568                         dst |= -1U << 20;
569                     }
570                   cmd_len += 4;
571                   *cycles = 6;
572                   sprintf (op1, "%d(r%d)", dst, regd);
573                   if (dst > 9 || dst < -9)
574                     sprintf (comm1, "#0x%05x", dst);
575                 }
576               else
577                 return -1;
578             }
579         }
580
581       *op2 = 0;
582       *comm2 = 0;
583
584       return cmd_len;
585     }
586
587   /* Two operands exactly.  */
588   if (ad == 0 && regd == 3)
589     {
590       /* R2/R3 are illegal as dest: may be data section.  */
591       strcpy (comm1, _("Warning: illegal as 2-op instr"));
592       return -1;
593     }
594
595   /* Source.  */
596   if (as == 0)
597     {
598       *cycles = 1;
599       if (regs == 3)
600         {
601           /* Constants.  */
602           sprintf (op1, "#0");
603           sprintf (comm1, "r3 As==00");
604         }
605       else
606         {
607           /* Register.  */
608           sprintf (op1, "r%d", regs);
609         }
610     }
611   else if (as == 2)
612     {
613       * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2);
614     }
615   else if (as == 3)
616     {
617       if (regs == 0)
618         {
619           *cycles = 3;
620           /* Absolute. @pc+.  */
621           if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
622             {
623               cmd_len += 2;
624               sprintf (op1, "#%d", dst);
625               if (dst > 9 || dst < 0)
626                 sprintf (comm1, "#0x%04x", PS (dst));
627               if (extension_word)
628                 {
629                   dst &= 0xffff;
630                   dst |= extended_src << 16;
631                   if (dst & 0x80000)
632                     dst |= -1U << 20;
633                   sprintf (op1, "#%d", dst);
634                   if (dst > 9 || dst < 0)
635                     sprintf (comm1, "0x%05x", dst & 0xfffff);
636                 }
637             }
638           else
639             return -1;
640         }
641       else
642         * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
643     }
644   else if (as == 1)
645     {
646       if (regs == 0)
647         {
648           *cycles = 4;
649           /* PC relative.  */
650           if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
651             {
652               cmd_len += 2;
653               sprintf (op1, "0x%04x", PS (dst));
654               sprintf (comm1, "PC rel. 0x%04x",
655                        PS ((short) addr + 2 + dst));
656               if (extension_word)
657                 {
658                   dst &= 0xffff;
659                   dst |= extended_src << 16;
660                   if (dst & 0x80000)
661                     dst |= -1U << 20;
662                   sprintf (op1, "0x%05x", dst & 0xfffff);
663                   sprintf (comm1, "PC rel. 0x%05lx",
664                            (long) ((addr + 2 + dst) & 0xfffff));
665                 }
666             }
667           else
668             return -1;
669         }
670       else if (regs == 2)
671         {
672           *cycles = 2;
673           /* Absolute.  */
674           if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
675             {
676               cmd_len += 2;
677               sprintf (op1, "&0x%04x", PS (dst));
678               sprintf (comm1, "0x%04x", PS (dst));
679               if (extension_word)
680                 {
681                   dst &= 0xffff;
682                   dst |= extended_src << 16;
683                   sprintf (op1, "&0x%05x", dst & 0xfffff);
684                   * comm1 = 0;
685                 }
686             }
687           else
688             return -1;
689         }
690       else if (regs == 3)
691         {
692           *cycles = 1;
693           sprintf (op1, "#1");
694           sprintf (comm1, "r3 As==01");
695         }
696       else
697         {
698           *cycles = 3;
699           /* Indexed.  */
700           if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
701             {
702               cmd_len += 2;
703               if (extension_word)
704                 {
705                   dst &= 0xffff;
706                   dst |= extended_src << 16;
707                   if (dst & 0x80000)
708                     dst |= -1U << 20;
709                 }
710               sprintf (op1, "%d(r%d)", dst, regs);
711               if (dst > 9 || dst < -9)
712                 sprintf (comm1, "0x%05x", dst);
713             }
714           else
715             return -1;
716         }
717     }
718
719   /* Destination. Special care needed on addr + XXXX.  */
720
721   if (ad == 0)
722     {
723       /* Register.  */
724       if (regd == 0)
725         {
726           *cycles += 1;
727           sprintf (op2, "r0");
728         }
729       else if (regd == 1)
730         sprintf (op2, "r1");
731
732       else if (regd == 2)
733         sprintf (op2, "r2");
734
735       else
736         sprintf (op2, "r%d", regd);
737     }
738   else  /* ad == 1.  */
739     {
740       * cycles += 3;
741
742       if (regd == 0)
743         {
744           /* PC relative.  */
745           *cycles += 1;
746           if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
747             {
748               sprintf (op2, "0x%04x", PS (dst));
749               sprintf (comm2, "PC rel. 0x%04x",
750                        PS ((short) addr + cmd_len + dst));
751               if (extension_word)
752                 {
753                   dst |= extended_dst << 16;
754                   if (dst & 0x80000)
755                     dst |= -1U << 20;
756                   sprintf (op2, "0x%05x", dst & 0xfffff);
757                   sprintf (comm2, "PC rel. 0x%05lx",
758                            (long)((addr + cmd_len + dst) & 0xfffff));
759                 }
760             }
761           else
762             return -1;
763           cmd_len += 2;
764         }
765       else if (regd == 2)
766         {
767           /* Absolute.  */
768           if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
769             {
770               cmd_len += 2;
771               sprintf (op2, "&0x%04x", PS (dst));
772               if (extension_word)
773                 {
774                   dst |= extended_dst << 16;
775                   sprintf (op2, "&0x%05x", dst & 0xfffff);
776                 }
777             }
778           else
779             return -1;
780         }
781       else
782         {
783           if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
784             {
785               cmd_len += 2;
786               if (dst > 9 || dst < 0)
787                 sprintf (comm2, "0x%04x", PS (dst));
788               if (extension_word)
789                 {
790                   dst |= extended_dst << 16;
791                   if (dst & 0x80000)
792                     dst |= -1U << 20;
793                   if (dst > 9 || dst < 0)
794                     sprintf (comm2, "0x%05x", dst & 0xfffff);
795                 }
796               sprintf (op2, "%d(r%d)", dst, regd);
797             }
798           else
799             return -1;
800         }
801     }
802
803   return cmd_len;
804 }
805
806 static int
807 msp430_branchinstr (disassemble_info *info,
808                     struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
809                     bfd_vma addr ATTRIBUTE_UNUSED,
810                     unsigned short insn,
811                     char *op1,
812                     char *comm1,
813                     int *cycles)
814 {
815   int regs = 0, regd = 0;
816   int as = 0;
817   int cmd_len = 2;
818   int dst = 0;
819   unsigned short udst = 0;
820
821   regd = insn & 0x0f;
822   regs = (insn & 0x0f00) >> 8;
823   as = (insn & 0x0030) >> 4;
824
825   if (regd != 0)        /* Destination register is not a PC.  */
826     return 0;
827
828   /* dst is a source register.  */
829   if (as == 0)
830     {
831       /* Constants.  */
832       if (regs == 3)
833         {
834           *cycles = 1;
835           sprintf (op1, "#0");
836           sprintf (comm1, "r3 As==00");
837         }
838       else
839         {
840           /* Register.  */
841           *cycles = 1;
842           sprintf (op1, "r%d", regs);
843         }
844     }
845   else if (as == 2)
846     {
847       * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2);
848     }
849   else if (as == 3)
850     {
851       if (regs == 0)
852         {
853           /* Absolute. @pc+  */
854           *cycles = 3;
855           if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
856             {
857               cmd_len += 2;
858               sprintf (op1, "#0x%04x", PS (udst));
859             }
860           else
861             return -1;
862         }
863       else
864         * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
865     }
866   else if (as == 1)
867     {
868       * cycles = 3;
869
870       if (regs == 0)
871         {
872           /* PC relative.  */
873           if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
874             {
875               cmd_len += 2;
876               (*cycles)++;
877               sprintf (op1, "0x%04x", PS (dst));
878               sprintf (comm1, "PC rel. 0x%04x",
879                        PS ((short) addr + 2 + dst));
880             }
881           else
882             return -1;
883         }
884       else if (regs == 2)
885         {
886           /* Absolute.  */
887           if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
888             {
889               cmd_len += 2;
890               sprintf (op1, "&0x%04x", PS (udst));
891             }
892           else
893             return -1;
894         }
895       else if (regs == 3)
896         {
897           (*cycles)--;
898           sprintf (op1, "#1");
899           sprintf (comm1, "r3 As==01");
900         }
901       else
902         {
903           /* Indexed.  */
904           if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
905             {
906               cmd_len += 2;
907               sprintf (op1, "%d(r%d)", dst, regs);
908             }
909           else
910             return -1;
911         }
912     }
913
914   return cmd_len;
915 }
916
917 static int
918 msp430x_calla_instr (disassemble_info * info,
919                      bfd_vma            addr,
920                      unsigned short     insn,
921                      char *             op1,
922                      char *             comm1,
923                      int *              cycles)
924 {
925   unsigned int   ureg = insn & 0xf;
926   int            reg = insn & 0xf;
927   int            am = (insn & 0xf0) >> 4;
928   int            cmd_len = 2;
929   unsigned short udst = 0;
930   int            dst = 0;
931
932   switch (am)
933     {
934     case 4: /* CALLA Rdst */
935       *cycles = 1;
936       sprintf (op1, "r%d", reg);
937       break;
938
939     case 5: /* CALLA x(Rdst) */
940       *cycles = 3;
941       if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
942         {
943           cmd_len += 2;
944           sprintf (op1, "%d(r%d)", dst, reg);
945           if (reg == 0)
946             sprintf (comm1, "PC rel. 0x%05lx", (long) (addr + 2 + dst));
947           else
948             sprintf (comm1, "0x%05x", dst);
949         }
950       else
951         return -1;
952       break;
953
954     case 6: /* CALLA @Rdst */
955       *cycles = 2;
956       sprintf (op1, "@r%d", reg);
957       break;
958
959     case 7: /* CALLA @Rdst+ */
960       *cycles = 2;
961       sprintf (op1, "@r%d+", reg);
962       break;
963
964     case 8: /* CALLA &abs20 */
965       if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
966         {
967           cmd_len += 2;
968           *cycles = 4;
969           sprintf (op1, "&%d", (ureg << 16) + udst);
970           sprintf (comm1, "0x%05x", (ureg << 16) + udst);
971         }
972       else
973         return -1;
974       break;
975
976     case 9: /* CALLA pcrel-sym */
977       if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
978         {
979           cmd_len += 2;
980           *cycles = 4;
981           sprintf (op1, "%d(PC)", (reg << 16) + dst);
982           sprintf (comm1, "PC rel. 0x%05lx",
983                    (long) (addr + 2 + dst + (reg << 16)));
984         }
985       else
986         return -1;
987       break;
988
989     case 11: /* CALLA #imm20 */
990       if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
991         {
992           cmd_len += 2;
993           *cycles = 4;
994           sprintf (op1, "#%d", (ureg << 16) + udst);
995           sprintf (comm1, "0x%05x", (ureg << 16) + udst);
996         }
997       else
998         return -1;
999       break;
1000
1001     default:
1002       strcpy (comm1, _("Warning: unrecognised CALLA addressing mode"));
1003       return -1;
1004     }
1005
1006   return cmd_len;
1007 }
1008
1009 int
1010 print_insn_msp430 (bfd_vma addr, disassemble_info *info)
1011 {
1012   void *stream = info->stream;
1013   fprintf_ftype prin = info->fprintf_func;
1014   struct msp430_opcode_s *opcode;
1015   char op1[32], op2[32], comm1[64], comm2[64];
1016   int cmd_len = 0;
1017   unsigned short insn;
1018   int cycles = 0;
1019   char *bc = "";
1020   unsigned short extension_word = 0;
1021   unsigned short bits;
1022
1023   if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
1024     return -1;
1025
1026   if (((int) addr & 0xffff) > 0xffdf)
1027     {
1028       (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn);
1029       return 2;
1030     }
1031
1032   *comm1 = 0;
1033   *comm2 = 0;
1034
1035   /* Check for an extension word.  */
1036   if ((insn & 0xf800) == 0x1800)
1037     {
1038       extension_word = insn;
1039       addr += 2;
1040       if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
1041         return -1;
1042    }
1043
1044   for (opcode = msp430_opcodes; opcode->name; opcode++)
1045     {
1046       if ((insn & opcode->bin_mask) == opcode->bin_opcode
1047           && opcode->bin_opcode != 0x9300)
1048         {
1049           *op1 = 0;
1050           *op2 = 0;
1051           *comm1 = 0;
1052           *comm2 = 0;
1053
1054           /* r0 as destination. Ad should be zero.  */
1055           if (opcode->insn_opnumb == 3
1056               && (insn & 0x000f) == 0
1057               && (insn & 0x0080) == 0)
1058             {
1059               int ret =
1060                 msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
1061                                     &cycles);
1062
1063               if (ret == -1)
1064                 return -1;
1065               cmd_len += ret;
1066               if (cmd_len)
1067                 break;
1068             }
1069
1070           switch (opcode->insn_opnumb)
1071             {
1072               int n;
1073               int reg;
1074               int ret;
1075
1076             case 4:
1077               ret = msp430x_calla_instr (info, addr, insn,
1078                                          op1, comm1, & cycles);
1079               if (ret == -1)
1080                 return -1;
1081               cmd_len += ret;
1082               break;
1083
1084             case 5: /* PUSHM/POPM */
1085               n = (insn & 0xf0) >> 4;
1086               reg = (insn & 0xf);
1087
1088               sprintf (op1, "#%d", n + 1);
1089               if (opcode->bin_opcode == 0x1400)
1090                 /* PUSHM */
1091                 sprintf (op2, "r%d", reg);
1092               else
1093                 /* POPM */
1094                 sprintf (op2, "r%d", reg + n);
1095               if (insn & 0x100)
1096                 sprintf (comm1, "16-bit words");
1097               else
1098                 {
1099                   sprintf (comm1, "20-bit words");
1100                   bc =".a";
1101                 }
1102
1103               cycles = 2; /*FIXME*/
1104               cmd_len = 2;
1105               break;
1106
1107             case 6: /* RRAM, RRCM, RRUM, RLAM.  */
1108               n = ((insn >> 10) & 0x3) + 1;
1109               reg = (insn & 0xf);
1110               if ((insn & 0x10) == 0)
1111                 bc =".a";
1112               sprintf (op1, "#%d", n);
1113               sprintf (op2, "r%d", reg);
1114               cycles = 2; /*FIXME*/
1115               cmd_len = 2;
1116               break;
1117
1118             case 8: /* ADDA, CMPA, SUBA.  */
1119               reg = (insn & 0xf);
1120               n = (insn >> 8) & 0xf;
1121               if (insn & 0x40)
1122                 {
1123                   sprintf (op1, "r%d", n);
1124                   cmd_len = 2;
1125                 }
1126               else
1127                 {
1128                   n <<= 16;
1129                   if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
1130                     {
1131                       n |= bits;
1132                       sprintf (op1, "#%d", n);
1133                       if (n > 9 || n < 0)
1134                         sprintf (comm1, "0x%05x", n);
1135                     }
1136                   else
1137                     return -1;
1138                   cmd_len = 4;
1139                 }
1140               sprintf (op2, "r%d", reg);
1141               cycles = 2; /*FIXME*/
1142               break;
1143
1144             case 9: /* MOVA */
1145               reg = (insn & 0xf);
1146               n = (insn >> 8) & 0xf;
1147               switch ((insn >> 4) & 0xf)
1148                 {
1149                 case 0: /* MOVA @Rsrc, Rdst */
1150                   cmd_len = 2;
1151                   sprintf (op1, "@r%d", n);
1152                   if (strcmp (opcode->name, "bra") != 0)
1153                     sprintf (op2, "r%d", reg);
1154                   break;
1155
1156                 case 1: /* MOVA @Rsrc+, Rdst */
1157                   cmd_len = 2;
1158                   if (strcmp (opcode->name, "reta") != 0)
1159                     {
1160                       sprintf (op1, "@r%d+", n);
1161                       if (strcmp (opcode->name, "bra") != 0)
1162                         sprintf (op2, "r%d", reg);
1163                     }
1164                   break;
1165
1166                 case 2: /* MOVA &abs20, Rdst */
1167                   cmd_len = 4;
1168                   n <<= 16;
1169                   if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
1170                     {
1171                       n |= bits;
1172                       sprintf (op1, "&%d", n);
1173                       if (n > 9 || n < 0)
1174                         sprintf (comm1, "0x%05x", n);
1175                       if (strcmp (opcode->name, "bra") != 0)
1176                         sprintf (op2, "r%d", reg);
1177                     }
1178                   else
1179                     return -1;
1180                   break;
1181
1182                 case 3: /* MOVA x(Rsrc), Rdst */
1183                   cmd_len = 4;
1184                   if (strcmp (opcode->name, "bra") != 0)
1185                     sprintf (op2, "r%d", reg);
1186                   reg = n;
1187                   if (msp430dis_opcode_signed (addr + 2, info, &n, comm1))
1188                     {
1189                       sprintf (op1, "%d(r%d)", n, reg);
1190                       if (n > 9 || n < 0)
1191                         {
1192                           if (reg == 0)
1193                             sprintf (comm1, "PC rel. 0x%05lx",
1194                                      (long) (addr + 2 + n));
1195                           else
1196                             sprintf (comm1, "0x%05x", n);
1197                         }
1198                     }
1199                   else
1200                     return -1;
1201                   break;
1202
1203                 case 6: /* MOVA Rsrc, &abs20 */
1204                   cmd_len = 4;
1205                   reg <<= 16;
1206                   if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm2))
1207                     {
1208                       reg |= bits;
1209                       sprintf (op1, "r%d", n);
1210                       sprintf (op2, "&%d", reg);
1211                       if (reg > 9 || reg < 0)
1212                         sprintf (comm2, "0x%05x", reg);
1213                     }
1214                   else
1215                     return -1;
1216                   break;
1217
1218                 case 7: /* MOVA Rsrc, x(Rdst) */
1219                   cmd_len = 4;
1220                   sprintf (op1, "r%d", n);
1221                   if (msp430dis_opcode_signed (addr + 2, info, &n, comm2))
1222                     {
1223                       sprintf (op2, "%d(r%d)", n, reg);
1224                       if (n > 9 || n < 0)
1225                         {
1226                           if (reg == 0)
1227                             sprintf (comm2, "PC rel. 0x%05lx",
1228                                      (long) (addr + 2 + n));
1229                           else
1230                             sprintf (comm2, "0x%05x", n);
1231                         }
1232                     }
1233                   else
1234                     return -1;
1235                   break;
1236
1237                 case 8: /* MOVA #imm20, Rdst */
1238                   cmd_len = 4;
1239                   n <<= 16;
1240                   if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
1241                     {
1242                       n |= bits;
1243                       if (n & 0x80000)
1244                         n |= -1U << 20;
1245                       sprintf (op1, "#%d", n);
1246                       if (n > 9 || n < 0)
1247                         sprintf (comm1, "0x%05x", n);
1248                       if (strcmp (opcode->name, "bra") != 0)
1249                         sprintf (op2, "r%d", reg);
1250                     }
1251                   else
1252                     return -1;
1253                   break;
1254
1255                 case 12: /* MOVA Rsrc, Rdst */
1256                   cmd_len = 2;
1257                   sprintf (op1, "r%d", n);
1258                   if (strcmp (opcode->name, "bra") != 0)
1259                     sprintf (op2, "r%d", reg);
1260                   break;
1261
1262                 default:
1263                   break;
1264                 }
1265               cycles = 2; /* FIXME */
1266               break;
1267             }
1268
1269           if (cmd_len)
1270             break;
1271
1272           switch (opcode->insn_opnumb)
1273             {
1274               int ret;
1275
1276             case 0:
1277               cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles);
1278               break;
1279             case 2:
1280               ret =
1281                 msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
1282                                       comm1, comm2,
1283                                       extension_word,
1284                                       &cycles);
1285
1286               if (ret == -1)
1287                 return -1;
1288               cmd_len += ret;
1289               if (insn & BYTE_OPERATION)
1290                 {
1291                   if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
1292                     bc = ".a";
1293                   else
1294                     bc = ".b";
1295                 }
1296               else if (extension_word)
1297                 {
1298                   if (extension_word & BYTE_OPERATION)
1299                     bc = ".w";
1300                   else
1301                     {
1302                       bc = ".?";
1303                       sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1304                     }
1305                 }
1306
1307               break;
1308             case 1:
1309               ret =
1310                 msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
1311                                       extension_word,
1312                                       &cycles);
1313
1314               if (ret == -1)
1315                 return -1;
1316               cmd_len += ret;
1317               if (extension_word
1318                   && (strcmp (opcode->name, "swpb") == 0
1319                       || strcmp (opcode->name, "sxt") == 0))
1320                 {
1321                   if (insn & BYTE_OPERATION)
1322                     {
1323                       bc = ".?";
1324                       sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1325                     }
1326                   else if (extension_word & BYTE_OPERATION)
1327                     bc = ".w";
1328                   else
1329                     bc = ".a";
1330                 }
1331               else if (insn & BYTE_OPERATION && opcode->fmt != 3)
1332                 {
1333                   if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
1334                     bc = ".a";
1335                   else
1336                     bc = ".b";
1337                 }
1338               else if (extension_word)
1339                 {
1340                   if (extension_word & (1 << 6))
1341                     bc = ".w";
1342                   else
1343                     {
1344                       bc = ".?";
1345                       sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1346                     }
1347                 }
1348               break;
1349             default:
1350               break;
1351             }
1352         }
1353
1354       if (cmd_len)
1355         break;
1356     }
1357
1358   if (cmd_len < 1)
1359     {
1360       /* Unknown opcode, or invalid combination of operands.  */
1361       if (extension_word)
1362         {
1363           prin (stream, ".word  0x%04x, 0x%04x; ????", extension_word, PS (insn));
1364           if (*comm1)
1365             prin (stream, "\t %s", comm1);
1366           return 4;
1367         }
1368       (*prin) (stream, ".word   0x%04x; ????", PS (insn));
1369       return 2;
1370     }
1371
1372   /* Display the repeat count (if set) for extended register mode.  */
1373   if (cmd_len == 2 && ((extension_word & 0xf) != 0))
1374     {
1375       if (extension_word & (1 << 7))
1376         prin (stream, "rpt r%d { ", extension_word & 0xf);
1377       else
1378         prin (stream, "rpt #%d { ", (extension_word & 0xf) + 1);
1379     }
1380
1381   /* Special case:  RRC with an extension word and the ZC bit set is actually RRU.  */
1382   if (extension_word
1383       && (extension_word & IGNORE_CARRY_BIT)
1384       && strcmp (opcode->name, "rrc") == 0)
1385     (*prin) (stream, "rrux%s", bc);
1386   else if (extension_word && opcode->name[strlen (opcode->name) - 1] != 'x')
1387     (*prin) (stream, "%sx%s", opcode->name, bc);
1388   else
1389     (*prin) (stream, "%s%s", opcode->name, bc);
1390
1391   if (*op1)
1392     (*prin) (stream, "\t%s", op1);
1393   if (*op2)
1394     (*prin) (stream, ",");
1395
1396   if (strlen (op1) < 7)
1397     (*prin) (stream, "\t");
1398   if (!strlen (op1))
1399     (*prin) (stream, "\t");
1400
1401   if (*op2)
1402     (*prin) (stream, "%s", op2);
1403   if (strlen (op2) < 8)
1404     (*prin) (stream, "\t");
1405
1406   if (*comm1 || *comm2)
1407     (*prin) (stream, ";");
1408   else if (cycles)
1409     {
1410       if (*op2)
1411         (*prin) (stream, ";");
1412       else
1413         {
1414           if (strlen (op1) < 7)
1415             (*prin) (stream, ";");
1416           else
1417             (*prin) (stream, "\t;");
1418         }
1419     }
1420   if (*comm1)
1421     (*prin) (stream, "%s", comm1);
1422   if (*comm1 && *comm2)
1423     (*prin) (stream, ",");
1424   if (*comm2)
1425     (*prin) (stream, " %s", comm2);
1426
1427   if (extension_word)
1428     cmd_len += 2;
1429
1430   return cmd_len;
1431 }