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