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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [binutils-2.20.1/] [gas/] [config/] [tc-or32.c] - Diff between revs 206 and 241

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 206 Rev 241
/* Assembly backend for the OpenRISC 1000.
/* Assembly backend for the OpenRISC 1000.
   Copyright (C) 2002, 2003, 2005, 2007, 2009
   Copyright (C) 2002, 2003, 2005, 2007, 2009
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
   Contributed by Damjan Lampret <lampret@opencores.org>.
   Contributed by Damjan Lampret <lampret@opencores.org>.
   Modified bu Johan Rydberg, <johan.rydberg@netinsight.se>.
   Modified bu Johan Rydberg, <johan.rydberg@netinsight.se>.
               Gyorgy Jeney <nog@sdf.lonestar.org>
               Gyorgy Jeney <nog@sdf.lonestar.org>
   Based upon a29k port.
   Based upon a29k port.
 
 
   This file is part of GAS, the GNU Assembler.
   This file is part of GAS, the GNU Assembler.
 
 
   GAS is free software; you can redistribute it and/or modify
   GAS 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 3, or (at your option)
   the Free Software Foundation; either version 3, or (at your option)
   any later version.
   any later version.
 
 
   GAS is distributed in the hope that it will be useful,
   GAS 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 GAS; see the file COPYING.  If not, write to
   along with GAS; see the file COPYING.  If not, write to
   the Free Software Foundation, 51 Franklin Street - Fifth Floor,
   the Free Software Foundation, 51 Franklin Street - Fifth Floor,
   Boston, MA 02110-1301, USA.  */
   Boston, MA 02110-1301, USA.  */
 
 
/* tc-a29k.c used as a template.  */
/* tc-a29k.c used as a template.  */
 
 
#include "safe-ctype.h"
#include "safe-ctype.h"
#include "as.h"
#include "as.h"
#include "opcode/or32.h"
#include "opcode/or32.h"
#include "struc-symbol.h"
#include "struc-symbol.h"
#include "elf/or32.h"
#include "elf/or32.h"
 
 
#define DEBUG 0
#define DEBUG 0
 
 
#ifndef REGISTER_PREFIX
#ifndef REGISTER_PREFIX
#define REGISTER_PREFIX   '%'
#define REGISTER_PREFIX   '%'
#endif
#endif
 
 
/* Make it easier to clone this machine desc into another one.  */
/* Make it easier to clone this machine desc into another one.  */
#define machine_opcode  or32_opcode
#define machine_opcode  or32_opcode
#define machine_opcodes or32_opcodes
#define machine_opcodes or32_opcodes
#define machine_ip      or32_ip
#define machine_ip      or32_ip
#define machine_it      or32_it
#define machine_it      or32_it
 
 
/* Handle of the OPCODE hash table.  */
/* Handle of the OPCODE hash table.  */
static struct hash_control *op_hash = NULL;
static struct hash_control *op_hash = NULL;
 
 
struct machine_it
struct machine_it
{
{
  char *          error;
  char *          error;
  unsigned long   opcode;
  unsigned long   opcode;
  struct nlist *  nlistp;
  struct nlist *  nlistp;
  expressionS     exp;
  expressionS     exp;
  int             pcrel;
  int             pcrel;
  int             reloc;
  int             reloc;
}
}
the_insn;
the_insn;
 
 
const pseudo_typeS md_pseudo_table[] =
const pseudo_typeS md_pseudo_table[] =
{
{
  {"align",   s_align_bytes,  4 },
  {"align",   s_align_bytes,  4 },
  {"space",   s_space,        0 },
  {"space",   s_space,        0 },
  {"cputype", s_ignore,       0 },
  {"cputype", s_ignore,       0 },
  {"reg",     s_lsym,         0 },  /* Register equate, same as equ.  */
  {"reg",     s_lsym,         0 },  /* Register equate, same as equ.  */
  {"sect",    s_ignore,       0 },  /* Creation of coff sections.  */
  {"sect",    s_ignore,       0 },  /* Creation of coff sections.  */
  {"proc",    s_ignore,       0 },  /* Start of a function.  */
  {"proc",    s_ignore,       0 },  /* Start of a function.  */
  {"endproc", s_ignore,       0 },  /* Function end.  */
  {"endproc", s_ignore,       0 },  /* Function end.  */
  {"half",    cons,           2 },
  {"half",    cons,           2 },
  {"word",    cons,           4 },
  {"word",    cons,           4 },
  {NULL,      0,              0 },
  {NULL,      0,              0 },
};
};
 
 
int md_short_jump_size  = 4;
int md_short_jump_size  = 4;
int md_long_jump_size   = 4;
int md_long_jump_size   = 4;
 
 
/* This array holds the chars that always start a comment.
/* This array holds the chars that always start a comment.
   If the pre-processor is disabled, these aren't very useful.  */
   If the pre-processor is disabled, these aren't very useful.  */
const char comment_chars[] = "#";
const char comment_chars[] = "#";
 
 
/* This array holds the chars that only start a comment at the beginning of
/* This array holds the chars that only start a comment at the beginning of
   a line.  If the line seems to have the form '# 123 filename'
   a line.  If the line seems to have the form '# 123 filename'
   .line and .file directives will appear in the pre-processed output.  */
   .line and .file directives will appear in the pre-processed output.  */
/* Note that input_file.c hand checks for '#' at the beginning of the
/* Note that input_file.c hand checks for '#' at the beginning of the
   first line of the input file.  This is because the compiler outputs
   first line of the input file.  This is because the compiler outputs
   #NO_APP at the beginning of its output.  */
   #NO_APP at the beginning of its output.  */
/* Also note that comments like this one will always work.  */
/* Also note that comments like this one will always work.  */
const char line_comment_chars[] = "#";
const char line_comment_chars[] = "#";
 
 
/* We needed an unused char for line separation to work around the
/* We needed an unused char for line separation to work around the
   lack of macros, using sed and such.  */
   lack of macros, using sed and such.  */
const char line_separator_chars[] = ";";
const char line_separator_chars[] = ";";
 
 
/* Chars that can be used to separate mant from exp in floating point nums.  */
/* Chars that can be used to separate mant from exp in floating point nums.  */
const char EXP_CHARS[] = "eE";
const char EXP_CHARS[] = "eE";
 
 
/* Chars that mean this number is a floating point constant.
/* Chars that mean this number is a floating point constant.
   As in 0f12.456
   As in 0f12.456
   or    0d1.2345e12.  */
   or    0d1.2345e12.  */
const char FLT_CHARS[] = "rRsSfFdDxXpP";
const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
 
/* "l.jalr r9" precalculated opcode.  */
/* "l.jalr r9" precalculated opcode.  */
static unsigned long jalr_r9_opcode;
static unsigned long jalr_r9_opcode;
 
 
static void machine_ip (char *);
static void machine_ip (char *);
 
 
 
 
/* Set bits in machine opcode according to insn->encoding
/* Set bits in machine opcode according to insn->encoding
   description and passed operand.  */
   description and passed operand.  */
 
 
