OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.0/] [opcodes/] [sparc-dis.c] - Diff between revs 107 and 1765

Only display areas with differences | Details | Blame | View Log

Rev 107 Rev 1765
/* Print SPARC instructions.
/* Print SPARC instructions.
   Copyright (C) 1989, 91-97, 1998 Free Software Foundation, Inc.
   Copyright (C) 1989, 91-97, 1998 Free Software Foundation, Inc.
 
 
This program is free software; you can redistribute it and/or modify
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
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
(at your option) any later version.
 
 
This program is distributed in the hope that it will be useful,
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
GNU General Public License for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 
#include <stdio.h>
#include <stdio.h>
 
 
#include "ansidecl.h"
#include "ansidecl.h"
#include "sysdep.h"
#include "sysdep.h"
#include "opcode/sparc.h"
#include "opcode/sparc.h"
#include "dis-asm.h"
#include "dis-asm.h"
#include "libiberty.h"
#include "libiberty.h"
#include "opintl.h"
#include "opintl.h"
 
 
/* Bitmask of v9 architectures.  */
/* Bitmask of v9 architectures.  */
#define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \
#define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \
                 | (1 << SPARC_OPCODE_ARCH_V9A))
                 | (1 << SPARC_OPCODE_ARCH_V9A))
/* 1 if INSN is for v9 only.  */
/* 1 if INSN is for v9 only.  */
#define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9))
#define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9))
/* 1 if INSN is for v9.  */
/* 1 if INSN is for v9.  */
#define V9_P(insn) (((insn)->architecture & MASK_V9) != 0)
#define V9_P(insn) (((insn)->architecture & MASK_V9) != 0)
 
 
/* The sorted opcode table.  */
/* The sorted opcode table.  */
static const struct sparc_opcode **sorted_opcodes;
static const struct sparc_opcode **sorted_opcodes;
 
 
/* For faster lookup, after insns are sorted they are hashed.  */
/* For faster lookup, after insns are sorted they are hashed.  */
/* ??? I think there is room for even more improvement.  */
/* ??? I think there is room for even more improvement.  */
 
 
#define HASH_SIZE 256
#define HASH_SIZE 256
/* It is important that we only look at insn code bits as that is how the
/* It is important that we only look at insn code bits as that is how the
   opcode table is hashed.  OPCODE_BITS is a table of valid bits for each
   opcode table is hashed.  OPCODE_BITS is a table of valid bits for each
   of the main types (0,1,2,3).  */
   of the main types (0,1,2,3).  */
static int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 };
static int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 };
#define HASH_INSN(INSN) \
#define HASH_INSN(INSN) \
  ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19))
  ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19))
struct opcode_hash {
struct opcode_hash {
  struct opcode_hash *next;
  struct opcode_hash *next;
  const struct sparc_opcode *opcode;
  const struct sparc_opcode *opcode;
};
};
static struct opcode_hash *opcode_hash_table[HASH_SIZE];
static struct opcode_hash *opcode_hash_table[HASH_SIZE];
 
 
static void build_hash_table
static void build_hash_table
  PARAMS ((const struct sparc_opcode **, struct opcode_hash **, int));
  PARAMS ((const struct sparc_opcode **, struct opcode_hash **, int));
static int is_delayed_branch PARAMS ((unsigned long));
static int is_delayed_branch PARAMS ((unsigned long));
static int compare_opcodes PARAMS ((const PTR, const PTR));
static int compare_opcodes PARAMS ((const PTR, const PTR));
static int compute_arch_mask PARAMS ((unsigned long));
static int compute_arch_mask PARAMS ((unsigned long));
 
 
/* Sign-extend a value which is N bits long.  */
/* Sign-extend a value which is N bits long.  */
#define SEX(value, bits) \
#define SEX(value, bits) \
        ((((int)(value)) << ((8 * sizeof (int)) - bits))        \
        ((((int)(value)) << ((8 * sizeof (int)) - bits))        \
                         >> ((8 * sizeof (int)) - bits) )
                         >> ((8 * sizeof (int)) - bits) )
 
 
static  char *reg_names[] =
static  char *reg_names[] =
{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
  "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
  "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
  "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
  "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
  "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",
  "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",
  "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
  "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
  "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
  "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
  "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
  "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
  "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
  "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
  "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
  "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
  "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",
  "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",
  "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",
  "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",
  "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",
  "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",
/* psr, wim, tbr, fpsr, cpsr are v8 only.  */
/* psr, wim, tbr, fpsr, cpsr are v8 only.  */
  "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr"
  "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr"
};
};
 
 
#define freg_names      (&reg_names[4 * 8])
#define freg_names      (&reg_names[4 * 8])
 
 
/* These are ordered according to there register number in
/* These are ordered according to there register number in
   rdpr and wrpr insns.  */
   rdpr and wrpr insns.  */
static char *v9_priv_reg_names[] =
static char *v9_priv_reg_names[] =
{
{
  "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl",
  "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl",
  "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin",
  "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin",
  "wstate", "fq"
  "wstate", "fq"
  /* "ver" - special cased */
  /* "ver" - special cased */
};
};
 
 
/* These are ordered according to there register number in
/* These are ordered according to there register number in
   rd and wr insns (-16).  */
   rd and wr insns (-16).  */
static char *v9a_asr_reg_names[] =
static char *v9a_asr_reg_names[] =
{
{
  "pcr", "pic", "dcr", "gsr", "set_softint", "clear_softint",
  "pcr", "pic", "dcr", "gsr", "set_softint", "clear_softint",
  "softint", "tick_cmpr"
  "softint", "tick_cmpr"
};
};
 
 
/* Macros used to extract instruction fields.  Not all fields have
/* Macros used to extract instruction fields.  Not all fields have
   macros defined here, only those which are actually used.  */
   macros defined here, only those which are actually used.  */
 
 
