PR binutils/12325
[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 {
bab84c47 128 *buf++ = '+';
8cc66334
EW
129 break;
130 }
131 }
132
bab84c47 133 *buf = '\0';
463f102c
DC
134 if (AVR_UNDEF_P (insn))
135 sprintf (comment, _("undefined"));
bab84c47
DC
136 break;
137
138 case 'b':
139 {
463f102c 140 unsigned int x;
bab84c47
DC
141
142 x = (insn & 7);
143 x |= (insn >> 7) & (3 << 3);
144 x |= (insn >> 8) & (1 << 5);
145
146 if (insn & 0x8)
147 *buf++ = 'Y';
148 else
149 *buf++ = 'Z';
150 sprintf (buf, "+%d", x);
151 sprintf (comment, "0x%02x", x);
152 }
153 break;
154
155 case 'h':
246f4c05
SS
156 *sym = 1;
157 *sym_addr = ((((insn & 1) | ((insn & 0x1f0) >> 3)) << 16) | insn2) * 2;
c4f5c3d7 158 /* See PR binutils/2454. Ideally we would like to display the hex
52f16a0e
NC
159 value of the address only once, but this would mean recoding
160 objdump_print_address() which would affect many targets. */
00988f49 161 sprintf (buf, "%#lx", (unsigned long) *sym_addr);
c8941035 162 strcpy (comment, comment_start);
bab84c47
DC
163 break;
164
165 case 'L':
166 {
167 int rel_addr = (((insn & 0xfff) ^ 0x800) - 0x800) * 2;
168 sprintf (buf, ".%+-8d", rel_addr);
246f4c05
SS
169 *sym = 1;
170 *sym_addr = pc + 2 + rel_addr;
c8941035 171 strcpy (comment, comment_start);
bab84c47
DC
172 }
173 break;
174
175 case 'l':
176 {
177 int rel_addr = ((((insn >> 3) & 0x7f) ^ 0x40) - 0x40) * 2;
af692060 178
bab84c47 179 sprintf (buf, ".%+-8d", rel_addr);
246f4c05
SS
180 *sym = 1;
181 *sym_addr = pc + 2 + rel_addr;
c8941035 182 strcpy (comment, comment_start);
bab84c47
DC
183 }
184 break;
185
186 case 'i':
187 sprintf (buf, "0x%04X", insn2);
188 break;
189
190 case 'M':
191 sprintf (buf, "0x%02X", ((insn & 0xf00) >> 4) | (insn & 0xf));
192 sprintf (comment, "%d", ((insn & 0xf00) >> 4) | (insn & 0xf));
193 break;
194
195 case 'n':
463f102c
DC
196 sprintf (buf, "??");
197 fprintf (stderr, _("Internal disassembler error"));
198 ok = 0;
bab84c47
DC
199 break;
200
201 case 'K':
463f102c
DC
202 {
203 unsigned int x;
204
205 x = (insn & 0xf) | ((insn >> 2) & 0x30);
206 sprintf (buf, "0x%02x", x);
207 sprintf (comment, "%d", x);
208 }
bab84c47
DC
209 break;
210
211 case 's':
212 sprintf (buf, "%d", insn & 7);
213 break;
214
215 case 'S':
216 sprintf (buf, "%d", (insn >> 4) & 7);
217 break;
218
219 case 'P':
220 {
221 unsigned int x;
47b0e7ad 222
bab84c47
DC
223 x = (insn & 0xf);
224 x |= (insn >> 5) & 0x30;
225 sprintf (buf, "0x%02x", x);
226 sprintf (comment, "%d", x);
227 }
228 break;
229
230 case 'p':
231 {
232 unsigned int x;
233
234 x = (insn >> 3) & 0x1f;
235 sprintf (buf, "0x%02x", x);
236 sprintf (comment, "%d", x);
237 }
238 break;
239
8cc66334
EW
240 case 'E':
241 sprintf (buf, "%d", (insn >> 4) & 15);
242 break;
243
bab84c47
DC
244 case '?':
245 *buf = '\0';
246 break;
247
248 default:
463f102c
DC
249 sprintf (buf, "??");
250 fprintf (stderr, _("unknown constraint `%c'"), constraint);
251 ok = 0;
bab84c47 252 }
463f102c
DC
253
254 return ok;
adde6300
AM
255}
256
bab84c47 257static unsigned short
47b0e7ad 258avrdis_opcode (bfd_vma addr, disassemble_info *info)
adde6300
AM
259{
260 bfd_byte buffer[2];
261 int status;
47b0e7ad
NC
262
263 status = info->read_memory_func (addr, buffer, 2, info);
264
265 if (status == 0)
266 return bfd_getl16 (buffer);
267
268 info->memory_error_func (status, addr, info);
269 return -1;
adde6300
AM
270}
271
272
273int
47b0e7ad 274print_insn_avr (bfd_vma addr, disassemble_info *info)
adde6300 275{
bab84c47 276 unsigned int insn, insn2;
11041102
KD
277 const struct avr_opcodes_s *opcode;
278 static unsigned int *maskptr;
adde6300
AM
279 void *stream = info->stream;
280 fprintf_ftype prin = info->fprintf_func;
11041102 281 static unsigned int *avr_bin_masks;
bab84c47 282 static int initialized;
adde6300 283 int cmd_len = 2;
463f102c
DC
284 int ok = 0;
285 char op1[20], op2[20], comment1[40], comment2[40];
246f4c05
SS
286 int sym_op1 = 0, sym_op2 = 0;
287 bfd_vma sym_addr1, sym_addr2;
adde6300 288
af692060 289
bab84c47
DC
290 if (!initialized)
291 {
11041102
KD
292 unsigned int nopcodes;
293
af692060
NC
294 /* PR 4045: Try to avoid duplicating the 0x prefix that
295 objdump_print_addr() will put on addresses when there
296 is no symbol table available. */
297 if (info->symtab_size == 0)
298 comment_start = " ";
299
11041102 300 nopcodes = sizeof (avr_opcodes) / sizeof (struct avr_opcodes_s);
bab84c47 301
47b0e7ad 302 avr_bin_masks = xmalloc (nopcodes * sizeof (unsigned int));
11041102
KD
303
304 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
305 opcode->name;
306 opcode++, maskptr++)
bab84c47
DC
307 {
308 char * s;
309 unsigned int bin = 0;
310 unsigned int mask = 0;
311
312 for (s = opcode->opcode; *s; ++s)
313 {
314 bin <<= 1;
315 mask <<= 1;
316 bin |= (*s == '1');
317 mask |= (*s == '1' || *s == '0');
318 }
319 assert (s - opcode->opcode == 16);
320 assert (opcode->bin_opcode == bin);
11041102 321 *maskptr = mask;
bab84c47 322 }
11041102
KD
323
324 initialized = 1;
bab84c47 325 }
adde6300 326
bab84c47
DC
327 insn = avrdis_opcode (addr, info);
328
11041102
KD
329 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
330 opcode->name;
331 opcode++, maskptr++)
47b0e7ad
NC
332 if ((insn & *maskptr) == opcode->bin_opcode)
333 break;
bab84c47 334
463f102c
DC
335 /* Special case: disassemble `ldd r,b+0' as `ld r,b', and
336 `std b+0,r' as `st b,r' (next entry in the table). */
337
338 if (AVR_DISP0_P (insn))
339 opcode++;
340
341 op1[0] = 0;
342 op2[0] = 0;
343 comment1[0] = 0;
344 comment2[0] = 0;
345
bab84c47 346 if (opcode->name)
adde6300 347 {
8cc66334
EW
348 char *constraints = opcode->constraints;
349 char *opcode_str = opcode->opcode;
bab84c47 350
00d2865b 351 insn2 = 0;
463f102c 352 ok = 1;
bab84c47
DC
353
354 if (opcode->insn_size > 1)
355 {
356 insn2 = avrdis_opcode (addr + 2, info);
357 cmd_len = 4;
358 }
359
8cc66334 360 if (*constraints && *constraints != '?')
bab84c47 361 {
8cc66334 362 int regs = REGISTER_P (*constraints);
bab84c47 363
8cc66334 364 ok = avr_operand (insn, insn2, addr, *constraints, opcode_str, op1, comment1, 0, &sym_op1, &sym_addr1);
bab84c47 365
8cc66334
EW
366 if (ok && *(++constraints) == ',')
367 ok = avr_operand (insn, insn2, addr, *(++constraints), opcode_str, op2,
246f4c05 368 *comment1 ? comment2 : comment1, regs, &sym_op2, &sym_addr2);
bab84c47 369 }
463f102c 370 }
bab84c47 371
463f102c
DC
372 if (!ok)
373 {
374 /* Unknown opcode, or invalid combination of operands. */
375 sprintf (op1, "0x%04x", insn);
376 op2[0] = 0;
377 sprintf (comment1, "????");
378 comment2[0] = 0;
379 }
bab84c47 380
463f102c 381 (*prin) (stream, "%s", ok ? opcode->name : ".word");
bab84c47 382
463f102c 383 if (*op1)
246f4c05 384 (*prin) (stream, "\t%s", op1);
bab84c47 385
463f102c
DC
386 if (*op2)
387 (*prin) (stream, ", %s", op2);
388
389 if (*comment1)
390 (*prin) (stream, "\t; %s", comment1);
391
246f4c05 392 if (sym_op1)
73f643e9 393 info->print_address_func (sym_addr1, info);
246f4c05 394
463f102c
DC
395 if (*comment2)
396 (*prin) (stream, " %s", comment2);
bab84c47 397
246f4c05 398 if (sym_op2)
73f643e9 399 info->print_address_func (sym_addr2, info);
246f4c05 400
adde6300
AM
401 return cmd_len;
402}
This page took 0.692408 seconds and 4 git commands to generate.