static void
static void
encode (const struct machine_opcode *insn,
encode (const struct machine_opcode *insn,
        unsigned long *opcode,
        unsigned long *opcode,
        signed long param_val,
        signed long param_val,
        char param_ch)
        char param_ch)
{
{
  int opc_pos = 0;
  int opc_pos = 0;
  int param_pos = 0;
  int param_pos = 0;
  char *enc;
  char *enc;
 
 
#if DEBUG
#if DEBUG
  printf ("    encode:  opcode=%.8x  param_val=%.8x abs=%.8x param_ch=%c\n",
  printf ("    encode:  opcode=%.8x  param_val=%.8x abs=%.8x param_ch=%c\n",
          (unsigned int) *opcode,(unsigned int) param_val, abs (param_val), param_ch);
          (unsigned int) *opcode,(unsigned int) param_val, abs (param_val), param_ch);
#endif
#endif
  for (enc = insn->encoding; *enc != '\0'; enc++)
  for (enc = insn->encoding; *enc != '\0'; enc++)
    if (*enc == param_ch)
    if (*enc == param_ch)
      {
      {
        if (enc - 2 >= insn->encoding && (*(enc - 2) == '0') && (*(enc - 1) == 'x'))
        if (enc - 2 >= insn->encoding && (*(enc - 2) == '0') && (*(enc - 1) == 'x'))
          continue;
          continue;
        else
        else
          param_pos ++;
          param_pos ++;
      }
      }
 
 
  opc_pos = 32;
  opc_pos = 32;
 
 
  for (enc = insn->encoding; *enc != '\0';)
  for (enc = insn->encoding; *enc != '\0';)
    {
    {
      if ((*enc == '0') && (*(enc + 1) == 'x'))
      if ((*enc == '0') && (*(enc + 1) == 'x'))
        {
        {
          int tmp = strtol (enc, NULL, 16);
          int tmp = strtol (enc, NULL, 16);
 
 
          opc_pos -= 4;
          opc_pos -= 4;
          *opcode |= tmp << opc_pos;
          *opcode |= tmp << opc_pos;
          enc += 3;
          enc += 3;
        }
        }
      else if ((*enc == '0') || (*enc == '-'))
      else if ((*enc == '0') || (*enc == '-'))
        {
        {
          opc_pos--;
          opc_pos--;
          enc++;
          enc++;
        }
        }
      else if (*enc == '1')
      else if (*enc == '1')
        {
        {
          opc_pos--;
          opc_pos--;
          *opcode |= 1 << opc_pos;
          *opcode |= 1 << opc_pos;
          enc++;
          enc++;
        }
        }
      else if (*enc == param_ch)
      else if (*enc == param_ch)
        {
        {
          opc_pos--;
          opc_pos--;
          param_pos--;
          param_pos--;
          *opcode |= ((param_val >> param_pos) & 0x1) << opc_pos;
          *opcode |= ((param_val >> param_pos) & 0x1) << opc_pos;
          enc++;
          enc++;
        }
        }
      else if (ISALPHA (*enc))
      else if (ISALPHA (*enc))
        {
        {
          opc_pos--;
          opc_pos--;
          enc++;
          enc++;
        }
        }
      else
      else
        enc++;
        enc++;
    }
    }
 
 
#if DEBUG
#if DEBUG
  printf ("    opcode=%.8lx\n", *opcode);
  printf ("    opcode=%.8lx\n", *opcode);
#endif
#endif
}
}
 
 
/* This function is called once, at assembler startup time.  It should
/* This function is called once, at assembler startup time.  It should
   set up all the tables, etc., that the MD part of the assembler will
   set up all the tables, etc., that the MD part of the assembler will
   need.  */
   need.  */
 
 
void
void
md_begin (void)
md_begin (void)
{
{
  const char *retval = NULL;
  const char *retval = NULL;
  int lose = 0;
  int lose = 0;
  int skipnext = 0;
  int skipnext = 0;
  unsigned int i;
  unsigned int i;
 
 
  /* Hash up all the opcodes for fast use later.  */
  /* Hash up all the opcodes for fast use later.  */
  op_hash = hash_new ();
  op_hash = hash_new ();
 
 
  for (i = 0; i < or32_num_opcodes; i++)
  for (i = 0; i < or32_num_opcodes; i++)
    {
    {
      const char *name = machine_opcodes[i].name;
      const char *name = machine_opcodes[i].name;
 
 
      if (skipnext)
      if (skipnext)
        {
        {
          skipnext = 0;
          skipnext = 0;
          continue;
          continue;
        }
        }
 
 
      retval = hash_insert (op_hash, name, (void *) &machine_opcodes[i]);
      retval = hash_insert (op_hash, name, (void *) &machine_opcodes[i]);
      if (retval != NULL)
      if (retval != NULL)
        {
        {
          fprintf (stderr, "internal error: can't hash `%s': %s\n",
          fprintf (stderr, "internal error: can't hash `%s': %s\n",
                   machine_opcodes[i].name, retval);
                   machine_opcodes[i].name, retval);
          lose = 1;
          lose = 1;
        }
        }
    }
    }
 
 
  if (lose)
  if (lose)
    as_fatal (_("Broken assembler.  No assembly attempted."));
    as_fatal (_("Broken assembler.  No assembly attempted."));
 
 
  encode (&machine_opcodes[insn_index ("l.jalr")], &jalr_r9_opcode, 9, 'B');
  encode (&machine_opcodes[insn_index ("l.jalr")], &jalr_r9_opcode, 9, 'B');
}
}
 
 
/* Returns non zero if instruction is to be used.  */
/* Returns non zero if instruction is to be used.  */
 
 
static int
static int
check_invalid_opcode (unsigned long opcode)
check_invalid_opcode (unsigned long opcode)
{
{
  return opcode == jalr_r9_opcode;
  return opcode == jalr_r9_opcode;
}
}
 
 
/* Assemble a single instruction.  Its label has already been handled
/* Assemble a single instruction.  Its label has already been handled
   by the generic front end.  We just parse opcode and operands, and
   by the generic front end.  We just parse opcode and operands, and
   produce the bytes of data and relocation.  */
   produce the bytes of data and relocation.  */
 
 
void
void
md_assemble (char *str)
md_assemble (char *str)
{
{
  char *toP;
  char *toP;
 
 
#if DEBUG
#if DEBUG
  printf ("NEW INSTRUCTION\n");
  printf ("NEW INSTRUCTION\n");
#endif
#endif
 
 
  know (str);
  know (str);
  machine_ip (str);
  machine_ip (str);
  toP = frag_more (4);
  toP = frag_more (4);
 
 
  /* Put out the opcode.  */
  /* Put out the opcode.  */
  md_number_to_chars (toP, the_insn.opcode, 4);
  md_number_to_chars (toP, the_insn.opcode, 4);
 
 
  /* Put out the symbol-dependent stuff.  */
  /* Put out the symbol-dependent stuff.  */
  if (the_insn.reloc != BFD_RELOC_NONE)
  if (the_insn.reloc != BFD_RELOC_NONE)
    {
    {
      fix_new_exp (frag_now,
      fix_new_exp (frag_now,
                   (toP - frag_now->fr_literal),
                   (toP - frag_now->fr_literal),
                   4,   /* size */
                   4,   /* size */
                   &the_insn.exp,
                   &the_insn.exp,
                   the_insn.pcrel,
                   the_insn.pcrel,
                   the_insn.reloc);
                   the_insn.reloc);
    }
    }
}
}
 
 
static int mask_or_shift = 0;
static int mask_or_shift = 0;
 
 
 
