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