xref: /openbsd-src/gnu/usr.bin/binutils-2.17/opcodes/msp430-dis.c (revision 3d8817e467ea46cf4772788d6804dd293abfb01a)
1*3d8817e4Smiod /* Disassemble MSP430 instructions.
2*3d8817e4Smiod    Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
3*3d8817e4Smiod 
4*3d8817e4Smiod    Contributed by Dmitry Diky <diwil@mail.ru>
5*3d8817e4Smiod 
6*3d8817e4Smiod    This program is free software; you can redistribute it and/or modify
7*3d8817e4Smiod    it under the terms of the GNU General Public License as published by
8*3d8817e4Smiod    the Free Software Foundation; either version 2 of the License, or
9*3d8817e4Smiod    (at your option) any later version.
10*3d8817e4Smiod 
11*3d8817e4Smiod    This program is distributed in the hope that it will be useful,
12*3d8817e4Smiod    but WITHOUT ANY WARRANTY; without even the implied warranty of
13*3d8817e4Smiod    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*3d8817e4Smiod    GNU General Public License for more details.
15*3d8817e4Smiod 
16*3d8817e4Smiod    You should have received a copy of the GNU General Public License
17*3d8817e4Smiod    along with this program; if not, write to the Free Software
18*3d8817e4Smiod    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19*3d8817e4Smiod    MA 02110-1301, USA.  */
20*3d8817e4Smiod 
21*3d8817e4Smiod #include <stdio.h>
22*3d8817e4Smiod #include <ctype.h>
23*3d8817e4Smiod #include <string.h>
24*3d8817e4Smiod #include <sys/types.h>
25*3d8817e4Smiod 
26*3d8817e4Smiod #include "dis-asm.h"
27*3d8817e4Smiod #include "opintl.h"
28*3d8817e4Smiod #include "libiberty.h"
29*3d8817e4Smiod 
30*3d8817e4Smiod #define DASM_SECTION
31*3d8817e4Smiod #include "opcode/msp430.h"
32*3d8817e4Smiod #undef DASM_SECTION
33*3d8817e4Smiod 
34*3d8817e4Smiod 
35*3d8817e4Smiod #define PS(x)   (0xffff & (x))
36*3d8817e4Smiod 
37*3d8817e4Smiod static unsigned short
msp430dis_opcode(bfd_vma addr,disassemble_info * info)38*3d8817e4Smiod msp430dis_opcode (bfd_vma addr, disassemble_info *info)
39*3d8817e4Smiod {
40*3d8817e4Smiod   bfd_byte buffer[2];
41*3d8817e4Smiod   int status;
42*3d8817e4Smiod 
43*3d8817e4Smiod   status = info->read_memory_func (addr, buffer, 2, info);
44*3d8817e4Smiod   if (status != 0)
45*3d8817e4Smiod     {
46*3d8817e4Smiod       info->memory_error_func (status, addr, info);
47*3d8817e4Smiod       return -1;
48*3d8817e4Smiod     }
49*3d8817e4Smiod   return bfd_getl16 (buffer);
50*3d8817e4Smiod }
51*3d8817e4Smiod 
52*3d8817e4Smiod static int
msp430_nooperands(struct msp430_opcode_s * opcode,bfd_vma addr ATTRIBUTE_UNUSED,unsigned short insn ATTRIBUTE_UNUSED,char * comm,int * cycles)53*3d8817e4Smiod msp430_nooperands (struct msp430_opcode_s *opcode,
54*3d8817e4Smiod 		   bfd_vma addr ATTRIBUTE_UNUSED,
55*3d8817e4Smiod 		   unsigned short insn ATTRIBUTE_UNUSED,
56*3d8817e4Smiod 		   char *comm,
57*3d8817e4Smiod 		   int *cycles)
58*3d8817e4Smiod {
59*3d8817e4Smiod   /* Pop with constant.  */
60*3d8817e4Smiod   if (insn == 0x43b2)
61*3d8817e4Smiod     return 0;
62*3d8817e4Smiod   if (insn == opcode->bin_opcode)
63*3d8817e4Smiod     return 2;
64*3d8817e4Smiod 
65*3d8817e4Smiod   if (opcode->fmt == 0)
66*3d8817e4Smiod     {
67*3d8817e4Smiod       if ((insn & 0x0f00) != 3 || (insn & 0x0f00) != 2)
68*3d8817e4Smiod 	return 0;
69*3d8817e4Smiod 
70*3d8817e4Smiod       strcpy (comm, "emulated...");
71*3d8817e4Smiod       *cycles = 1;
72*3d8817e4Smiod     }
73*3d8817e4Smiod   else
74*3d8817e4Smiod     {
75*3d8817e4Smiod       strcpy (comm, "return from interupt");
76*3d8817e4Smiod       *cycles = 5;
77*3d8817e4Smiod     }
78*3d8817e4Smiod 
79*3d8817e4Smiod   return 2;
80*3d8817e4Smiod }
81*3d8817e4Smiod 
82*3d8817e4Smiod static int
msp430_singleoperand(disassemble_info * info,struct msp430_opcode_s * opcode,bfd_vma addr,unsigned short insn,char * op,char * comm,int * cycles)83*3d8817e4Smiod msp430_singleoperand (disassemble_info *info,
84*3d8817e4Smiod 		      struct msp430_opcode_s *opcode,
85*3d8817e4Smiod 		      bfd_vma addr,
86*3d8817e4Smiod 		      unsigned short insn,
87*3d8817e4Smiod 		      char *op,
88*3d8817e4Smiod 		      char *comm,
89*3d8817e4Smiod 		      int *cycles)
90*3d8817e4Smiod {
91*3d8817e4Smiod   int regs = 0, regd = 0;
92*3d8817e4Smiod   int ad = 0, as = 0;
93*3d8817e4Smiod   int where = 0;
94*3d8817e4Smiod   int cmd_len = 2;
95*3d8817e4Smiod   short dst = 0;
96*3d8817e4Smiod 
97*3d8817e4Smiod   regd = insn & 0x0f;
98*3d8817e4Smiod   regs = (insn & 0x0f00) >> 8;
99*3d8817e4Smiod   as = (insn & 0x0030) >> 4;
100*3d8817e4Smiod   ad = (insn & 0x0080) >> 7;
101*3d8817e4Smiod 
102*3d8817e4Smiod   switch (opcode->fmt)
103*3d8817e4Smiod     {
104*3d8817e4Smiod     case 0:			/* Emulated work with dst register.  */
105*3d8817e4Smiod       if (regs != 2 && regs != 3 && regs != 1)
106*3d8817e4Smiod 	return 0;
107*3d8817e4Smiod 
108*3d8817e4Smiod       /* Check if not clr insn.  */
109*3d8817e4Smiod       if (opcode->bin_opcode == 0x4300 && (ad || as))
110*3d8817e4Smiod 	return 0;
111*3d8817e4Smiod 
112*3d8817e4Smiod       /* Check if really inc, incd insns.  */
113*3d8817e4Smiod       if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3)
114*3d8817e4Smiod 	return 0;
115*3d8817e4Smiod 
116*3d8817e4Smiod       if (ad == 0)
117*3d8817e4Smiod 	{
118*3d8817e4Smiod 	  *cycles = 1;
119*3d8817e4Smiod 
120*3d8817e4Smiod 	  /* Register.  */
121*3d8817e4Smiod 	  if (regd == 0)
122*3d8817e4Smiod 	    {
123*3d8817e4Smiod 	      *cycles += 1;
124*3d8817e4Smiod 	      sprintf (op, "r0");
125*3d8817e4Smiod 	    }
126*3d8817e4Smiod 	  else if (regd == 1)
127*3d8817e4Smiod 	    sprintf (op, "r1");
128*3d8817e4Smiod 
129*3d8817e4Smiod 	  else if (regd == 2)
130*3d8817e4Smiod 	    sprintf (op, "r2");
131*3d8817e4Smiod 
132*3d8817e4Smiod 	  else
133*3d8817e4Smiod 	    sprintf (op, "r%d", regd);
134*3d8817e4Smiod 	}
135*3d8817e4Smiod       else	/* ad == 1 msp430dis_opcode.  */
136*3d8817e4Smiod 	{
137*3d8817e4Smiod 	  if (regd == 0)
138*3d8817e4Smiod 	    {
139*3d8817e4Smiod 	      /* PC relative.  */
140*3d8817e4Smiod 	      dst = msp430dis_opcode (addr + 2, info);
141*3d8817e4Smiod 	      cmd_len += 2;
142*3d8817e4Smiod 	      *cycles = 4;
143*3d8817e4Smiod 	      sprintf (op, "0x%04x", dst);
144*3d8817e4Smiod 	      sprintf (comm, "PC rel. abs addr 0x%04x",
145*3d8817e4Smiod 		       PS ((short) (addr + 2) + dst));
146*3d8817e4Smiod 	    }
147*3d8817e4Smiod 	  else if (regd == 2)
148*3d8817e4Smiod 	    {
149*3d8817e4Smiod 	      /* Absolute.  */
150*3d8817e4Smiod 	      dst = msp430dis_opcode (addr + 2, info);
151*3d8817e4Smiod 	      cmd_len += 2;
152*3d8817e4Smiod 	      *cycles = 4;
153*3d8817e4Smiod 	      sprintf (op, "&0x%04x", PS (dst));
154*3d8817e4Smiod 	    }
155*3d8817e4Smiod 	  else
156*3d8817e4Smiod 	    {
157*3d8817e4Smiod 	      dst = msp430dis_opcode (addr + 2, info);
158*3d8817e4Smiod 	      cmd_len += 2;
159*3d8817e4Smiod 	      *cycles = 4;
160*3d8817e4Smiod 	      sprintf (op, "%d(r%d)", dst, regd);
161*3d8817e4Smiod 	    }
162*3d8817e4Smiod 	}
163*3d8817e4Smiod       break;
164*3d8817e4Smiod 
165*3d8817e4Smiod     case 2:	/* rrc, push, call, swpb, rra, sxt, push, call, reti etc...  */
166*3d8817e4Smiod       if (as == 0)
167*3d8817e4Smiod 	{
168*3d8817e4Smiod 	  if (regd == 3)
169*3d8817e4Smiod 	    {
170*3d8817e4Smiod 	      /* Constsnts.  */
171*3d8817e4Smiod 	      sprintf (op, "#0");
172*3d8817e4Smiod 	      sprintf (comm, "r3 As==00");
173*3d8817e4Smiod 	    }
174*3d8817e4Smiod 	  else
175*3d8817e4Smiod 	    {
176*3d8817e4Smiod 	      /* Register.  */
177*3d8817e4Smiod 	      sprintf (op, "r%d", regd);
178*3d8817e4Smiod 	    }
179*3d8817e4Smiod 	  *cycles = 1;
180*3d8817e4Smiod 	}
181*3d8817e4Smiod       else if (as == 2)
182*3d8817e4Smiod 	{
183*3d8817e4Smiod 	  *cycles = 1;
184*3d8817e4Smiod 	  if (regd == 2)
185*3d8817e4Smiod 	    {
186*3d8817e4Smiod 	      sprintf (op, "#4");
187*3d8817e4Smiod 	      sprintf (comm, "r2 As==10");
188*3d8817e4Smiod 	    }
189*3d8817e4Smiod 	  else if (regd == 3)
190*3d8817e4Smiod 	    {
191*3d8817e4Smiod 	      sprintf (op, "#2");
192*3d8817e4Smiod 	      sprintf (comm, "r3 As==10");
193*3d8817e4Smiod 	    }
194*3d8817e4Smiod 	  else
195*3d8817e4Smiod 	    {
196*3d8817e4Smiod 	      *cycles = 3;
197*3d8817e4Smiod 	      /* Indexed register mode @Rn.  */
198*3d8817e4Smiod 	      sprintf (op, "@r%d", regd);
199*3d8817e4Smiod 	    }
200*3d8817e4Smiod 	}
201*3d8817e4Smiod       else if (as == 3)
202*3d8817e4Smiod 	{
203*3d8817e4Smiod 	  *cycles = 1;
204*3d8817e4Smiod 	  if (regd == 2)
205*3d8817e4Smiod 	    {
206*3d8817e4Smiod 	      sprintf (op, "#8");
207*3d8817e4Smiod 	      sprintf (comm, "r2 As==11");
208*3d8817e4Smiod 	    }
209*3d8817e4Smiod 	  else if (regd == 3)
210*3d8817e4Smiod 	    {
211*3d8817e4Smiod 	      sprintf (op, "#-1");
212*3d8817e4Smiod 	      sprintf (comm, "r3 As==11");
213*3d8817e4Smiod 	    }
214*3d8817e4Smiod 	  else if (regd == 0)
215*3d8817e4Smiod 	    {
216*3d8817e4Smiod 	      *cycles = 3;
217*3d8817e4Smiod 	      /* absolute. @pc+ */
218*3d8817e4Smiod 	      dst = msp430dis_opcode (addr + 2, info);
219*3d8817e4Smiod 	      cmd_len += 2;
220*3d8817e4Smiod 	      sprintf (op, "#%d", dst);
221*3d8817e4Smiod 	      sprintf (comm, "#0x%04x", PS (dst));
222*3d8817e4Smiod 	    }
223*3d8817e4Smiod 	  else
224*3d8817e4Smiod 	    {
225*3d8817e4Smiod 	      *cycles = 3;
226*3d8817e4Smiod 	      sprintf (op, "@r%d+", regd);
227*3d8817e4Smiod 	    }
228*3d8817e4Smiod 	}
229*3d8817e4Smiod       else if (as == 1)
230*3d8817e4Smiod 	{
231*3d8817e4Smiod 	  *cycles = 4;
232*3d8817e4Smiod 	  if (regd == 0)
233*3d8817e4Smiod 	    {
234*3d8817e4Smiod 	      /* PC relative.  */
235*3d8817e4Smiod 	      dst = msp430dis_opcode (addr + 2, info);
236*3d8817e4Smiod 	      cmd_len += 2;
237*3d8817e4Smiod 	      sprintf (op, "0x%04x", PS (dst));
238*3d8817e4Smiod 	      sprintf (comm, "PC rel. 0x%04x",
239*3d8817e4Smiod 		       PS ((short) addr + 2 + dst));
240*3d8817e4Smiod 	    }
241*3d8817e4Smiod 	  else if (regd == 2)
242*3d8817e4Smiod 	    {
243*3d8817e4Smiod 	      /* Absolute.  */
244*3d8817e4Smiod 	      dst = msp430dis_opcode (addr + 2, info);
245*3d8817e4Smiod 	      cmd_len += 2;
246*3d8817e4Smiod 	      sprintf (op, "&0x%04x", PS (dst));
247*3d8817e4Smiod 	    }
248*3d8817e4Smiod 	  else if (regd == 3)
249*3d8817e4Smiod 	    {
250*3d8817e4Smiod 	      *cycles = 1;
251*3d8817e4Smiod 	      sprintf (op, "#1");
252*3d8817e4Smiod 	      sprintf (comm, "r3 As==01");
253*3d8817e4Smiod 	    }
254*3d8817e4Smiod 	  else
255*3d8817e4Smiod 	    {
256*3d8817e4Smiod 	      /* Indexd.  */
257*3d8817e4Smiod 	      dst = msp430dis_opcode (addr + 2, info);
258*3d8817e4Smiod 	      cmd_len += 2;
259*3d8817e4Smiod 	      sprintf (op, "%d(r%d)", dst, regd);
260*3d8817e4Smiod 	    }
261*3d8817e4Smiod 	}
262*3d8817e4Smiod       break;
263*3d8817e4Smiod 
264*3d8817e4Smiod     case 3:			/* Jumps.  */
265*3d8817e4Smiod       where = insn & 0x03ff;
266*3d8817e4Smiod       if (where & 0x200)
267*3d8817e4Smiod 	where |= ~0x03ff;
268*3d8817e4Smiod       if (where > 512 || where < -511)
269*3d8817e4Smiod 	return 0;
270*3d8817e4Smiod 
271*3d8817e4Smiod       where *= 2;
272*3d8817e4Smiod       sprintf (op, "$%+-8d", where + 2);
273*3d8817e4Smiod       sprintf (comm, "abs 0x%x", PS ((short) (addr) + 2 + where));
274*3d8817e4Smiod       *cycles = 2;
275*3d8817e4Smiod       return 2;
276*3d8817e4Smiod       break;
277*3d8817e4Smiod     default:
278*3d8817e4Smiod       cmd_len = 0;
279*3d8817e4Smiod     }
280*3d8817e4Smiod 
281*3d8817e4Smiod   return cmd_len;
282*3d8817e4Smiod }
283*3d8817e4Smiod 
284*3d8817e4Smiod static int
msp430_doubleoperand(disassemble_info * info,struct msp430_opcode_s * opcode,bfd_vma addr,unsigned short insn,char * op1,char * op2,char * comm1,char * comm2,int * cycles)285*3d8817e4Smiod msp430_doubleoperand (disassemble_info *info,
286*3d8817e4Smiod 		      struct msp430_opcode_s *opcode,
287*3d8817e4Smiod 		      bfd_vma addr,
288*3d8817e4Smiod 		      unsigned short insn,
289*3d8817e4Smiod 		      char *op1,
290*3d8817e4Smiod 		      char *op2,
291*3d8817e4Smiod 		      char *comm1,
292*3d8817e4Smiod 		      char *comm2,
293*3d8817e4Smiod 		      int *cycles)
294*3d8817e4Smiod {
295*3d8817e4Smiod   int regs = 0, regd = 0;
296*3d8817e4Smiod   int ad = 0, as = 0;
297*3d8817e4Smiod   int cmd_len = 2;
298*3d8817e4Smiod   short dst = 0;
299*3d8817e4Smiod 
300*3d8817e4Smiod   regd = insn & 0x0f;
301*3d8817e4Smiod   regs = (insn & 0x0f00) >> 8;
302*3d8817e4Smiod   as = (insn & 0x0030) >> 4;
303*3d8817e4Smiod   ad = (insn & 0x0080) >> 7;
304*3d8817e4Smiod 
305*3d8817e4Smiod   if (opcode->fmt == 0)
306*3d8817e4Smiod     {
307*3d8817e4Smiod       /* Special case: rla and rlc are the only 2 emulated instructions that
308*3d8817e4Smiod 	 fall into two operand instructions.  */
309*3d8817e4Smiod       /* With dst, there are only:
310*3d8817e4Smiod 	 Rm       	Register,
311*3d8817e4Smiod          x(Rm)     	Indexed,
312*3d8817e4Smiod          0xXXXX    	Relative,
313*3d8817e4Smiod          &0xXXXX    	Absolute
314*3d8817e4Smiod          emulated_ins   dst
315*3d8817e4Smiod          basic_ins      dst, dst.  */
316*3d8817e4Smiod 
317*3d8817e4Smiod       if (regd != regs || as != ad)
318*3d8817e4Smiod 	return 0;		/* May be 'data' section.  */
319*3d8817e4Smiod 
320*3d8817e4Smiod       if (ad == 0)
321*3d8817e4Smiod 	{
322*3d8817e4Smiod 	  /* Register mode.  */
323*3d8817e4Smiod 	  if (regd == 3)
324*3d8817e4Smiod 	    {
325*3d8817e4Smiod 	      strcpy (comm1, _("Illegal as emulation instr"));
326*3d8817e4Smiod 	      return -1;
327*3d8817e4Smiod 	    }
328*3d8817e4Smiod 
329*3d8817e4Smiod 	  sprintf (op1, "r%d", regd);
330*3d8817e4Smiod 	  *cycles = 1;
331*3d8817e4Smiod 	}
332*3d8817e4Smiod       else			/* ad == 1 */
333*3d8817e4Smiod 	{
334*3d8817e4Smiod 	  if (regd == 0)
335*3d8817e4Smiod 	    {
336*3d8817e4Smiod 	      /* PC relative, Symbolic.  */
337*3d8817e4Smiod 	      dst = msp430dis_opcode (addr + 2, info);
338*3d8817e4Smiod 	      cmd_len += 4;
339*3d8817e4Smiod 	      *cycles = 6;
340*3d8817e4Smiod 	      sprintf (op1, "0x%04x", PS (dst));
341*3d8817e4Smiod 	      sprintf (comm1, "PC rel. 0x%04x",
342*3d8817e4Smiod 		       PS ((short) addr + 2 + dst));
343*3d8817e4Smiod 
344*3d8817e4Smiod 	    }
345*3d8817e4Smiod 	  else if (regd == 2)
346*3d8817e4Smiod 	    {
347*3d8817e4Smiod 	      /* Absolute.  */
348*3d8817e4Smiod 	      dst = msp430dis_opcode (addr + 2, info);
349*3d8817e4Smiod 	      /* If the 'src' field is not the same as the dst
350*3d8817e4Smiod 		 then this is not an rla instruction.  */
351*3d8817e4Smiod 	      if (dst != msp430dis_opcode (addr + 4, info))
352*3d8817e4Smiod 		return 0;
353*3d8817e4Smiod 	      cmd_len += 4;
354*3d8817e4Smiod 	      *cycles = 6;
355*3d8817e4Smiod 	      sprintf (op1, "&0x%04x", PS (dst));
356*3d8817e4Smiod 	    }
357*3d8817e4Smiod 	  else
358*3d8817e4Smiod 	    {
359*3d8817e4Smiod 	      /* Indexed.  */
360*3d8817e4Smiod 	      dst = msp430dis_opcode (addr + 2, info);
361*3d8817e4Smiod 	      cmd_len += 4;
362*3d8817e4Smiod 	      *cycles = 6;
363*3d8817e4Smiod 	      sprintf (op1, "%d(r%d)", dst, regd);
364*3d8817e4Smiod 	    }
365*3d8817e4Smiod 	}
366*3d8817e4Smiod 
367*3d8817e4Smiod       *op2 = 0;
368*3d8817e4Smiod       *comm2 = 0;
369*3d8817e4Smiod       return cmd_len;
370*3d8817e4Smiod     }
371*3d8817e4Smiod 
372*3d8817e4Smiod   /* Two operands exactly.  */
373*3d8817e4Smiod   if (ad == 0 && regd == 3)
374*3d8817e4Smiod     {
375*3d8817e4Smiod       /* R2/R3 are illegal as dest: may be data section.  */
376*3d8817e4Smiod       strcpy (comm1, _("Illegal as 2-op instr"));
377*3d8817e4Smiod       return -1;
378*3d8817e4Smiod     }
379*3d8817e4Smiod 
380*3d8817e4Smiod   /* Source.  */
381*3d8817e4Smiod   if (as == 0)
382*3d8817e4Smiod     {
383*3d8817e4Smiod       *cycles = 1;
384*3d8817e4Smiod       if (regs == 3)
385*3d8817e4Smiod 	{
386*3d8817e4Smiod 	  /* Constsnts.  */
387*3d8817e4Smiod 	  sprintf (op1, "#0");
388*3d8817e4Smiod 	  sprintf (comm1, "r3 As==00");
389*3d8817e4Smiod 	}
390*3d8817e4Smiod       else
391*3d8817e4Smiod 	{
392*3d8817e4Smiod 	  /* Register.  */
393*3d8817e4Smiod 	  sprintf (op1, "r%d", regs);
394*3d8817e4Smiod 	}
395*3d8817e4Smiod     }
396*3d8817e4Smiod   else if (as == 2)
397*3d8817e4Smiod     {
398*3d8817e4Smiod       *cycles = 1;
399*3d8817e4Smiod 
400*3d8817e4Smiod       if (regs == 2)
401*3d8817e4Smiod 	{
402*3d8817e4Smiod 	  sprintf (op1, "#4");
403*3d8817e4Smiod 	  sprintf (comm1, "r2 As==10");
404*3d8817e4Smiod 	}
405*3d8817e4Smiod       else if (regs == 3)
406*3d8817e4Smiod 	{
407*3d8817e4Smiod 	  sprintf (op1, "#2");
408*3d8817e4Smiod 	  sprintf (comm1, "r3 As==10");
409*3d8817e4Smiod 	}
410*3d8817e4Smiod       else
411*3d8817e4Smiod 	{
412*3d8817e4Smiod 	  *cycles = 2;
413*3d8817e4Smiod 
414*3d8817e4Smiod 	  /* Indexed register mode @Rn.  */
415*3d8817e4Smiod 	  sprintf (op1, "@r%d", regs);
416*3d8817e4Smiod 	}
417*3d8817e4Smiod       if (!regs)
418*3d8817e4Smiod 	*cycles = 3;
419*3d8817e4Smiod     }
420*3d8817e4Smiod   else if (as == 3)
421*3d8817e4Smiod     {
422*3d8817e4Smiod       if (regs == 2)
423*3d8817e4Smiod 	{
424*3d8817e4Smiod 	  sprintf (op1, "#8");
425*3d8817e4Smiod 	  sprintf (comm1, "r2 As==11");
426*3d8817e4Smiod 	  *cycles = 1;
427*3d8817e4Smiod 	}
428*3d8817e4Smiod       else if (regs == 3)
429*3d8817e4Smiod 	{
430*3d8817e4Smiod 	  sprintf (op1, "#-1");
431*3d8817e4Smiod 	  sprintf (comm1, "r3 As==11");
432*3d8817e4Smiod 	  *cycles = 1;
433*3d8817e4Smiod 	}
434*3d8817e4Smiod       else if (regs == 0)
435*3d8817e4Smiod 	{
436*3d8817e4Smiod 	  *cycles = 3;
437*3d8817e4Smiod 	  /* Absolute. @pc+.  */
438*3d8817e4Smiod 	  dst = msp430dis_opcode (addr + 2, info);
439*3d8817e4Smiod 	  cmd_len += 2;
440*3d8817e4Smiod 	  sprintf (op1, "#%d", dst);
441*3d8817e4Smiod 	  sprintf (comm1, "#0x%04x", PS (dst));
442*3d8817e4Smiod 	}
443*3d8817e4Smiod       else
444*3d8817e4Smiod 	{
445*3d8817e4Smiod 	  *cycles = 2;
446*3d8817e4Smiod 	  sprintf (op1, "@r%d+", regs);
447*3d8817e4Smiod 	}
448*3d8817e4Smiod     }
449*3d8817e4Smiod   else if (as == 1)
450*3d8817e4Smiod     {
451*3d8817e4Smiod       if (regs == 0)
452*3d8817e4Smiod 	{
453*3d8817e4Smiod 	  *cycles = 4;
454*3d8817e4Smiod 	  /* PC relative.  */
455*3d8817e4Smiod 	  dst = msp430dis_opcode (addr + 2, info);
456*3d8817e4Smiod 	  cmd_len += 2;
457*3d8817e4Smiod 	  sprintf (op1, "0x%04x", PS (dst));
458*3d8817e4Smiod 	  sprintf (comm1, "PC rel. 0x%04x",
459*3d8817e4Smiod 		   PS ((short) addr + 2 + dst));
460*3d8817e4Smiod 	}
461*3d8817e4Smiod       else if (regs == 2)
462*3d8817e4Smiod 	{
463*3d8817e4Smiod 	  *cycles = 2;
464*3d8817e4Smiod 	  /* Absolute.  */
465*3d8817e4Smiod 	  dst = msp430dis_opcode (addr + 2, info);
466*3d8817e4Smiod 	  cmd_len += 2;
467*3d8817e4Smiod 	  sprintf (op1, "&0x%04x", PS (dst));
468*3d8817e4Smiod 	  sprintf (comm1, "0x%04x", PS (dst));
469*3d8817e4Smiod 	}
470*3d8817e4Smiod       else if (regs == 3)
471*3d8817e4Smiod 	{
472*3d8817e4Smiod 	  *cycles = 1;
473*3d8817e4Smiod 	  sprintf (op1, "#1");
474*3d8817e4Smiod 	  sprintf (comm1, "r3 As==01");
475*3d8817e4Smiod 	}
476*3d8817e4Smiod       else
477*3d8817e4Smiod 	{
478*3d8817e4Smiod 	  *cycles = 3;
479*3d8817e4Smiod 	  /* Indexed.  */
480*3d8817e4Smiod 	  dst = msp430dis_opcode (addr + 2, info);
481*3d8817e4Smiod 	  cmd_len += 2;
482*3d8817e4Smiod 	  sprintf (op1, "%d(r%d)", dst, regs);
483*3d8817e4Smiod 	}
484*3d8817e4Smiod     }
485*3d8817e4Smiod 
486*3d8817e4Smiod   /* Destination. Special care needed on addr + XXXX.  */
487*3d8817e4Smiod 
488*3d8817e4Smiod   if (ad == 0)
489*3d8817e4Smiod     {
490*3d8817e4Smiod       /* Register.  */
491*3d8817e4Smiod       if (regd == 0)
492*3d8817e4Smiod 	{
493*3d8817e4Smiod 	  *cycles += 1;
494*3d8817e4Smiod 	  sprintf (op2, "r0");
495*3d8817e4Smiod 	}
496*3d8817e4Smiod       else if (regd == 1)
497*3d8817e4Smiod 	sprintf (op2, "r1");
498*3d8817e4Smiod 
499*3d8817e4Smiod       else if (regd == 2)
500*3d8817e4Smiod 	sprintf (op2, "r2");
501*3d8817e4Smiod 
502*3d8817e4Smiod       else
503*3d8817e4Smiod 	sprintf (op2, "r%d", regd);
504*3d8817e4Smiod     }
505*3d8817e4Smiod   else	/* ad == 1.  */
506*3d8817e4Smiod     {
507*3d8817e4Smiod       * cycles += 3;
508*3d8817e4Smiod 
509*3d8817e4Smiod       if (regd == 0)
510*3d8817e4Smiod 	{
511*3d8817e4Smiod 	  /* PC relative.  */
512*3d8817e4Smiod 	  *cycles += 1;
513*3d8817e4Smiod 	  dst = msp430dis_opcode (addr + cmd_len, info);
514*3d8817e4Smiod 	  sprintf (op2, "0x%04x", PS (dst));
515*3d8817e4Smiod 	  sprintf (comm2, "PC rel. 0x%04x",
516*3d8817e4Smiod 		   PS ((short) addr + cmd_len + dst));
517*3d8817e4Smiod 	  cmd_len += 2;
518*3d8817e4Smiod 	}
519*3d8817e4Smiod       else if (regd == 2)
520*3d8817e4Smiod 	{
521*3d8817e4Smiod 	  /* Absolute.  */
522*3d8817e4Smiod 	  dst = msp430dis_opcode (addr + cmd_len, info);
523*3d8817e4Smiod 	  cmd_len += 2;
524*3d8817e4Smiod 	  sprintf (op2, "&0x%04x", PS (dst));
525*3d8817e4Smiod 	}
526*3d8817e4Smiod       else
527*3d8817e4Smiod 	{
528*3d8817e4Smiod 	  dst = msp430dis_opcode (addr + cmd_len, info);
529*3d8817e4Smiod 	  cmd_len += 2;
530*3d8817e4Smiod 	  sprintf (op2, "%d(r%d)", dst, regd);
531*3d8817e4Smiod 	}
532*3d8817e4Smiod     }
533*3d8817e4Smiod 
534*3d8817e4Smiod   return cmd_len;
535*3d8817e4Smiod }
536*3d8817e4Smiod 
537*3d8817e4Smiod static int
msp430_branchinstr(disassemble_info * info,struct msp430_opcode_s * opcode ATTRIBUTE_UNUSED,bfd_vma addr ATTRIBUTE_UNUSED,unsigned short insn,char * op1,char * comm1,int * cycles)538*3d8817e4Smiod msp430_branchinstr (disassemble_info *info,
539*3d8817e4Smiod 		    struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
540*3d8817e4Smiod 		    bfd_vma addr ATTRIBUTE_UNUSED,
541*3d8817e4Smiod 		    unsigned short insn,
542*3d8817e4Smiod 		    char *op1,
543*3d8817e4Smiod 		    char *comm1,
544*3d8817e4Smiod 		    int *cycles)
545*3d8817e4Smiod {
546*3d8817e4Smiod   int regs = 0, regd = 0;
547*3d8817e4Smiod   int ad = 0, as = 0;
548*3d8817e4Smiod   int cmd_len = 2;
549*3d8817e4Smiod   short dst = 0;
550*3d8817e4Smiod 
551*3d8817e4Smiod   regd = insn & 0x0f;
552*3d8817e4Smiod   regs = (insn & 0x0f00) >> 8;
553*3d8817e4Smiod   as = (insn & 0x0030) >> 4;
554*3d8817e4Smiod   ad = (insn & 0x0080) >> 7;
555*3d8817e4Smiod 
556*3d8817e4Smiod   if (regd != 0)	/* Destination register is not a PC.  */
557*3d8817e4Smiod     return 0;
558*3d8817e4Smiod 
559*3d8817e4Smiod   /* dst is a source register.  */
560*3d8817e4Smiod   if (as == 0)
561*3d8817e4Smiod     {
562*3d8817e4Smiod       /* Constants.  */
563*3d8817e4Smiod       if (regs == 3)
564*3d8817e4Smiod 	{
565*3d8817e4Smiod 	  *cycles = 1;
566*3d8817e4Smiod 	  sprintf (op1, "#0");
567*3d8817e4Smiod 	  sprintf (comm1, "r3 As==00");
568*3d8817e4Smiod 	}
569*3d8817e4Smiod       else
570*3d8817e4Smiod 	{
571*3d8817e4Smiod 	  /* Register.  */
572*3d8817e4Smiod 	  *cycles = 1;
573*3d8817e4Smiod 	  sprintf (op1, "r%d", regs);
574*3d8817e4Smiod 	}
575*3d8817e4Smiod     }
576*3d8817e4Smiod   else if (as == 2)
577*3d8817e4Smiod     {
578*3d8817e4Smiod       if (regs == 2)
579*3d8817e4Smiod 	{
580*3d8817e4Smiod 	  *cycles = 2;
581*3d8817e4Smiod 	  sprintf (op1, "#4");
582*3d8817e4Smiod 	  sprintf (comm1, "r2 As==10");
583*3d8817e4Smiod 	}
584*3d8817e4Smiod       else if (regs == 3)
585*3d8817e4Smiod 	{
586*3d8817e4Smiod 	  *cycles = 1;
587*3d8817e4Smiod 	  sprintf (op1, "#2");
588*3d8817e4Smiod 	  sprintf (comm1, "r3 As==10");
589*3d8817e4Smiod 	}
590*3d8817e4Smiod       else
591*3d8817e4Smiod 	{
592*3d8817e4Smiod 	  /* Indexed register mode @Rn.  */
593*3d8817e4Smiod 	  *cycles = 2;
594*3d8817e4Smiod 	  sprintf (op1, "@r%d", regs);
595*3d8817e4Smiod 	}
596*3d8817e4Smiod     }
597*3d8817e4Smiod   else if (as == 3)
598*3d8817e4Smiod     {
599*3d8817e4Smiod       if (regs == 2)
600*3d8817e4Smiod 	{
601*3d8817e4Smiod 	  *cycles = 1;
602*3d8817e4Smiod 	  sprintf (op1, "#8");
603*3d8817e4Smiod 	  sprintf (comm1, "r2 As==11");
604*3d8817e4Smiod 	}
605*3d8817e4Smiod       else if (regs == 3)
606*3d8817e4Smiod 	{
607*3d8817e4Smiod 	  *cycles = 1;
608*3d8817e4Smiod 	  sprintf (op1, "#-1");
609*3d8817e4Smiod 	  sprintf (comm1, "r3 As==11");
610*3d8817e4Smiod 	}
611*3d8817e4Smiod       else if (regs == 0)
612*3d8817e4Smiod 	{
613*3d8817e4Smiod 	  /* Absolute. @pc+  */
614*3d8817e4Smiod 	  *cycles = 3;
615*3d8817e4Smiod 	  dst = msp430dis_opcode (addr + 2, info);
616*3d8817e4Smiod 	  cmd_len += 2;
617*3d8817e4Smiod 	  sprintf (op1, "#0x%04x", PS (dst));
618*3d8817e4Smiod 	}
619*3d8817e4Smiod       else
620*3d8817e4Smiod 	{
621*3d8817e4Smiod 	  *cycles = 2;
622*3d8817e4Smiod 	  sprintf (op1, "@r%d+", regs);
623*3d8817e4Smiod 	}
624*3d8817e4Smiod     }
625*3d8817e4Smiod   else if (as == 1)
626*3d8817e4Smiod     {
627*3d8817e4Smiod       * cycles = 3;
628*3d8817e4Smiod 
629*3d8817e4Smiod       if (regs == 0)
630*3d8817e4Smiod 	{
631*3d8817e4Smiod 	  /* PC relative.  */
632*3d8817e4Smiod 	  dst = msp430dis_opcode (addr + 2, info);
633*3d8817e4Smiod 	  cmd_len += 2;
634*3d8817e4Smiod 	  (*cycles)++;
635*3d8817e4Smiod 	  sprintf (op1, "0x%04x", PS (dst));
636*3d8817e4Smiod 	  sprintf (comm1, "PC rel. 0x%04x",
637*3d8817e4Smiod 		   PS ((short) addr + 2 + dst));
638*3d8817e4Smiod 	}
639*3d8817e4Smiod       else if (regs == 2)
640*3d8817e4Smiod 	{
641*3d8817e4Smiod 	  /* Absolute.  */
642*3d8817e4Smiod 	  dst = msp430dis_opcode (addr + 2, info);
643*3d8817e4Smiod 	  cmd_len += 2;
644*3d8817e4Smiod 	  sprintf (op1, "&0x%04x", PS (dst));
645*3d8817e4Smiod 	}
646*3d8817e4Smiod       else if (regs == 3)
647*3d8817e4Smiod 	{
648*3d8817e4Smiod 	  (*cycles)--;
649*3d8817e4Smiod 	  sprintf (op1, "#1");
650*3d8817e4Smiod 	  sprintf (comm1, "r3 As==01");
651*3d8817e4Smiod 	}
652*3d8817e4Smiod       else
653*3d8817e4Smiod 	{
654*3d8817e4Smiod 	  /* Indexd.  */
655*3d8817e4Smiod 	  dst = msp430dis_opcode (addr + 2, info);
656*3d8817e4Smiod 	  cmd_len += 2;
657*3d8817e4Smiod 	  sprintf (op1, "%d(r%d)", dst, regs);
658*3d8817e4Smiod 	}
659*3d8817e4Smiod     }
660*3d8817e4Smiod 
661*3d8817e4Smiod   return cmd_len;
662*3d8817e4Smiod }
663*3d8817e4Smiod 
664*3d8817e4Smiod int
print_insn_msp430(bfd_vma addr,disassemble_info * info)665*3d8817e4Smiod print_insn_msp430 (bfd_vma addr, disassemble_info *info)
666*3d8817e4Smiod {
667*3d8817e4Smiod   void *stream = info->stream;
668*3d8817e4Smiod   fprintf_ftype prin = info->fprintf_func;
669*3d8817e4Smiod   struct msp430_opcode_s *opcode;
670*3d8817e4Smiod   char op1[32], op2[32], comm1[64], comm2[64];
671*3d8817e4Smiod   int cmd_len = 0;
672*3d8817e4Smiod   unsigned short insn;
673*3d8817e4Smiod   int cycles = 0;
674*3d8817e4Smiod   char *bc = "";
675*3d8817e4Smiod   char dinfo[32];		/* Debug purposes.  */
676*3d8817e4Smiod 
677*3d8817e4Smiod   insn = msp430dis_opcode (addr, info);
678*3d8817e4Smiod   sprintf (dinfo, "0x%04x", insn);
679*3d8817e4Smiod 
680*3d8817e4Smiod   if (((int) addr & 0xffff) > 0xffdf)
681*3d8817e4Smiod     {
682*3d8817e4Smiod       (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn);
683*3d8817e4Smiod       return 2;
684*3d8817e4Smiod     }
685*3d8817e4Smiod 
686*3d8817e4Smiod   *comm1 = 0;
687*3d8817e4Smiod   *comm2 = 0;
688*3d8817e4Smiod 
689*3d8817e4Smiod   for (opcode = msp430_opcodes; opcode->name; opcode++)
690*3d8817e4Smiod     {
691*3d8817e4Smiod       if ((insn & opcode->bin_mask) == opcode->bin_opcode
692*3d8817e4Smiod 	  && opcode->bin_opcode != 0x9300)
693*3d8817e4Smiod 	{
694*3d8817e4Smiod 	  *op1 = 0;
695*3d8817e4Smiod 	  *op2 = 0;
696*3d8817e4Smiod 	  *comm1 = 0;
697*3d8817e4Smiod 	  *comm2 = 0;
698*3d8817e4Smiod 
699*3d8817e4Smiod 	  /* r0 as destination. Ad should be zero.  */
700*3d8817e4Smiod 	  if (opcode->insn_opnumb == 3 && (insn & 0x000f) == 0
701*3d8817e4Smiod 	      && (0x0080 & insn) == 0)
702*3d8817e4Smiod 	    {
703*3d8817e4Smiod 	      cmd_len =
704*3d8817e4Smiod 		msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
705*3d8817e4Smiod 				    &cycles);
706*3d8817e4Smiod 	      if (cmd_len)
707*3d8817e4Smiod 		break;
708*3d8817e4Smiod 	    }
709*3d8817e4Smiod 
710*3d8817e4Smiod 	  switch (opcode->insn_opnumb)
711*3d8817e4Smiod 	    {
712*3d8817e4Smiod 	    case 0:
713*3d8817e4Smiod 	      cmd_len = msp430_nooperands (opcode, addr, insn, comm1, &cycles);
714*3d8817e4Smiod 	      break;
715*3d8817e4Smiod 	    case 2:
716*3d8817e4Smiod 	      cmd_len =
717*3d8817e4Smiod 		msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
718*3d8817e4Smiod 				      comm1, comm2, &cycles);
719*3d8817e4Smiod 	      if (insn & BYTE_OPERATION)
720*3d8817e4Smiod 		bc = ".b";
721*3d8817e4Smiod 	      break;
722*3d8817e4Smiod 	    case 1:
723*3d8817e4Smiod 	      cmd_len =
724*3d8817e4Smiod 		msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
725*3d8817e4Smiod 				      &cycles);
726*3d8817e4Smiod 	      if (insn & BYTE_OPERATION && opcode->fmt != 3)
727*3d8817e4Smiod 		bc = ".b";
728*3d8817e4Smiod 	      break;
729*3d8817e4Smiod 	    default:
730*3d8817e4Smiod 	      break;
731*3d8817e4Smiod 	    }
732*3d8817e4Smiod 	}
733*3d8817e4Smiod 
734*3d8817e4Smiod       if (cmd_len)
735*3d8817e4Smiod 	break;
736*3d8817e4Smiod     }
737*3d8817e4Smiod 
738*3d8817e4Smiod   dinfo[5] = 0;
739*3d8817e4Smiod 
740*3d8817e4Smiod   if (cmd_len < 1)
741*3d8817e4Smiod     {
742*3d8817e4Smiod       /* Unknown opcode, or invalid combination of operands.  */
743*3d8817e4Smiod       (*prin) (stream, ".word	0x%04x;	????", PS (insn));
744*3d8817e4Smiod       return 2;
745*3d8817e4Smiod     }
746*3d8817e4Smiod 
747*3d8817e4Smiod   (*prin) (stream, "%s%s", opcode->name, bc);
748*3d8817e4Smiod 
749*3d8817e4Smiod   if (*op1)
750*3d8817e4Smiod     (*prin) (stream, "\t%s", op1);
751*3d8817e4Smiod   if (*op2)
752*3d8817e4Smiod     (*prin) (stream, ",");
753*3d8817e4Smiod 
754*3d8817e4Smiod   if (strlen (op1) < 7)
755*3d8817e4Smiod     (*prin) (stream, "\t");
756*3d8817e4Smiod   if (!strlen (op1))
757*3d8817e4Smiod     (*prin) (stream, "\t");
758*3d8817e4Smiod 
759*3d8817e4Smiod   if (*op2)
760*3d8817e4Smiod     (*prin) (stream, "%s", op2);
761*3d8817e4Smiod   if (strlen (op2) < 8)
762*3d8817e4Smiod     (*prin) (stream, "\t");
763*3d8817e4Smiod 
764*3d8817e4Smiod   if (*comm1 || *comm2)
765*3d8817e4Smiod     (*prin) (stream, ";");
766*3d8817e4Smiod   else if (cycles)
767*3d8817e4Smiod     {
768*3d8817e4Smiod       if (*op2)
769*3d8817e4Smiod 	(*prin) (stream, ";");
770*3d8817e4Smiod       else
771*3d8817e4Smiod 	{
772*3d8817e4Smiod 	  if (strlen (op1) < 7)
773*3d8817e4Smiod 	    (*prin) (stream, ";");
774*3d8817e4Smiod 	  else
775*3d8817e4Smiod 	    (*prin) (stream, "\t;");
776*3d8817e4Smiod 	}
777*3d8817e4Smiod     }
778*3d8817e4Smiod   if (*comm1)
779*3d8817e4Smiod     (*prin) (stream, "%s", comm1);
780*3d8817e4Smiod   if (*comm1 && *comm2)
781*3d8817e4Smiod     (*prin) (stream, ",");
782*3d8817e4Smiod   if (*comm2)
783*3d8817e4Smiod     (*prin) (stream, " %s", comm2);
784*3d8817e4Smiod   return cmd_len;
785*3d8817e4Smiod }
786