/*----------------------------------------------------------------------------*/
 
/*!Parse an operand
 
 
 
   We use some semantic information about the operand to determine its type.
 
 
 
   @param[in]  s         Pointer to start of the operand string
 
   @param[out] operandp  The parsed operand expression
 
   @param[in]  opt       Non-zero (TRUE) if this operand is optional, zero
 
                         (FALSE) otherwise.
 
   @param[in]  is_reg    Non-zero (TRUE) if this operand is a register, zero
 
                         (FALSE) otherwise.
 
 
 
   @return  Pointer to the operand string immediately after the operand just
 
            parsed.                                                           */
 
/*----------------------------------------------------------------------------*/
static char *
static char *
parse_operand (char *s, expressionS *operandp, int opt)
parse_operand (char        *s,
 
               expressionS *operandp,
 
               int          opt,
 
               int          is_reg)
{
{
  char *save = input_line_pointer;
  char *save = input_line_pointer;
  char *new_pointer;
  char *new_pointer;
 
 
#if DEBUG
#if DEBUG
  printf ("  PROCESS NEW OPERAND(%s) == %c (%d)\n", s, opt ? opt : '!', opt);
  printf ("  PROCESS NEW OPERAND(%s): %s, %s\n", s,
 
          opt ? "optional" : "not optional",
 
          is_reg ? "register", "not register");
#endif
#endif
 
 
  input_line_pointer = s;
  input_line_pointer = s;
 
 
  if (strncasecmp (s, "HI(", 3) == 0)
  if (strncasecmp (s, "HI(", 3) == 0)
    {
    {
      mask_or_shift = BFD_RELOC_HI16;
      mask_or_shift = BFD_RELOC_HI16;
 
 
      input_line_pointer += 3;
      input_line_pointer += 3;
    }
    }
  else if (strncasecmp (s, "LO(", 3) == 0)
  else if (strncasecmp (s, "LO(", 3) == 0)
    {
    {
      mask_or_shift = BFD_RELOC_LO16;
      mask_or_shift = BFD_RELOC_LO16;
 
 
      input_line_pointer += 3;
      input_line_pointer += 3;
    }
    }
  else
  else
    mask_or_shift = 0;
    mask_or_shift = 0;
 
 
  if ((*s == '(') && (*(s+1) == 'r'))
  if ((*s == '(') && (*(s+1) == 'r'))
    s++;
    s++;
 
 
 
  /* JPB 18-Aug-10: The old assumption was that any symbol starting with 'r'
 
     and followed by a digit was a register. That was fine when we prepended
 
     underscores, but not when that was dropped. We need to makes sure that
 
     this is a register operand. */
 
  if (is_reg)
 
    {
  if ((*s == 'r') && ISDIGIT (*(s + 1)))
  if ((*s == 'r') && ISDIGIT (*(s + 1)))
    {
        {
      operandp->X_add_number = strtol (s + 1, NULL, 10);
          operandp->X_add_number = strtol (s + 1, NULL, 10);
      operandp->X_op = O_register;
      operandp->X_op = O_register;
      operandp->X_add_symbol = NULL;// Added to stop a know() in machine_ip()
          operandp->X_add_symbol = NULL;// Added to stop know() in machine_ip()
      operandp->X_op_symbol = NULL; // Added to stop a know() in machine_ip()
          operandp->X_op_symbol = NULL; // Added to stop know() in machine_ip()
                                    // erroring out - it appears this wasn't 
                                        // erroring out - it appears this
                                    // getting cleared sometimes. - JB 100718
                                        // wasn't getting cleared sometimes. -
 
                                        // JB 100718
 
        }
 
      else
 
        {
 
          as_bad (_("register expected"));
 
        }
 
 
 
      /* Skip the argument */
      for (; (*s != ',') && (*s != '\0');)
      for (; (*s != ',') && (*s != '\0');)
        s++;
        s++;
      input_line_pointer = save;
      input_line_pointer = save;
      return s;
      return s;
    }
    }
 
 
  expression (operandp);
  expression (operandp);
 
 
  if (operandp->X_op == O_absent)
  if (operandp->X_op == O_absent)
    {
    {
      if (! opt)
      if (! opt)
        as_bad (_("missing operand"));
        as_bad (_("missing operand"));
      else
      else
        {
        {
          operandp->X_add_number = 0;
          operandp->X_add_number = 0;
          operandp->X_op = O_constant;
          operandp->X_op = O_constant;
        }
        }
    }
    }
 
 
  new_pointer = input_line_pointer;
  new_pointer = input_line_pointer;
  input_line_pointer = save;
  input_line_pointer = save;
 
 
#if DEBUG
#if DEBUG
  printf ("  %s=parse_operand(%s): operandp->X_op = %u\n", new_pointer, s,
  printf ("  %s=parse_operand(%s): operandp->X_op = %u\n", new_pointer, s,
          operandp->X_op);
          operandp->X_op);
#endif
#endif
 
 
  return new_pointer;
  return new_pointer;
}
}
 
 
/* Instruction parsing.  Takes a string containing the opcode.
/* Instruction parsing.  Takes a string containing the opcode.
   Operands are at input_line_pointer.  Output is in the_insn.
   Operands are at input_line_pointer.  Output is in the_insn.
   Warnings or errors are generated.  */
   Warnings or errors are generated.  */
 
 
