aboutsummaryrefslogtreecommitdiff
path: root/opcodes/avr-dis.c
diff options
context:
space:
mode:
Diffstat (limited to 'opcodes/avr-dis.c')
-rw-r--r--opcodes/avr-dis.c125
1 files changed, 82 insertions, 43 deletions
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;
}