1/* Disassemble AVR instructions.
2   Copyright 1999, 2000, 2002, 2004, 2005, 2006
3   Free Software Foundation, Inc.
4
5   Contributed by Denis Chertykov <denisc@overta.ru>
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
20
21#include <assert.h>
22#include "sysdep.h"
23#include "dis-asm.h"
24#include "opintl.h"
25#include "libiberty.h"
26
27struct avr_opcodes_s
28{
29  char *name;
30  char *constraints;
31  char *opcode;
32  int insn_size;		/* In words.  */
33  int isa;
34  unsigned int bin_opcode;
35};
36
37#define AVR_INSN(NAME, CONSTR, OPCODE, SIZE, ISA, BIN) \
38{#NAME, CONSTR, OPCODE, SIZE, ISA, BIN},
39
40const struct avr_opcodes_s avr_opcodes[] =
41{
42  #include "opcode/avr.h"
43  {NULL, NULL, NULL, 0, 0, 0}
44};
45
46static int
47avr_operand (unsigned int insn, unsigned int insn2, unsigned int pc, int constraint,
48             char *buf, char *comment, int regs, int *sym, bfd_vma *sym_addr)
49{
50  int ok = 1;
51  *sym = 0;
52
53  switch (constraint)
54    {
55      /* Any register operand.  */
56    case 'r':
57      if (regs)
58	insn = (insn & 0xf) | ((insn & 0x0200) >> 5); /* Source register.  */
59      else
60	insn = (insn & 0x01f0) >> 4; /* Destination register.  */
61
62      sprintf (buf, "r%d", insn);
63      break;
64
65    case 'd':
66      if (regs)
67	sprintf (buf, "r%d", 16 + (insn & 0xf));
68      else
69	sprintf (buf, "r%d", 16 + ((insn & 0xf0) >> 4));
70      break;
71
72    case 'w':
73      sprintf (buf, "r%d", 24 + ((insn & 0x30) >> 3));
74      break;
75
76    case 'a':
77      if (regs)
78	sprintf (buf, "r%d", 16 + (insn & 7));
79      else
80	sprintf (buf, "r%d", 16 + ((insn >> 4) & 7));
81      break;
82
83    case 'v':
84      if (regs)
85	sprintf (buf, "r%d", (insn & 0xf) * 2);
86      else
87	sprintf (buf, "r%d", ((insn & 0xf0) >> 3));
88      break;
89
90    case 'e':
91      {
92	char *xyz;
93
94	switch (insn & 0x100f)
95	  {
96	    case 0x0000: xyz = "Z";  break;
97	    case 0x1001: xyz = "Z+"; break;
98	    case 0x1002: xyz = "-Z"; break;
99	    case 0x0008: xyz = "Y";  break;
100	    case 0x1009: xyz = "Y+"; break;
101	    case 0x100a: xyz = "-Y"; break;
102	    case 0x100c: xyz = "X";  break;
103	    case 0x100d: xyz = "X+"; break;
104	    case 0x100e: xyz = "-X"; break;
105	    default: xyz = "??"; ok = 0;
106	  }
107	sprintf (buf, xyz);
108
109	if (AVR_UNDEF_P (insn))
110	  sprintf (comment, _("undefined"));
111      }
112      break;
113
114    case 'z':
115      *buf++ = 'Z';
116      if (insn & 0x1)
117	*buf++ = '+';
118      *buf = '\0';
119      if (AVR_UNDEF_P (insn))
120	sprintf (comment, _("undefined"));
121      break;
122
123    case 'b':
124      {
125	unsigned int x;
126
127	x = (insn & 7);
128	x |= (insn >> 7) & (3 << 3);
129	x |= (insn >> 8) & (1 << 5);
130
131	if (insn & 0x8)
132	  *buf++ = 'Y';
133	else
134	  *buf++ = 'Z';
135	sprintf (buf, "+%d", x);
136	sprintf (comment, "0x%02x", x);
137      }
138      break;
139
140    case 'h':
141      *sym = 1;
142      *sym_addr = ((((insn & 1) | ((insn & 0x1f0) >> 3)) << 16) | insn2) * 2;
143      /* See PR binutils/2545.  Ideally we would like to display the hex
144	 value of the address only once, but this would mean recoding
145	 objdump_print_address() which would affect many targets.  */
146      sprintf (buf, "%#lx", (unsigned long) *sym_addr);
147      sprintf (comment, "0x");
148
149      break;
150
151    case 'L':
152      {
153	int rel_addr = (((insn & 0xfff) ^ 0x800) - 0x800) * 2;
154	sprintf (buf, ".%+-8d", rel_addr);
155        *sym = 1;
156        *sym_addr = pc + 2 + rel_addr;
157	sprintf (comment, "0x");
158      }
159      break;
160
161    case 'l':
162      {
163	int rel_addr = ((((insn >> 3) & 0x7f) ^ 0x40) - 0x40) * 2;
164	sprintf (buf, ".%+-8d", rel_addr);
165        *sym = 1;
166        *sym_addr = pc + 2 + rel_addr;
167	sprintf (comment, "0x");
168      }
169      break;
170
171    case 'i':
172      sprintf (buf, "0x%04X", insn2);
173      break;
174
175    case 'M':
176      sprintf (buf, "0x%02X", ((insn & 0xf00) >> 4) | (insn & 0xf));
177      sprintf (comment, "%d", ((insn & 0xf00) >> 4) | (insn & 0xf));
178      break;
179
180    case 'n':
181      sprintf (buf, "??");
182      fprintf (stderr, _("Internal disassembler error"));
183      ok = 0;
184      break;
185
186    case 'K':
187      {
188	unsigned int x;
189
190	x = (insn & 0xf) | ((insn >> 2) & 0x30);
191	sprintf (buf, "0x%02x", x);
192	sprintf (comment, "%d", x);
193      }
194      break;
195
196    case 's':
197      sprintf (buf, "%d", insn & 7);
198      break;
199
200    case 'S':
201      sprintf (buf, "%d", (insn >> 4) & 7);
202      break;
203
204    case 'P':
205      {
206	unsigned int x;
207
208	x = (insn & 0xf);
209	x |= (insn >> 5) & 0x30;
210	sprintf (buf, "0x%02x", x);
211	sprintf (comment, "%d", x);
212      }
213      break;
214
215    case 'p':
216      {
217	unsigned int x;
218
219	x = (insn >> 3) & 0x1f;
220	sprintf (buf, "0x%02x", x);
221	sprintf (comment, "%d", x);
222      }
223      break;
224
225    case '?':
226      *buf = '\0';
227      break;
228
229    default:
230      sprintf (buf, "??");
231      fprintf (stderr, _("unknown constraint `%c'"), constraint);
232      ok = 0;
233    }
234
235    return ok;
236}
237
238static unsigned short
239avrdis_opcode (bfd_vma addr, disassemble_info *info)
240{
241  bfd_byte buffer[2];
242  int status;
243
244  status = info->read_memory_func (addr, buffer, 2, info);
245
246  if (status == 0)
247    return bfd_getl16 (buffer);
248
249  info->memory_error_func (status, addr, info);
250  return -1;
251}
252
253
254int
255print_insn_avr (bfd_vma addr, disassemble_info *info)
256{
257  unsigned int insn, insn2;
258  const struct avr_opcodes_s *opcode;
259  static unsigned int *maskptr;
260  void *stream = info->stream;
261  fprintf_ftype prin = info->fprintf_func;
262  static unsigned int *avr_bin_masks;
263  static int initialized;
264  int cmd_len = 2;
265  int ok = 0;
266  char op1[20], op2[20], comment1[40], comment2[40];
267  int sym_op1 = 0, sym_op2 = 0;
268  bfd_vma sym_addr1, sym_addr2;
269
270  if (!initialized)
271    {
272      unsigned int nopcodes;
273
274      nopcodes = sizeof (avr_opcodes) / sizeof (struct avr_opcodes_s);
275
276      avr_bin_masks = xmalloc (nopcodes * sizeof (unsigned int));
277
278      for (opcode = avr_opcodes, maskptr = avr_bin_masks;
279	   opcode->name;
280	   opcode++, maskptr++)
281	{
282	  char * s;
283	  unsigned int bin = 0;
284	  unsigned int mask = 0;
285
286	  for (s = opcode->opcode; *s; ++s)
287	    {
288	      bin <<= 1;
289	      mask <<= 1;
290	      bin |= (*s == '1');
291	      mask |= (*s == '1' || *s == '0');
292	    }
293	  assert (s - opcode->opcode == 16);
294	  assert (opcode->bin_opcode == bin);
295	  *maskptr = mask;
296	}
297
298      initialized = 1;
299    }
300
301  insn = avrdis_opcode (addr, info);
302
303  for (opcode = avr_opcodes, maskptr = avr_bin_masks;
304       opcode->name;
305       opcode++, maskptr++)
306    if ((insn & *maskptr) == opcode->bin_opcode)
307      break;
308
309  /* Special case: disassemble `ldd r,b+0' as `ld r,b', and
310     `std b+0,r' as `st b,r' (next entry in the table).  */
311
312  if (AVR_DISP0_P (insn))
313    opcode++;
314
315  op1[0] = 0;
316  op2[0] = 0;
317  comment1[0] = 0;
318  comment2[0] = 0;
319
320  if (opcode->name)
321    {
322      char *op = opcode->constraints;
323
324      insn2 = 0;
325      ok = 1;
326
327      if (opcode->insn_size > 1)
328	{
329	  insn2 = avrdis_opcode (addr + 2, info);
330	  cmd_len = 4;
331	}
332
333      if (*op && *op != '?')
334	{
335	  int regs = REGISTER_P (*op);
336
337	  ok = avr_operand (insn, insn2, addr, *op, op1, comment1, 0, &sym_op1, &sym_addr1);
338
339	  if (ok && *(++op) == ',')
340	    ok = avr_operand (insn, insn2, addr, *(++op), op2,
341			      *comment1 ? comment2 : comment1, regs, &sym_op2, &sym_addr2);
342	}
343    }
344
345  if (!ok)
346    {
347      /* Unknown opcode, or invalid combination of operands.  */
348      sprintf (op1, "0x%04x", insn);
349      op2[0] = 0;
350      sprintf (comment1, "????");
351      comment2[0] = 0;
352    }
353
354  (*prin) (stream, "%s", ok ? opcode->name : ".word");
355
356  if (*op1)
357      (*prin) (stream, "\t%s", op1);
358
359  if (*op2)
360    (*prin) (stream, ", %s", op2);
361
362  if (*comment1)
363    (*prin) (stream, "\t; %s", comment1);
364
365  if (sym_op1)
366    info->print_address_func (sym_addr1, info);
367
368  if (*comment2)
369    (*prin) (stream, " %s", comment2);
370
371  if (sym_op2)
372    info->print_address_func (sym_addr2, info);
373
374  return cmd_len;
375}
376