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