Home | History | Annotate | Download | only in opcodes
      1 /* Disassemble MSP430 instructions.
      2    Copyright (C) 2002-2014 Free Software Foundation, Inc.
      3 
      4    Contributed by Dmitry Diky <diwil (at) 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 (extension_word)
    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 (extension_word)
    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 (extension_word)
    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 (extension_word)
    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 (extension_word)
    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 (extension_word)
    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 (extension_word)
    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 (extension_word)
    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 (extension_word)
    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 (extension_word)
    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, _("unrecognised 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 }
   1230