static void
static void
machine_ip (char *str)
machine_ip (char *str)
{
{
  char *s;
  char *s;
  const char *args;
  const char *args;
  const struct machine_opcode *insn;
  const struct machine_opcode *insn;
  unsigned long opcode;
  unsigned long opcode;
  expressionS operand;
  expressionS operand;
  int reloc = BFD_RELOC_NONE;
  int reloc = BFD_RELOC_NONE;
 
 
#if DEBUG
#if DEBUG
  printf ("machine_ip(%s)\n", str);
  printf ("machine_ip(%s)\n", str);
#endif
#endif
 
 
  s = str;
  s = str;
  for (; ISALNUM (*s) || *s == '.' || *s == '_'; ++s)
  for (; ISALNUM (*s) || *s == '.' || *s == '_'; ++s)
    if (ISUPPER (*s))
    if (ISUPPER (*s))
      *s = TOLOWER (*s);
      *s = TOLOWER (*s);
 
 
  switch (*s)
  switch (*s)
    {
    {
    case '\0':
    case '\0':
      break;
      break;
 
 
    case ' ':     /* FIXME-SOMEDAY more whitespace.  */
    case ' ':     /* FIXME-SOMEDAY more whitespace.  */
      *s++ = '\0';
      *s++ = '\0';
      break;
      break;
 
 
    default:
    default:
      as_bad (_("unknown opcode1: `%s'"), str);
      as_bad (_("unknown opcode1: `%s'"), str);
      return;
      return;
    }
    }
 
 
  if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL)
  if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL)
    {
    {
      as_bad (_("unknown opcode2 `%s'."), str);
      as_bad (_("unknown opcode2 `%s'."), str);
      return;
      return;
    }
    }
 
 
  opcode = 0;
  opcode = 0;
  memset (&the_insn, '\0', sizeof (the_insn));
  memset (&the_insn, '\0', sizeof (the_insn));
  the_insn.reloc = BFD_RELOC_NONE;
  the_insn.reloc = BFD_RELOC_NONE;
 
 
  reloc = BFD_RELOC_NONE;
  reloc = BFD_RELOC_NONE;
 
 
  /* Build the opcode, checking as we go to make sure that the
  /* Build the opcode, checking as we go to make sure that the
     operands match.
     operands match.
 
 
     If an operand matches, we modify the_insn or opcode appropriately,
     If an operand matches, we modify the_insn or opcode appropriately,
     and do a "continue".  If an operand fails to match, we "break".  */
     and do a "continue".  If an operand fails to match, we "break".  */
  if (insn->args[0] != '\0')
  if (insn->args[0] != '\0')
    /* Prime the pump.  */
    /* Prime the pump.  */
    s = parse_operand (s,
    s = parse_operand (s,
                       &operand,
                       &operand,
                       (insn->args[0] == 'I') ||
                       (insn->args[0] == 'I') ||
                       (strcmp(insn->name, "l.nop") == 0) );
                       (strcmp(insn->name, "l.nop") == 0),
 
                       'r' == insn->args[0]);
 
 
  for (args = insn->args;; ++args)
  for (args = insn->args;; ++args)
    {
    {
#if DEBUG
#if DEBUG
      printf ("  args = %s\n", args);
      printf ("  args = %s\n", args);
#endif
#endif
      switch (*args)
      switch (*args)
        {
        {
        case '\0':    /* End of args.  */
        case '\0':    /* End of args.  */
          /* We have have 0 args, do the bazoooka!  */
          /* We have have 0 args, do the bazoooka!  */
          if (args == insn->args)
          if (args == insn->args)
            encode (insn, &opcode, 0, 0);
            encode (insn, &opcode, 0, 0);
 
 
          if (*s == '\0')
          if (*s == '\0')
            {
            {
              /* We are truly done.  */
              /* We are truly done.  */
              the_insn.opcode = opcode;
              the_insn.opcode = opcode;
              if (check_invalid_opcode (opcode))
              if (check_invalid_opcode (opcode))
                as_bad (_("instruction not allowed: %s"), str);
                as_bad (_("instruction not allowed: %s"), str);
              return;
              return;
            }
            }
          as_bad (_("too many operands: %s"), s);
          as_bad (_("too many operands: %s"), s);
          break;
          break;
 
 
        case ',':   /* Must match a comma.  */
        case ',':   /* Must match a comma.  */
          if (*s++ == ',')
          if (*s++ == ',')
            {
            {
              reloc = BFD_RELOC_NONE;
              reloc = BFD_RELOC_NONE;
 
 
              /* Parse next operand.  */
              /* Parse next operand.  */
              s = parse_operand (s, &operand, args[1] == 'I');
              s = parse_operand (s, &operand, args[1] == 'I', 'r' == args[1]);
#if DEBUG
#if DEBUG
              printf ("    ',' case: operand->X_add_number = %d, *args = %s, *s = %s\n",
              printf ("    ',' case: operand->X_add_number = %d, *args = %s, *s = %s\n",
                      (int) operand.X_add_number, args, s);
                      (int) operand.X_add_number, args, s);
#endif
#endif
              continue;
              continue;
            }
            }
          break;
          break;
 
 
        case '(':   /* Must match a (.  */
        case '(':   /* Must match a (.  */
          s = parse_operand (s, &operand, args[1] == 'I');
          s = parse_operand (s, &operand, args[1] == 'I', 'r' == args[1]);
          continue;
          continue;
 
 
        case ')':   /* Must match a ).  */
        case ')':   /* Must match a ).  */
          continue;
          continue;
 
 
        case 'r':   /* A general register.  */
        case 'r':   /* A general register.  */
          args++;
          args++;
 
 
          if (operand.X_op != O_register)
          if (operand.X_op != O_register)
            break;    /* Only registers.  */
            break;    /* Only registers.  */
#if DEBUG
#if DEBUG
          printf("   (operand.X_add_symbol == 0)=%d",
          printf("   (operand.X_add_symbol == 0)=%d",
                 (operand.X_add_symbol == NULL));
                 (operand.X_add_symbol == NULL));
          printf("   (operand.X_op_symbol(%x) == 0)=%d",
          printf("   (operand.X_op_symbol(%x) == 0)=%d",
                 (unsigned int)operand.X_op_symbol,
                 (unsigned int)operand.X_op_symbol,
                 (operand.X_op_symbol == NULL));
                 (operand.X_op_symbol == NULL));
#endif    
#endif    
          know (operand.X_add_symbol == NULL);
          know (operand.X_add_symbol == NULL);
          know (operand.X_op_symbol == NULL);
          know (operand.X_op_symbol == NULL);
          encode (insn, &opcode, operand.X_add_number, *args);
          encode (insn, &opcode, operand.X_add_number, *args);
#if DEBUG
#if DEBUG
          printf ("    r: operand->X_op = %d\n", operand.X_op);
          printf ("    r: operand->X_op = %d\n", operand.X_op);
#endif
#endif
          continue;
          continue;
 
 
        default:
        default:
          if (mask_or_shift)
          if (mask_or_shift)
            {
            {
#if DEBUG
#if DEBUG
              printf ("mask_or_shift = %d\n", mask_or_shift);
              printf ("mask_or_shift = %d\n", mask_or_shift);
#endif
#endif
              reloc = mask_or_shift;
              reloc = mask_or_shift;
            }
            }
          mask_or_shift = 0;
          mask_or_shift = 0;
          if (*s == '(')
          if (*s == '(')
            operand.X_op = O_constant;
            operand.X_op = O_constant;
          else if (*s == ')')
          else if (*s == ')')
            s += 1;
            s += 1;
#if DEBUG
#if DEBUG
          printf ("    default case: operand->X_add_number = %d, *args = %s, *s = %s\n",(int) operand.X_add_number, args, s);
          printf ("    default case: operand->X_add_number = %d, *args = %s, *s = %s\n",(int) operand.X_add_number, args, s);
#endif
#endif
          if (operand.X_op == O_constant)
          if (operand.X_op == O_constant)
            {
            {
            unsigned long add = operand.X_add_number;
            unsigned long add = operand.X_add_number;
              if (reloc == BFD_RELOC_NONE)
              if (reloc == BFD_RELOC_NONE)
                {
                {
                  bfd_vma v, mask;
                  bfd_vma v, mask;
 
 
                  mask = 0x3ffffff;
                  mask = 0x3ffffff;
                  v = abs (operand.X_add_number) & ~ mask;
                  v = abs (operand.X_add_number) & ~ mask;
                  if (v)
                  if (v)
                    as_bad (_("call/jmp target out of range (1)"));
                    as_bad (_("call/jmp target out of range (1)"));
                }
                }
 
 
              if (reloc == BFD_RELOC_HI16)
              if (reloc == BFD_RELOC_HI16)
                add = ((operand.X_add_number >> 16) & 0xffff);
                add = ((operand.X_add_number >> 16) & 0xffff);
 
 
              the_insn.pcrel = 0;
              the_insn.pcrel = 0;
              encode (insn, &opcode, add, *args);
              encode (insn, &opcode, add, *args);
              continue;
              continue;
            }
            }
 
 
          if (reloc == BFD_RELOC_NONE)
          if (reloc == BFD_RELOC_NONE)
            the_insn.reloc = BFD_RELOC_28_PCREL_S2;
            the_insn.reloc = BFD_RELOC_28_PCREL_S2;
          else
          else
            the_insn.reloc = reloc;
            the_insn.reloc = reloc;
 
 
          /* the_insn.reloc = insn->reloc;  */
          /* the_insn.reloc = insn->reloc;  */
#if DEBUG
#if DEBUG
          printf ("    reloc sym=%d\n", the_insn.reloc);
          printf ("    reloc sym=%d\n", the_insn.reloc);
          printf ("    BFD_RELOC_NONE=%d\n", BFD_RELOC_NONE);
          printf ("    BFD_RELOC_NONE=%d\n", BFD_RELOC_NONE);
#endif
#endif
          the_insn.exp = operand;
          the_insn.exp = operand;
 
 
          /*  the_insn.reloc_offset = 1;  */
          /*  the_insn.reloc_offset = 1;  */
          the_insn.pcrel = 1; /* Assume PC-relative jump.  */
          the_insn.pcrel = 1; /* Assume PC-relative jump.  */
 
 
          /* FIXME-SOON, Do we figure out whether abs later, after
          /* FIXME-SOON, Do we figure out whether abs later, after
             know sym val?  */
             know sym val?  */
          if (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_HI16)
          if (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_HI16)
            the_insn.pcrel = 0;
            the_insn.pcrel = 0;
 
 
          if (reloc == BFD_RELOC_NONE)
          if (reloc == BFD_RELOC_NONE)
            encode (insn, &opcode, operand.X_add_number, *args);
            encode (insn, &opcode, operand.X_add_number, *args);
          else
          else
            encode (insn, &opcode, 0, *args);
            encode (insn, &opcode, 0, *args);
          continue;
          continue;
        }
        }
 
 
      /* Types or values of args don't match.  */
      /* Types or values of args don't match.  */
      as_bad (_("invalid operands"));
      as_bad (_("invalid operands"));
      return;
      return;
    }
    }
}
}
 
 
char *
char *
md_atof (int type, char * litP, int *  sizeP)
md_atof (int type, char * litP, int *  sizeP)
{
{
  return ieee_md_atof (type, litP, sizeP, TRUE);
  return ieee_md_atof (type, litP, sizeP, TRUE);
}
}
 
 
/* Write out big-endian.  */
/* Write out big-endian.  */
 
 
void
void
md_number_to_chars (char *buf, valueT val, int n)
md_number_to_chars (char *buf, valueT val, int n)
{
{
  number_to_chars_bigendian (buf, val, n);
  number_to_chars_bigendian (buf, val, n);
}
}
 
 
void
void
md_apply_fix (fixS * fixP, valueT * val, segT seg ATTRIBUTE_UNUSED)
md_apply_fix (fixS * fixP, valueT * val, segT seg ATTRIBUTE_UNUSED)
{
{
  bfd_byte *buf;
  bfd_byte *buf;
  long insn;
  long insn;
 
 
  buf = (bfd_byte *) (fixP->fx_where + fixP->fx_frag->fr_literal);
  buf = (bfd_byte *) (fixP->fx_where + fixP->fx_frag->fr_literal);
 
 
#if DEBUG
#if DEBUG
  printf ("md_apply_fix *val=%x fixP->fx_r_type=%i sym=%s\n",(unsigned int)*val,
  printf ("md_apply_fix *val=%x fixP->fx_r_type=%i sym=%s\n",(unsigned int)*val,
           fixP->fx_r_type, fixP->fx_addsy ? fixP->fx_addsy->bsym->name : "(none)");
           fixP->fx_r_type, fixP->fx_addsy ? fixP->fx_addsy->bsym->name : "(none)");
#endif
#endif
 
 
  if ((fixP->fx_addsy == (symbolS *) NULL) && !fixP->fx_pcrel)
  if ((fixP->fx_addsy == (symbolS *) NULL) && !fixP->fx_pcrel)
    fixP->fx_done = 1;
    fixP->fx_done = 1;
 
 
  switch (fixP->fx_r_type)
  switch (fixP->fx_r_type)
    {
    {
    case BFD_RELOC_32:      /* XXXXXXXX pattern in a word.  */
    case BFD_RELOC_32:      /* XXXXXXXX pattern in a word.  */
#if DEBUG
#if DEBUG
      printf ("reloc_const: val=%x\n", (unsigned int) *val);
      printf ("reloc_const: val=%x\n", (unsigned int) *val);
#endif
#endif
      /* If we are deleting this reloc entry, we must fill in the
      /* If we are deleting this reloc entry, we must fill in the
               value now.  This can happen if we have a .word which is not
               value now.  This can happen if we have a .word which is not
               resolved when it appears but is later defined.  We also need
               resolved when it appears but is later defined.  We also need
               to fill in the value if this is an embedded PIC switch table
               to fill in the value if this is an embedded PIC switch table
               entry.  */
               entry.  */
      if (fixP->fx_done)
      if (fixP->fx_done)
        md_number_to_chars ((char *) buf, *val, 4);
        md_number_to_chars ((char *) buf, *val, 4);
      break;
      break;
 
 
    case BFD_RELOC_16:      /* XXXX0000 pattern in a word.  */
    case BFD_RELOC_16:      /* XXXX0000 pattern in a word.  */
#if DEBUG
#if DEBUG
      printf ("reloc_const: val=%x\n", (unsigned int)*val);
      printf ("reloc_const: val=%x\n", (unsigned int)*val);
#endif
#endif
      /* If we are deleting this reloc entry, we must fill in the
      /* If we are deleting this reloc entry, we must fill in the
         value now.  */
         value now.  */
      gas_assert (fixP->fx_size == 2);
      gas_assert (fixP->fx_size == 2);
      if (fixP->fx_done)
      if (fixP->fx_done)
              md_number_to_chars ((char *) buf, *val, 2);
              md_number_to_chars ((char *) buf, *val, 2);
      break;
      break;
 
 
    case BFD_RELOC_8:      /* XX000000 pattern in a word.  */
    case BFD_RELOC_8:      /* XX000000 pattern in a word.  */
    case BFD_RELOC_LO16:      /* 0000XXXX pattern in a word.  */
    case BFD_RELOC_LO16:      /* 0000XXXX pattern in a word.  */
#if DEBUG
#if DEBUG
      printf ("reloc_const: val=%x\n", (unsigned int)*val);
      printf ("reloc_const: val=%x\n", (unsigned int)*val);
#endif
#endif
      break;
      break;
 
 
    case BFD_RELOC_HI16:    /* 0000XXXX pattern in a word.  */
    case BFD_RELOC_HI16:    /* 0000XXXX pattern in a word.  */
#if DEBUG
#if DEBUG
      printf ("reloc_consth: val=%x\n", (unsigned int)*val);
      printf ("reloc_consth: val=%x\n", (unsigned int)*val);
#endif
#endif
      break;
      break;
 
 
    case BFD_RELOC_28_PCREL_S2:  /* 0000XXXX pattern in a word.  */
    case BFD_RELOC_28_PCREL_S2:  /* 0000XXXX pattern in a word.  */
#if DEBUG
#if DEBUG
      printf("reloc_pcrel: *val=%x done=%d fixP->fx_pcrel=%i line=%i\n",
      printf("reloc_pcrel: *val=%x done=%d fixP->fx_pcrel=%i line=%i\n",
             (unsigned int) *val, fixP->fx_done, fixP->fx_pcrel, fixP->fx_line);
             (unsigned int) *val, fixP->fx_done, fixP->fx_pcrel, fixP->fx_line);
#endif
#endif
      if ((*val & 0x3) != 0)
      if ((*val & 0x3) != 0)
        as_bad_where (fixP->fx_file, fixP->fx_line,
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("Branch to odd address (%lx)"), (long) *val);
                      _("Branch to odd address (%lx)"), (long) *val);
 
 
      /*
      /*
       * We need to save the bits in the instruction since fixup_segment()
       * We need to save the bits in the instruction since fixup_segment()
       * might be deleting the relocation entry (i.e., a branch within
       * might be deleting the relocation entry (i.e., a branch within
       * the current segment).
       * the current segment).
       */
       */
      if (! fixP->fx_done)
      if (! fixP->fx_done)
        break;
        break;
 
 
      /* update old instruction data */
      /* update old instruction data */
      if (target_big_endian)
      if (target_big_endian)
        insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
        insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
      else
      else
        insn = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
        insn = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
      insn |= (*val >> 2) & 0x03ffffff;
      insn |= (*val >> 2) & 0x03ffffff;
      md_number_to_chars ((char *) buf, insn, 4);
      md_number_to_chars ((char *) buf, insn, 4);
#if DEBUG
#if DEBUG
      printf("Resulting instruction: %08x\n", (unsigned int)insn);
      printf("Resulting instruction: %08x\n", (unsigned int)insn);
#endif
#endif
      break;
      break;
 
 
    case BFD_RELOC_VTABLE_INHERIT:
    case BFD_RELOC_VTABLE_INHERIT:
    case BFD_RELOC_VTABLE_ENTRY:
    case BFD_RELOC_VTABLE_ENTRY:
      fixP->fx_done = 0;
      fixP->fx_done = 0;
      break;
      break;
 
 
    case BFD_RELOC_NONE:
    case BFD_RELOC_NONE:
    default:
    default:
      as_bad (_("bad relocation type: 0x%02x"), fixP->fx_r_type);
      as_bad (_("bad relocation type: 0x%02x"), fixP->fx_r_type);
      break;
      break;
    }
    }
 
 
  fixP->fx_addnumber = *val; /* Remember value for emit_reloc.  */
  fixP->fx_addnumber = *val; /* Remember value for emit_reloc.  */
}
}
 
 
/* Should never be called for or32.  */
/* Should never be called for or32.  */
 
 
void
void
md_create_short_jump (char *    ptr       ATTRIBUTE_UNUSED,
md_create_short_jump (char *    ptr       ATTRIBUTE_UNUSED,
                      addressT  from_addr ATTRIBUTE_UNUSED,
                      addressT  from_addr ATTRIBUTE_UNUSED,
                      addressT  to_addr   ATTRIBUTE_UNUSED,
                      addressT  to_addr   ATTRIBUTE_UNUSED,
                      fragS *   frag      ATTRIBUTE_UNUSED,
                      fragS *   frag      ATTRIBUTE_UNUSED,
                      symbolS * to_symbol ATTRIBUTE_UNUSED)
                      symbolS * to_symbol ATTRIBUTE_UNUSED)
{
{
  as_fatal ("or32_create_short_jmp\n");
  as_fatal ("or32_create_short_jmp\n");
}
}
 
 
/* Should never be called for or32.  */
/* Should never be called for or32.  */
 
 
void
void
md_convert_frag (bfd *   headers ATTRIBUTE_UNUSED,
md_convert_frag (bfd *   headers ATTRIBUTE_UNUSED,
                 segT    seg     ATTRIBUTE_UNUSED,
                 segT    seg     ATTRIBUTE_UNUSED,
                 fragS * fragP   ATTRIBUTE_UNUSED)
                 fragS * fragP   ATTRIBUTE_UNUSED)
{
{
  as_fatal ("or32_convert_frag\n");
  as_fatal ("or32_convert_frag\n");
}
}
 
 
/* Should never be called for or32.  */
/* Should never be called for or32.  */
 
 
void
void
md_create_long_jump (char *    ptr       ATTRIBUTE_UNUSED,
md_create_long_jump (char *    ptr       ATTRIBUTE_UNUSED,
                     addressT  from_addr ATTRIBUTE_UNUSED,
                     addressT  from_addr ATTRIBUTE_UNUSED,
                     addressT  to_addr   ATTRIBUTE_UNUSED,
                     addressT  to_addr   ATTRIBUTE_UNUSED,
                     fragS *   frag      ATTRIBUTE_UNUSED,
                     fragS *   frag      ATTRIBUTE_UNUSED,
                     symbolS * to_symbol ATTRIBUTE_UNUSED)
                     symbolS * to_symbol ATTRIBUTE_UNUSED)
{
{
  as_fatal ("or32_create_long_jump\n");
  as_fatal ("or32_create_long_jump\n");
}
}
 
 
/* Should never be called for or32.  */
/* Should never be called for or32.  */
 
 
int
int
md_estimate_size_before_relax (fragS * fragP   ATTRIBUTE_UNUSED,
md_estimate_size_before_relax (fragS * fragP   ATTRIBUTE_UNUSED,
                               segT    segtype ATTRIBUTE_UNUSED)
                               segT    segtype ATTRIBUTE_UNUSED)
{
{
  as_fatal ("or32_estimate_size_before_relax\n");
  as_fatal ("or32_estimate_size_before_relax\n");
  return 0;
  return 0;
}
}
 
 
/* Translate internal representation of relocation info to target format.
/* Translate internal representation of relocation info to target format.
 
 
   On sparc/29k: first 4 bytes are normal unsigned long address, next three
   On sparc/29k: first 4 bytes are normal unsigned long address, next three
   bytes are index, most sig. byte first.  Byte 7 is broken up with
   bytes are index, most sig. byte first.  Byte 7 is broken up with
   bit 7 as external, bits 6 & 5 unused, and the lower
   bit 7 as external, bits 6 & 5 unused, and the lower
   five bits as relocation type.  Next 4 bytes are long addend.  */
   five bits as relocation type.  Next 4 bytes are long addend.  */
