2006-07-18 Paul Brook <paul@codesourcery.com>
[deliverable/binutils-gdb.git] / opcodes / avr-dis.c
CommitLineData
adde6300 1/* Disassemble AVR instructions.
00988f49
AM
2 Copyright 1999, 2000, 2002, 2004, 2005, 2006
3 Free Software Foundation, Inc.
adde6300
AM
4
5 Contributed by Denis Chertykov <denisc@overta.ru>
6
47b0e7ad
NC
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.
adde6300 11
47b0e7ad
NC
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.
adde6300 16
47b0e7ad
NC
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. */
adde6300 20
bab84c47 21#include <assert.h>
0d8dfecf 22#include "sysdep.h"
adde6300
AM
23#include "dis-asm.h"
24#include "opintl.h"
11041102 25#include "libiberty.h"
3c504221 26
bab84c47 27struct avr_opcodes_s
adde6300 28{
bab84c47
DC
29 char *name;
30 char *constraints;
31 char *opcode;
47b0e7ad 32 int insn_size; /* In words. */
bab84c47
DC
33 int isa;
34 unsigned int bin_opcode;
bab84c47 35};
adde6300 36
bab84c47 37#define AVR_INSN(NAME, CONSTR, OPCODE, SIZE, ISA, BIN) \
11041102 38{#NAME, CONSTR, OPCODE, SIZE, ISA, BIN},
adde6300 39
11041102 40const struct avr_opcodes_s avr_opcodes[] =
adde6300 41{
bab84c47 42 #include "opcode/avr.h"
11041102 43 {NULL, NULL, NULL, 0, 0, 0}
bab84c47 44};
adde6300 45
463f102c 46static int
246f4c05
SS
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)
adde6300 49{
463f102c 50 int ok = 1;
246f4c05 51 *sym = 0;
463f102c 52
bab84c47
DC
53 switch (constraint)
54 {
55 /* Any register operand. */
56 case 'r':
57 if (regs)
47b0e7ad 58 insn = (insn & 0xf) | ((insn & 0x0200) >> 5); /* Source register. */
bab84c47 59 else
47b0e7ad 60 insn = (insn & 0x01f0) >> 4; /* Destination register. */
bab84c47
DC
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;
adde6300 82
bab84c47
DC
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':
463f102c
DC
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 }
bab84c47
DC
112 break;
113
114 case 'z':
115 *buf++ = 'Z';
116 if (insn & 0x1)
117 *buf++ = '+';
118 *buf = '\0';
463f102c
DC
119 if (AVR_UNDEF_P (insn))
120 sprintf (comment, _("undefined"));
bab84c47
DC
121 break;
122
123 case 'b':
124 {
463f102c 125 unsigned int x;
bab84c47
DC
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':
246f4c05
SS
141 *sym = 1;
142 *sym_addr = ((((insn & 1) | ((insn & 0x1f0) >> 3)) << 16) | insn2) * 2;
52f16a0e
NC
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. */
00988f49 146 sprintf (buf, "%#lx", (unsigned long) *sym_addr);
52f16a0e
NC
147 sprintf (comment, "0x");
148
bab84c47
DC
149 break;
150
151 case 'L':
152 {
153 int rel_addr = (((insn & 0xfff) ^ 0x800) - 0x800) * 2;
154 sprintf (buf, ".%+-8d", rel_addr);
246f4c05
SS
155 *sym = 1;
156 *sym_addr = pc + 2 + rel_addr;
157 sprintf (comment, "0x");
bab84c47
DC
158 }
159 break;
160
161 case 'l':
162 {
163 int rel_addr = ((((insn >> 3) & 0x7f) ^ 0x40) - 0x40) * 2;
164 sprintf (buf, ".%+-8d", rel_addr);
246f4c05
SS
165 *sym = 1;
166 *sym_addr = pc + 2 + rel_addr;
167 sprintf (comment, "0x");
bab84c47
DC
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':
463f102c
DC
181 sprintf (buf, "??");
182 fprintf (stderr, _("Internal disassembler error"));
183 ok = 0;
bab84c47
DC
184 break;
185
186 case 'K':
463f102c
DC
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 }
bab84c47
DC
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;
47b0e7ad 207
bab84c47
DC
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:
463f102c
DC
230 sprintf (buf, "??");
231 fprintf (stderr, _("unknown constraint `%c'"), constraint);
232 ok = 0;
bab84c47 233 }
463f102c
DC
234
235 return ok;
adde6300
AM
236}
237
bab84c47 238static unsigned short
47b0e7ad 239avrdis_opcode (bfd_vma addr, disassemble_info *info)
adde6300
AM
240{
241 bfd_byte buffer[2];
242 int status;
47b0e7ad
NC
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;
adde6300
AM
251}
252
253
254int
47b0e7ad 255print_insn_avr (bfd_vma addr, disassemble_info *info)
adde6300 256{
bab84c47 257 unsigned int insn, insn2;
11041102
KD
258 const struct avr_opcodes_s *opcode;
259 static unsigned int *maskptr;
adde6300
AM
260 void *stream = info->stream;
261 fprintf_ftype prin = info->fprintf_func;
11041102 262 static unsigned int *avr_bin_masks;
bab84c47 263 static int initialized;
adde6300 264 int cmd_len = 2;
463f102c
DC
265 int ok = 0;
266 char op1[20], op2[20], comment1[40], comment2[40];
246f4c05
SS
267 int sym_op1 = 0, sym_op2 = 0;
268 bfd_vma sym_addr1, sym_addr2;
adde6300 269
bab84c47
DC
270 if (!initialized)
271 {
11041102
KD
272 unsigned int nopcodes;
273
274 nopcodes = sizeof (avr_opcodes) / sizeof (struct avr_opcodes_s);
bab84c47 275
47b0e7ad 276 avr_bin_masks = xmalloc (nopcodes * sizeof (unsigned int));
11041102
KD
277
278 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
279 opcode->name;
280 opcode++, maskptr++)
bab84c47
DC
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);
11041102 295 *maskptr = mask;
bab84c47 296 }
11041102
KD
297
298 initialized = 1;
bab84c47 299 }
adde6300 300
bab84c47
DC
301 insn = avrdis_opcode (addr, info);
302
11041102
KD
303 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
304 opcode->name;
305 opcode++, maskptr++)
47b0e7ad
NC
306 if ((insn & *maskptr) == opcode->bin_opcode)
307 break;
bab84c47 308
463f102c
DC
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
bab84c47 320 if (opcode->name)
adde6300 321 {
bab84c47
DC
322 char *op = opcode->constraints;
323
00d2865b 324 insn2 = 0;
463f102c 325 ok = 1;
bab84c47
DC
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
246f4c05 337 ok = avr_operand (insn, insn2, addr, *op, op1, comment1, 0, &sym_op1, &sym_addr1);
bab84c47 338
463f102c
DC
339 if (ok && *(++op) == ',')
340 ok = avr_operand (insn, insn2, addr, *(++op), op2,
246f4c05 341 *comment1 ? comment2 : comment1, regs, &sym_op2, &sym_addr2);
bab84c47 342 }
463f102c 343 }
bab84c47 344
463f102c
DC
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 }
bab84c47 353
463f102c 354 (*prin) (stream, "%s", ok ? opcode->name : ".word");
bab84c47 355
463f102c 356 if (*op1)
246f4c05 357 (*prin) (stream, "\t%s", op1);
bab84c47 358
463f102c
DC
359 if (*op2)
360 (*prin) (stream, ", %s", op2);
361
362 if (*comment1)
363 (*prin) (stream, "\t; %s", comment1);
364
246f4c05 365 if (sym_op1)
73f643e9 366 info->print_address_func (sym_addr1, info);
246f4c05 367
463f102c
DC
368 if (*comment2)
369 (*prin) (stream, " %s", comment2);
bab84c47 370
246f4c05 371 if (sym_op2)
73f643e9 372 info->print_address_func (sym_addr2, info);
246f4c05 373
adde6300
AM
374 return cmd_len;
375}
This page took 0.299675 seconds and 4 git commands to generate.