* avr-dis.c (avr_operand): Use PARAMS macro in declaration.
authorDenis Chertykov <denisc@overta.ru>
Sun, 6 Aug 2000 14:12:36 +0000 (14:12 +0000)
committerDenis Chertykov <denisc@overta.ru>
Sun, 6 Aug 2000 14:12:36 +0000 (14:12 +0000)
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.

opcodes/ChangeLog
opcodes/avr-dis.c

index 574d60d3e7bf1e801d6124494d8a7c7263dfcc6f..04440c283c94b991f4e90b7508edb7cd61663f9a 100644 (file)
@@ -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.
index ee91d7f223c6b609609370b76f353886cba7f631..db46cb4845fb97a5bbc1b31b4e27f7ee657aca16 100644 (file)
@@ -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;
 }