/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com.  */
/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com.  */
 
 
#ifdef OBJ_AOUT
#ifdef OBJ_AOUT
void
void
tc_aout_fix_to_chars (char *where,
tc_aout_fix_to_chars (char *where,
                      fixS *fixP,
                      fixS *fixP,
                      relax_addressT segment_address_in_file)
                      relax_addressT segment_address_in_file)
{
{
  long r_symbolnum;
  long r_symbolnum;
 
 
#if DEBUG
#if DEBUG
  printf ("tc_aout_fix_to_chars\n");
  printf ("tc_aout_fix_to_chars\n");
#endif
#endif
 
 
  know (fixP->fx_r_type < BFD_RELOC_NONE);
  know (fixP->fx_r_type < BFD_RELOC_NONE);
  know (fixP->fx_addsy != NULL);
  know (fixP->fx_addsy != NULL);
 
 
  md_number_to_chars
  md_number_to_chars
    (where,
    (where,
     fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
     fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
     4);
     4);
 
 
  r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy)
  r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy)
     ? S_GET_TYPE (fixP->fx_addsy)
     ? S_GET_TYPE (fixP->fx_addsy)
     : fixP->fx_addsy->sy_number);
     : fixP->fx_addsy->sy_number);
 
 
  where[4] = (r_symbolnum >> 16) & 0x0ff;
  where[4] = (r_symbolnum >> 16) & 0x0ff;
  where[5] = (r_symbolnum >> 8) & 0x0ff;
  where[5] = (r_symbolnum >> 8) & 0x0ff;
  where[6] = r_symbolnum & 0x0ff;
  where[6] = r_symbolnum & 0x0ff;
  where[7] = (((!S_IS_DEFINED (fixP->fx_addsy)) << 7) & 0x80) | (0 & 0x60) | (fixP->fx_r_type & 0x1F);
  where[7] = (((!S_IS_DEFINED (fixP->fx_addsy)) << 7) & 0x80) | (0 & 0x60) | (fixP->fx_r_type & 0x1F);
 
 
  /* Also easy.  */
  /* Also easy.  */
  md_number_to_chars (&where[8], fixP->fx_addnumber, 4);
  md_number_to_chars (&where[8], fixP->fx_addnumber, 4);
}
}
 
 
#endif /* OBJ_AOUT */
#endif /* OBJ_AOUT */


