]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - opcodes/avr-dis.c
Tidy some code. Print pc rel addresses as signed.
[thirdparty/binutils-gdb.git] / opcodes / avr-dis.c
1 /* Disassemble AVR instructions.
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 Contributed by Denis Chertykov <denisc@overta.ru>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19
20
21 #include "dis-asm.h"
22 #include "opintl.h"
23
24 typedef unsigned char u8;
25 typedef unsigned short u16;
26 typedef unsigned long u32;
27
28 #define IFMASK(a,b) ((opcode & (a)) == (b))
29
30 static char* SREG_flags = "CZNVSHTI";
31 static char* sect94[] = {"COM","NEG","SWAP","INC","NULL","ASR","LSR","ROR",
32 0,0,"DEC",0,0,0,0,0};
33 static char* sect98[] = {"CBI","SBIC","SBI","SBIS"};
34 static char* branchs[] = {
35 "BRCS","BREQ","BRMI","BRVS",
36 "BRLT","BRHS","BRTS","BRIE",
37 "BRCC","BRNE","BRPL","BRVC",
38 "BRGE","BRHC","BRTC","BRID"
39 };
40
41 static char* last4[] = {"BLD","BST","SBRC","SBRS"};
42
43
44 static void dispLDD PARAMS ((u16, char *));
45
46 static void
47 dispLDD (opcode, dest)
48 u16 opcode;
49 char *dest;
50 {
51 opcode = (((opcode & 0x2000) >> 8) | ((opcode & 0x0c00) >> 7)
52 | (opcode & 7));
53 sprintf(dest, "%d", opcode);
54 }
55
56
57 static void regPP PARAMS ((u16, char *));
58
59 static void
60 regPP (opcode, dest)
61 u16 opcode;
62 char *dest;
63 {
64 opcode = ((opcode & 0x0600) >> 5) | (opcode & 0xf);
65 sprintf(dest, "0x%02X", opcode);
66 }
67
68
69 static void reg50 PARAMS ((u16, char *));
70
71 static void
72 reg50 (opcode, dest)
73 u16 opcode;
74 char *dest;
75 {
76 opcode = (opcode & 0x01f0) >> 4;
77 sprintf(dest, "R%d", opcode);
78 }
79
80
81 static void reg104 PARAMS ((u16, char *));
82
83 static void
84 reg104 (opcode, dest)
85 u16 opcode;
86 char *dest;
87 {
88 opcode = (opcode & 0xf) | ((opcode & 0x0200) >> 5);
89 sprintf(dest, "R%d", opcode);
90 }
91
92
93 static void reg40 PARAMS ((u16, char *));
94
95 static void
96 reg40 (opcode, dest)
97 u16 opcode;
98 char *dest;
99 {
100 opcode = (opcode & 0xf0) >> 4;
101 sprintf(dest, "R%d", opcode + 16);
102 }
103
104
105 static void reg20w PARAMS ((u16, char *));
106
107 static void
108 reg20w (opcode, dest)
109 u16 opcode;
110 char *dest;
111 {
112 opcode = (opcode & 0x30) >> 4;
113 sprintf(dest, "R%d", 24 + opcode * 2);
114 }
115
116
117 static void lit404 PARAMS ((u16, char *));
118
119 static void
120 lit404 (opcode, dest)
121 u16 opcode;
122 char *dest;
123 {
124 opcode = ((opcode & 0xf00) >> 4) | (opcode & 0xf);
125 sprintf(dest, "0x%02X", opcode);
126 }
127
128
129 static void lit204 PARAMS ((u16, char *));
130
131 static void
132 lit204 (opcode, dest)
133 u16 opcode;
134 char *dest;
135 {
136 opcode = ((opcode & 0xc0) >> 2) | (opcode & 0xf);
137 sprintf(dest, "0x%02X", opcode);
138 }
139
140
141 static void add0fff PARAMS ((u16, char *, int));
142
143 static void
144 add0fff (op, dest, pc)
145 u16 op;
146 char *dest;
147 int pc;
148 {
149 int rel_addr = (((op & 0xfff) ^ 0x800) - 0x800) * 2;
150 sprintf(dest, ".%+-8d ; 0x%06X", rel_addr, pc + 2 + rel_addr);
151 }
152
153
154 static void add03f8 PARAMS ((u16, char *, int));
155
156 static void
157 add03f8 (op, dest, pc)
158 u16 op;
159 char *dest;
160 int pc;
161 {
162 int rel_addr = ((((op >> 3) & 0x7f) ^ 0x40) - 0x40) * 2;
163 sprintf(dest, ".%+-8d ; 0x%06X", rel_addr, pc + 2 + rel_addr);
164 }
165
166
167 static u16 avrdis_opcode PARAMS ((bfd_vma, disassemble_info *));
168
169 static u16
170 avrdis_opcode (addr, info)
171 bfd_vma addr;
172 disassemble_info *info;
173 {
174 bfd_byte buffer[2];
175 int status;
176 status = info->read_memory_func(addr, buffer, 2, info);
177 if (status != 0)
178 {
179 info->memory_error_func(status, addr, info);
180 return -1;
181 }
182 return bfd_getl16 (buffer);
183 }
184
185
186 int
187 print_insn_avr(addr, info)
188 bfd_vma addr;
189 disassemble_info *info;
190 {
191 char rr[200];
192 char rd[200];
193 u16 opcode;
194 void *stream = info->stream;
195 fprintf_ftype prin = info->fprintf_func;
196 int cmd_len = 2;
197
198 opcode = avrdis_opcode (addr, info);
199
200 if (IFMASK(0xd000, 0x8000))
201 {
202 char letter;
203 reg50(opcode, rd);
204 dispLDD(opcode, rr);
205 if (opcode & 8)
206 letter = 'Y';
207 else
208 letter = 'Z';
209 if (opcode & 0x0200)
210 (*prin) (stream, " STD %c+%s,%s", letter, rr, rd);
211 else
212 (*prin) (stream, " LDD %s,%c+%s", rd, letter, rr);
213 }
214 else
215 {
216 switch (opcode & 0xf000)
217 {
218 case 0x0000:
219 {
220 reg50(opcode, rd);
221 reg104(opcode, rr);
222 switch (opcode & 0x0c00)
223 {
224 case 0x0000:
225 (*prin) (stream, " NOP");
226 break;
227 case 0x0400:
228 (*prin) (stream, " CPC %s,%s", rd, rr);
229 break;
230 case 0x0800:
231 (*prin) (stream, " SBC %s,%s", rd, rr);
232 break;
233 case 0x0c00:
234 (*prin) (stream, " ADD %s,%s", rd, rr);
235 break;
236 }
237 }
238 break;
239 case 0x1000:
240 {
241 reg50(opcode, rd);
242 reg104(opcode, rr);
243 switch (opcode & 0x0c00)
244 {
245 case 0x0000:
246 (*prin) (stream, " CPSE %s,%s", rd, rr);
247 break;
248 case 0x0400:
249 (*prin) (stream, " CP %s,%s", rd, rr);
250 break;
251 case 0x0800:
252 (*prin) (stream, " SUB %s,%s", rd, rr);
253 break;
254 case 0x0c00:
255 (*prin) (stream, " ADC %s,%s", rd, rr);
256 break;
257 }
258 }
259 break;
260 case 0x2000:
261 {
262 reg50(opcode, rd);
263 reg104(opcode, rr);
264 switch (opcode & 0x0c00)
265 {
266 case 0x0000:
267 (*prin) (stream, " AND %s,%s", rd, rr);
268 break;
269 case 0x0400:
270 (*prin) (stream, " EOR %s,%s", rd, rr);
271 break;
272 case 0x0800:
273 (*prin) (stream, " OR %s,%s", rd, rr);
274 break;
275 case 0x0c00:
276 (*prin) (stream, " MOV %s,%s", rd, rr);
277 break;
278 }
279 }
280 break;
281 case 0x3000:
282 {
283 reg40(opcode, rd);
284 lit404(opcode, rr);
285 (*prin) (stream, " CPI %s,%s", rd, rr);
286 }
287 break;
288 case 0x4000:
289 {
290 reg40(opcode, rd);
291 lit404(opcode, rr);
292 (*prin) (stream, " SBCI %s,%s", rd, rr);
293 }
294 break;
295 case 0x5000:
296 {
297 reg40(opcode, rd);
298 lit404(opcode, rr);
299 (*prin) (stream, " SUBI %s,%s", rd, rr);
300 }
301 break;
302 case 0x6000:
303 {
304 reg40(opcode, rd);
305 lit404(opcode, rr);
306 (*prin) (stream, " ORI %s,%s", rd, rr);
307 }
308 break;
309 case 0x7000:
310 {
311 reg40(opcode, rd);
312 lit404(opcode, rr);
313 (*prin) (stream, " ANDI %s,%s", rd, rr);
314 }
315 break;
316 case 0x9000:
317 {
318 switch (opcode & 0x0e00)
319 {
320 case 0x0000:
321 {
322 reg50(opcode, rd);
323 switch (opcode & 0xf)
324 {
325 case 0x0:
326 {
327 (*prin) (stream, " LDS %s,0x%04X", rd,
328 avrdis_opcode(addr + 2, info));
329 cmd_len = 4;
330 }
331 break;
332 case 0x1:
333 (*prin) (stream, " LD %s,Z+", rd);
334 break;
335 case 0x2:
336 (*prin) (stream, " LD %s,-Z", rd);
337 break;
338 case 0x9:
339 (*prin) (stream, " LD %s,Y+", rd);
340 break;
341 case 0xa:
342 (*prin) (stream, " LD %s,-Y", rd);
343 break;
344 case 0xc:
345 (*prin) (stream, " LD %s,X", rd);
346 break;
347 case 0xd:
348 (*prin) (stream, " LD %s,X+", rd);
349 break;
350 case 0xe:
351 (*prin) (stream, " LD %s,-X", rd);
352 break;
353 case 0xf:
354 (*prin) (stream, " POP %s", rd);
355 break;
356 default:
357 (*prin) (stream, " ????");
358 break;
359 }
360 }
361 break;
362 case 0x0200:
363 {
364 reg50(opcode, rd);
365 switch (opcode & 0xf)
366 {
367 case 0x0:
368 {
369 (*prin) (stream, " STS 0x%04X,%s",
370 avrdis_opcode(addr + 2, info), rd);
371 cmd_len = 4;
372 }
373 break;
374 case 0x1:
375 (*prin) (stream, " ST Z+,%s", rd);
376 break;
377 case 0x2:
378 (*prin) (stream, " ST -Z,%s", rd);
379 break;
380 case 0x9:
381 (*prin) (stream, " ST Y+,%s", rd);
382 break;
383 case 0xa:
384 (*prin) (stream, " ST -Y,%s", rd);
385 break;
386 case 0xc:
387 (*prin) (stream, " ST X,%s", rd);
388 break;
389 case 0xd:
390 (*prin) (stream, " ST X+,%s", rd);
391 break;
392 case 0xe:
393 (*prin) (stream, " ST -X,%s", rd);
394 break;
395 case 0xf:
396 (*prin) (stream, " PUSH %s", rd);
397 break;
398 default:
399 (*prin) (stream, " ????");
400 break;
401 }
402 }
403 break;
404 case 0x0400:
405 {
406 if (IFMASK(0x020c, 0x000c))
407 {
408 u32 k = ((opcode & 0x01f0) >> 3) | (opcode & 1);
409 k = (k << 16) | avrdis_opcode(addr + 2, info);
410 if (opcode & 0x0002)
411 (*prin) (stream, " CALL 0x%06X", k*2);
412 else
413 (*prin) (stream, " JMP 0x%06X", k*2);
414 cmd_len = 4;
415 }
416 else if (IFMASK(0x010f, 0x0008))
417 {
418 int sf = (opcode & 0x70) >> 4;
419 if (opcode & 0x0080)
420 (*prin) (stream, " CL%c", SREG_flags[sf]);
421 else
422 (*prin) (stream, " SE%c", SREG_flags[sf]);
423 }
424 else if (IFMASK(0x000f, 0x0009))
425 {
426 if (opcode & 0x0100)
427 (*prin) (stream, " ICALL");
428 else
429 (*prin) (stream, " IJMP");
430 }
431 else if (IFMASK(0x010f, 0x0108))
432 {
433 if (IFMASK(0x0090, 0x0000))
434 (*prin) (stream, " RET");
435 else if (IFMASK(0x0090, 0x0010))
436 (*prin) (stream, " RETI");
437 else if (IFMASK(0x00e0, 0x0080))
438 (*prin) (stream, " SLEEP");
439 else if (IFMASK(0x00e0, 0x00a0))
440 (*prin) (stream, " WDR");
441 else if (IFMASK(0x00f0, 0x00c0))
442 (*prin) (stream, " LPM");
443 else if (IFMASK(0x00f0, 0x00d0))
444 (*prin) (stream, " ELPM");
445 else
446 (*prin) (stream, " ????");
447 }
448 else
449 {
450 const char* p;
451 reg50(opcode, rd);
452 p = sect94[opcode & 0xf];
453 if (!p)
454 p = "????";
455 (*prin) (stream, " %-8s%s", p, rd);
456 }
457 }
458 break;
459 case 0x0600:
460 {
461 if (opcode & 0x0200)
462 {
463 lit204(opcode, rd);
464 reg20w(opcode, rr);
465 if (opcode & 0x0100)
466 (*prin) (stream, " SBIW %s,%s", rr, rd);
467 else
468 (*prin) (stream, " ADIW %s,%s", rr, rd);
469 }
470 }
471 break;
472 case 0x0800:
473 case 0x0a00:
474 {
475 (*prin) (stream, " %-8s0x%02X,%d",
476 sect98[(opcode & 0x0300) >> 8],
477 (opcode & 0xf8) >> 3,
478 opcode & 7);
479 }
480 break;
481 default:
482 {
483 reg50(opcode, rd);
484 reg104(opcode, rr);
485 (*prin) (stream, " MUL %s,%s", rd, rr);
486 }
487 }
488 }
489 break;
490 case 0xb000:
491 {
492 reg50(opcode, rd);
493 regPP(opcode, rr);
494 if (opcode & 0x0800)
495 (*prin) (stream, " OUT %s,%s", rr, rd);
496 else
497 (*prin) (stream, " IN %s,%s", rd, rr);
498 }
499 break;
500 case 0xc000:
501 {
502 add0fff(opcode, rd, addr);
503 (*prin) (stream, " RJMP %s", rd);
504 }
505 break;
506 case 0xd000:
507 {
508 add0fff(opcode, rd, addr);
509 (*prin) (stream, " RCALL %s", rd);
510 }
511 break;
512 case 0xe000:
513 {
514 reg40(opcode, rd);
515 lit404(opcode, rr);
516 (*prin) (stream, " LDI %s,%s", rd, rr);
517 }
518 break;
519 case 0xf000:
520 {
521 if (opcode & 0x0800)
522 {
523 reg50(opcode, rd);
524 (*prin) (stream, " %-8s%s,%d",
525 last4[(opcode & 0x0600) >> 9],
526 rd, opcode & 7);
527 }
528 else
529 {
530 char* p;
531 add03f8(opcode, rd, addr);
532 p = branchs[((opcode & 0x0400) >> 7) | (opcode & 7)];
533 (*prin) (stream, " %-8s%s", p, rd);
534 }
535 }
536 break;
537 }
538 }
539 return cmd_len;
540 }