]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/avr-dis.c
Print symbol names in comments for LDS/STS disassembly.
[thirdparty/binutils-gdb.git] / opcodes / avr-dis.c
CommitLineData
adde6300 1/* Disassemble AVR instructions.
6f2750fe 2 Copyright (C) 1999-2016 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>
adde6300
AM
25#include "dis-asm.h"
26#include "opintl.h"
11041102 27#include "libiberty.h"
3c504221 28
bab84c47 29struct avr_opcodes_s
adde6300 30{
bab84c47
DC
31 char *name;
32 char *constraints;
33 char *opcode;
47b0e7ad 34 int insn_size; /* In words. */
bab84c47
DC
35 int isa;
36 unsigned int bin_opcode;
bab84c47 37};
adde6300 38
bab84c47 39#define AVR_INSN(NAME, CONSTR, OPCODE, SIZE, ISA, BIN) \
11041102 40{#NAME, CONSTR, OPCODE, SIZE, ISA, BIN},
adde6300 41
11041102 42const struct avr_opcodes_s avr_opcodes[] =
adde6300 43{
bab84c47 44 #include "opcode/avr.h"
11041102 45 {NULL, NULL, NULL, 0, 0, 0}
bab84c47 46};
adde6300 47
af692060
NC
48static const char * comment_start = "0x";
49
463f102c 50static int
246f4c05 51avr_operand (unsigned int insn, unsigned int insn2, unsigned int pc, int constraint,
8cc66334 52 char *opcode_str, char *buf, char *comment, int regs, int *sym, bfd_vma *sym_addr)
adde6300 53{
463f102c 54 int ok = 1;
246f4c05 55 *sym = 0;
463f102c 56
bab84c47
DC
57 switch (constraint)
58 {
59 /* Any register operand. */
60 case 'r':
61 if (regs)
47b0e7ad 62 insn = (insn & 0xf) | ((insn & 0x0200) >> 5); /* Source register. */
bab84c47 63 else
47b0e7ad 64 insn = (insn & 0x01f0) >> 4; /* Destination register. */
43e65147 65
bab84c47
DC
66 sprintf (buf, "r%d", insn);
67 break;
68
69 case 'd':
70 if (regs)
71 sprintf (buf, "r%d", 16 + (insn & 0xf));
72 else
73 sprintf (buf, "r%d", 16 + ((insn & 0xf0) >> 4));
74 break;
43e65147 75
bab84c47
DC
76 case 'w':
77 sprintf (buf, "r%d", 24 + ((insn & 0x30) >> 3));
78 break;
43e65147 79
bab84c47
DC
80 case 'a':
81 if (regs)
82 sprintf (buf, "r%d", 16 + (insn & 7));
83 else
84 sprintf (buf, "r%d", 16 + ((insn >> 4) & 7));
85 break;
adde6300 86
bab84c47
DC
87 case 'v':
88 if (regs)
89 sprintf (buf, "r%d", (insn & 0xf) * 2);
90 else
91 sprintf (buf, "r%d", ((insn & 0xf0) >> 3));
92 break;
93
94 case 'e':
463f102c
DC
95 {
96 char *xyz;
97
98 switch (insn & 0x100f)
99 {
100 case 0x0000: xyz = "Z"; break;
101 case 0x1001: xyz = "Z+"; break;
102 case 0x1002: xyz = "-Z"; break;
103 case 0x0008: xyz = "Y"; break;
104 case 0x1009: xyz = "Y+"; break;
105 case 0x100a: xyz = "-Y"; break;
106 case 0x100c: xyz = "X"; break;
107 case 0x100d: xyz = "X+"; break;
108 case 0x100e: xyz = "-X"; break;
109 default: xyz = "??"; ok = 0;
110 }
c8941035 111 strcpy (buf, xyz);
463f102c
DC
112
113 if (AVR_UNDEF_P (insn))
114 sprintf (comment, _("undefined"));
115 }
bab84c47
DC
116 break;
117
118 case 'z':
119 *buf++ = 'Z';
8cc66334
EW
120
121 /* Check for post-increment. */
122 char *s;
123 for (s = opcode_str; *s; ++s)
124 {
125 if (*s == '+')
126 {
5d73b1f1
NC
127 if (insn & (1 << (15 - (s - opcode_str))))
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;
43e65147 141
bab84c47
DC
142 x = (insn & 7);
143 x |= (insn >> 7) & (3 << 3);
144 x |= (insn >> 8) & (1 << 5);
43e65147 145
bab84c47
DC
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;
43e65147 154
bab84c47 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. */
43e65147 161 sprintf (buf, "%#lx", (unsigned long) *sym_addr);
c8941035 162 strcpy (comment, comment_start);
bab84c47 163 break;
43e65147 164
bab84c47
DC
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':
1857fe72
DC
187 {
188 unsigned int val = insn2 | 0x800000;
189 *sym = 1;
190 *sym_addr = val;
191 sprintf (buf, "0x%04X", insn2);
192 strcpy (comment, comment_start);
193 }
bab84c47 194 break;
f36e8886
BS
195
196 case 'j':
197 {
198 unsigned int val = ((insn & 0xf) | ((insn & 0x600) >> 5)
199 | ((insn & 0x100) >> 2));
1857fe72
DC
200 *sym = 1;
201 *sym_addr = val | 0x800000;
f36e8886 202 sprintf (buf, "0x%02x", val);
1857fe72 203 strcpy (comment, comment_start);
f36e8886
BS
204 }
205 break;
43e65147 206
bab84c47
DC
207 case 'M':
208 sprintf (buf, "0x%02X", ((insn & 0xf00) >> 4) | (insn & 0xf));
209 sprintf (comment, "%d", ((insn & 0xf00) >> 4) | (insn & 0xf));
210 break;
211
212 case 'n':
463f102c
DC
213 sprintf (buf, "??");
214 fprintf (stderr, _("Internal disassembler error"));
215 ok = 0;
bab84c47 216 break;
43e65147 217
bab84c47 218 case 'K':
463f102c
DC
219 {
220 unsigned int x;
221
222 x = (insn & 0xf) | ((insn >> 2) & 0x30);
223 sprintf (buf, "0x%02x", x);
224 sprintf (comment, "%d", x);
225 }
bab84c47 226 break;
43e65147 227
bab84c47
DC
228 case 's':
229 sprintf (buf, "%d", insn & 7);
230 break;
43e65147 231
bab84c47
DC
232 case 'S':
233 sprintf (buf, "%d", (insn >> 4) & 7);
234 break;
43e65147 235
bab84c47
DC
236 case 'P':
237 {
238 unsigned int x;
47b0e7ad 239
bab84c47
DC
240 x = (insn & 0xf);
241 x |= (insn >> 5) & 0x30;
242 sprintf (buf, "0x%02x", x);
243 sprintf (comment, "%d", x);
244 }
245 break;
246
247 case 'p':
248 {
249 unsigned int x;
43e65147 250
bab84c47
DC
251 x = (insn >> 3) & 0x1f;
252 sprintf (buf, "0x%02x", x);
253 sprintf (comment, "%d", x);
254 }
255 break;
43e65147 256
8cc66334
EW
257 case 'E':
258 sprintf (buf, "%d", (insn >> 4) & 15);
259 break;
43e65147 260
bab84c47
DC
261 case '?':
262 *buf = '\0';
263 break;
43e65147 264
bab84c47 265 default:
463f102c
DC
266 sprintf (buf, "??");
267 fprintf (stderr, _("unknown constraint `%c'"), constraint);
268 ok = 0;
bab84c47 269 }
463f102c
DC
270
271 return ok;
adde6300
AM
272}
273
bab84c47 274static unsigned short
47b0e7ad 275avrdis_opcode (bfd_vma addr, disassemble_info *info)
adde6300
AM
276{
277 bfd_byte buffer[2];
278 int status;
47b0e7ad
NC
279
280 status = info->read_memory_func (addr, buffer, 2, info);
281
282 if (status == 0)
283 return bfd_getl16 (buffer);
284
285 info->memory_error_func (status, addr, info);
286 return -1;
adde6300
AM
287}
288
289
290int
47b0e7ad 291print_insn_avr (bfd_vma addr, disassemble_info *info)
adde6300 292{
bab84c47 293 unsigned int insn, insn2;
11041102
KD
294 const struct avr_opcodes_s *opcode;
295 static unsigned int *maskptr;
adde6300
AM
296 void *stream = info->stream;
297 fprintf_ftype prin = info->fprintf_func;
11041102 298 static unsigned int *avr_bin_masks;
bab84c47 299 static int initialized;
adde6300 300 int cmd_len = 2;
463f102c
DC
301 int ok = 0;
302 char op1[20], op2[20], comment1[40], comment2[40];
246f4c05
SS
303 int sym_op1 = 0, sym_op2 = 0;
304 bfd_vma sym_addr1, sym_addr2;
adde6300 305
af692060 306
bab84c47
DC
307 if (!initialized)
308 {
11041102
KD
309 unsigned int nopcodes;
310
af692060
NC
311 /* PR 4045: Try to avoid duplicating the 0x prefix that
312 objdump_print_addr() will put on addresses when there
313 is no symbol table available. */
314 if (info->symtab_size == 0)
315 comment_start = " ";
316
11041102 317 nopcodes = sizeof (avr_opcodes) / sizeof (struct avr_opcodes_s);
43e65147 318
47b0e7ad 319 avr_bin_masks = xmalloc (nopcodes * sizeof (unsigned int));
11041102
KD
320
321 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
322 opcode->name;
323 opcode++, maskptr++)
bab84c47
DC
324 {
325 char * s;
326 unsigned int bin = 0;
327 unsigned int mask = 0;
43e65147 328
bab84c47
DC
329 for (s = opcode->opcode; *s; ++s)
330 {
331 bin <<= 1;
332 mask <<= 1;
333 bin |= (*s == '1');
334 mask |= (*s == '1' || *s == '0');
335 }
336 assert (s - opcode->opcode == 16);
337 assert (opcode->bin_opcode == bin);
11041102 338 *maskptr = mask;
bab84c47 339 }
11041102
KD
340
341 initialized = 1;
bab84c47 342 }
adde6300 343
bab84c47 344 insn = avrdis_opcode (addr, info);
43e65147 345
11041102
KD
346 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
347 opcode->name;
348 opcode++, maskptr++)
f36e8886
BS
349 {
350 if ((opcode->isa == AVR_ISA_TINY) && (info->mach != bfd_mach_avrtiny))
351 continue;
352 if ((insn & *maskptr) == opcode->bin_opcode)
353 break;
354 }
43e65147 355
463f102c
DC
356 /* Special case: disassemble `ldd r,b+0' as `ld r,b', and
357 `std b+0,r' as `st b,r' (next entry in the table). */
358
359 if (AVR_DISP0_P (insn))
360 opcode++;
361
362 op1[0] = 0;
363 op2[0] = 0;
364 comment1[0] = 0;
365 comment2[0] = 0;
366
bab84c47 367 if (opcode->name)
adde6300 368 {
8cc66334
EW
369 char *constraints = opcode->constraints;
370 char *opcode_str = opcode->opcode;
bab84c47 371
00d2865b 372 insn2 = 0;
463f102c 373 ok = 1;
bab84c47
DC
374
375 if (opcode->insn_size > 1)
376 {
377 insn2 = avrdis_opcode (addr + 2, info);
378 cmd_len = 4;
379 }
380
8cc66334 381 if (*constraints && *constraints != '?')
bab84c47 382 {
8cc66334 383 int regs = REGISTER_P (*constraints);
bab84c47 384
8cc66334 385 ok = avr_operand (insn, insn2, addr, *constraints, opcode_str, op1, comment1, 0, &sym_op1, &sym_addr1);
bab84c47 386
8cc66334
EW
387 if (ok && *(++constraints) == ',')
388 ok = avr_operand (insn, insn2, addr, *(++constraints), opcode_str, op2,
246f4c05 389 *comment1 ? comment2 : comment1, regs, &sym_op2, &sym_addr2);
bab84c47 390 }
463f102c 391 }
bab84c47 392
463f102c
DC
393 if (!ok)
394 {
395 /* Unknown opcode, or invalid combination of operands. */
396 sprintf (op1, "0x%04x", insn);
397 op2[0] = 0;
398 sprintf (comment1, "????");
399 comment2[0] = 0;
400 }
bab84c47 401
463f102c 402 (*prin) (stream, "%s", ok ? opcode->name : ".word");
bab84c47 403
463f102c 404 if (*op1)
246f4c05 405 (*prin) (stream, "\t%s", op1);
bab84c47 406
463f102c
DC
407 if (*op2)
408 (*prin) (stream, ", %s", op2);
409
410 if (*comment1)
411 (*prin) (stream, "\t; %s", comment1);
412
246f4c05 413 if (sym_op1)
73f643e9 414 info->print_address_func (sym_addr1, info);
246f4c05 415
463f102c
DC
416 if (*comment2)
417 (*prin) (stream, " %s", comment2);
bab84c47 418
246f4c05 419 if (sym_op2)
73f643e9 420 info->print_address_func (sym_addr2, info);
246f4c05 421
adde6300
AM
422 return cmd_len;
423}