* mips-dis.c (print_insn_mips16): Better handling of an extend
authorIan Lance Taylor <ian@airs.com>
Tue, 28 Jan 1997 20:58:28 +0000 (20:58 +0000)
committerIan Lance Taylor <ian@airs.com>
Tue, 28 Jan 1997 20:58:28 +0000 (20:58 +0000)
  opcode followed by an instruction which can not be extended.

opcodes/ChangeLog
opcodes/mips-dis.c

index 82ca249f97dc8d61f984d6695899476239ae5698..0e443a6ce209523a1c85ec31155c10e57665da35 100644 (file)
@@ -1,3 +1,8 @@
+Tue Jan 28 15:57:34 1997  Ian Lance Taylor  <ian@cygnus.com>
+
+       * mips-dis.c (print_insn_mips16): Better handling of an extend
+       opcode followed by an instruction which can not be extended.
+
 Fri Jan 24 12:08:21 1997  J.T. Conklin  <jtc@cygnus.com>
 
        * m68k-opc.c (m68k_opcodes): Changed operand specifier for the
index e89fca7c68d59d1d8f27b8350fd63f8a7416b215..745b6bfb61e4dfc4d8aa16ffa89198fd5bf266a3 100644 (file)
@@ -383,12 +383,20 @@ print_insn_mips16 (memaddr, info)
          return -1;
        }
 
-      length += 2;
-
       if (info->endian == BFD_ENDIAN_BIG)
        insn = bfd_getb16 (buffer);
       else
        insn = bfd_getl16 (buffer);
+
+      /* Check for an extend opcode followed by an extend opcode.  */
+      if ((insn & 0xf800) == 0xf000)
+       {
+         (*info->fprintf_func) (info->stream, "extend 0x%x",
+                                (unsigned int) extend);
+         return length;
+       }
+
+      length += 2;
     }
 
   /* FIXME: Should probably use a hash table on the major opcode here.  */
@@ -403,8 +411,12 @@ print_insn_mips16 (memaddr, info)
          if (strchr (op->args, 'a') != NULL)
            {
              if (use_extend)
-               (*info->fprintf_func) (info->stream, "extend 0x%x",
-                                      (unsigned int) extend);
+               {
+                 (*info->fprintf_func) (info->stream, "extend 0x%x",
+                                        (unsigned int) extend);
+                 return length - 2;
+               }
+
              use_extend = false;
 
              memaddr += 2;
@@ -422,7 +434,9 @@ print_insn_mips16 (memaddr, info)
                }
            }
 
-         (*info->fprintf_func) (info->stream, "%s ", op->name);
+         (*info->fprintf_func) (info->stream, "%s", op->name);
+         if (op->args[0] != '\0')
+           (*info->fprintf_func) (info->stream, "\t");
 
          for (s = op->args; *s != '\0'; s++)
            {
@@ -715,11 +729,51 @@ print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info)
          (*info->fprintf_func) (info->stream, "%d", immed);
        else
          {
+           bfd_vma baseaddr;
            bfd_vma val;
 
            if (branch)
-             immed *= 2;
-           val = ((memaddr + 2) & ~ ((1 << shift) - 1)) + immed;
+             {
+               immed *= 2;
+               baseaddr = memaddr + 2;
+             }
+           else if (use_extend)
+             baseaddr = memaddr;
+           else
+             {
+               int status;
+               bfd_byte buffer[2];
+
+               baseaddr = memaddr;
+
+               /* If this instruction is in the delay slot of a jr
+                   instruction, the base address is the address of the
+                   jr instruction.  If it is in the delay slot of jalr
+                   instruction, the base address is the address of the
+                   jalr instruction.  This test is unreliable: we have
+                   no way of knowing whether the previous word is
+                   instruction or data.  */
+               status = (*info->read_memory_func) (memaddr - 4, buffer, 2,
+                                                   info);
+               if (status == 0
+                   && (((info->endian == BFD_ENDIAN_BIG
+                         ? bfd_getb16 (buffer)
+                         : bfd_getl16 (buffer))
+                        & 0xf800) == 0x1800))
+                 baseaddr = memaddr - 4;
+               else
+                 {
+                   status = (*info->read_memory_func) (memaddr - 2, buffer,
+                                                       2, info);
+                   if (status == 0
+                       && (((info->endian == BFD_ENDIAN_BIG
+                             ? bfd_getb16 (buffer)
+                             : bfd_getl16 (buffer))
+                            & 0xf81f) == 0xe800))
+                     baseaddr = memaddr - 2;
+                 }
+             }
+           val = (baseaddr & ~ ((1 << shift) - 1)) + immed;
            (*info->print_address_func) (val, info);
          }
       }