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