const char *md_shortopts = "";
const char *md_shortopts = "";
 
 
struct option md_longopts[] =
struct option md_longopts[] =
{
{
  { NULL, no_argument, NULL, 0 }
  { NULL, no_argument, NULL, 0 }
};
};
size_t md_longopts_size = sizeof (md_longopts);
size_t md_longopts_size = sizeof (md_longopts);
 
 
int
int
md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED)
md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED)
{
{
  return 0;
  return 0;
}
}
 
 
void
void
md_show_usage (FILE * stream ATTRIBUTE_UNUSED)
md_show_usage (FILE * stream ATTRIBUTE_UNUSED)
{
{
}
}


/* This is called when a line is unrecognized.  This is used to handle
/* This is called when a line is unrecognized.  This is used to handle
   definitions of or32 style local labels.  */
   definitions of or32 style local labels.  */
 
 
int
int
or32_unrecognized_line (int c)
or32_unrecognized_line (int c)
{
{
  int lab;
  int lab;
  char *s;
  char *s;
 
 
  if (c != '$'
  if (c != '$'
      || ! ISDIGIT ((unsigned char) input_line_pointer[0]))
      || ! ISDIGIT ((unsigned char) input_line_pointer[0]))
    return 0;
    return 0;
 
 
  s = input_line_pointer;
  s = input_line_pointer;
 
 
  lab = 0;
  lab = 0;
  while (ISDIGIT ((unsigned char) *s))
  while (ISDIGIT ((unsigned char) *s))
    {
    {
      lab = lab * 10 + *s - '0';
      lab = lab * 10 + *s - '0';
      ++s;
      ++s;
    }
    }
 
 
  if (*s != ':')
  if (*s != ':')
    /* Not a label definition.  */
    /* Not a label definition.  */
    return 0;
    return 0;
 
 
  if (dollar_label_defined (lab))
  if (dollar_label_defined (lab))
    {
    {
      as_bad (_("label \"$%d\" redefined"), lab);
      as_bad (_("label \"$%d\" redefined"), lab);
      return 0;
      return 0;
    }
    }
 
 
  define_dollar_label (lab);
  define_dollar_label (lab);
  colon (dollar_label_name (lab, 0));
  colon (dollar_label_name (lab, 0));
  input_line_pointer = s + 1;
  input_line_pointer = s + 1;
 
 
  return 1;
  return 1;
}
}
 
 
/* Default the values of symbols known that should be "predefined".  We
/* Default the values of symbols known that should be "predefined".  We
   don't bother to predefine them unless you actually use one, since there
   don't bother to predefine them unless you actually use one, since there
   are a lot of them.  */
   are a lot of them.  */
 
 