#define X_RD(i) (((i) >> 25) & 0x1f)
#define X_RD(i) (((i) >> 25) & 0x1f)
#define X_RS1(i) (((i) >> 14) & 0x1f)
#define X_RS1(i) (((i) >> 14) & 0x1f)
#define X_LDST_I(i) (((i) >> 13) & 1)
#define X_LDST_I(i) (((i) >> 13) & 1)
#define X_ASI(i) (((i) >> 5) & 0xff)
#define X_ASI(i) (((i) >> 5) & 0xff)
#define X_RS2(i) (((i) >> 0) & 0x1f)
#define X_RS2(i) (((i) >> 0) & 0x1f)
#define X_IMM(i,n) (((i) >> 0) & ((1 << (n)) - 1))
#define X_IMM(i,n) (((i) >> 0) & ((1 << (n)) - 1))
#define X_SIMM(i,n) SEX (X_IMM ((i), (n)), (n))
#define X_SIMM(i,n) SEX (X_IMM ((i), (n)), (n))
#define X_DISP22(i) (((i) >> 0) & 0x3fffff)
#define X_DISP22(i) (((i) >> 0) & 0x3fffff)
#define X_IMM22(i) X_DISP22 (i)
#define X_IMM22(i) X_DISP22 (i)
#define X_DISP30(i) (((i) >> 0) & 0x3fffffff)
#define X_DISP30(i) (((i) >> 0) & 0x3fffffff)
 
 
/* These are for v9.  */
/* These are for v9.  */
#define X_DISP16(i) (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff))
#define X_DISP16(i) (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff))
#define X_DISP19(i) (((i) >> 0) & 0x7ffff)
#define X_DISP19(i) (((i) >> 0) & 0x7ffff)
#define X_MEMBAR(i) ((i) & 0x7f)
#define X_MEMBAR(i) ((i) & 0x7f)
 
 
/* Here is the union which was used to extract instruction fields
/* Here is the union which was used to extract instruction fields
   before the shift and mask macros were written.
   before the shift and mask macros were written.
 
 
   union sparc_insn
   union sparc_insn
     {
     {
       unsigned long int code;
       unsigned long int code;
       struct
       struct
         {
         {
           unsigned int anop:2;
           unsigned int anop:2;
           #define      op      ldst.anop
           #define      op      ldst.anop
           unsigned int anrd:5;
           unsigned int anrd:5;
           #define      rd      ldst.anrd
           #define      rd      ldst.anrd
           unsigned int op3:6;
           unsigned int op3:6;
           unsigned int anrs1:5;
           unsigned int anrs1:5;
           #define      rs1     ldst.anrs1
           #define      rs1     ldst.anrs1
           unsigned int i:1;
           unsigned int i:1;
           unsigned int anasi:8;
           unsigned int anasi:8;
           #define      asi     ldst.anasi
           #define      asi     ldst.anasi
           unsigned int anrs2:5;
           unsigned int anrs2:5;
           #define      rs2     ldst.anrs2
           #define      rs2     ldst.anrs2
           #define      shcnt   rs2
           #define      shcnt   rs2
         } ldst;
         } ldst;
       struct
       struct
         {
         {
           unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1;
           unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1;
           unsigned int IMM13:13;
           unsigned int IMM13:13;
           #define      imm13   IMM13.IMM13
           #define      imm13   IMM13.IMM13
         } IMM13;
         } IMM13;
       struct
       struct
         {
         {
           unsigned int anop:2;
           unsigned int anop:2;
           unsigned int a:1;
           unsigned int a:1;
           unsigned int cond:4;
           unsigned int cond:4;
           unsigned int op2:3;
           unsigned int op2:3;
           unsigned int DISP22:22;
           unsigned int DISP22:22;
           #define      disp22  branch.DISP22
           #define      disp22  branch.DISP22
           #define      imm22   disp22
           #define      imm22   disp22
         } branch;
         } branch;
       struct
       struct
         {
         {
           unsigned int anop:2;
           unsigned int anop:2;
           unsigned int a:1;
           unsigned int a:1;
           unsigned int z:1;
           unsigned int z:1;
           unsigned int rcond:3;
           unsigned int rcond:3;
           unsigned int op2:3;
           unsigned int op2:3;
           unsigned int DISP16HI:2;
           unsigned int DISP16HI:2;
           unsigned int p:1;
           unsigned int p:1;
           unsigned int _rs1:5;
           unsigned int _rs1:5;
           unsigned int DISP16LO:14;
           unsigned int DISP16LO:14;
         } branch16;
         } branch16;
       struct
       struct
         {
         {
           unsigned int anop:2;
           unsigned int anop:2;
           unsigned int adisp30:30;
           unsigned int adisp30:30;
           #define      disp30  call.adisp30
           #define      disp30  call.adisp30
         } call;
         } call;
     };
     };
 
 
   */
   */
 
 
/* Nonzero if INSN is the opcode for a delayed branch.  */
/* Nonzero if INSN is the opcode for a delayed branch.  */
static int
static int
is_delayed_branch (insn)
is_delayed_branch (insn)
     unsigned long insn;
     unsigned long insn;
{
{
  struct opcode_hash *op;
  struct opcode_hash *op;
 
 
  for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)
  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
      if ((opcode->match & insn) == opcode->match
          && (opcode->lose & insn) == 0)
          && (opcode->lose & insn) == 0)
        return (opcode->flags & F_DELAYED);
        return (opcode->flags & F_DELAYED);
    }
    }
  return 0;
  return 0;
}
}
 
 
/* extern void qsort (); */
/* extern void qsort (); */
 
 
/* Records current mask of SPARC_OPCODE_ARCH_FOO values, used to pass value
/* Records current mask of SPARC_OPCODE_ARCH_FOO values, used to pass value
   to compare_opcodes.  */
   to compare_opcodes.  */
static unsigned int current_arch_mask;
static unsigned int current_arch_mask;
 
 
/* Print one instruction from MEMADDR on INFO->STREAM.
/* Print one instruction from MEMADDR on INFO->STREAM.
 
 
   We suffix the instruction with a comment that gives the absolute
   We suffix the instruction with a comment that gives the absolute
   address involved, as well as its symbolic form, if the instruction
   address involved, as well as its symbolic form, if the instruction
   is preceded by a findable `sethi' and it either adds an immediate
   is preceded by a findable `sethi' and it either adds an immediate
   displacement to that register, or it is an `add' or `or' instruction
   displacement to that register, or it is an `add' or `or' instruction
   on that register.  */
   on that register.  */
 
 
