diff options
Diffstat (limited to 'opcodes')
-rw-r--r-- | opcodes/ChangeLog | 12 | ||||
-rw-r--r-- | opcodes/avr-dis.c | 125 |
2 files changed, 94 insertions, 43 deletions
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 574d60d..04440c2 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,15 @@ +2000-07-29 Marek Michalkiewicz <marekm@linux.org.pl> + + * avr-dis.c (avr_operand): Use PARAMS macro in declaration. + Change return type from void to int. Check the combination + of operands, return 1 if valid. Fix to avoid BUF overflow. + Report undefined combinations of operands in COMMENT. + Report internal errors to stderr. Output the adiw/sbiw + constant operand in both decimal and hex. + (print_insn_avr): Disassemble ldd/std with displacement of 0 + as ld/st. Check avr_operand () return value, handle invalid + combinations of operands like unknown opcodes. + 2000-08-04 Ben Elliston <bje@redhat.com> * cgen-dis.in, cgen-asm.in, cgen-ibld.in: New files. diff --git a/opcodes/avr-dis.c b/opcodes/avr-dis.c index ee91d7f..db46cb4 100644 --- a/opcodes/avr-dis.c +++ b/opcodes/avr-dis.c @@ -43,12 +43,10 @@ struct avr_opcodes_s avr_opcodes[] = {NULL, NULL, NULL, 0, 0, 0, 0} }; +static int avr_operand PARAMS ((unsigned int, unsigned int, + unsigned int, int, char *, char *, int)); -static void avr_operand (unsigned int insn, unsigned int insn2, - unsigned int pc, int constraint, char *buf, - char *comment, int regs); - -static void +static int avr_operand (insn, insn2, pc, constraint, buf, comment, regs) unsigned int insn; unsigned int insn2; @@ -58,6 +56,8 @@ avr_operand (insn, insn2, pc, constraint, buf, comment, regs) char *comment; int regs; { + int ok = 1; + switch (constraint) { /* Any register operand. */ @@ -96,18 +96,27 @@ avr_operand (insn, insn2, pc, constraint, buf, comment, regs) break; case 'e': - if (insn & 0x2) - *buf++ = '-'; - switch ((insn >> 2) & 0x3) - { - case 0: *buf++ = 'Z'; break; - case 2: *buf++ = 'Y'; break; - case 3: *buf++ = 'X'; break; - default: buf += sprintf (buf, _(" unknown register ")); break; - } - if (insn & 0x1) - *buf++ = '+'; - *buf = '\0'; + { + char *xyz; + + switch (insn & 0x100f) + { + case 0x0000: xyz = "Z"; break; + case 0x1001: xyz = "Z+"; break; + case 0x1002: xyz = "-Z"; break; + case 0x0008: xyz = "Y"; break; + case 0x1009: xyz = "Y+"; break; + case 0x100a: xyz = "-Y"; break; + case 0x100c: xyz = "X"; break; + case 0x100d: xyz = "X+"; break; + case 0x100e: xyz = "-X"; break; + default: xyz = "??"; ok = 0; + } + sprintf (buf, xyz); + + if (AVR_UNDEF_P (insn)) + sprintf (comment, _("undefined")); + } break; case 'z': @@ -115,11 +124,13 @@ avr_operand (insn, insn2, pc, constraint, buf, comment, regs) if (insn & 0x1) *buf++ = '+'; *buf = '\0'; + if (AVR_UNDEF_P (insn)) + sprintf (comment, _("undefined")); break; case 'b': { - unsigned int x = insn; + unsigned int x; x = (insn & 7); x |= (insn >> 7) & (3 << 3); @@ -165,11 +176,19 @@ avr_operand (insn, insn2, pc, constraint, buf, comment, regs) break; case 'n': - sprintf (buf, _("Internal disassembler error")); + sprintf (buf, "??"); + fprintf (stderr, _("Internal disassembler error")); + ok = 0; break; case 'K': - sprintf (buf, "%d", (insn & 0xf) | ((insn >> 2) & 0x30)); + { + unsigned int x; + + x = (insn & 0xf) | ((insn >> 2) & 0x30); + sprintf (buf, "0x%02x", x); + sprintf (comment, "%d", x); + } break; case 's': @@ -205,8 +224,12 @@ avr_operand (insn, insn2, pc, constraint, buf, comment, regs) break; default: - sprintf (buf, _("unknown constraint `%c'"), constraint); + sprintf (buf, "??"); + fprintf (stderr, _("unknown constraint `%c'"), constraint); + ok = 0; } + + return ok; } static unsigned short avrdis_opcode PARAMS ((bfd_vma, disassemble_info *)); @@ -239,6 +262,8 @@ print_insn_avr(addr, info) fprintf_ftype prin = info->fprintf_func; static int initialized; int cmd_len = 2; + int ok = 0; + char op1[20], op2[20], comment1[40], comment2[40]; if (!initialized) { @@ -271,16 +296,23 @@ print_insn_avr(addr, info) break; } + /* Special case: disassemble `ldd r,b+0' as `ld r,b', and + `std b+0,r' as `st b,r' (next entry in the table). */ + + if (AVR_DISP0_P (insn)) + opcode++; + + op1[0] = 0; + op2[0] = 0; + comment1[0] = 0; + comment2[0] = 0; + if (opcode->name) { - char op1[20], op2[20], comment1[40], comment2[40]; char *op = opcode->constraints; - op1[0] = 0; - op2[0] = 0; - comment1[0] = 0; - comment2[0] = 0; insn2 = 0; + ok = 1; if (opcode->insn_size > 1) { @@ -292,29 +324,36 @@ print_insn_avr(addr, info) { int regs = REGISTER_P (*op); - avr_operand (insn, insn2, addr, *op, op1, comment1, 0); + ok = avr_operand (insn, insn2, addr, *op, op1, comment1, 0); - if (*(++op) == ',') - avr_operand (insn, insn2, addr, *(++op), op2, - *comment1 ? comment2 : comment1, regs); + if (ok && *(++op) == ',') + ok = avr_operand (insn, insn2, addr, *(++op), op2, + *comment1 ? comment2 : comment1, regs); } + } - (*prin) (stream, " %-8s", opcode->name); + if (!ok) + { + /* Unknown opcode, or invalid combination of operands. */ + sprintf (op1, "0x%04x", insn); + op2[0] = 0; + sprintf (comment1, "????"); + comment2[0] = 0; + } - if (*op1) - (*prin) (stream, "%s", op1); + (*prin) (stream, "%s", ok ? opcode->name : ".word"); - if (*op2) - (*prin) (stream, ", %s", op2); + if (*op1) + (*prin) (stream, "\t%s", op1); - if (*comment1) - (*prin) (stream, "\t; %s", comment1); + if (*op2) + (*prin) (stream, ", %s", op2); + + if (*comment1) + (*prin) (stream, "\t; %s", comment1); + + if (*comment2) + (*prin) (stream, " %s", comment2); - if (*comment2) - (*prin) (stream, " %s", comment2); - } - else - (*prin) (stream, ".word 0x%04x\t; ????", insn); - return cmd_len; } |