Tidy some code. Print pc rel addresses as signed.
[binutils.git] / opcodes / avr-dis.c
blob78766869ffa7e1e1c6467ef4a6617b86ea785af8
1 /* Disassemble AVR instructions.
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
4 Contributed by Denis Chertykov <denisc@overta.ru>
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.
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.
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. */
21 #include "dis-asm.h"
22 #include "opintl.h"
24 typedef unsigned char u8;
25 typedef unsigned short u16;
26 typedef unsigned long u32;
28 #define IFMASK(a,b) ((opcode & (a)) == (b))
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"
41 static char* last4[] = {"BLD","BST","SBRC","SBRS"};
44 static void dispLDD PARAMS ((u16, char *));
46 static void
47 dispLDD (opcode, dest)
48 u16 opcode;
49 char *dest;
51 opcode = (((opcode & 0x2000) >> 8) | ((opcode & 0x0c00) >> 7)
52 | (opcode & 7));
53 sprintf(dest, "%d", opcode);
57 static void regPP PARAMS ((u16, char *));
59 static void
60 regPP (opcode, dest)
61 u16 opcode;
62 char *dest;
64 opcode = ((opcode & 0x0600) >> 5) | (opcode & 0xf);
65 sprintf(dest, "0x%02X", opcode);
69 static void reg50 PARAMS ((u16, char *));
71 static void
72 reg50 (opcode, dest)
73 u16 opcode;
74 char *dest;
76 opcode = (opcode & 0x01f0) >> 4;
77 sprintf(dest, "R%d", opcode);
81 static void reg104 PARAMS ((u16, char *));
83 static void
84 reg104 (opcode, dest)
85 u16 opcode;
86 char *dest;
88 opcode = (opcode & 0xf) | ((opcode & 0x0200) >> 5);
89 sprintf(dest, "R%d", opcode);
93 static void reg40 PARAMS ((u16, char *));
95 static void
96 reg40 (opcode, dest)
97 u16 opcode;
98 char *dest;
100 opcode = (opcode & 0xf0) >> 4;
101 sprintf(dest, "R%d", opcode + 16);
105 static void reg20w PARAMS ((u16, char *));
107 static void
108 reg20w (opcode, dest)
109 u16 opcode;
110 char *dest;
112 opcode = (opcode & 0x30) >> 4;
113 sprintf(dest, "R%d", 24 + opcode * 2);
117 static void lit404 PARAMS ((u16, char *));
119 static void
120 lit404 (opcode, dest)
121 u16 opcode;
122 char *dest;
124 opcode = ((opcode & 0xf00) >> 4) | (opcode & 0xf);
125 sprintf(dest, "0x%02X", opcode);
129 static void lit204 PARAMS ((u16, char *));
131 static void
132 lit204 (opcode, dest)
133 u16 opcode;
134 char *dest;
136 opcode = ((opcode & 0xc0) >> 2) | (opcode & 0xf);
137 sprintf(dest, "0x%02X", opcode);
141 static void add0fff PARAMS ((u16, char *, int));
143 static void
144 add0fff (op, dest, pc)
145 u16 op;
146 char *dest;
147 int pc;
149 int rel_addr = (((op & 0xfff) ^ 0x800) - 0x800) * 2;
150 sprintf(dest, ".%+-8d ; 0x%06X", rel_addr, pc + 2 + rel_addr);
154 static void add03f8 PARAMS ((u16, char *, int));
156 static void
157 add03f8 (op, dest, pc)
158 u16 op;
159 char *dest;
160 int pc;
162 int rel_addr = ((((op >> 3) & 0x7f) ^ 0x40) - 0x40) * 2;
163 sprintf(dest, ".%+-8d ; 0x%06X", rel_addr, pc + 2 + rel_addr);
167 static u16 avrdis_opcode PARAMS ((bfd_vma, disassemble_info *));
169 static u16
170 avrdis_opcode (addr, info)
171 bfd_vma addr;
172 disassemble_info *info;
174 bfd_byte buffer[2];
175 int status;
176 status = info->read_memory_func(addr, buffer, 2, info);
177 if (status != 0)
179 info->memory_error_func(status, addr, info);
180 return -1;
182 return bfd_getl16 (buffer);
187 print_insn_avr(addr, info)
188 bfd_vma addr;
189 disassemble_info *info;
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;
198 opcode = avrdis_opcode (addr, info);
200 if (IFMASK(0xd000, 0x8000))
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);
214 else
216 switch (opcode & 0xf000)
218 case 0x0000:
220 reg50(opcode, rd);
221 reg104(opcode, rr);
222 switch (opcode & 0x0c00)
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;
238 break;
239 case 0x1000:
241 reg50(opcode, rd);
242 reg104(opcode, rr);
243 switch (opcode & 0x0c00)
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;
259 break;
260 case 0x2000:
262 reg50(opcode, rd);
263 reg104(opcode, rr);
264 switch (opcode & 0x0c00)
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;
280 break;
281 case 0x3000:
283 reg40(opcode, rd);
284 lit404(opcode, rr);
285 (*prin) (stream, " CPI %s,%s", rd, rr);
287 break;
288 case 0x4000:
290 reg40(opcode, rd);
291 lit404(opcode, rr);
292 (*prin) (stream, " SBCI %s,%s", rd, rr);
294 break;
295 case 0x5000:
297 reg40(opcode, rd);
298 lit404(opcode, rr);
299 (*prin) (stream, " SUBI %s,%s", rd, rr);
301 break;
302 case 0x6000:
304 reg40(opcode, rd);
305 lit404(opcode, rr);
306 (*prin) (stream, " ORI %s,%s", rd, rr);
308 break;
309 case 0x7000:
311 reg40(opcode, rd);
312 lit404(opcode, rr);
313 (*prin) (stream, " ANDI %s,%s", rd, rr);
315 break;
316 case 0x9000:
318 switch (opcode & 0x0e00)
320 case 0x0000:
322 reg50(opcode, rd);
323 switch (opcode & 0xf)
325 case 0x0:
327 (*prin) (stream, " LDS %s,0x%04X", rd,
328 avrdis_opcode(addr + 2, info));
329 cmd_len = 4;
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;
361 break;
362 case 0x0200:
364 reg50(opcode, rd);
365 switch (opcode & 0xf)
367 case 0x0:
369 (*prin) (stream, " STS 0x%04X,%s",
370 avrdis_opcode(addr + 2, info), rd);
371 cmd_len = 4;
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;
403 break;
404 case 0x0400:
406 if (IFMASK(0x020c, 0x000c))
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;
416 else if (IFMASK(0x010f, 0x0008))
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]);
424 else if (IFMASK(0x000f, 0x0009))
426 if (opcode & 0x0100)
427 (*prin) (stream, " ICALL");
428 else
429 (*prin) (stream, " IJMP");
431 else if (IFMASK(0x010f, 0x0108))
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, " ????");
448 else
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);
458 break;
459 case 0x0600:
461 if (opcode & 0x0200)
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);
471 break;
472 case 0x0800:
473 case 0x0a00:
475 (*prin) (stream, " %-8s0x%02X,%d",
476 sect98[(opcode & 0x0300) >> 8],
477 (opcode & 0xf8) >> 3,
478 opcode & 7);
480 break;
481 default:
483 reg50(opcode, rd);
484 reg104(opcode, rr);
485 (*prin) (stream, " MUL %s,%s", rd, rr);
489 break;
490 case 0xb000:
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);
499 break;
500 case 0xc000:
502 add0fff(opcode, rd, addr);
503 (*prin) (stream, " RJMP %s", rd);
505 break;
506 case 0xd000:
508 add0fff(opcode, rd, addr);
509 (*prin) (stream, " RCALL %s", rd);
511 break;
512 case 0xe000:
514 reg40(opcode, rd);
515 lit404(opcode, rr);
516 (*prin) (stream, " LDI %s,%s", rd, rr);
518 break;
519 case 0xf000:
521 if (opcode & 0x0800)
523 reg50(opcode, rd);
524 (*prin) (stream, " %-8s%s,%d",
525 last4[(opcode & 0x0600) >> 9],
526 rd, opcode & 7);
528 else
530 char* p;
531 add03f8(opcode, rd, addr);
532 p = branchs[((opcode & 0x0400) >> 7) | (opcode & 7)];
533 (*prin) (stream, " %-8s%s", p, rd);
536 break;
539 return cmd_len;