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