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