int
int
print_insn_sparc (memaddr, info)
print_insn_sparc (memaddr, info)
     bfd_vma memaddr;
     bfd_vma memaddr;
     disassemble_info *info;
     disassemble_info *info;
{
{
  FILE *stream = info->stream;
  FILE *stream = info->stream;
  bfd_byte buffer[4];
  bfd_byte buffer[4];
  unsigned long insn;
  unsigned long insn;
  register struct opcode_hash *op;
  register struct opcode_hash *op;
  /* Nonzero of opcode table has been initialized.  */
  /* Nonzero of opcode table has been initialized.  */
  static int opcodes_initialized = 0;
  static int opcodes_initialized = 0;
  /* bfd mach number of last call.  */
  /* bfd mach number of last call.  */
  static unsigned long current_mach = 0;
  static unsigned long current_mach = 0;
  bfd_vma (*getword) PARAMS ((const unsigned char *));
  bfd_vma (*getword) PARAMS ((const unsigned char *));
 
 
  if (!opcodes_initialized
  if (!opcodes_initialized
      || info->mach != current_mach)
      || info->mach != current_mach)
    {
    {
      int i;
      int i;
 
 
      current_arch_mask = compute_arch_mask (info->mach);
      current_arch_mask = compute_arch_mask (info->mach);
 
 
      if (!opcodes_initialized)
      if (!opcodes_initialized)
        sorted_opcodes = (const struct sparc_opcode **)
        sorted_opcodes = (const struct sparc_opcode **)
          xmalloc (sparc_num_opcodes * sizeof (struct sparc_opcode *));
          xmalloc (sparc_num_opcodes * sizeof (struct sparc_opcode *));
      /* Reset the sorted table so we can resort it.  */
      /* Reset the sorted table so we can resort it.  */
      for (i = 0; i < sparc_num_opcodes; ++i)
      for (i = 0; i < sparc_num_opcodes; ++i)
        sorted_opcodes[i] = &sparc_opcodes[i];
        sorted_opcodes[i] = &sparc_opcodes[i];
      qsort ((char *) sorted_opcodes, sparc_num_opcodes,
      qsort ((char *) sorted_opcodes, sparc_num_opcodes,
             sizeof (sorted_opcodes[0]), compare_opcodes);
             sizeof (sorted_opcodes[0]), compare_opcodes);
 
 
      build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes);
      build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes);
      current_mach = info->mach;
      current_mach = info->mach;
      opcodes_initialized = 1;
      opcodes_initialized = 1;
    }
    }
 
 
  {
  {
    int status =
    int status =
      (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info);
      (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info);
    if (status != 0)
    if (status != 0)
      {
      {
        (*info->memory_error_func) (status, memaddr, info);
        (*info->memory_error_func) (status, memaddr, info);
        return -1;
        return -1;
      }
      }
  }
  }
 
 
  /* On SPARClite variants such as DANlite (sparc86x), instructions
  /* 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)
  if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite)
    getword = bfd_getb32;
    getword = bfd_getb32;
  else
  else
    getword = bfd_getl32;
    getword = bfd_getl32;
 
 
  insn = getword (buffer);
  insn = getword (buffer);
 
 
  info->insn_info_valid = 1;                    /* We do return this info */
  info->insn_info_valid = 1;                    /* We do return this info */
  info->insn_type = dis_nonbranch;              /* Assume non branch insn */
  info->insn_type = dis_nonbranch;              /* Assume non branch insn */
  info->branch_delay_insns = 0;                  /* Assume no delay */
  info->branch_delay_insns = 0;                  /* Assume no delay */
  info->target = 0;                              /* Assume no target known */
  info->target = 0;                              /* Assume no target known */
 
 
  for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)
  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 the insn isn't supported by the current architecture, skip it.  */
      if (! (opcode->architecture & current_arch_mask))
      if (! (opcode->architecture & current_arch_mask))
        continue;
        continue;
 
 
      if ((opcode->match & insn) == opcode->match
      if ((opcode->match & insn) == opcode->match
          && (opcode->lose & insn) == 0)
          && (opcode->lose & insn) == 0)
        {
        {
          /* Nonzero means that we have found an instruction which has
          /* Nonzero means that we have found an instruction which has
             the effect of adding or or'ing the imm13 field to rs1.  */
             the effect of adding or or'ing the imm13 field to rs1.  */
          int imm_added_to_rs1 = 0;
          int imm_added_to_rs1 = 0;
          int imm_ored_to_rs1 = 0;
          int imm_ored_to_rs1 = 0;
 
 
          /* Nonzero means that we have found a plus sign in the args
          /* Nonzero means that we have found a plus sign in the args
             field of the opcode table.  */
             field of the opcode table.  */
          int found_plus = 0;
          int found_plus = 0;
 
 
          /* Nonzero means we have an annulled branch.  */
          /* Nonzero means we have an annulled branch.  */
          int is_annulled = 0;
          int is_annulled = 0;
 
 
          /* Do we have an `add' or `or' instruction combining an
          /* Do we have an `add' or `or' instruction combining an
             immediate with rs1?  */
             immediate with rs1?  */
          if (opcode->match == 0x80102000) /* or */
          if (opcode->match == 0x80102000) /* or */
            imm_ored_to_rs1 = 1;
            imm_ored_to_rs1 = 1;
          if (opcode->match == 0x80002000) /* add */
          if (opcode->match == 0x80002000) /* add */
            imm_added_to_rs1 = 1;
            imm_added_to_rs1 = 1;
 
 
          if (X_RS1 (insn) != X_RD (insn)
          if (X_RS1 (insn) != X_RD (insn)
              && strchr (opcode->args, 'r') != 0)
              && strchr (opcode->args, 'r') != 0)
              /* Can't do simple format if source and dest are different.  */
              /* Can't do simple format if source and dest are different.  */
              continue;
              continue;
          if (X_RS2 (insn) != X_RD (insn)
          if (X_RS2 (insn) != X_RD (insn)
              && strchr (opcode->args, 'O') != 0)
              && strchr (opcode->args, 'O') != 0)
              /* Can't do simple format if source and dest are different.  */
              /* Can't do simple format if source and dest are different.  */
              continue;
              continue;
 
 
          (*info->fprintf_func) (stream, opcode->name);
          (*info->fprintf_func) (stream, opcode->name);
 
 
          {
          {
            register CONST char *s;
            register CONST char *s;
 
 
            if (opcode->args[0] != ',')
            if (opcode->args[0] != ',')
              (*info->fprintf_func) (stream, " ");
              (*info->fprintf_func) (stream, " ");
            for (s = opcode->args; *s != '\0'; ++s)
            for (s = opcode->args; *s != '\0'; ++s)
              {
              {
                while (*s == ',')
                while (*s == ',')
                  {
                  {
                    (*info->fprintf_func) (stream, ",");
                    (*info->fprintf_func) (stream, ",");
                    ++s;
                    ++s;
                    switch (*s) {
                    switch (*s) {
                    case 'a':
                    case 'a':
                      (*info->fprintf_func) (stream, "a");
                      (*info->fprintf_func) (stream, "a");
                      is_annulled = 1;
                      is_annulled = 1;
                      ++s;
                      ++s;
                      continue;
                      continue;
                    case 'N':
                    case 'N':
                      (*info->fprintf_func) (stream, "pn");
                      (*info->fprintf_func) (stream, "pn");
                      ++s;
                      ++s;
                      continue;
                      continue;
 
 
                    case 'T':
                    case 'T':
                      (*info->fprintf_func) (stream, "pt");
                      (*info->fprintf_func) (stream, "pt");
                      ++s;
                      ++s;
                      continue;
                      continue;
 
 
                    default:
                    default:
                      break;
                      break;
                    }           /* switch on arg */
                    }           /* switch on arg */
                  }             /* while there are comma started args */
                  }             /* while there are comma started args */
 
 
                (*info->fprintf_func) (stream, " ");
                (*info->fprintf_func) (stream, " ");
 
 
                switch (*s)
                switch (*s)
                  {
                  {
                  case '+':
                  case '+':
                    found_plus = 1;
                    found_plus = 1;
 
 
                    /* note fall-through */
                    /* note fall-through */
                  default:
                  default:
                    (*info->fprintf_func) (stream, "%c", *s);
                    (*info->fprintf_func) (stream, "%c", *s);
                    break;
                    break;
 
 
                  case '#':
                  case '#':
                    (*info->fprintf_func) (stream, "0");
                    (*info->fprintf_func) (stream, "0");
                    break;
                    break;
 
 
#define reg(n)  (*info->fprintf_func) (stream, "%%%s", reg_names[n])
#define reg(n)  (*info->fprintf_func) (stream, "%%%s", reg_names[n])
                  case '1':
                  case '1':
                  case 'r':
                  case 'r':
                    reg (X_RS1 (insn));
                    reg (X_RS1 (insn));
                    break;
                    break;
 
 
                  case '2':
                  case '2':
                  case 'O':
                  case 'O':
                    reg (X_RS2 (insn));
                    reg (X_RS2 (insn));
                    break;
                    break;
 
 
                  case 'd':
                  case 'd':
                    reg (X_RD (insn));
                    reg (X_RD (insn));
                    break;
                    break;
#undef  reg
#undef  reg
 
 
#define freg(n)         (*info->fprintf_func) (stream, "%%%s", freg_names[n])
#define freg(n)         (*info->fprintf_func) (stream, "%%%s", freg_names[n])
#define fregx(n)        (*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)])
#define fregx(n)        (*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)])
                  case 'e':
                  case 'e':
                    freg (X_RS1 (insn));
                    freg (X_RS1 (insn));
                    break;
                    break;
                  case 'v':     /* double/even */
                  case 'v':     /* double/even */
                  case 'V':     /* quad/multiple of 4 */
                  case 'V':     /* quad/multiple of 4 */
                    fregx (X_RS1 (insn));
                    fregx (X_RS1 (insn));
                    break;
                    break;
 
 
                  case 'f':
                  case 'f':
                    freg (X_RS2 (insn));
                    freg (X_RS2 (insn));
                    break;
                    break;
                  case 'B':     /* double/even */
                  case 'B':     /* double/even */
                  case 'R':     /* quad/multiple of 4 */
                  case 'R':     /* quad/multiple of 4 */
                    fregx (X_RS2 (insn));
                    fregx (X_RS2 (insn));
                    break;
                    break;
 
 
                  case 'g':
                  case 'g':
                    freg (X_RD (insn));
                    freg (X_RD (insn));
                    break;
                    break;
                  case 'H':     /* double/even */
                  case 'H':     /* double/even */
                  case 'J':     /* quad/multiple of 4 */
                  case 'J':     /* quad/multiple of 4 */
                    fregx (X_RD (insn));
                    fregx (X_RD (insn));
                    break;
                    break;
#undef  freg
#undef  freg
#undef  fregx
#undef  fregx
 
 
#define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n))
#define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n))
                  case 'b':
                  case 'b':
                    creg (X_RS1 (insn));
                    creg (X_RS1 (insn));
                    break;
                    break;
 
 
                  case 'c':
                  case 'c':
                    creg (X_RS2 (insn));
                    creg (X_RS2 (insn));
                    break;
                    break;
 
 
                  case 'D':
                  case 'D':
                    creg (X_RD (insn));
                    creg (X_RD (insn));
                    break;
                    break;
#undef  creg
#undef  creg
 
 
                  case 'h':
                  case 'h':
                    (*info->fprintf_func) (stream, "%%hi(%#x)",
                    (*info->fprintf_func) (stream, "%%hi(%#x)",
                                           (0xFFFFFFFF
                                           (0xFFFFFFFF
                                            & ((int) X_IMM22 (insn) << 10)));
                                            & ((int) X_IMM22 (insn) << 10)));
                    break;
                    break;
 
 
                  case 'i':     /* 13 bit immediate */
                  case 'i':     /* 13 bit immediate */
                  case 'I':     /* 11 bit immediate */
                  case 'I':     /* 11 bit immediate */
                  case 'j':     /* 10 bit immediate */
                  case 'j':     /* 10 bit immediate */
                    {
                    {
                      int imm;
                      int imm;
 
 
                      if (*s == 'i')
                      if (*s == 'i')
                        imm = X_SIMM (insn, 13);
                        imm = X_SIMM (insn, 13);
                      else if (*s == 'I')
                      else if (*s == 'I')
                        imm = X_SIMM (insn, 11);
                        imm = X_SIMM (insn, 11);
                      else
                      else
                        imm = X_SIMM (insn, 10);
                        imm = X_SIMM (insn, 10);
 
 
                      /* Check to see whether we have a 1+i, and take
                      /* Check to see whether we have a 1+i, and take
                         note of that fact.
                         note of that fact.
 
 
                         Note: because of the way we sort the table,
                         Note: because of the way we sort the table,
                         we will be matching 1+i rather than i+1,
                         we will be matching 1+i rather than i+1,
                         so it is OK to assume that i is after +,
                         so it is OK to assume that i is after +,
                         not before it.  */
                         not before it.  */
                      if (found_plus)
                      if (found_plus)
                        imm_added_to_rs1 = 1;
                        imm_added_to_rs1 = 1;
 
 
                      if (imm <= 9)
                      if (imm <= 9)
                        (*info->fprintf_func) (stream, "%d", imm);
                        (*info->fprintf_func) (stream, "%d", imm);
                      else
                      else
                        (*info->fprintf_func) (stream, "%#x", imm);
                        (*info->fprintf_func) (stream, "%#x", imm);
                    }
                    }
                    break;
                    break;
 
 
                  case 'X':     /* 5 bit unsigned immediate */
                  case 'X':     /* 5 bit unsigned immediate */
                  case 'Y':     /* 6 bit unsigned immediate */
                  case 'Y':     /* 6 bit unsigned immediate */
                    {
                    {
                      int imm = X_IMM (insn, *s == 'X' ? 5 : 6);
                      int imm = X_IMM (insn, *s == 'X' ? 5 : 6);
 
 
                      if (imm <= 9)
                      if (imm <= 9)
                        (info->fprintf_func) (stream, "%d", imm);
                        (info->fprintf_func) (stream, "%d", imm);
                      else
                      else
                        (info->fprintf_func) (stream, "%#x", (unsigned) imm);
                        (info->fprintf_func) (stream, "%#x", (unsigned) imm);
                    }
                    }
                    break;
                    break;
 
 
                  case 'K':
                  case 'K':
                    {
                    {
                      int mask = X_MEMBAR (insn);
                      int mask = X_MEMBAR (insn);
                      int bit = 0x40, printed_one = 0;
                      int bit = 0x40, printed_one = 0;
                      const char *name;
                      const char *name;
 
 
                      if (mask == 0)
                      if (mask == 0)
                        (info->fprintf_func) (stream, "0");
                        (info->fprintf_func) (stream, "0");
                      else
                      else
                        while (bit)
                        while (bit)
                          {
                          {
                            if (mask & bit)
                            if (mask & bit)
                              {
                              {
                                if (printed_one)
                                if (printed_one)
                                  (info->fprintf_func) (stream, "|");
                                  (info->fprintf_func) (stream, "|");
                                name = sparc_decode_membar (bit);
                                name = sparc_decode_membar (bit);
                                (info->fprintf_func) (stream, "%s", name);
                                (info->fprintf_func) (stream, "%s", name);
                                printed_one = 1;
                                printed_one = 1;
                              }
                              }
                            bit >>= 1;
                            bit >>= 1;
                          }
                          }
                      break;
                      break;
                    }
                    }
 
 
                  case 'k':
                  case 'k':
                    info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4;
                    info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4;
                    (*info->print_address_func) (info->target, info);
                    (*info->print_address_func) (info->target, info);
                    break;
                    break;
 
 
                  case 'G':
                  case 'G':
                    info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4;
                    info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4;
                    (*info->print_address_func) (info->target, info);
                    (*info->print_address_func) (info->target, info);
                    break;
                    break;
 
 
                  case '6':
                  case '6':
                  case '7':
                  case '7':
                  case '8':
                  case '8':
                  case '9':
                  case '9':
                    (*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0');
                    (*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0');
                    break;
                    break;
 
 
                  case 'z':
                  case 'z':
                    (*info->fprintf_func) (stream, "%%icc");
                    (*info->fprintf_func) (stream, "%%icc");
                    break;
                    break;
 
 
                  case 'Z':
                  case 'Z':
                    (*info->fprintf_func) (stream, "%%xcc");
                    (*info->fprintf_func) (stream, "%%xcc");
                    break;
                    break;
 
 
                  case 'E':
                  case 'E':
                    (*info->fprintf_func) (stream, "%%ccr");
                    (*info->fprintf_func) (stream, "%%ccr");
                    break;
                    break;
 
 
                  case 's':
                  case 's':
                    (*info->fprintf_func) (stream, "%%fprs");
                    (*info->fprintf_func) (stream, "%%fprs");
                    break;
                    break;
 
 
                  case 'o':
                  case 'o':
                    (*info->fprintf_func) (stream, "%%asi");
                    (*info->fprintf_func) (stream, "%%asi");
                    break;
                    break;
 
 
                  case 'W':
                  case 'W':
                    (*info->fprintf_func) (stream, "%%tick");
                    (*info->fprintf_func) (stream, "%%tick");
                    break;
                    break;
 
 
                  case 'P':
                  case 'P':
                    (*info->fprintf_func) (stream, "%%pc");
                    (*info->fprintf_func) (stream, "%%pc");
                    break;
                    break;
 
 
                  case '?':
                  case '?':
                    if (X_RS1 (insn) == 31)
                    if (X_RS1 (insn) == 31)
                      (*info->fprintf_func) (stream, "%%ver");
                      (*info->fprintf_func) (stream, "%%ver");
                    else if ((unsigned) X_RS1 (insn) < 16)
                    else if ((unsigned) X_RS1 (insn) < 16)
                      (*info->fprintf_func) (stream, "%%%s",
                      (*info->fprintf_func) (stream, "%%%s",
                                             v9_priv_reg_names[X_RS1 (insn)]);
                                             v9_priv_reg_names[X_RS1 (insn)]);
                    else
                    else
                      (*info->fprintf_func) (stream, "%%reserved");
                      (*info->fprintf_func) (stream, "%%reserved");
                    break;
                    break;
 
 
                  case '!':
                  case '!':
                    if ((unsigned) X_RD (insn) < 15)
                    if ((unsigned) X_RD (insn) < 15)
                      (*info->fprintf_func) (stream, "%%%s",
                      (*info->fprintf_func) (stream, "%%%s",
                                             v9_priv_reg_names[X_RD (insn)]);
                                             v9_priv_reg_names[X_RD (insn)]);
                    else
                    else
                      (*info->fprintf_func) (stream, "%%reserved");
                      (*info->fprintf_func) (stream, "%%reserved");
                    break;
                    break;
 
 
                  case '/':
                  case '/':
                    if (X_RS1 (insn) < 16 || X_RS1 (insn) > 23)
                    if (X_RS1 (insn) < 16 || X_RS1 (insn) > 23)
                      (*info->fprintf_func) (stream, "%%reserved");
                      (*info->fprintf_func) (stream, "%%reserved");
                    else
                    else
                      (*info->fprintf_func) (stream, "%%%s",
                      (*info->fprintf_func) (stream, "%%%s",
                                             v9a_asr_reg_names[X_RS1 (insn)-16]);
                                             v9a_asr_reg_names[X_RS1 (insn)-16]);
                    break;
                    break;
 
 
                  case '_':
                  case '_':
                    if (X_RD (insn) < 16 || X_RD (insn) > 23)
                    if (X_RD (insn) < 16 || X_RD (insn) > 23)
                      (*info->fprintf_func) (stream, "%%reserved");
                      (*info->fprintf_func) (stream, "%%reserved");
                    else
                    else
                      (*info->fprintf_func) (stream, "%%%s",
                      (*info->fprintf_func) (stream, "%%%s",
                                             v9a_asr_reg_names[X_RD (insn)-16]);
                                             v9a_asr_reg_names[X_RD (insn)-16]);
                    break;
                    break;
 
 
                  case '*':
                  case '*':
                    {
                    {
                      const char *name = sparc_decode_prefetch (X_RD (insn));
                      const char *name = sparc_decode_prefetch (X_RD (insn));
 
 
                      if (name)
                      if (name)
                        (*info->fprintf_func) (stream, "%s", name);
                        (*info->fprintf_func) (stream, "%s", name);
                      else
                      else
                        (*info->fprintf_func) (stream, "%d", X_RD (insn));
                        (*info->fprintf_func) (stream, "%d", X_RD (insn));
                      break;
                      break;
                    }
                    }
 
 
                  case 'M':
                  case 'M':
                    (*info->fprintf_func) (stream, "%%asr%d", X_RS1 (insn));
                    (*info->fprintf_func) (stream, "%%asr%d", X_RS1 (insn));
                    break;
                    break;
 
 
                  case 'm':
                  case 'm':
                    (*info->fprintf_func) (stream, "%%asr%d", X_RD (insn));
                    (*info->fprintf_func) (stream, "%%asr%d", X_RD (insn));
                    break;
                    break;
 
 
                  case 'L':
                  case 'L':
                    info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4;
                    info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4;
                    (*info->print_address_func) (info->target, info);
                    (*info->print_address_func) (info->target, info);
                    break;
                    break;
 
 
                  case 'n':
                  case 'n':
                    (*info->fprintf_func)
                    (*info->fprintf_func)
                      (stream, "%#x", SEX (X_DISP22 (insn), 22));
                      (stream, "%#x", SEX (X_DISP22 (insn), 22));
                    break;
                    break;
 
 
                  case 'l':
                  case 'l':
                    info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4;
                    info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4;
                    (*info->print_address_func) (info->target, info);
                    (*info->print_address_func) (info->target, info);
                    break;
                    break;
 
 
                  case 'A':
                  case 'A':
                    {
                    {
                      const char *name = sparc_decode_asi (X_ASI (insn));
                      const char *name = sparc_decode_asi (X_ASI (insn));
 
 
                      if (name)
                      if (name)
                        (*info->fprintf_func) (stream, "%s", name);
                        (*info->fprintf_func) (stream, "%s", name);
                      else
                      else
                        (*info->fprintf_func) (stream, "(%d)", X_ASI (insn));
                        (*info->fprintf_func) (stream, "(%d)", X_ASI (insn));
                      break;
                      break;
                    }
                    }
 
 
                  case 'C':
                  case 'C':
                    (*info->fprintf_func) (stream, "%%csr");
                    (*info->fprintf_func) (stream, "%%csr");
                    break;
                    break;
 
 
                  case 'F':
                  case 'F':
                    (*info->fprintf_func) (stream, "%%fsr");
                    (*info->fprintf_func) (stream, "%%fsr");
                    break;
                    break;
 
 
                  case 'p':
                  case 'p':
                    (*info->fprintf_func) (stream, "%%psr");
                    (*info->fprintf_func) (stream, "%%psr");
                    break;
                    break;
 
 
                  case 'q':
                  case 'q':
                    (*info->fprintf_func) (stream, "%%fq");
                    (*info->fprintf_func) (stream, "%%fq");
                    break;
                    break;
 
 
                  case 'Q':
                  case 'Q':
                    (*info->fprintf_func) (stream, "%%cq");
                    (*info->fprintf_func) (stream, "%%cq");
                    break;
                    break;
 
 
                  case 't':
                  case 't':
                    (*info->fprintf_func) (stream, "%%tbr");
                    (*info->fprintf_func) (stream, "%%tbr");
                    break;
                    break;
 
 
                  case 'w':
                  case 'w':
                    (*info->fprintf_func) (stream, "%%wim");
                    (*info->fprintf_func) (stream, "%%wim");
                    break;
                    break;
 
 
                  case 'x':
                  case 'x':
                    (*info->fprintf_func) (stream, "%d",
                    (*info->fprintf_func) (stream, "%d",
                                           ((X_LDST_I (insn) << 8)
                                           ((X_LDST_I (insn) << 8)
                                            + X_ASI (insn)));
                                            + X_ASI (insn)));
                    break;
                    break;
 
 
                  case 'y':
                  case 'y':
                    (*info->fprintf_func) (stream, "%%y");
                    (*info->fprintf_func) (stream, "%%y");
                    break;
                    break;
 
 
                  case 'u':
                  case 'u':
                  case 'U':
                  case 'U':
                    {
                    {
                      int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn);
                      int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn);
                      const char *name = sparc_decode_sparclet_cpreg (val);
                      const char *name = sparc_decode_sparclet_cpreg (val);
 
 
                      if (name)
                      if (name)
                        (*info->fprintf_func) (stream, "%s", name);
                        (*info->fprintf_func) (stream, "%s", name);
                      else
                      else
                        (*info->fprintf_func) (stream, "%%cpreg(%d)", val);
                        (*info->fprintf_func) (stream, "%%cpreg(%d)", val);
                      break;
                      break;
                    }
                    }
                  }
                  }
              }
              }
          }
          }
 
 
          /* If we are adding or or'ing something to rs1, then
          /* If we are adding or or'ing something to rs1, then
             check to see whether the previous instruction was
             check to see whether the previous instruction was
             a sethi to the same register as in the sethi.
             a sethi to the same register as in the sethi.
             If so, attempt to print the result of the add or
             If so, attempt to print the result of the add or
             or (in this context add and or do the same thing)
             or (in this context add and or do the same thing)
             and its symbolic value.  */
             and its symbolic value.  */
          if (imm_ored_to_rs1 || imm_added_to_rs1)
          if (imm_ored_to_rs1 || imm_added_to_rs1)
            {
            {
              unsigned long prev_insn;
              unsigned long prev_insn;
              int errcode;
              int errcode;
 
 
              errcode =
              errcode =
                (*info->read_memory_func)
                (*info->read_memory_func)
                  (memaddr - 4, buffer, sizeof (buffer), info);
                  (memaddr - 4, buffer, sizeof (buffer), info);
              prev_insn = getword (buffer);
              prev_insn = getword (buffer);
 
 
              if (errcode == 0)
              if (errcode == 0)
                {
                {
                  /* If it is a delayed branch, we need to look at the
                  /* If it is a delayed branch, we need to look at the
                     instruction before the delayed branch.  This handles
                     instruction before the delayed branch.  This handles
                     sequences such as
                     sequences such as
 
 
                     sethi %o1, %hi(_foo), %o1
                     sethi %o1, %hi(_foo), %o1
                     call _printf
                     call _printf
                     or %o1, %lo(_foo), %o1
                     or %o1, %lo(_foo), %o1
                     */
                     */
 
 
                  if (is_delayed_branch (prev_insn))
                  if (is_delayed_branch (prev_insn))
                    {
                    {
                      errcode = (*info->read_memory_func)
                      errcode = (*info->read_memory_func)
                        (memaddr - 8, buffer, sizeof (buffer), info);
                        (memaddr - 8, buffer, sizeof (buffer), info);
                      prev_insn = getword (buffer);
                      prev_insn = getword (buffer);
                    }
                    }
                }
                }
 
 
              /* If there was a problem reading memory, then assume
              /* If there was a problem reading memory, then assume
                 the previous instruction was not sethi.  */
                 the previous instruction was not sethi.  */
              if (errcode == 0)
              if (errcode == 0)
                {
                {
                  /* Is it sethi to the same register?  */
                  /* Is it sethi to the same register?  */
                  if ((prev_insn & 0xc1c00000) == 0x01000000
                  if ((prev_insn & 0xc1c00000) == 0x01000000
                      && X_RD (prev_insn) == X_RS1 (insn))
                      && X_RD (prev_insn) == X_RS1 (insn))
                    {
                    {
                      (*info->fprintf_func) (stream, "\t! ");
                      (*info->fprintf_func) (stream, "\t! ");
                      info->target =
                      info->target =
                        (0xFFFFFFFF & (int) X_IMM22 (prev_insn) << 10);
                        (0xFFFFFFFF & (int) X_IMM22 (prev_insn) << 10);
                      if (imm_added_to_rs1)
                      if (imm_added_to_rs1)
                        info->target += X_SIMM (insn, 13);
                        info->target += X_SIMM (insn, 13);
                      else
                      else
                        info->target |= X_SIMM (insn, 13);
                        info->target |= X_SIMM (insn, 13);
                      (*info->print_address_func) (info->target, info);
                      (*info->print_address_func) (info->target, info);
                      info->insn_type = dis_dref;
                      info->insn_type = dis_dref;
                      info->data_size = 4;  /* FIXME!!! */
                      info->data_size = 4;  /* FIXME!!! */
                    }
                    }
                }
                }
            }
            }
 
 
          if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR))
          if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR))
            {
            {
                /* FIXME -- check is_annulled flag */
                /* FIXME -- check is_annulled flag */
              if (opcode->flags & F_UNBR)
              if (opcode->flags & F_UNBR)
                info->insn_type = dis_branch;
                info->insn_type = dis_branch;
              if (opcode->flags & F_CONDBR)
              if (opcode->flags & F_CONDBR)
                info->insn_type = dis_condbranch;
                info->insn_type = dis_condbranch;
              if (opcode->flags & F_JSR)
              if (opcode->flags & F_JSR)
                info->insn_type = dis_jsr;
                info->insn_type = dis_jsr;
              if (opcode->flags & F_DELAYED)
              if (opcode->flags & F_DELAYED)
                info->branch_delay_insns = 1;
                info->branch_delay_insns = 1;
            }
            }
 
 
          return sizeof (buffer);
          return sizeof (buffer);
        }
        }
    }
    }
 
 
  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"));
  (*info->fprintf_func) (stream, _("unknown"));
  return sizeof (buffer);
  return sizeof (buffer);
}
}
 
 
/* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values.  */
/* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values.  */
 
 
static int
static int
compute_arch_mask (mach)
compute_arch_mask (mach)
     unsigned long mach;
     unsigned long mach;
{
{
  switch (mach)
  switch (mach)
    {
    {
    case 0 :
    case 0 :
    case bfd_mach_sparc :
    case bfd_mach_sparc :
      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8);
      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8);
    case bfd_mach_sparc_sparclet :
    case bfd_mach_sparc_sparclet :
      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET);
      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET);
    case bfd_mach_sparc_sparclite :
    case bfd_mach_sparc_sparclite :
    case bfd_mach_sparc_sparclite_le :
    case bfd_mach_sparc_sparclite_le :
      /* sparclites insns are recognized by default (because that's how
      /* sparclites insns are recognized by default (because that's how
         they've always been treated, for better or worse).  Kludge this by
         they've always been treated, for better or worse).  Kludge this by
         indicating generic v8 is also selected.  */
         indicating generic v8 is also selected.  */
      return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE)
      return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE)
              | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8));
              | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8));
    case bfd_mach_sparc_v8plus :
    case bfd_mach_sparc_v8plus :
    case bfd_mach_sparc_v9 :
    case bfd_mach_sparc_v9 :
      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9);
      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9);
    case bfd_mach_sparc_v8plusa :
    case bfd_mach_sparc_v8plusa :
    case bfd_mach_sparc_v9a :
    case bfd_mach_sparc_v9a :
      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A);
      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A);
    }
    }
  abort ();
  abort ();
}
}
 
 
/* Compare opcodes A and B.  */
/* Compare opcodes A and B.  */
 
 
static int
static int
compare_opcodes (a, b)
compare_opcodes (a, b)
     const PTR a;
     const PTR a;
     const PTR b;
     const PTR b;
{
{
  struct sparc_opcode *op0 = * (struct sparc_opcode **) a;
  struct sparc_opcode *op0 = * (struct sparc_opcode **) a;
  struct sparc_opcode *op1 = * (struct sparc_opcode **) b;
  struct sparc_opcode *op1 = * (struct sparc_opcode **) b;
  unsigned long int match0 = op0->match, match1 = op1->match;
  unsigned long int match0 = op0->match, match1 = op1->match;
  unsigned long int lose0 = op0->lose, lose1 = op1->lose;
  unsigned long int lose0 = op0->lose, lose1 = op1->lose;
  register unsigned int i;
  register unsigned int i;
 
 
  /* If one (and only one) insn isn't supported by the current architecture,
  /* If one (and only one) insn isn't supported by the current architecture,
     prefer the one that is.  If neither are supported, but they're both for
     prefer the one that is.  If neither are supported, but they're both for
     the same architecture, continue processing.  Otherwise (both unsupported
     the same architecture, continue processing.  Otherwise (both unsupported
     and for different architectures), prefer lower numbered arch's (fudged
     and for different architectures), prefer lower numbered arch's (fudged
     by comparing the bitmasks).  */
     by comparing the bitmasks).  */
  if (op0->architecture & current_arch_mask)
  if (op0->architecture & current_arch_mask)
    {
    {
      if (! (op1->architecture & current_arch_mask))
      if (! (op1->architecture & current_arch_mask))
        return -1;
        return -1;
    }
    }
  else
  else
    {
    {
      if (op1->architecture & current_arch_mask)
      if (op1->architecture & current_arch_mask)
        return 1;
        return 1;
      else if (op0->architecture != op1->architecture)
      else if (op0->architecture != op1->architecture)
        return op0->architecture - op1->architecture;
        return op0->architecture - op1->architecture;
    }
    }
 
 
  /* If a bit is set in both match and lose, there is something
  /* If a bit is set in both match and lose, there is something
     wrong with the opcode table.  */
     wrong with the opcode table.  */
  if (match0 & lose0)
  if (match0 & lose0)
    {
    {
      fprintf
      fprintf
        (stderr,
        (stderr,
         /* xgettext:c-format */
         /* xgettext:c-format */
         _("Internal error:  bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"),
         _("Internal error:  bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"),
         op0->name, match0, lose0);
         op0->name, match0, lose0);
      op0->lose &= ~op0->match;
      op0->lose &= ~op0->match;
      lose0 = op0->lose;
      lose0 = op0->lose;
    }
    }
 
 
  if (match1 & lose1)
  if (match1 & lose1)
    {
    {
      fprintf
      fprintf
        (stderr,
        (stderr,
         /* xgettext:c-format */
         /* xgettext:c-format */
         _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"),
         _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"),
         op1->name, match1, lose1);
         op1->name, match1, lose1);
      op1->lose &= ~op1->match;
      op1->lose &= ~op1->match;
      lose1 = op1->lose;
      lose1 = op1->lose;
    }
    }
 
 
  /* Because the bits that are variable in one opcode are constant in
  /* Because the bits that are variable in one opcode are constant in
     another, it is important to order the opcodes in the right order.  */
     another, it is important to order the opcodes in the right order.  */
  for (i = 0; i < 32; ++i)
  for (i = 0; i < 32; ++i)
    {
    {
      unsigned long int x = 1 << i;
      unsigned long int x = 1 << i;
      int x0 = (match0 & x) != 0;
      int x0 = (match0 & x) != 0;
      int x1 = (match1 & x) != 0;
      int x1 = (match1 & x) != 0;
 
 
      if (x0 != x1)
      if (x0 != x1)
        return x1 - x0;
        return x1 - x0;
    }
    }
 
 
  for (i = 0; i < 32; ++i)
  for (i = 0; i < 32; ++i)
    {
    {
      unsigned long int x = 1 << i;
      unsigned long int x = 1 << i;
      int x0 = (lose0 & x) != 0;
      int x0 = (lose0 & x) != 0;
      int x1 = (lose1 & x) != 0;
      int x1 = (lose1 & x) != 0;
 
 
      if (x0 != x1)
      if (x0 != x1)
        return x1 - x0;
        return x1 - x0;
    }
    }
 
 
  /* They are functionally equal.  So as long as the opcode table is
  /* They are functionally equal.  So as long as the opcode table is
     valid, we can put whichever one first we want, on aesthetic grounds.  */
     valid, we can put whichever one first we want, on aesthetic grounds.  */
 
 
  /* Our first aesthetic ground is that aliases defer to real insns.  */
  /* Our first aesthetic ground is that aliases defer to real insns.  */
  {
  {
    int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS);
    int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS);
    if (alias_diff != 0)
    if (alias_diff != 0)
      /* Put the one that isn't an alias first.  */
      /* Put the one that isn't an alias first.  */
      return alias_diff;
      return alias_diff;
  }
  }
 
 
  /* Except for aliases, two "identical" instructions had
  /* Except for aliases, two "identical" instructions had
     better have the same opcode.  This is a sanity check on the table.  */
     better have the same opcode.  This is a sanity check on the table.  */
  i = strcmp (op0->name, op1->name);
  i = strcmp (op0->name, op1->name);
  if (i)
  if (i)
    {
    {
      if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */
      if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */
        return i;
        return i;
      else
      else
        fprintf (stderr,
        fprintf (stderr,
                 /* xgettext:c-format */
                 /* xgettext:c-format */
                 _("Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"),
                 _("Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"),
                 op0->name, op1->name);
                 op0->name, op1->name);
    }
    }
 
 
  /* Fewer arguments are preferred.  */
  /* Fewer arguments are preferred.  */
  {
  {
    int length_diff = strlen (op0->args) - strlen (op1->args);
    int length_diff = strlen (op0->args) - strlen (op1->args);
    if (length_diff != 0)
    if (length_diff != 0)
      /* Put the one with fewer arguments first.  */
      /* Put the one with fewer arguments first.  */
      return length_diff;
      return length_diff;
  }
  }
 
 
  /* Put 1+i before i+1.  */
  /* Put 1+i before i+1.  */
  {
  {
    char *p0 = (char *) strchr (op0->args, '+');
    char *p0 = (char *) strchr (op0->args, '+');
    char *p1 = (char *) strchr (op1->args, '+');
    char *p1 = (char *) strchr (op1->args, '+');
 
 
    if (p0 && p1)
    if (p0 && p1)
      {
      {
        /* There is a plus in both operands.  Note that a plus
        /* There is a plus in both operands.  Note that a plus
           sign cannot be the first character in args,
           sign cannot be the first character in args,
           so the following [-1]'s are valid.  */
           so the following [-1]'s are valid.  */
        if (p0[-1] == 'i' && p1[1] == 'i')
        if (p0[-1] == 'i' && p1[1] == 'i')
          /* op0 is i+1 and op1 is 1+i, so op1 goes first.  */
          /* op0 is i+1 and op1 is 1+i, so op1 goes first.  */
          return 1;
          return 1;
        if (p0[1] == 'i' && p1[-1] == 'i')
        if (p0[1] == 'i' && p1[-1] == 'i')
          /* op0 is 1+i and op1 is i+1, so op0 goes first.  */
          /* op0 is 1+i and op1 is i+1, so op0 goes first.  */
          return -1;
          return -1;
      }
      }
  }
  }
 
 
  /* Put 1,i before i,1.  */
  /* Put 1,i before i,1.  */
  {
  {
    int i0 = strncmp (op0->args, "i,1", 3) == 0;
    int i0 = strncmp (op0->args, "i,1", 3) == 0;
    int i1 = strncmp (op1->args, "i,1", 3) == 0;
    int i1 = strncmp (op1->args, "i,1", 3) == 0;
 
 
    if (i0 ^ i1)
    if (i0 ^ i1)
      return i0 - i1;
      return i0 - i1;
  }
  }
 
 
  /* They are, as far as we can tell, identical.
  /* They are, as far as we can tell, identical.
     Since qsort may have rearranged the table partially, there is
     Since qsort may have rearranged the table partially, there is
     no way to tell which one was first in the opcode table as
     no way to tell which one was first in the opcode table as
     written, so just say there are equal.  */
     written, so just say there are equal.  */
  /* ??? This is no longer true now that we sort a vector of pointers,
  /* ??? This is no longer true now that we sort a vector of pointers,
     not the table itself.  */
     not the table itself.  */
  return 0;
  return 0;
}
}
 
 
/* Build a hash table from the opcode table.
/* Build a hash table from the opcode table.
   OPCODE_TABLE is a sorted list of pointers into the opcode table.  */
   OPCODE_TABLE is a sorted list of pointers into the opcode table.  */
 
 
