1/* Disassemble MSP430 instructions.
2   Copyright (C) 2002-2024 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 "disassemble.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 bool
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 bool
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 bool
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	      else
274		return -1;
275	    }
276	  else if (regd == 2)
277	    {
278	      /* Absolute.  */
279	      if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
280		{
281		  cmd_len += 2;
282		  *cycles = 4;
283		  sprintf (op, "&0x%04x", PS (dst));
284		  if (extended_dst)
285		    {
286		      dst |= extended_dst << 16;
287		      sprintf (op, "&0x%05x", dst & 0xfffff);
288		    }
289		}
290	      else
291		return -1;
292	    }
293	  else
294	    {
295	      if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
296		{
297		  cmd_len += 2;
298		  *cycles = 4;
299		  if (extended_dst)
300		    {
301		      dst |= extended_dst << 16;
302		      if (dst & 0x80000)
303			dst |= -1U << 20;
304		    }
305		  sprintf (op, "%d(r%d)", dst, regd);
306		}
307	      else
308		return -1;
309	    }
310	}
311      break;
312
313    case 2:	/* rrc, push, call, swpb, rra, sxt, push, call, reti etc...  */
314      if (as == 0)
315	{
316	  if (regd == 3)
317	    {
318	      /* Constsnts.  */
319	      sprintf (op, "#0");
320	      sprintf (comm, "r3 As==00");
321	    }
322	  else
323	    {
324	      /* Register.  */
325	      sprintf (op, "r%d", regd);
326	    }
327	  *cycles = 1;
328	}
329      else if (as == 2)
330	{
331	  * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3);
332	}
333      else if (as == 3)
334	{
335	  if (regd == 0)
336	    {
337	      *cycles = 3;
338	      /* absolute. @pc+ */
339	      if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
340		{
341		  cmd_len += 2;
342		  sprintf (op, "#%d", dst);
343		  if (dst > 9 || dst < 0)
344		    sprintf (comm, "#0x%04x", PS (dst));
345		  if (extended_dst)
346		    {
347		      dst |= extended_dst << 16;
348		      if (dst & 0x80000)
349			dst |= -1U << 20;
350		      sprintf (op, "#%d", dst);
351		      if (dst > 9 || dst < 0)
352			sprintf (comm, "#0x%05x", dst);
353		    }
354		}
355	      else
356		return -1;
357	    }
358	  else
359	    * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
360	}
361      else if (as == 1)
362	{
363	  *cycles = 4;
364	  if (regd == 0)
365	    {
366	      /* PC relative.  */
367	      if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
368		{
369		  cmd_len += 2;
370		  sprintf (op, "0x%04x", PS (dst));
371		  sprintf (comm, "PC rel. 0x%04x",
372			   PS ((short) addr + 2 + dst));
373		  if (extended_dst)
374		    {
375		      dst |= extended_dst << 16;
376		      sprintf (op, "0x%05x", dst & 0xffff);
377		      sprintf (comm, "PC rel. 0x%05lx",
378			       (long)((addr + 2 + dst) & 0xfffff));
379		    }
380		}
381	      else
382		return -1;
383	    }
384	  else if (regd == 2)
385	    {
386	      /* Absolute.  */
387	      if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
388		{
389		  cmd_len += 2;
390		  sprintf (op, "&0x%04x", PS (dst));
391		  if (extended_dst)
392		    {
393		      dst |= extended_dst << 16;
394		      sprintf (op, "&0x%05x", dst & 0xfffff);
395		    }
396		}
397	      else
398		return -1;
399	    }
400	  else if (regd == 3)
401	    {
402	      *cycles = 1;
403	      sprintf (op, "#1");
404	      sprintf (comm, "r3 As==01");
405	    }
406	  else
407	    {
408	      /* Indexed.  */
409	      if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
410		{
411		  cmd_len += 2;
412		  if (extended_dst)
413		    {
414		      dst |= extended_dst << 16;
415		      if (dst & 0x80000)
416			dst |= -1U << 20;
417		    }
418		  sprintf (op, "%d(r%d)", dst, regd);
419		  if (dst > 9 || dst < 0)
420		    sprintf (comm, "%05x", dst);
421		}
422	      else
423		return -1;
424	    }
425	}
426      break;
427
428    case 3:			/* Jumps.  */
429      where = insn & 0x03ff;
430      if (where & 0x200)
431	where |= ~0x03ff;
432      if (where > 512 || where < -511)
433	return 0;
434
435      where *= 2;
436      sprintf (op, "$%+-8d", where + 2);
437      sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where));
438      *cycles = 2;
439      return 2;
440      break;
441
442    default:
443      cmd_len = 0;
444    }
445
446  return cmd_len;
447}
448
449static int
450msp430_doubleoperand (disassemble_info *info,
451		      struct msp430_opcode_s *opcode,
452		      bfd_vma addr,
453		      unsigned short insn,
454		      char *op1,
455		      char *op2,
456		      char *comm1,
457		      char *comm2,
458		      unsigned short extension_word,
459		      int *cycles)
460{
461  int regs = 0, regd = 0;
462  int ad = 0, as = 0;
463  int cmd_len = 2;
464  int dst = 0;
465  int fmt;
466  int extended_dst = extension_word & 0xf;
467  int extended_src = (extension_word >> 7) & 0xf;
468
469  regd = insn & 0x0f;
470  regs = (insn & 0x0f00) >> 8;
471  as = (insn & 0x0030) >> 4;
472  ad = (insn & 0x0080) >> 7;
473
474  if (opcode->fmt < 0)
475    fmt = (- opcode->fmt) - 1;
476  else
477    fmt = opcode->fmt;
478
479  if (fmt == 0)
480    {
481      /* Special case: rla and rlc are the only 2 emulated instructions that
482	 fall into two operand instructions.  */
483      /* With dst, there are only:
484	 Rm       	Register,
485         x(Rm)     	Indexed,
486         0xXXXX    	Relative,
487         &0xXXXX    	Absolute
488         emulated_ins   dst
489         basic_ins      dst, dst.  */
490
491      if (regd != regs || as != ad)
492	return 0;		/* May be 'data' section.  */
493
494      if (ad == 0)
495	{
496	  /* Register mode.  */
497	  if (regd == 3)
498	    {
499	      strcpy (comm1, _("Warning: illegal as emulation instr"));
500	      return -1;
501	    }
502
503	  sprintf (op1, "r%d", regd);
504	  *cycles = 1;
505	}
506      else			/* ad == 1 */
507	{
508	  if (regd == 0)
509	    {
510	      /* PC relative, Symbolic.  */
511	      if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
512		{
513		  cmd_len += 4;
514		  *cycles = 6;
515		  sprintf (op1, "0x%04x", PS (dst));
516		  sprintf (comm1, "PC rel. 0x%04x",
517			   PS ((short) addr + 2 + dst));
518		  if (extension_word)
519		    {
520		      dst |= extended_dst << 16;
521		      if (dst & 0x80000)
522			dst |= -1U << 20;
523		      sprintf (op1, "0x%05x", dst & 0xfffff);
524		      sprintf (comm1, "PC rel. 0x%05lx",
525			       (long)((addr + 2 + dst) & 0xfffff));
526		    }
527		}
528	      else
529		return -1;
530	    }
531	  else if (regd == 2)
532	    {
533	      /* Absolute.  */
534	      if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
535		{
536		  int src;
537
538		  /* If the 'src' field is not the same as the dst
539		     then this is not an rla instruction.  */
540		  if (msp430dis_opcode_signed (addr + 4, info, &src, comm2))
541		    {
542		      if (src != dst)
543			return 0;
544		    }
545		  else
546		    return -1;
547		  cmd_len += 4;
548		  *cycles = 6;
549		  sprintf (op1, "&0x%04x", PS (dst));
550		  if (extension_word)
551		    {
552		      dst |= extended_dst << 16;
553		      sprintf (op1, "&0x%05x", dst & 0xfffff);
554		    }
555		}
556	      else
557		return -1;
558	    }
559	  else
560	    {
561	      /* Indexed.  */
562	      if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
563		{
564		  if (extension_word)
565		    {
566		      dst |= extended_dst << 16;
567		      if (dst & 0x80000)
568			dst |= -1U << 20;
569		    }
570		  cmd_len += 4;
571		  *cycles = 6;
572		  sprintf (op1, "%d(r%d)", dst, regd);
573		  if (dst > 9 || dst < -9)
574		    sprintf (comm1, "#0x%05x", dst);
575		}
576	      else
577		return -1;
578	    }
579	}
580
581      *op2 = 0;
582      *comm2 = 0;
583
584      return cmd_len;
585    }
586
587  /* Two operands exactly.  */
588  if (ad == 0 && regd == 3)
589    {
590      /* R2/R3 are illegal as dest: may be data section.  */
591      strcpy (comm1, _("Warning: illegal as 2-op instr"));
592      return -1;
593    }
594
595  /* Source.  */
596  if (as == 0)
597    {
598      *cycles = 1;
599      if (regs == 3)
600	{
601	  /* Constants.  */
602	  sprintf (op1, "#0");
603	  sprintf (comm1, "r3 As==00");
604	}
605      else
606	{
607	  /* Register.  */
608	  sprintf (op1, "r%d", regs);
609	}
610    }
611  else if (as == 2)
612    {
613      * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2);
614    }
615  else if (as == 3)
616    {
617      if (regs == 0)
618	{
619	  *cycles = 3;
620	  /* Absolute. @pc+.  */
621	  if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
622	    {
623	      cmd_len += 2;
624	      sprintf (op1, "#%d", dst);
625	      if (dst > 9 || dst < 0)
626		sprintf (comm1, "#0x%04x", PS (dst));
627	      if (extension_word)
628		{
629		  dst &= 0xffff;
630		  dst |= extended_src << 16;
631		  if (dst & 0x80000)
632		    dst |= -1U << 20;
633		  sprintf (op1, "#%d", dst);
634		  if (dst > 9 || dst < 0)
635		    sprintf (comm1, "0x%05x", dst & 0xfffff);
636		}
637	    }
638	  else
639	    return -1;
640	}
641      else
642	* cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
643    }
644  else if (as == 1)
645    {
646      if (regs == 0)
647	{
648	  *cycles = 4;
649	  /* PC relative.  */
650	  if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
651	    {
652	      cmd_len += 2;
653	      sprintf (op1, "0x%04x", PS (dst));
654	      sprintf (comm1, "PC rel. 0x%04x",
655		       PS ((short) addr + 2 + dst));
656	      if (extension_word)
657		{
658		  dst &= 0xffff;
659		  dst |= extended_src << 16;
660		  if (dst & 0x80000)
661		    dst |= -1U << 20;
662		  sprintf (op1, "0x%05x", dst & 0xfffff);
663		  sprintf (comm1, "PC rel. 0x%05lx",
664			   (long) ((addr + 2 + dst) & 0xfffff));
665		}
666	    }
667	  else
668	    return -1;
669	}
670      else if (regs == 2)
671	{
672	  *cycles = 2;
673	  /* Absolute.  */
674	  if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
675	    {
676	      cmd_len += 2;
677	      sprintf (op1, "&0x%04x", PS (dst));
678	      sprintf (comm1, "0x%04x", PS (dst));
679	      if (extension_word)
680		{
681		  dst &= 0xffff;
682		  dst |= extended_src << 16;
683		  sprintf (op1, "&0x%05x", dst & 0xfffff);
684		  * comm1 = 0;
685		}
686	    }
687	  else
688	    return -1;
689	}
690      else if (regs == 3)
691	{
692	  *cycles = 1;
693	  sprintf (op1, "#1");
694	  sprintf (comm1, "r3 As==01");
695	}
696      else
697	{
698	  *cycles = 3;
699	  /* Indexed.  */
700	  if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
701	    {
702	      cmd_len += 2;
703	      if (extension_word)
704		{
705		  dst &= 0xffff;
706		  dst |= extended_src << 16;
707		  if (dst & 0x80000)
708		    dst |= -1U << 20;
709		}
710	      sprintf (op1, "%d(r%d)", dst, regs);
711	      if (dst > 9 || dst < -9)
712		sprintf (comm1, "0x%05x", dst);
713	    }
714	  else
715	    return -1;
716	}
717    }
718
719  /* Destination. Special care needed on addr + XXXX.  */
720
721  if (ad == 0)
722    {
723      /* Register.  */
724      if (regd == 0)
725	{
726	  *cycles += 1;
727	  sprintf (op2, "r0");
728	}
729      else if (regd == 1)
730	sprintf (op2, "r1");
731
732      else if (regd == 2)
733	sprintf (op2, "r2");
734
735      else
736	sprintf (op2, "r%d", regd);
737    }
738  else	/* ad == 1.  */
739    {
740      * cycles += 3;
741
742      if (regd == 0)
743	{
744	  /* PC relative.  */
745	  *cycles += 1;
746	  if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
747	    {
748	      sprintf (op2, "0x%04x", PS (dst));
749	      sprintf (comm2, "PC rel. 0x%04x",
750		       PS ((short) addr + cmd_len + dst));
751	      if (extension_word)
752		{
753		  dst |= extended_dst << 16;
754		  if (dst & 0x80000)
755		    dst |= -1U << 20;
756		  sprintf (op2, "0x%05x", dst & 0xfffff);
757		  sprintf (comm2, "PC rel. 0x%05lx",
758			   (long)((addr + cmd_len + dst) & 0xfffff));
759		}
760	    }
761	  else
762	    return -1;
763	  cmd_len += 2;
764	}
765      else if (regd == 2)
766	{
767	  /* Absolute.  */
768	  if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
769	    {
770	      cmd_len += 2;
771	      sprintf (op2, "&0x%04x", PS (dst));
772	      if (extension_word)
773		{
774		  dst |= extended_dst << 16;
775		  sprintf (op2, "&0x%05x", dst & 0xfffff);
776		}
777	    }
778	  else
779	    return -1;
780	}
781      else
782	{
783	  if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
784	    {
785	      cmd_len += 2;
786	      if (dst > 9 || dst < 0)
787		sprintf (comm2, "0x%04x", PS (dst));
788	      if (extension_word)
789		{
790		  dst |= extended_dst << 16;
791		  if (dst & 0x80000)
792		    dst |= -1U << 20;
793		  if (dst > 9 || dst < 0)
794		    sprintf (comm2, "0x%05x", dst & 0xfffff);
795		}
796	      sprintf (op2, "%d(r%d)", dst, regd);
797	    }
798	  else
799	    return -1;
800	}
801    }
802
803  return cmd_len;
804}
805
806static int
807msp430_branchinstr (disassemble_info *info,
808		    struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
809		    bfd_vma addr ATTRIBUTE_UNUSED,
810		    unsigned short insn,
811		    char *op1,
812		    char *comm1,
813		    int *cycles)
814{
815  int regs = 0, regd = 0;
816  int as = 0;
817  int cmd_len = 2;
818  int dst = 0;
819  unsigned short udst = 0;
820
821  regd = insn & 0x0f;
822  regs = (insn & 0x0f00) >> 8;
823  as = (insn & 0x0030) >> 4;
824
825  if (regd != 0)	/* Destination register is not a PC.  */
826    return 0;
827
828  /* dst is a source register.  */
829  if (as == 0)
830    {
831      /* Constants.  */
832      if (regs == 3)
833	{
834	  *cycles = 1;
835	  sprintf (op1, "#0");
836	  sprintf (comm1, "r3 As==00");
837	}
838      else
839	{
840	  /* Register.  */
841	  *cycles = 1;
842	  sprintf (op1, "r%d", regs);
843	}
844    }
845  else if (as == 2)
846    {
847      * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2);
848    }
849  else if (as == 3)
850    {
851      if (regs == 0)
852	{
853	  /* Absolute. @pc+  */
854	  *cycles = 3;
855	  if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
856	    {
857	      cmd_len += 2;
858	      sprintf (op1, "#0x%04x", PS (udst));
859	    }
860	  else
861	    return -1;
862	}
863      else
864	* cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
865    }
866  else if (as == 1)
867    {
868      * cycles = 3;
869
870      if (regs == 0)
871	{
872	  /* PC relative.  */
873	  if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
874	    {
875	      cmd_len += 2;
876	      (*cycles)++;
877	      sprintf (op1, "0x%04x", PS (dst));
878	      sprintf (comm1, "PC rel. 0x%04x",
879		       PS ((short) addr + 2 + dst));
880	    }
881	  else
882	    return -1;
883	}
884      else if (regs == 2)
885	{
886	  /* Absolute.  */
887	  if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
888	    {
889	      cmd_len += 2;
890	      sprintf (op1, "&0x%04x", PS (udst));
891	    }
892	  else
893	    return -1;
894	}
895      else if (regs == 3)
896	{
897	  (*cycles)--;
898	  sprintf (op1, "#1");
899	  sprintf (comm1, "r3 As==01");
900	}
901      else
902	{
903	  /* Indexed.  */
904	  if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
905	    {
906	      cmd_len += 2;
907	      sprintf (op1, "%d(r%d)", dst, regs);
908	    }
909	  else
910	    return -1;
911	}
912    }
913
914  return cmd_len;
915}
916
917static int
918msp430x_calla_instr (disassemble_info * info,
919		     bfd_vma            addr,
920		     unsigned short     insn,
921		     char *             op1,
922		     char *             comm1,
923		     int *              cycles)
924{
925  unsigned int   ureg = insn & 0xf;
926  int            reg = insn & 0xf;
927  int            am = (insn & 0xf0) >> 4;
928  int            cmd_len = 2;
929  unsigned short udst = 0;
930  int            dst = 0;
931
932  switch (am)
933    {
934    case 4: /* CALLA Rdst */
935      *cycles = 1;
936      sprintf (op1, "r%d", reg);
937      break;
938
939    case 5: /* CALLA x(Rdst) */
940      *cycles = 3;
941      if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
942	{
943	  cmd_len += 2;
944	  sprintf (op1, "%d(r%d)", dst, reg);
945	  if (reg == 0)
946	    sprintf (comm1, "PC rel. 0x%05lx", (long) (addr + 2 + dst));
947	  else
948	    sprintf (comm1, "0x%05x", dst);
949	}
950      else
951	return -1;
952      break;
953
954    case 6: /* CALLA @Rdst */
955      *cycles = 2;
956      sprintf (op1, "@r%d", reg);
957      break;
958
959    case 7: /* CALLA @Rdst+ */
960      *cycles = 2;
961      sprintf (op1, "@r%d+", reg);
962      break;
963
964    case 8: /* CALLA &abs20 */
965      if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
966	{
967	  cmd_len += 2;
968	  *cycles = 4;
969	  sprintf (op1, "&%d", (ureg << 16) + udst);
970	  sprintf (comm1, "0x%05x", (ureg << 16) + udst);
971	}
972      else
973	return -1;
974      break;
975
976    case 9: /* CALLA pcrel-sym */
977      if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
978	{
979	  cmd_len += 2;
980	  *cycles = 4;
981	  sprintf (op1, "%d(PC)", (reg << 16) + dst);
982	  sprintf (comm1, "PC rel. 0x%05lx",
983		   (long) (addr + 2 + dst + (reg << 16)));
984	}
985      else
986	return -1;
987      break;
988
989    case 11: /* CALLA #imm20 */
990      if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
991	{
992	  cmd_len += 2;
993	  *cycles = 4;
994	  sprintf (op1, "#%d", (ureg << 16) + udst);
995	  sprintf (comm1, "0x%05x", (ureg << 16) + udst);
996	}
997      else
998	return -1;
999      break;
1000
1001    default:
1002      strcpy (comm1, _("Warning: unrecognised CALLA addressing mode"));
1003      return -1;
1004    }
1005
1006  return cmd_len;
1007}
1008
1009int
1010print_insn_msp430 (bfd_vma addr, disassemble_info *info)
1011{
1012  void *stream = info->stream;
1013  fprintf_ftype prin = info->fprintf_func;
1014  struct msp430_opcode_s *opcode;
1015  char op1[32], op2[32], comm1[64], comm2[64];
1016  int cmd_len = 0;
1017  unsigned short insn;
1018  int cycles = 0;
1019  char *bc = "";
1020  unsigned short extension_word = 0;
1021  unsigned short bits;
1022
1023  if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
1024    return -1;
1025
1026  if (((int) addr & 0xffff) > 0xffdf)
1027    {
1028      (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn);
1029      return 2;
1030    }
1031
1032  *comm1 = 0;
1033  *comm2 = 0;
1034
1035  /* Check for an extension word.  */
1036  if ((insn & 0xf800) == 0x1800)
1037    {
1038      extension_word = insn;
1039      addr += 2;
1040      if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
1041	return -1;
1042   }
1043
1044  for (opcode = msp430_opcodes; opcode->name; opcode++)
1045    {
1046      if ((insn & opcode->bin_mask) == opcode->bin_opcode
1047	  && opcode->bin_opcode != 0x9300)
1048	{
1049	  *op1 = 0;
1050	  *op2 = 0;
1051	  *comm1 = 0;
1052	  *comm2 = 0;
1053
1054	  /* r0 as destination. Ad should be zero.  */
1055	  if (opcode->insn_opnumb == 3
1056	      && (insn & 0x000f) == 0
1057	      && (insn & 0x0080) == 0)
1058	    {
1059	      int ret =
1060		msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
1061				    &cycles);
1062
1063	      if (ret == -1)
1064		return -1;
1065	      cmd_len += ret;
1066	      if (cmd_len)
1067		break;
1068	    }
1069
1070	  switch (opcode->insn_opnumb)
1071	    {
1072	      int n;
1073	      int reg;
1074	      int ret;
1075
1076	    case 4:
1077	      ret = msp430x_calla_instr (info, addr, insn,
1078					 op1, comm1, & cycles);
1079	      if (ret == -1)
1080		return -1;
1081	      cmd_len += ret;
1082	      break;
1083
1084	    case 5: /* PUSHM/POPM */
1085	      n = (insn & 0xf0) >> 4;
1086	      reg = (insn & 0xf);
1087
1088	      sprintf (op1, "#%d", n + 1);
1089	      if (opcode->bin_opcode == 0x1400)
1090		/* PUSHM */
1091		sprintf (op2, "r%d", reg);
1092	      else
1093		/* POPM */
1094		sprintf (op2, "r%d", reg + n);
1095	      if (insn & 0x100)
1096		sprintf (comm1, "16-bit words");
1097	      else
1098		{
1099		  sprintf (comm1, "20-bit words");
1100		  bc =".a";
1101		}
1102
1103	      cycles = 2; /*FIXME*/
1104	      cmd_len = 2;
1105	      break;
1106
1107	    case 6: /* RRAM, RRCM, RRUM, RLAM.  */
1108	      n = ((insn >> 10) & 0x3) + 1;
1109	      reg = (insn & 0xf);
1110	      if ((insn & 0x10) == 0)
1111		bc =".a";
1112	      sprintf (op1, "#%d", n);
1113	      sprintf (op2, "r%d", reg);
1114	      cycles = 2; /*FIXME*/
1115	      cmd_len = 2;
1116	      break;
1117
1118	    case 8: /* ADDA, CMPA, SUBA.  */
1119	      reg = (insn & 0xf);
1120	      n = (insn >> 8) & 0xf;
1121	      if (insn & 0x40)
1122		{
1123		  sprintf (op1, "r%d", n);
1124		  cmd_len = 2;
1125		}
1126	      else
1127		{
1128		  n <<= 16;
1129		  if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
1130		    {
1131		      n |= bits;
1132		      sprintf (op1, "#%d", n);
1133		      if (n > 9 || n < 0)
1134			sprintf (comm1, "0x%05x", n);
1135		    }
1136		  else
1137		    return -1;
1138		  cmd_len = 4;
1139		}
1140	      sprintf (op2, "r%d", reg);
1141	      cycles = 2; /*FIXME*/
1142	      break;
1143
1144	    case 9: /* MOVA */
1145	      reg = (insn & 0xf);
1146	      n = (insn >> 8) & 0xf;
1147	      switch ((insn >> 4) & 0xf)
1148		{
1149		case 0: /* MOVA @Rsrc, Rdst */
1150		  cmd_len = 2;
1151		  sprintf (op1, "@r%d", n);
1152		  if (strcmp (opcode->name, "bra") != 0)
1153		    sprintf (op2, "r%d", reg);
1154		  break;
1155
1156		case 1: /* MOVA @Rsrc+, Rdst */
1157		  cmd_len = 2;
1158		  if (strcmp (opcode->name, "reta") != 0)
1159		    {
1160		      sprintf (op1, "@r%d+", n);
1161		      if (strcmp (opcode->name, "bra") != 0)
1162			sprintf (op2, "r%d", reg);
1163		    }
1164		  break;
1165
1166		case 2: /* MOVA &abs20, Rdst */
1167		  cmd_len = 4;
1168		  n <<= 16;
1169		  if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
1170		    {
1171		      n |= bits;
1172		      sprintf (op1, "&%d", n);
1173		      if (n > 9 || n < 0)
1174			sprintf (comm1, "0x%05x", n);
1175		      if (strcmp (opcode->name, "bra") != 0)
1176			sprintf (op2, "r%d", reg);
1177		    }
1178		  else
1179		    return -1;
1180		  break;
1181
1182		case 3: /* MOVA x(Rsrc), Rdst */
1183		  cmd_len = 4;
1184		  if (strcmp (opcode->name, "bra") != 0)
1185		    sprintf (op2, "r%d", reg);
1186		  reg = n;
1187		  if (msp430dis_opcode_signed (addr + 2, info, &n, comm1))
1188		    {
1189		      sprintf (op1, "%d(r%d)", n, reg);
1190		      if (n > 9 || n < 0)
1191			{
1192			  if (reg == 0)
1193			    sprintf (comm1, "PC rel. 0x%05lx",
1194				     (long) (addr + 2 + n));
1195			  else
1196			    sprintf (comm1, "0x%05x", n);
1197			}
1198		    }
1199		  else
1200		    return -1;
1201		  break;
1202
1203		case 6: /* MOVA Rsrc, &abs20 */
1204		  cmd_len = 4;
1205		  reg <<= 16;
1206		  if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm2))
1207		    {
1208		      reg |= bits;
1209		      sprintf (op1, "r%d", n);
1210		      sprintf (op2, "&%d", reg);
1211		      if (reg > 9 || reg < 0)
1212			sprintf (comm2, "0x%05x", reg);
1213		    }
1214		  else
1215		    return -1;
1216		  break;
1217
1218		case 7: /* MOVA Rsrc, x(Rdst) */
1219		  cmd_len = 4;
1220		  sprintf (op1, "r%d", n);
1221		  if (msp430dis_opcode_signed (addr + 2, info, &n, comm2))
1222		    {
1223		      sprintf (op2, "%d(r%d)", n, reg);
1224		      if (n > 9 || n < 0)
1225			{
1226			  if (reg == 0)
1227			    sprintf (comm2, "PC rel. 0x%05lx",
1228				     (long) (addr + 2 + n));
1229			  else
1230			    sprintf (comm2, "0x%05x", n);
1231			}
1232		    }
1233		  else
1234		    return -1;
1235		  break;
1236
1237		case 8: /* MOVA #imm20, Rdst */
1238		  cmd_len = 4;
1239		  n <<= 16;
1240		  if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
1241		    {
1242		      n |= bits;
1243		      if (n & 0x80000)
1244			n |= -1U << 20;
1245		      sprintf (op1, "#%d", n);
1246		      if (n > 9 || n < 0)
1247			sprintf (comm1, "0x%05x", n);
1248		      if (strcmp (opcode->name, "bra") != 0)
1249			sprintf (op2, "r%d", reg);
1250		    }
1251		  else
1252		    return -1;
1253		  break;
1254
1255		case 12: /* MOVA Rsrc, Rdst */
1256		  cmd_len = 2;
1257		  sprintf (op1, "r%d", n);
1258		  if (strcmp (opcode->name, "bra") != 0)
1259		    sprintf (op2, "r%d", reg);
1260		  break;
1261
1262		default:
1263		  break;
1264		}
1265	      cycles = 2; /* FIXME */
1266	      break;
1267	    }
1268
1269	  if (cmd_len)
1270	    break;
1271
1272	  switch (opcode->insn_opnumb)
1273	    {
1274	      int ret;
1275
1276	    case 0:
1277	      cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles);
1278	      break;
1279	    case 2:
1280	      ret =
1281		msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
1282				      comm1, comm2,
1283				      extension_word,
1284				      &cycles);
1285
1286	      if (ret == -1)
1287		return -1;
1288	      cmd_len += ret;
1289	      if (insn & BYTE_OPERATION)
1290		{
1291		  if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
1292		    bc = ".a";
1293		  else
1294		    bc = ".b";
1295		}
1296	      else if (extension_word)
1297		{
1298		  if (extension_word & BYTE_OPERATION)
1299		    bc = ".w";
1300		  else
1301		    {
1302		      bc = ".?";
1303		      sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1304		    }
1305		}
1306
1307	      break;
1308	    case 1:
1309	      ret =
1310		msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
1311				      extension_word,
1312				      &cycles);
1313
1314	      if (ret == -1)
1315		return -1;
1316	      cmd_len += ret;
1317	      if (extension_word
1318		  && (strcmp (opcode->name, "swpb") == 0
1319		      || strcmp (opcode->name, "sxt") == 0))
1320		{
1321		  if (insn & BYTE_OPERATION)
1322		    {
1323		      bc = ".?";
1324		      sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1325		    }
1326		  else if (extension_word & BYTE_OPERATION)
1327		    bc = ".w";
1328		  else
1329		    bc = ".a";
1330		}
1331	      else if (insn & BYTE_OPERATION && opcode->fmt != 3)
1332		{
1333		  if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
1334		    bc = ".a";
1335		  else
1336		    bc = ".b";
1337		}
1338	      else if (extension_word)
1339		{
1340		  if (extension_word & (1 << 6))
1341		    bc = ".w";
1342		  else
1343		    {
1344		      bc = ".?";
1345		      sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1346		    }
1347		}
1348	      break;
1349	    default:
1350	      break;
1351	    }
1352	}
1353
1354      if (cmd_len)
1355	break;
1356    }
1357
1358  if (cmd_len < 1)
1359    {
1360      /* Unknown opcode, or invalid combination of operands.  */
1361      if (extension_word)
1362	{
1363	  prin (stream, ".word	0x%04x, 0x%04x;	????", extension_word, PS (insn));
1364	  if (*comm1)
1365	    prin (stream, "\t %s", comm1);
1366	  return 4;
1367	}
1368      (*prin) (stream, ".word	0x%04x;	????", PS (insn));
1369      return 2;
1370    }
1371
1372  /* Display the repeat count (if set) for extended register mode.  */
1373  if (cmd_len == 2 && ((extension_word & 0xf) != 0))
1374    {
1375      if (extension_word & (1 << 7))
1376	prin (stream, "rpt r%d { ", extension_word & 0xf);
1377      else
1378	prin (stream, "rpt #%d { ", (extension_word & 0xf) + 1);
1379    }
1380
1381  /* Special case:  RRC with an extension word and the ZC bit set is actually RRU.  */
1382  if (extension_word
1383      && (extension_word & IGNORE_CARRY_BIT)
1384      && strcmp (opcode->name, "rrc") == 0)
1385    (*prin) (stream, "rrux%s", bc);
1386  else if (extension_word && opcode->name[strlen (opcode->name) - 1] != 'x')
1387    (*prin) (stream, "%sx%s", opcode->name, bc);
1388  else
1389    (*prin) (stream, "%s%s", opcode->name, bc);
1390
1391  if (*op1)
1392    (*prin) (stream, "\t%s", op1);
1393  if (*op2)
1394    (*prin) (stream, ",");
1395
1396  if (strlen (op1) < 7)
1397    (*prin) (stream, "\t");
1398  if (!strlen (op1))
1399    (*prin) (stream, "\t");
1400
1401  if (*op2)
1402    (*prin) (stream, "%s", op2);
1403  if (strlen (op2) < 8)
1404    (*prin) (stream, "\t");
1405
1406  if (*comm1 || *comm2)
1407    (*prin) (stream, ";");
1408  else if (cycles)
1409    {
1410      if (*op2)
1411	(*prin) (stream, ";");
1412      else
1413	{
1414	  if (strlen (op1) < 7)
1415	    (*prin) (stream, ";");
1416	  else
1417	    (*prin) (stream, "\t;");
1418	}
1419    }
1420  if (*comm1)
1421    (*prin) (stream, "%s", comm1);
1422  if (*comm1 && *comm2)
1423    (*prin) (stream, ",");
1424  if (*comm2)
1425    (*prin) (stream, " %s", comm2);
1426
1427  if (extension_word)
1428    cmd_len += 2;
1429
1430  return cmd_len;
1431}
1432