]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/avr-dis.c
"backtrace full/no-filters/hide" completer
[thirdparty/binutils-gdb.git] / opcodes / avr-dis.c
CommitLineData
adde6300 1/* Disassemble AVR instructions.
82704155 2 Copyright (C) 1999-2019 Free Software Foundation, Inc.
adde6300
AM
3
4 Contributed by Denis Chertykov <denisc@overta.ru>
5
9b201bb5
NC
6 This file is part of libopcodes.
7
8 This library is free software; you can redistribute it and/or modify
47b0e7ad 9 it under the terms of the GNU General Public License as published by
9b201bb5
NC
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
adde6300 12
9b201bb5
NC
13 It is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
adde6300 17
47b0e7ad
NC
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
9b201bb5
NC
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
adde6300 22
0d8dfecf 23#include "sysdep.h"
df7b86aa 24#include <assert.h>
88c1242d 25#include "disassemble.h"
adde6300 26#include "opintl.h"
11041102 27#include "libiberty.h"
0a7e1018 28#include "bfd_stdint.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. */
43e65147 66
bab84c47
DC
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;
43e65147 76
bab84c47
DC
77 case 'w':
78 sprintf (buf, "r%d", 24 + ((insn & 0x30) >> 3));
79 break;
43e65147 80
bab84c47
DC
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;
43e65147 142
bab84c47
DC
143 x = (insn & 7);
144 x |= (insn >> 7) & (3 << 3);
145 x |= (insn >> 8) & (1 << 5);
43e65147 146
bab84c47
DC
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;
43e65147 155
bab84c47 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. */
43e65147 162 sprintf (buf, "%#lx", (unsigned long) *sym_addr);
c8941035 163 strcpy (comment, comment_start);
bab84c47 164 break;
43e65147 165
bab84c47
DC
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':
1857fe72
DC
188 {
189 unsigned int val = insn2 | 0x800000;
190 *sym = 1;
191 *sym_addr = val;
192 sprintf (buf, "0x%04X", insn2);
193 strcpy (comment, comment_start);
194 }
bab84c47 195 break;
f36e8886
BS
196
197 case 'j':
198 {
199 unsigned int val = ((insn & 0xf) | ((insn & 0x600) >> 5)
200 | ((insn & 0x100) >> 2));
1857fe72
DC
201 *sym = 1;
202 *sym_addr = val | 0x800000;
f36e8886 203 sprintf (buf, "0x%02x", val);
1857fe72 204 strcpy (comment, comment_start);
f36e8886
BS
205 }
206 break;
43e65147 207
bab84c47
DC
208 case 'M':
209 sprintf (buf, "0x%02X", ((insn & 0xf00) >> 4) | (insn & 0xf));
210 sprintf (comment, "%d", ((insn & 0xf00) >> 4) | (insn & 0xf));
211 break;
212
213 case 'n':
463f102c 214 sprintf (buf, "??");
a6743a54
AM
215 /* xgettext:c-format */
216 opcodes_error_handler (_("internal disassembler error"));
463f102c 217 ok = 0;
bab84c47 218 break;
43e65147 219
bab84c47 220 case 'K':
463f102c
DC
221 {
222 unsigned int x;
223
224 x = (insn & 0xf) | ((insn >> 2) & 0x30);
225 sprintf (buf, "0x%02x", x);
226 sprintf (comment, "%d", x);
227 }
bab84c47 228 break;
43e65147 229
bab84c47
DC
230 case 's':
231 sprintf (buf, "%d", insn & 7);
232 break;
43e65147 233
bab84c47
DC
234 case 'S':
235 sprintf (buf, "%d", (insn >> 4) & 7);
236 break;
43e65147 237
bab84c47
DC
238 case 'P':
239 {
240 unsigned int x;
47b0e7ad 241
bab84c47
DC
242 x = (insn & 0xf);
243 x |= (insn >> 5) & 0x30;
244 sprintf (buf, "0x%02x", x);
245 sprintf (comment, "%d", x);
246 }
247 break;
248
249 case 'p':
250 {
251 unsigned int x;
43e65147 252
bab84c47
DC
253 x = (insn >> 3) & 0x1f;
254 sprintf (buf, "0x%02x", x);
255 sprintf (comment, "%d", x);
256 }
257 break;
43e65147 258
8cc66334
EW
259 case 'E':
260 sprintf (buf, "%d", (insn >> 4) & 15);
261 break;
43e65147 262
bab84c47
DC
263 case '?':
264 *buf = '\0';
265 break;
43e65147 266
bab84c47 267 default:
463f102c 268 sprintf (buf, "??");
a6743a54
AM
269 /* xgettext:c-format */
270 opcodes_error_handler (_("unknown constraint `%c'"), constraint);
463f102c 271 ok = 0;
bab84c47 272 }
463f102c
DC
273
274 return ok;
adde6300
AM
275}
276
0a7e1018
YQ
277/* Read the opcode from ADDR. Return 0 in success and save opcode
278 in *INSN, otherwise, return -1. */
279
280static int
281avrdis_opcode (bfd_vma addr, disassemble_info *info, uint16_t *insn)
adde6300
AM
282{
283 bfd_byte buffer[2];
284 int status;
47b0e7ad
NC
285
286 status = info->read_memory_func (addr, buffer, 2, info);
287
288 if (status == 0)
0a7e1018
YQ
289 {
290 *insn = bfd_getl16 (buffer);
291 return 0;
292 }
47b0e7ad
NC
293
294 info->memory_error_func (status, addr, info);
295 return -1;
adde6300
AM
296}
297
298
299int
47b0e7ad 300print_insn_avr (bfd_vma addr, disassemble_info *info)
adde6300 301{
0a7e1018 302 uint16_t insn, insn2;
11041102
KD
303 const struct avr_opcodes_s *opcode;
304 static unsigned int *maskptr;
adde6300
AM
305 void *stream = info->stream;
306 fprintf_ftype prin = info->fprintf_func;
11041102 307 static unsigned int *avr_bin_masks;
bab84c47 308 static int initialized;
adde6300 309 int cmd_len = 2;
463f102c
DC
310 int ok = 0;
311 char op1[20], op2[20], comment1[40], comment2[40];
246f4c05
SS
312 int sym_op1 = 0, sym_op2 = 0;
313 bfd_vma sym_addr1, sym_addr2;
adde6300 314
af692060 315
bab84c47
DC
316 if (!initialized)
317 {
11041102
KD
318 unsigned int nopcodes;
319
af692060
NC
320 /* PR 4045: Try to avoid duplicating the 0x prefix that
321 objdump_print_addr() will put on addresses when there
322 is no symbol table available. */
323 if (info->symtab_size == 0)
324 comment_start = " ";
325
11041102 326 nopcodes = sizeof (avr_opcodes) / sizeof (struct avr_opcodes_s);
43e65147 327
47b0e7ad 328 avr_bin_masks = xmalloc (nopcodes * sizeof (unsigned int));
11041102
KD
329
330 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
331 opcode->name;
332 opcode++, maskptr++)
bab84c47
DC
333 {
334 char * s;
335 unsigned int bin = 0;
336 unsigned int mask = 0;
43e65147 337
bab84c47
DC
338 for (s = opcode->opcode; *s; ++s)
339 {
340 bin <<= 1;
341 mask <<= 1;
342 bin |= (*s == '1');
343 mask |= (*s == '1' || *s == '0');
344 }
345 assert (s - opcode->opcode == 16);
346 assert (opcode->bin_opcode == bin);
11041102 347 *maskptr = mask;
bab84c47 348 }
11041102
KD
349
350 initialized = 1;
bab84c47 351 }
adde6300 352
0a7e1018
YQ
353 if (avrdis_opcode (addr, info, &insn) != 0)
354 return -1;
43e65147 355
11041102
KD
356 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
357 opcode->name;
358 opcode++, maskptr++)
f36e8886
BS
359 {
360 if ((opcode->isa == AVR_ISA_TINY) && (info->mach != bfd_mach_avrtiny))
361 continue;
362 if ((insn & *maskptr) == opcode->bin_opcode)
363 break;
364 }
43e65147 365
463f102c
DC
366 /* Special case: disassemble `ldd r,b+0' as `ld r,b', and
367 `std b+0,r' as `st b,r' (next entry in the table). */
368
369 if (AVR_DISP0_P (insn))
370 opcode++;
371
372 op1[0] = 0;
373 op2[0] = 0;
374 comment1[0] = 0;
375 comment2[0] = 0;
376
bab84c47 377 if (opcode->name)
adde6300 378 {
8cc66334
EW
379 char *constraints = opcode->constraints;
380 char *opcode_str = opcode->opcode;
bab84c47 381
00d2865b 382 insn2 = 0;
463f102c 383 ok = 1;
bab84c47
DC
384
385 if (opcode->insn_size > 1)
386 {
0a7e1018
YQ
387 if (avrdis_opcode (addr + 2, info, &insn2) != 0)
388 return -1;
bab84c47
DC
389 cmd_len = 4;
390 }
391
8cc66334 392 if (*constraints && *constraints != '?')
bab84c47 393 {
8cc66334 394 int regs = REGISTER_P (*constraints);
bab84c47 395
8cc66334 396 ok = avr_operand (insn, insn2, addr, *constraints, opcode_str, op1, comment1, 0, &sym_op1, &sym_addr1);
bab84c47 397
8cc66334
EW
398 if (ok && *(++constraints) == ',')
399 ok = avr_operand (insn, insn2, addr, *(++constraints), opcode_str, op2,
246f4c05 400 *comment1 ? comment2 : comment1, regs, &sym_op2, &sym_addr2);
bab84c47 401 }
463f102c 402 }
bab84c47 403
463f102c
DC
404 if (!ok)
405 {
406 /* Unknown opcode, or invalid combination of operands. */
407 sprintf (op1, "0x%04x", insn);
408 op2[0] = 0;
409 sprintf (comment1, "????");
410 comment2[0] = 0;
411 }
bab84c47 412
463f102c 413 (*prin) (stream, "%s", ok ? opcode->name : ".word");
bab84c47 414
463f102c 415 if (*op1)
246f4c05 416 (*prin) (stream, "\t%s", op1);
bab84c47 417
463f102c
DC
418 if (*op2)
419 (*prin) (stream, ", %s", op2);
420
421 if (*comment1)
422 (*prin) (stream, "\t; %s", comment1);
423
246f4c05 424 if (sym_op1)
73f643e9 425 info->print_address_func (sym_addr1, info);
246f4c05 426
463f102c
DC
427 if (*comment2)
428 (*prin) (stream, " %s", comment2);
bab84c47 429
246f4c05 430 if (sym_op2)
73f643e9 431 info->print_address_func (sym_addr2, info);
246f4c05 432
adde6300
AM
433 return cmd_len;
434}