source: branches/libc-0.6/src/binutils/opcodes/avr-dis.c

Last change on this file was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 7.8 KB
Line 
1/* Disassemble AVR instructions.
2 Copyright 1999, 2000 Free Software Foundation, Inc.
3
4 Contributed by Denis Chertykov <denisc@overta.ru>
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19
20#include <assert.h>
21#include "sysdep.h"
22#include "dis-asm.h"
23#include "opintl.h"
24#include "libiberty.h"
25
26struct avr_opcodes_s
27{
28 char *name;
29 char *constraints;
30 char *opcode;
31 int insn_size; /* in words */
32 int isa;
33 unsigned int bin_opcode;
34};
35
36#define AVR_INSN(NAME, CONSTR, OPCODE, SIZE, ISA, BIN) \
37{#NAME, CONSTR, OPCODE, SIZE, ISA, BIN},
38
39const struct avr_opcodes_s avr_opcodes[] =
40{
41 #include "opcode/avr.h"
42 {NULL, NULL, NULL, 0, 0, 0}
43};
44
45static int avr_operand PARAMS ((unsigned int, unsigned int,
46 unsigned int, int, char *, char *, int));
47
48static int
49avr_operand (insn, insn2, pc, constraint, buf, comment, regs)
50 unsigned int insn;
51 unsigned int insn2;
52 unsigned int pc;
53 int constraint;
54 char *buf;
55 char *comment;
56 int regs;
57{
58 int ok = 1;
59
60 switch (constraint)
61 {
62 /* Any register operand. */
63 case 'r':
64 if (regs)
65 insn = (insn & 0xf) | ((insn & 0x0200) >> 5); /* source register */
66 else
67 insn = (insn & 0x01f0) >> 4; /* destination register */
68
69 sprintf (buf, "r%d", insn);
70 break;
71
72 case 'd':
73 if (regs)
74 sprintf (buf, "r%d", 16 + (insn & 0xf));
75 else
76 sprintf (buf, "r%d", 16 + ((insn & 0xf0) >> 4));
77 break;
78
79 case 'w':
80 sprintf (buf, "r%d", 24 + ((insn & 0x30) >> 3));
81 break;
82
83 case 'a':
84 if (regs)
85 sprintf (buf, "r%d", 16 + (insn & 7));
86 else
87 sprintf (buf, "r%d", 16 + ((insn >> 4) & 7));
88 break;
89
90 case 'v':
91 if (regs)
92 sprintf (buf, "r%d", (insn & 0xf) * 2);
93 else
94 sprintf (buf, "r%d", ((insn & 0xf0) >> 3));
95 break;
96
97 case 'e':
98 {
99 char *xyz;
100
101 switch (insn & 0x100f)
102 {
103 case 0x0000: xyz = "Z"; break;
104 case 0x1001: xyz = "Z+"; break;
105 case 0x1002: xyz = "-Z"; break;
106 case 0x0008: xyz = "Y"; break;
107 case 0x1009: xyz = "Y+"; break;
108 case 0x100a: xyz = "-Y"; break;
109 case 0x100c: xyz = "X"; break;
110 case 0x100d: xyz = "X+"; break;
111 case 0x100e: xyz = "-X"; break;
112 default: xyz = "??"; ok = 0;
113 }
114 sprintf (buf, xyz);
115
116 if (AVR_UNDEF_P (insn))
117 sprintf (comment, _("undefined"));
118 }
119 break;
120
121 case 'z':
122 *buf++ = 'Z';
123 if (insn & 0x1)
124 *buf++ = '+';
125 *buf = '\0';
126 if (AVR_UNDEF_P (insn))
127 sprintf (comment, _("undefined"));
128 break;
129
130 case 'b':
131 {
132 unsigned int x;
133
134 x = (insn & 7);
135 x |= (insn >> 7) & (3 << 3);
136 x |= (insn >> 8) & (1 << 5);
137
138 if (insn & 0x8)
139 *buf++ = 'Y';
140 else
141 *buf++ = 'Z';
142 sprintf (buf, "+%d", x);
143 sprintf (comment, "0x%02x", x);
144 }
145 break;
146
147 case 'h':
148 sprintf (buf, "0x%x",
149 ((((insn & 1) | ((insn & 0x1f0) >> 3)) << 16) | insn2) * 2);
150 break;
151
152 case 'L':
153 {
154 int rel_addr = (((insn & 0xfff) ^ 0x800) - 0x800) * 2;
155 sprintf (buf, ".%+-8d", rel_addr);
156 sprintf (comment, "0x%x", pc + 2 + rel_addr);
157 }
158 break;
159
160 case 'l':
161 {
162 int rel_addr = ((((insn >> 3) & 0x7f) ^ 0x40) - 0x40) * 2;
163 sprintf (buf, ".%+-8d", rel_addr);
164 sprintf (comment, "0x%x", pc + 2 + rel_addr);
165 }
166 break;
167
168 case 'i':
169 sprintf (buf, "0x%04X", insn2);
170 break;
171
172 case 'M':
173 sprintf (buf, "0x%02X", ((insn & 0xf00) >> 4) | (insn & 0xf));
174 sprintf (comment, "%d", ((insn & 0xf00) >> 4) | (insn & 0xf));
175 break;
176
177 case 'n':
178 sprintf (buf, "??");
179 fprintf (stderr, _("Internal disassembler error"));
180 ok = 0;
181 break;
182
183 case 'K':
184 {
185 unsigned int x;
186
187 x = (insn & 0xf) | ((insn >> 2) & 0x30);
188 sprintf (buf, "0x%02x", x);
189 sprintf (comment, "%d", x);
190 }
191 break;
192
193 case 's':
194 sprintf (buf, "%d", insn & 7);
195 break;
196
197 case 'S':
198 sprintf (buf, "%d", (insn >> 4) & 7);
199 break;
200
201 case 'P':
202 {
203 unsigned int x;
204 x = (insn & 0xf);
205 x |= (insn >> 5) & 0x30;
206 sprintf (buf, "0x%02x", x);
207 sprintf (comment, "%d", x);
208 }
209 break;
210
211 case 'p':
212 {
213 unsigned int x;
214
215 x = (insn >> 3) & 0x1f;
216 sprintf (buf, "0x%02x", x);
217 sprintf (comment, "%d", x);
218 }
219 break;
220
221 case '?':
222 *buf = '\0';
223 break;
224
225 default:
226 sprintf (buf, "??");
227 fprintf (stderr, _("unknown constraint `%c'"), constraint);
228 ok = 0;
229 }
230
231 return ok;
232}
233
234static unsigned short avrdis_opcode PARAMS ((bfd_vma, disassemble_info *));
235
236static unsigned short
237avrdis_opcode (addr, info)
238 bfd_vma addr;
239 disassemble_info *info;
240{
241 bfd_byte buffer[2];
242 int status;
243 status = info->read_memory_func(addr, buffer, 2, info);
244 if (status != 0)
245 {
246 info->memory_error_func(status, addr, info);
247 return -1;
248 }
249 return bfd_getl16 (buffer);
250}
251
252
253int
254print_insn_avr(addr, info)
255 bfd_vma addr;
256 disassemble_info *info;
257{
258 unsigned int insn, insn2;
259 const struct avr_opcodes_s *opcode;
260 static unsigned int *maskptr;
261 void *stream = info->stream;
262 fprintf_ftype prin = info->fprintf_func;
263 static unsigned int *avr_bin_masks;
264 static int initialized;
265 int cmd_len = 2;
266 int ok = 0;
267 char op1[20], op2[20], comment1[40], comment2[40];
268
269 if (!initialized)
270 {
271 unsigned int nopcodes;
272
273 nopcodes = sizeof (avr_opcodes) / sizeof (struct avr_opcodes_s);
274
275 avr_bin_masks = (unsigned int *)
276 xmalloc (nopcodes * sizeof (unsigned int));
277
278 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
279 opcode->name;
280 opcode++, maskptr++)
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);
295 *maskptr = mask;
296 }
297
298 initialized = 1;
299 }
300
301 insn = avrdis_opcode (addr, info);
302
303 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
304 opcode->name;
305 opcode++, maskptr++)
306 {
307 if ((insn & *maskptr) == opcode->bin_opcode)
308 break;
309 }
310
311 /* Special case: disassemble `ldd r,b+0' as `ld r,b', and
312 `std b+0,r' as `st b,r' (next entry in the table). */
313
314 if (AVR_DISP0_P (insn))
315 opcode++;
316
317 op1[0] = 0;
318 op2[0] = 0;
319 comment1[0] = 0;
320 comment2[0] = 0;
321
322 if (opcode->name)
323 {
324 char *op = opcode->constraints;
325
326 insn2 = 0;
327 ok = 1;
328
329 if (opcode->insn_size > 1)
330 {
331 insn2 = avrdis_opcode (addr + 2, info);
332 cmd_len = 4;
333 }
334
335 if (*op && *op != '?')
336 {
337 int regs = REGISTER_P (*op);
338
339 ok = avr_operand (insn, insn2, addr, *op, op1, comment1, 0);
340
341 if (ok && *(++op) == ',')
342 ok = avr_operand (insn, insn2, addr, *(++op), op2,
343 *comment1 ? comment2 : comment1, regs);
344 }
345 }
346
347 if (!ok)
348 {
349 /* Unknown opcode, or invalid combination of operands. */
350 sprintf (op1, "0x%04x", insn);
351 op2[0] = 0;
352 sprintf (comment1, "????");
353 comment2[0] = 0;
354 }
355
356 (*prin) (stream, "%s", ok ? opcode->name : ".word");
357
358 if (*op1)
359 (*prin) (stream, "\t%s", op1);
360
361 if (*op2)
362 (*prin) (stream, ", %s", op2);
363
364 if (*comment1)
365 (*prin) (stream, "\t; %s", comment1);
366
367 if (*comment2)
368 (*prin) (stream, " %s", comment2);
369
370 return cmd_len;
371}
Note: See TracBrowser for help on using the repository browser.