symbolS *
symbolS *
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
{
{
  return NULL;
  return NULL;
}
}
 
 
/* Parse an operand that is machine-specific.  */
/* Parse an operand that is machine-specific.  */
 
 
void
void
md_operand (expressionS *expressionP)
md_operand (expressionS *expressionP)
{
{
#if DEBUG
#if DEBUG
  printf ("  md_operand(input_line_pointer = %s)\n", input_line_pointer);
  printf ("  md_operand(input_line_pointer = %s)\n", input_line_pointer);
#endif
#endif
 
 
  if (input_line_pointer[0] == REGISTER_PREFIX && input_line_pointer[1] == 'r')
  if (input_line_pointer[0] == REGISTER_PREFIX && input_line_pointer[1] == 'r')
    {
    {
      /* We have a numeric register expression.  No biggy.  */
      /* We have a numeric register expression.  No biggy.  */
      input_line_pointer += 2;  /* Skip %r */
      input_line_pointer += 2;  /* Skip %r */
      (void) expression (expressionP);
      (void) expression (expressionP);
 
 
      if (expressionP->X_op != O_constant
      if (expressionP->X_op != O_constant
          || expressionP->X_add_number > 255)
          || expressionP->X_add_number > 255)
        as_bad (_("Invalid expression after %%%%\n"));
        as_bad (_("Invalid expression after %%%%\n"));
      expressionP->X_op = O_register;
      expressionP->X_op = O_register;
    }
    }
  else if (input_line_pointer[0] == '&')
  else if (input_line_pointer[0] == '&')
    {
    {
      /* We are taking the 'address' of a register...this one is not
      /* We are taking the 'address' of a register...this one is not
         in the manual, but it *is* in traps/fpsymbol.h!  What they
         in the manual, but it *is* in traps/fpsymbol.h!  What they
         seem to want is the register number, as an absolute number.  */
         seem to want is the register number, as an absolute number.  */
      input_line_pointer++; /* Skip & */
      input_line_pointer++; /* Skip & */
      (void) expression (expressionP);
      (void) expression (expressionP);
 
 
      if (expressionP->X_op != O_register)
      if (expressionP->X_op != O_register)
        as_bad (_("invalid register in & expression"));
        as_bad (_("invalid register in & expression"));
      else
      else
        expressionP->X_op = O_constant;
        expressionP->X_op = O_constant;
    }
    }
  else if (input_line_pointer[0] == '$'
  else if (input_line_pointer[0] == '$'
           && ISDIGIT ((unsigned char) input_line_pointer[1]))
           && ISDIGIT ((unsigned char) input_line_pointer[1]))
    {
    {
      long lab;
      long lab;
      char *name;
      char *name;
      symbolS *sym;
      symbolS *sym;
 
 
      /* This is a local label.  */
      /* This is a local label.  */
      ++input_line_pointer;
      ++input_line_pointer;
      lab = (long) get_absolute_expression ();
      lab = (long) get_absolute_expression ();
 
 
      if (dollar_label_defined (lab))
      if (dollar_label_defined (lab))
        {
        {
          name = dollar_label_name (lab, 0);
          name = dollar_label_name (lab, 0);
          sym = symbol_find (name);
          sym = symbol_find (name);
        }
        }
      else
      else
        {
        {
          name = dollar_label_name (lab, 1);
          name = dollar_label_name (lab, 1);
          sym = symbol_find_or_make (name);
          sym = symbol_find_or_make (name);
        }
        }
 
 
      expressionP->X_op = O_symbol;
      expressionP->X_op = O_symbol;
      expressionP->X_add_symbol = sym;
      expressionP->X_add_symbol = sym;
      expressionP->X_add_number = 0;
      expressionP->X_add_number = 0;
    }
    }
  else if (input_line_pointer[0] == '$')
  else if (input_line_pointer[0] == '$')
    {
    {
      char *s;
      char *s;
      char type;
      char type;
      int fieldnum, fieldlimit;
      int fieldnum, fieldlimit;
      LITTLENUM_TYPE floatbuf[8];
      LITTLENUM_TYPE floatbuf[8];
 
 
      /* $float(), $doubleN(), or $extendN() convert floating values
      /* $float(), $doubleN(), or $extendN() convert floating values
         to integers.  */
         to integers.  */
      s = input_line_pointer;
      s = input_line_pointer;
 
 
      ++s;
      ++s;
 
 
      fieldnum = 0;
      fieldnum = 0;
      if (strncmp (s, "double", sizeof "double" - 1) == 0)
      if (strncmp (s, "double", sizeof "double" - 1) == 0)
        {
        {
          s += sizeof "double" - 1;
          s += sizeof "double" - 1;
          type = 'd';
          type = 'd';
          fieldlimit = 2;
          fieldlimit = 2;
        }
        }
      else if (strncmp (s, "float", sizeof "float" - 1) == 0)
      else if (strncmp (s, "float", sizeof "float" - 1) == 0)
        {
        {
          s += sizeof "float" - 1;
          s += sizeof "float" - 1;
          type = 'f';
          type = 'f';
          fieldlimit = 1;
          fieldlimit = 1;
        }
        }
      else if (strncmp (s, "extend", sizeof "extend" - 1) == 0)
      else if (strncmp (s, "extend", sizeof "extend" - 1) == 0)
        {
        {
          s += sizeof "extend" - 1;
          s += sizeof "extend" - 1;
          type = 'x';
          type = 'x';
          fieldlimit = 4;
          fieldlimit = 4;
        }
        }
      else
      else
        return;
        return;
 
 
      if (ISDIGIT (*s))
      if (ISDIGIT (*s))
        {
        {
          fieldnum = *s - '0';
          fieldnum = *s - '0';
          ++s;
          ++s;
        }
        }
      if (fieldnum >= fieldlimit)
      if (fieldnum >= fieldlimit)
        return;
        return;
 
 
      SKIP_WHITESPACE ();
      SKIP_WHITESPACE ();
      if (*s != '(')
      if (*s != '(')
        return;
        return;
      ++s;
      ++s;
      SKIP_WHITESPACE ();
      SKIP_WHITESPACE ();
 
 
      s = atof_ieee (s, type, floatbuf);
      s = atof_ieee (s, type, floatbuf);
      if (s == NULL)
      if (s == NULL)
        return;
        return;
      s = s;
      s = s;
 
 
      SKIP_WHITESPACE ();
      SKIP_WHITESPACE ();
      if (*s != ')')
      if (*s != ')')
        return;
        return;
      ++s;
      ++s;
      SKIP_WHITESPACE ();
      SKIP_WHITESPACE ();
 
 
      input_line_pointer = s;
      input_line_pointer = s;
      expressionP->X_op = O_constant;
      expressionP->X_op = O_constant;
      expressionP->X_unsigned = 1;
      expressionP->X_unsigned = 1;
      expressionP->X_add_number = ((floatbuf[fieldnum * 2]
      expressionP->X_add_number = ((floatbuf[fieldnum * 2]
                                    << LITTLENUM_NUMBER_OF_BITS)
                                    << LITTLENUM_NUMBER_OF_BITS)
                                   + floatbuf[fieldnum * 2 + 1]);
                                   + floatbuf[fieldnum * 2 + 1]);
    }
    }
}
}
 
 
/* Round up a section size to the appropriate boundary.  */
/* Round up a section size to the appropriate boundary.  */
 
 
valueT
valueT
md_section_align (asection * seg, valueT addr ATTRIBUTE_UNUSED)
md_section_align (asection * seg, valueT addr ATTRIBUTE_UNUSED)
{
{
  int align = bfd_get_section_alignment (stdoutput, seg);
  int align = bfd_get_section_alignment (stdoutput, seg);
  return ((addr + (1 << align) - 1) & (-1 << align));
  return ((addr + (1 << align) - 1) & (-1 << align));
}
}
 
 
/* Exactly what point is a PC-relative offset relative TO?
/* Exactly what point is a PC-relative offset relative TO?
   On the 29000, they're relative to the address of the instruction,
   On the 29000, they're relative to the address of the instruction,
   which we have set up as the address of the fixup too.  */
   which we have set up as the address of the fixup too.  */
 
 
