msp430-dis.c revision 1.1.1.3
1/* Disassemble MSP430 instructions.
2   Copyright (C) 2002-2013 Free Software Foundation, Inc.
3
4   Contributed by Dmitry Diky <diwil@mail.ru>
5
6   This file is part of the GNU opcodes library.
7
8   This library is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3, or (at your option)
11   any later version.
12
13   It is distributed in the hope that it will be useful, but WITHOUT
14   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16   License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21   MA 02110-1301, USA.  */
22
23#include "sysdep.h"
24#include <stdio.h>
25#include <ctype.h>
26#include <sys/types.h>
27
28#include "dis-asm.h"
29#include "opintl.h"
30#include "libiberty.h"
31
32#define DASM_SECTION
33#include "opcode/msp430.h"
34#undef DASM_SECTION
35
36
37#define PS(x)   (0xffff & (x))
38
39static unsigned short
40msp430dis_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
54static int
55msp430_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
84static int
85print_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
107static int
108print_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
130static int
131msp430_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
362static int
363msp430_doubleoperand (disassemble_info *info,
364		      struct msp430_opcode_s *opcode,
365		      bfd_vma addr,
366		      unsigned short insn,
367		      char *op1,
368		      char *op2,
369		      char *comm1,
370		      char *comm2,
371		      unsigned short extension_word,
372		      int *cycles)
373{
374  int regs = 0, regd = 0;
375  int ad = 0, as = 0;
376  int cmd_len = 2;
377  int dst = 0;
378  int fmt;
379  int extended_dst = extension_word & 0xf;
380  int extended_src = (extension_word >> 7) & 0xf;
381
382  regd = insn & 0x0f;
383  regs = (insn & 0x0f00) >> 8;
384  as = (insn & 0x0030) >> 4;
385  ad = (insn & 0x0080) >> 7;
386
387  if (opcode->fmt < 0)
388    fmt = (- opcode->fmt) - 1;
389  else
390    fmt = opcode->fmt;
391
392  if (fmt == 0)
393    {
394      /* Special case: rla and rlc are the only 2 emulated instructions that
395	 fall into two operand instructions.  */
396      /* With dst, there are only:
397	 Rm       	Register,
398         x(Rm)     	Indexed,
399         0xXXXX    	Relative,
400         &0xXXXX    	Absolute
401         emulated_ins   dst
402         basic_ins      dst, dst.  */
403
404      if (regd != regs || as != ad)
405	return 0;		/* May be 'data' section.  */
406
407      if (ad == 0)
408	{
409	  /* Register mode.  */
410	  if (regd == 3)
411	    {
412	      strcpy (comm1, _("Illegal as emulation instr"));
413	      return -1;
414	    }
415
416	  sprintf (op1, "r%d", regd);
417	  *cycles = 1;
418	}
419      else			/* ad == 1 */
420	{
421	  if (regd == 0)
422	    {
423	      /* PC relative, Symbolic.  */
424	      dst = msp430dis_opcode (addr + 2, info);
425	      cmd_len += 4;
426	      *cycles = 6;
427	      sprintf (op1, "0x%04x", PS (dst));
428	      sprintf (comm1, "PC rel. 0x%04x",
429		       PS ((short) addr + 2 + dst));
430	      if (extended_dst)
431		{
432		  dst |= extended_dst << 16;
433		  if (dst & 0x80000)
434		    dst |= -1 << 20;
435		  sprintf (op1, "0x%05x", dst & 0xfffff);
436		  sprintf (comm1, "PC rel. 0x%05lx",
437			   (long)((addr + 2 + dst) & 0xfffff));
438		}
439	    }
440	  else if (regd == 2)
441	    {
442	      /* Absolute.  */
443	      dst = msp430dis_opcode (addr + 2, info);
444	      /* If the 'src' field is not the same as the dst
445		 then this is not an rla instruction.  */
446	      if (dst != msp430dis_opcode (addr + 4, info))
447		return 0;
448	      cmd_len += 4;
449	      *cycles = 6;
450	      sprintf (op1, "&0x%04x", PS (dst));
451	      if (extended_dst)
452		{
453		  dst |= extended_dst << 16;
454		  sprintf (op1, "&0x%05x", dst & 0xfffff);
455		}
456	    }
457	  else
458	    {
459	      /* Indexed.  */
460	      dst = msp430dis_opcode (addr + 2, info);
461	      if (extended_dst)
462		{
463		  dst |= extended_dst << 16;
464		  if (dst & 0x80000)
465		    dst |= -1 << 20;
466		}
467	      else if (dst & 0x8000)
468		dst |= -1 << 16;
469	      cmd_len += 4;
470	      *cycles = 6;
471	      sprintf (op1, "%d(r%d)", dst, regd);
472	      if (dst > 9 || dst < -9)
473		sprintf (comm1, "#0x%05x", dst);
474	    }
475	}
476
477      *op2 = 0;
478      *comm2 = 0;
479
480      return cmd_len;
481    }
482
483  /* Two operands exactly.  */
484  if (ad == 0 && regd == 3)
485    {
486      /* R2/R3 are illegal as dest: may be data section.  */
487      strcpy (comm1, _("Illegal as 2-op instr"));
488      return -1;
489    }
490
491  /* Source.  */
492  if (as == 0)
493    {
494      *cycles = 1;
495      if (regs == 3)
496	{
497	  /* Constants.  */
498	  sprintf (op1, "#0");
499	  sprintf (comm1, "r3 As==00");
500	}
501      else
502	{
503	  /* Register.  */
504	  sprintf (op1, "r%d", regs);
505	}
506    }
507  else if (as == 2)
508    {
509      * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2);
510    }
511  else if (as == 3)
512    {
513      if (regs == 0)
514	{
515	  *cycles = 3;
516	  /* Absolute. @pc+.  */
517	  dst = msp430dis_opcode (addr + 2, info);
518	  cmd_len += 2;
519	  sprintf (op1, "#%d", dst);
520	  if (dst > 9 || dst < 0)
521	    sprintf (comm1, "#0x%04x", PS (dst));
522	  if (extended_src)
523	    {
524	      dst |= extended_src << 16;
525	      if (dst & 0x80000)
526		dst |= -1 << 20;
527	      sprintf (op1, "#%d", dst);
528	      if (dst > 9 || dst < 0)
529		sprintf (comm1, "0x%05x", dst & 0xfffff);
530	    }
531	}
532      else
533	* cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
534    }
535  else if (as == 1)
536    {
537      if (regs == 0)
538	{
539	  *cycles = 4;
540	  /* PC relative.  */
541	  dst = msp430dis_opcode (addr + 2, info);
542	  cmd_len += 2;
543	  sprintf (op1, "0x%04x", PS (dst));
544	  sprintf (comm1, "PC rel. 0x%04x",
545		   PS ((short) addr + 2 + dst));
546	  if (extended_src)
547	    {
548	      dst |= extended_src << 16;
549	      if (dst & 0x80000)
550		dst |= -1 << 20;
551	      sprintf (op1, "0x%05x", dst & 0xfffff);
552	      sprintf (comm1, "PC rel. 0x%05lx",
553		       (long) ((addr + 2 + dst) & 0xfffff));
554	    }
555	}
556      else if (regs == 2)
557	{
558	  *cycles = 2;
559	  /* Absolute.  */
560	  dst = msp430dis_opcode (addr + 2, info);
561	  cmd_len += 2;
562	  sprintf (op1, "&0x%04x", PS (dst));
563	  sprintf (comm1, "0x%04x", PS (dst));
564	  if (extended_src)
565	    {
566	      dst |= extended_src << 16;
567	      sprintf (op1, "&0x%05x", dst & 0xfffff);
568	      * comm1 = 0;
569	    }
570	}
571      else if (regs == 3)
572	{
573	  *cycles = 1;
574	  sprintf (op1, "#1");
575	  sprintf (comm1, "r3 As==01");
576	}
577      else
578	{
579	  *cycles = 3;
580	  /* Indexed.  */
581	  dst = msp430dis_opcode (addr + 2, info);
582	  cmd_len += 2;
583	  if (extended_src)
584	    {
585	      dst |= extended_src << 16;
586	      if (dst & 0x80000)
587		dst |= -1 << 20;
588	    }
589	  else if (dst & 0x8000)
590	    dst |= -1 << 16;
591	  sprintf (op1, "%d(r%d)", dst, regs);
592	  if (dst > 9 || dst < -9)
593	    sprintf (comm1, "0x%05x", dst);
594	}
595    }
596
597  /* Destination. Special care needed on addr + XXXX.  */
598
599  if (ad == 0)
600    {
601      /* Register.  */
602      if (regd == 0)
603	{
604	  *cycles += 1;
605	  sprintf (op2, "r0");
606	}
607      else if (regd == 1)
608	sprintf (op2, "r1");
609
610      else if (regd == 2)
611	sprintf (op2, "r2");
612
613      else
614	sprintf (op2, "r%d", regd);
615    }
616  else	/* ad == 1.  */
617    {
618      * cycles += 3;
619
620      if (regd == 0)
621	{
622	  /* PC relative.  */
623	  *cycles += 1;
624	  dst = msp430dis_opcode (addr + cmd_len, info);
625	  sprintf (op2, "0x%04x", PS (dst));
626	  sprintf (comm2, "PC rel. 0x%04x",
627		   PS ((short) addr + cmd_len + dst));
628	  if (extended_dst)
629	    {
630	      dst |= extended_dst << 16;
631	      if (dst & 0x80000)
632		dst |= -1 << 20;
633	      sprintf (op2, "0x%05x", dst & 0xfffff);
634	      sprintf (comm2, "PC rel. 0x%05lx",
635		       (long)((addr + cmd_len + dst) & 0xfffff));
636	    }
637	  cmd_len += 2;
638	}
639      else if (regd == 2)
640	{
641	  /* Absolute.  */
642	  dst = msp430dis_opcode (addr + cmd_len, info);
643	  cmd_len += 2;
644	  sprintf (op2, "&0x%04x", PS (dst));
645	  if (extended_dst)
646	    {
647	      dst |= extended_dst << 16;
648	      sprintf (op2, "&0x%05x", dst & 0xfffff);
649	    }
650	}
651      else
652	{
653	  dst = msp430dis_opcode (addr + cmd_len, info);
654	  cmd_len += 2;
655	  if (dst & 0x8000)
656	    dst |= -1 << 16;
657	  if (dst > 9 || dst < 0)
658	    sprintf (comm2, "0x%04x", PS (dst));
659	  if (extended_dst)
660	    {
661	      dst |= extended_dst << 16;
662	      if (dst & 0x80000)
663		dst |= -1 << 20;
664	      if (dst > 9 || dst < 0)
665		sprintf (comm2, "0x%05x", dst & 0xfffff);
666	    }
667	  sprintf (op2, "%d(r%d)", dst, regd);
668	}
669    }
670
671  return cmd_len;
672}
673
674static int
675msp430_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
770static int
771msp430x_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
846int
847print_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