2007-05-25 Andreas Tobler <a.tobler@schweiz.org>
[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
af692060
NC
46static const char * comment_start = "0x";
47
463f102c 48static int
246f4c05
SS
49avr_operand (unsigned int insn, unsigned int insn2, unsigned int pc, int constraint,
50 char *buf, char *comment, int regs, int *sym, bfd_vma *sym_addr)
adde6300 51{
463f102c 52 int ok = 1;
246f4c05 53 *sym = 0;
463f102c 54
bab84c47
DC
55 switch (constraint)
56 {
57 /* Any register operand. */
58 case 'r':
59 if (regs)
47b0e7ad 60 insn = (insn & 0xf) | ((insn & 0x0200) >> 5); /* Source register. */
bab84c47 61 else
47b0e7ad 62 insn = (insn & 0x01f0) >> 4; /* Destination register. */
bab84c47
DC
63
64 sprintf (buf, "r%d", insn);
65 break;
66
67 case 'd':
68 if (regs)
69 sprintf (buf, "r%d", 16 + (insn & 0xf));
70 else
71 sprintf (buf, "r%d", 16 + ((insn & 0xf0) >> 4));
72 break;
73
74 case 'w':
75 sprintf (buf, "r%d", 24 + ((insn & 0x30) >> 3));
76 break;
77
78 case 'a':
79 if (regs)
80 sprintf (buf, "r%d", 16 + (insn & 7));
81 else
82 sprintf (buf, "r%d", 16 + ((insn >> 4) & 7));
83 break;
adde6300 84
bab84c47
DC
85 case 'v':
86 if (regs)
87 sprintf (buf, "r%d", (insn & 0xf) * 2);
88 else
89 sprintf (buf, "r%d", ((insn & 0xf0) >> 3));
90 break;
91
92 case 'e':
463f102c
DC
93 {
94 char *xyz;
95
96 switch (insn & 0x100f)
97 {
98 case 0x0000: xyz = "Z"; break;
99 case 0x1001: xyz = "Z+"; break;
100 case 0x1002: xyz = "-Z"; break;
101 case 0x0008: xyz = "Y"; break;
102 case 0x1009: xyz = "Y+"; break;
103 case 0x100a: xyz = "-Y"; break;
104 case 0x100c: xyz = "X"; break;
105 case 0x100d: xyz = "X+"; break;
106 case 0x100e: xyz = "-X"; break;
107 default: xyz = "??"; ok = 0;
108 }
109 sprintf (buf, xyz);
110
111 if (AVR_UNDEF_P (insn))
112 sprintf (comment, _("undefined"));
113 }
bab84c47
DC
114 break;
115
116 case 'z':
117 *buf++ = 'Z';
118 if (insn & 0x1)
119 *buf++ = '+';
120 *buf = '\0';
463f102c
DC
121 if (AVR_UNDEF_P (insn))
122 sprintf (comment, _("undefined"));
bab84c47
DC
123 break;
124
125 case 'b':
126 {
463f102c 127 unsigned int x;
bab84c47
DC
128
129 x = (insn & 7);
130 x |= (insn >> 7) & (3 << 3);
131 x |= (insn >> 8) & (1 << 5);
132
133 if (insn & 0x8)
134 *buf++ = 'Y';
135 else
136 *buf++ = 'Z';
137 sprintf (buf, "+%d", x);
138 sprintf (comment, "0x%02x", x);
139 }
140 break;
141
142 case 'h':
246f4c05
SS
143 *sym = 1;
144 *sym_addr = ((((insn & 1) | ((insn & 0x1f0) >> 3)) << 16) | insn2) * 2;
c4f5c3d7 145 /* See PR binutils/2454. Ideally we would like to display the hex
52f16a0e
NC
146 value of the address only once, but this would mean recoding
147 objdump_print_address() which would affect many targets. */
00988f49 148 sprintf (buf, "%#lx", (unsigned long) *sym_addr);
af692060 149 sprintf (comment, comment_start);
bab84c47
DC
150 break;
151
152 case 'L':
153 {
154 int rel_addr = (((insn & 0xfff) ^ 0x800) - 0x800) * 2;
155 sprintf (buf, ".%+-8d", rel_addr);
246f4c05
SS
156 *sym = 1;
157 *sym_addr = pc + 2 + rel_addr;
af692060 158 sprintf (comment, comment_start);
bab84c47
DC
159 }
160 break;
161
162 case 'l':
163 {
164 int rel_addr = ((((insn >> 3) & 0x7f) ^ 0x40) - 0x40) * 2;
af692060 165
bab84c47 166 sprintf (buf, ".%+-8d", rel_addr);
246f4c05
SS
167 *sym = 1;
168 *sym_addr = pc + 2 + rel_addr;
af692060 169 sprintf (comment, comment_start);
bab84c47
DC
170 }
171 break;
172
173 case 'i':
174 sprintf (buf, "0x%04X", insn2);
175 break;
176
177 case 'M':
178 sprintf (buf, "0x%02X", ((insn & 0xf00) >> 4) | (insn & 0xf));
179 sprintf (comment, "%d", ((insn & 0xf00) >> 4) | (insn & 0xf));
180 break;
181
182 case 'n':
463f102c
DC
183 sprintf (buf, "??");
184 fprintf (stderr, _("Internal disassembler error"));
185 ok = 0;
bab84c47
DC
186 break;
187
188 case 'K':
463f102c
DC
189 {
190 unsigned int x;
191
192 x = (insn & 0xf) | ((insn >> 2) & 0x30);
193 sprintf (buf, "0x%02x", x);
194 sprintf (comment, "%d", x);
195 }
bab84c47
DC
196 break;
197
198 case 's':
199 sprintf (buf, "%d", insn & 7);
200 break;
201
202 case 'S':
203 sprintf (buf, "%d", (insn >> 4) & 7);
204 break;
205
206 case 'P':
207 {
208 unsigned int x;
47b0e7ad 209
bab84c47
DC
210 x = (insn & 0xf);
211 x |= (insn >> 5) & 0x30;
212 sprintf (buf, "0x%02x", x);
213 sprintf (comment, "%d", x);
214 }
215 break;
216
217 case 'p':
218 {
219 unsigned int x;
220
221 x = (insn >> 3) & 0x1f;
222 sprintf (buf, "0x%02x", x);
223 sprintf (comment, "%d", x);
224 }
225 break;
226
227 case '?':
228 *buf = '\0';
229 break;
230
231 default:
463f102c
DC
232 sprintf (buf, "??");
233 fprintf (stderr, _("unknown constraint `%c'"), constraint);
234 ok = 0;
bab84c47 235 }
463f102c
DC
236
237 return ok;
adde6300
AM
238}
239
bab84c47 240static unsigned short
47b0e7ad 241avrdis_opcode (bfd_vma addr, disassemble_info *info)
adde6300
AM
242{
243 bfd_byte buffer[2];
244 int status;
47b0e7ad
NC
245
246 status = info->read_memory_func (addr, buffer, 2, info);
247
248 if (status == 0)
249 return bfd_getl16 (buffer);
250
251 info->memory_error_func (status, addr, info);
252 return -1;
adde6300
AM
253}
254
255
256int
47b0e7ad 257print_insn_avr (bfd_vma addr, disassemble_info *info)
adde6300 258{
bab84c47 259 unsigned int insn, insn2;
11041102
KD
260 const struct avr_opcodes_s *opcode;
261 static unsigned int *maskptr;
adde6300
AM
262 void *stream = info->stream;
263 fprintf_ftype prin = info->fprintf_func;
11041102 264 static unsigned int *avr_bin_masks;
bab84c47 265 static int initialized;
adde6300 266 int cmd_len = 2;
463f102c
DC
267 int ok = 0;
268 char op1[20], op2[20], comment1[40], comment2[40];
246f4c05
SS
269 int sym_op1 = 0, sym_op2 = 0;
270 bfd_vma sym_addr1, sym_addr2;
adde6300 271
af692060 272
bab84c47
DC
273 if (!initialized)
274 {
11041102
KD
275 unsigned int nopcodes;
276
af692060
NC
277 /* PR 4045: Try to avoid duplicating the 0x prefix that
278 objdump_print_addr() will put on addresses when there
279 is no symbol table available. */
280 if (info->symtab_size == 0)
281 comment_start = " ";
282
11041102 283 nopcodes = sizeof (avr_opcodes) / sizeof (struct avr_opcodes_s);
bab84c47 284
47b0e7ad 285 avr_bin_masks = xmalloc (nopcodes * sizeof (unsigned int));
11041102
KD
286
287 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
288 opcode->name;
289 opcode++, maskptr++)
bab84c47
DC
290 {
291 char * s;
292 unsigned int bin = 0;
293 unsigned int mask = 0;
294
295 for (s = opcode->opcode; *s; ++s)
296 {
297 bin <<= 1;
298 mask <<= 1;
299 bin |= (*s == '1');
300 mask |= (*s == '1' || *s == '0');
301 }
302 assert (s - opcode->opcode == 16);
303 assert (opcode->bin_opcode == bin);
11041102 304 *maskptr = mask;
bab84c47 305 }
11041102
KD
306
307 initialized = 1;
bab84c47 308 }
adde6300 309
bab84c47
DC
310 insn = avrdis_opcode (addr, info);
311
11041102
KD
312 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
313 opcode->name;
314 opcode++, maskptr++)
47b0e7ad
NC
315 if ((insn & *maskptr) == opcode->bin_opcode)
316 break;
bab84c47 317
463f102c
DC
318 /* Special case: disassemble `ldd r,b+0' as `ld r,b', and
319 `std b+0,r' as `st b,r' (next entry in the table). */
320
321 if (AVR_DISP0_P (insn))
322 opcode++;
323
324 op1[0] = 0;
325 op2[0] = 0;
326 comment1[0] = 0;
327 comment2[0] = 0;
328
bab84c47 329 if (opcode->name)
adde6300 330 {
bab84c47
DC
331 char *op = opcode->constraints;
332
00d2865b 333 insn2 = 0;
463f102c 334 ok = 1;
bab84c47
DC
335
336 if (opcode->insn_size > 1)
337 {
338 insn2 = avrdis_opcode (addr + 2, info);
339 cmd_len = 4;
340 }
341
342 if (*op && *op != '?')
343 {
344 int regs = REGISTER_P (*op);
345
246f4c05 346 ok = avr_operand (insn, insn2, addr, *op, op1, comment1, 0, &sym_op1, &sym_addr1);
bab84c47 347
463f102c
DC
348 if (ok && *(++op) == ',')
349 ok = avr_operand (insn, insn2, addr, *(++op), op2,
246f4c05 350 *comment1 ? comment2 : comment1, regs, &sym_op2, &sym_addr2);
bab84c47 351 }
463f102c 352 }
bab84c47 353
463f102c
DC
354 if (!ok)
355 {
356 /* Unknown opcode, or invalid combination of operands. */
357 sprintf (op1, "0x%04x", insn);
358 op2[0] = 0;
359 sprintf (comment1, "????");
360 comment2[0] = 0;
361 }
bab84c47 362
463f102c 363 (*prin) (stream, "%s", ok ? opcode->name : ".word");
bab84c47 364
463f102c 365 if (*op1)
246f4c05 366 (*prin) (stream, "\t%s", op1);
bab84c47 367
463f102c
DC
368 if (*op2)
369 (*prin) (stream, ", %s", op2);
370
371 if (*comment1)
372 (*prin) (stream, "\t; %s", comment1);
373
246f4c05 374 if (sym_op1)
73f643e9 375 info->print_address_func (sym_addr1, info);
246f4c05 376
463f102c
DC
377 if (*comment2)
378 (*prin) (stream, " %s", comment2);
bab84c47 379
246f4c05 380 if (sym_op2)
73f643e9 381 info->print_address_func (sym_addr2, info);
246f4c05 382
adde6300
AM
383 return cmd_len;
384}
This page took 0.307701 seconds and 4 git commands to generate.