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