./
[deliverable/binutils-gdb.git] / opcodes / sparc-dis.c
index 0975b280e28ed64bf109984c108642c73449dd00..6f360c66051b4045f7b37e19c20634ba102ed6ca 100644 (file)
@@ -1,23 +1,23 @@
 /* Print SPARC instructions.
-   Copyright (C) 1989, 91-97, 1998 Free Software Foundation, Inc.
+   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2002, 2003, 2004 Free Software Foundation, Inc.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include <stdio.h>
 
-#include "ansidecl.h"
 #include "sysdep.h"
 #include "opcode/sparc.h"
 #include "dis-asm.h"
@@ -26,7 +26,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /* Bitmask of v9 architectures.  */
 #define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \
-                | (1 << SPARC_OPCODE_ARCH_V9A))
+                | (1 << SPARC_OPCODE_ARCH_V9A) \
+                | (1 << SPARC_OPCODE_ARCH_V9B))
 /* 1 if INSN is for v9 only.  */
 #define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9))
 /* 1 if INSN is for v9.  */
@@ -45,7 +46,8 @@ static const struct sparc_opcode **sorted_opcodes;
 static int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 };
 #define HASH_INSN(INSN) \
   ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19))
-struct opcode_hash {
+struct opcode_hash
+{
   struct opcode_hash *next;
   const struct sparc_opcode *opcode;
 };
@@ -96,7 +98,7 @@ static char *v9_priv_reg_names[] =
 static char *v9a_asr_reg_names[] =
 {
   "pcr", "pic", "dcr", "gsr", "set_softint", "clear_softint",
-  "softint", "tick_cmpr"
+  "softint", "tick_cmpr", "sys_tick", "sys_tick_cmpr"
 };
 
 /* Macros used to extract instruction fields.  Not all fields have
@@ -187,7 +189,7 @@ is_delayed_branch (insn)
 
   for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)
     {
-      CONST struct sparc_opcode *opcode = op->opcode;
+      const struct sparc_opcode *opcode = op->opcode;
       if ((opcode->match & insn) == opcode->match
          && (opcode->lose & insn) == 0)
        return (opcode->flags & F_DELAYED);
@@ -222,7 +224,7 @@ print_insn_sparc (memaddr, info)
   static int opcodes_initialized = 0;
   /* bfd mach number of last call.  */
   static unsigned long current_mach = 0;
-  bfd_vma (*getword) PARAMS ((const unsigned char *));
+  bfd_vma (*getword) (const void *);
 
   if (!opcodes_initialized
       || info->mach != current_mach)
@@ -256,7 +258,7 @@ print_insn_sparc (memaddr, info)
   }
 
   /* On SPARClite variants such as DANlite (sparc86x), instructions
-     are always big-endian even when the machine is in little-endian mode. */
+     are always big-endian even when the machine is in little-endian mode.  */
   if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite)
     getword = bfd_getb32;
   else
@@ -264,14 +266,14 @@ print_insn_sparc (memaddr, info)
 
   insn = getword (buffer);
 
