xref: /netbsd-src/external/gpl3/gdb/dist/opcodes/msp430-dis.c (revision f1aa49ed04d5d204a9f57d6a2d621025eb1f86d9)
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 
40 static bool
41 msp430dis_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 
71 static bool
72 msp430dis_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 
91 static bool
92 msp430dis_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 
116 static int
117 msp430_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 
146 static int
147 print_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 
169 static int
170 print_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 
192 static int
193 msp430_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 
449 static int
450 msp430_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 
806 static int
807 msp430_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 
917 static int
918 msp430x_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 
1009 int
1010 print_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