static void
static void
build_hash_table (opcode_table, hash_table, num_opcodes)
build_hash_table (opcode_table, hash_table, num_opcodes)
     const struct sparc_opcode **opcode_table;
     const struct sparc_opcode **opcode_table;
     struct opcode_hash **hash_table;
     struct opcode_hash **hash_table;
     int num_opcodes;
     int num_opcodes;
{
{
  register int i;
  register int i;
  int hash_count[HASH_SIZE];
  int hash_count[HASH_SIZE];
  static struct opcode_hash *hash_buf = NULL;
  static struct opcode_hash *hash_buf = NULL;
 
 
  /* Start at the end of the table and work backwards so that each
  /* Start at the end of the table and work backwards so that each
     chain is sorted.  */
     chain is sorted.  */
 
 
  memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0]));
  memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0]));
  memset (hash_count, 0, HASH_SIZE * sizeof (hash_count[0]));
  memset (hash_count, 0, HASH_SIZE * sizeof (hash_count[0]));
  if (hash_buf != NULL)
  if (hash_buf != NULL)
    free (hash_buf);
    free (hash_buf);
  hash_buf = (struct opcode_hash *) xmalloc (sizeof (struct opcode_hash) * num_opcodes);
  hash_buf = (struct opcode_hash *) xmalloc (sizeof (struct opcode_hash) * num_opcodes);
  for (i = num_opcodes - 1; i >= 0; --i)
  for (i = num_opcodes - 1; i >= 0; --i)
    {
    {
      register int hash = HASH_INSN (opcode_table[i]->match);
      register int hash = HASH_INSN (opcode_table[i]->match);
      register struct opcode_hash *h = &hash_buf[i];
      register struct opcode_hash *h = &hash_buf[i];
      h->next = hash_table[hash];
      h->next = hash_table[hash];
      h->opcode = opcode_table[i];
      h->opcode = opcode_table[i];
      hash_table[hash] = h;
      hash_table[hash] = h;
      ++hash_count[hash];
      ++hash_count[hash];
    }
    }
 
 
#if 0 /* for debugging */
#if 0 /* for debugging */
  {
  {
    int min_count = num_opcodes, max_count = 0;
    int min_count = num_opcodes, max_count = 0;
    int total;
    int total;
 
 
    for (i = 0; i < HASH_SIZE; ++i)
    for (i = 0; i < HASH_SIZE; ++i)
      {
      {
        if (hash_count[i] < min_count)
        if (hash_count[i] < min_count)
          min_count = hash_count[i];
          min_count = hash_count[i];
        if (hash_count[i] > max_count)
        if (hash_count[i] > max_count)
          max_count = hash_count[i];
          max_count = hash_count[i];
        total += hash_count[i];
        total += hash_count[i];
      }
      }
 
 
    printf ("Opcode hash table stats: min %d, max %d, ave %f\n",
    printf ("Opcode hash table stats: min %d, max %d, ave %f\n",
            min_count, max_count, (double) total / HASH_SIZE);
            min_count, max_count, (double) total / HASH_SIZE);
  }
  }
#endif
#endif
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.