-  info->insn_info_valid = 1;                   /* We do return this info */
-  info->insn_type = dis_nonbranch;             /* Assume non branch insn */
-  info->branch_delay_insns = 0;                        /* Assume no delay */
-  info->target = 0;                            /* Assume no target known */
+  info->insn_info_valid = 1;                   /* We do return this info */
+  info->insn_type = dis_nonbranch;             /* Assume non branch insn */
+  info->branch_delay_insns = 0;                        /* Assume no delay */
+  info->target = 0;                            /* Assume no target known */
 
   for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)
     {
-      CONST struct sparc_opcode *opcode = op->opcode;
+      const struct sparc_opcode *opcode = op->opcode;
 
       /* If the insn isn't supported by the current architecture, skip it.  */
       if (! (opcode->architecture & current_arch_mask))
@@ -283,6 +285,7 @@ print_insn_sparc (memaddr, info)
          /* Nonzero means that we have found an instruction which has
             the effect of adding or or'ing the imm13 field to rs1.  */
          int imm_added_to_rs1 = 0;
+         int imm_ored_to_rs1 = 0;
 
          /* Nonzero means that we have found a plus sign in the args
             field of the opcode table.  */
@@ -293,8 +296,9 @@ print_insn_sparc (memaddr, info)
 
          /* Do we have an `add' or `or' instruction combining an
              immediate with rs1?  */
-         if (opcode->match == 0x80102000 || opcode->match == 0x80002000)
-         /*                      (or)                           (add)  */
+         if (opcode->match == 0x80102000) /* or */
+           imm_ored_to_rs1 = 1;
+         if (opcode->match == 0x80002000) /* add */
            imm_added_to_rs1 = 1;
 
          if (X_RS1 (insn) != X_RD (insn)
@@ -309,36 +313,38 @@ print_insn_sparc (memaddr, info)
          (*info->fprintf_func) (stream, opcode->name);
 
          {
-           register CONST char *s;
+           register const char *s;
 
            if (opcode->args[0] != ',')
              (*info->fprintf_func) (stream, " ");
+
            for (s = opcode->args; *s != '\0'; ++s)
              {
                while (*s == ',')
                  {
                    (*info->fprintf_func) (stream, ",");
                    ++s;
-                   switch (*s) {
-                   case 'a':
-                     (*info->fprintf_func) (stream, "a");
-                     is_annulled = 1;
-                     ++s;
-                     continue;
-                   case 'N':
-                     (*info->fprintf_func) (stream, "pn");
-                     ++s;
-                     continue;
-
-                   case 'T':
-                     (*info->fprintf_func) (stream, "pt");
-                     ++s;
-                     continue;
-
-                   default:
-                     break;
-                   }           /* switch on arg */
-                 }             /* while there are comma started args */
+                   switch (*s)
+                     {
+                     case 'a':
+                       (*info->fprintf_func) (stream, "a");
+                       is_annulled = 1;
+                       ++s;
+                       continue;
+                     case 'N':
+                       (*info->fprintf_func) (stream, "pn");
+                       ++s;
+                       continue;
+
+                     case 'T':
+                       (*info->fprintf_func) (stream, "pt");
+                       ++s;
+                       continue;
+
+                     default:
+                       break;
+                     }
+                 }
 
                (*info->fprintf_func) (stream, " ");
                        
@@ -416,7 +422,7 @@ print_insn_sparc (memaddr, info)
 
                  case 'h':
                    (*info->fprintf_func) (stream, "%%hi(%#x)",
-                                          (0xFFFFFFFF
+                                          ((unsigned) 0xFFFFFFFF
                                            & ((int) X_IMM22 (insn) << 10)));
                    break;
 
@@ -462,6 +468,10 @@ print_insn_sparc (memaddr, info)
                    }
                    break;
 
+                 case '3':
+                   (info->fprintf_func) (stream, "%d", X_IMM (insn, 3));
+                   break;
+
                  case 'K':
                    {
                      int mask = X_MEMBAR (insn);
@@ -550,7 +560,7 @@ print_insn_sparc (memaddr, info)
                    break;
 
                  case '/':
-                   if (X_RS1 (insn) < 16 || X_RS1 (insn) > 23)
+                   if (X_RS1 (insn) < 16 || X_RS1 (insn) > 25)
                      (*info->fprintf_func) (stream, "%%reserved");
                    else
                      (*info->fprintf_func) (stream, "%%%s",
@@ -558,7 +568,7 @@ print_insn_sparc (memaddr, info)
                    break;
 
                  case '_':
-                   if (X_RD (insn) < 16 || X_RD (insn) > 23)
+                   if (X_RD (insn) < 16 || X_RD (insn) > 25)
                      (*info->fprintf_func) (stream, "%%reserved");
                    else
                      (*info->fprintf_func) (stream, "%%%s",
@@ -670,31 +680,38 @@ print_insn_sparc (memaddr, info)
             If so, attempt to print the result of the add or
             or (in this context add and or do the same thing)
             and its symbolic value.  */
-         if (imm_added_to_rs1)
+         if (imm_ored_to_rs1 || imm_added_to_rs1)
            {
              unsigned long prev_insn;
              int errcode;
 
-             errcode =
-               (*info->read_memory_func)
+             if (memaddr >= 4)
+               errcode =
+                 (*info->read_memory_func)
                  (memaddr - 4, buffer, sizeof (buffer), info);
+             else
+               errcode = 1;
+
              prev_insn = getword (buffer);
 
              if (errcode == 0)
                {
                  /* If it is a delayed branch, we need to look at the
                     instruction before the delayed branch.  This handles
-                    sequences such as
+                    sequences such as:
 
                     sethi %o1, %hi(_foo), %o1
                     call _printf
-                    or %o1, %lo(_foo), %o1
-                    */
+                    or %o1, %lo(_foo), %o1  */
 
                  if (is_delayed_branch (prev_insn))
                    {
-                     errcode = (*info->read_memory_func)
-                       (memaddr - 8, buffer, sizeof (buffer), info);
+                     if (memaddr >= 8)
+                       errcode = (*info->read_memory_func)
+                         (memaddr - 8, buffer, sizeof (buffer), info);
+                     else
+                       errcode = 1;
+
                      prev_insn = getword (buffer);
                    }
                }
@@ -709,8 +726,12 @@ print_insn_sparc (memaddr, info)
                    {
                      (*info->fprintf_func) (stream, "\t! ");
                      info->target = 
-                       (0xFFFFFFFF & (int) X_IMM22 (prev_insn) << 10)
-                       | X_SIMM (insn, 13);
+                       ((unsigned) 0xFFFFFFFF
+                        & ((int) X_IMM22 (prev_insn) << 10));
+                     if (imm_added_to_rs1)
+                       info->target += X_SIMM (insn, 13);
+                     else
+                       info->target |= X_SIMM (insn, 13);
                      (*info->print_address_func) (info->target, info);
                      info->insn_type = dis_dref;
                      info->data_size = 4;  /* FIXME!!! */
@@ -735,7 +756,7 @@ print_insn_sparc (memaddr, info)
        }
     }
 
-  info->insn_type = dis_noninsn;       /* Mark as non-valid instruction */
+  info->insn_type = dis_noninsn;       /* Mark as non-valid instruction */
   (*info->fprintf_func) (stream, _("unknown"));
   return sizeof (buffer);
 }
@@ -766,6 +787,9 @@ compute_arch_mask (mach)
     case bfd_mach_sparc_v8plusa :
     case bfd_mach_sparc_v9a :
       return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A);
+    case bfd_mach_sparc_v8plusb :
+    case bfd_mach_sparc_v9b :
+      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B);
     }
   abort ();
 }
This page took 0.044606 seconds and 4 git commands to generate.