long
long
md_pcrel_from (fixS *fixP)
md_pcrel_from (fixS *fixP)
{
{
  return fixP->fx_where + fixP->fx_frag->fr_address;
  return fixP->fx_where + fixP->fx_frag->fr_address;
}
}
 
 
/* Generate a reloc for a fixup.  */
/* Generate a reloc for a fixup.  */
 
 
arelent *
arelent *
tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
{
{
  arelent *reloc;
  arelent *reloc;
 
 
  reloc = xmalloc (sizeof (arelent));
  reloc = xmalloc (sizeof (arelent));
  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
 
 
  if (reloc->howto == (reloc_howto_type *) NULL)
  if (reloc->howto == (reloc_howto_type *) NULL)
    {
    {
      as_bad_where (fixp->fx_file, fixp->fx_line,
      as_bad_where (fixp->fx_file, fixp->fx_line,
                    _("reloc %d not supported by object file format"),
                    _("reloc %d not supported by object file format"),
                    (int) fixp->fx_r_type);
                    (int) fixp->fx_r_type);
      return NULL;
      return NULL;
    }
    }
 
 
  if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
  if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
    reloc->address = fixp->fx_offset;
    reloc->address = fixp->fx_offset;
  else if (fixp->fx_pcrel)
  else if (fixp->fx_pcrel)
  {
  {
    bfd_vma pcrel_address;
    bfd_vma pcrel_address;
    pcrel_address = reloc->address;
    pcrel_address = reloc->address;
    if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
    if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
    {
    {
      /* At this point, fx_addnumber is "symbol offset - pcrel_address".
      /* At this point, fx_addnumber is "symbol offset - pcrel_address".
               Relocations want only the symbol offset.  */
               Relocations want only the symbol offset.  */
      reloc->addend = fixp->fx_addnumber;
      reloc->addend = fixp->fx_addnumber;
    }
    }
    else
    else
    {
    {
      if (OUTPUT_FLAVOR != bfd_target_aout_flavour)
      if (OUTPUT_FLAVOR != bfd_target_aout_flavour)
        /* A gruesome hack which is a result of the gruesome gas reloc
        /* A gruesome hack which is a result of the gruesome gas reloc
           handling.  */
           handling.  */
        reloc->addend = pcrel_address;
        reloc->addend = pcrel_address;
      else
      else
        reloc->addend = -pcrel_address;
        reloc->addend = -pcrel_address;
    }
    }
  }
  }
  else
  else
    reloc->addend = fixp->fx_addnumber;
    reloc->addend = fixp->fx_addnumber;
  return reloc;
  return reloc;
}
}
 
 

powered by: WebSVN 2.1.0

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