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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [binutils-2.18.50/] [gas/] [config/] [tc-mn10200.c] - Diff between revs 38 and 156

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

Rev 38 Rev 156
/* tc-mn10200.c -- Assembler code for the Matsushita 10200
/* tc-mn10200.c -- Assembler code for the Matsushita 10200
   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
   2005, 2006, 2007  Free Software Foundation, Inc.
   2005, 2006, 2007  Free Software Foundation, Inc.
 
 
   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.  */
 
 
#include "as.h"
#include "as.h"
#include "safe-ctype.h"
#include "safe-ctype.h"
#include "subsegs.h"
#include "subsegs.h"
#include "opcode/mn10200.h"
#include "opcode/mn10200.h"


/* Structure to hold information about predefined registers.  */
/* Structure to hold information about predefined registers.  */
struct reg_name
struct reg_name
{
{
  const char *name;
  const char *name;
  int value;
  int value;
};
};
 
 
/* Generic assembler global variables which must be defined by all
/* Generic assembler global variables which must be defined by all
   targets.  */
   targets.  */
 
 
/* Characters which always start a comment.  */
/* Characters which always start a comment.  */
const char comment_chars[] = "#";
const char comment_chars[] = "#";
 
 
/* Characters which start a comment at the beginning of a line.  */
/* Characters which start a comment at the beginning of a line.  */
const char line_comment_chars[] = ";#";
const char line_comment_chars[] = ";#";
 
 
/* Characters which may be used to separate multiple commands on a
/* Characters which may be used to separate multiple commands on a
   single line.  */
   single line.  */
const char line_separator_chars[] = ";";
const char line_separator_chars[] = ";";
 
 
/* Characters which are used to indicate an exponent in a floating
/* Characters which are used to indicate an exponent in a floating
   point number.  */
   point number.  */
const char EXP_CHARS[] = "eE";
const char EXP_CHARS[] = "eE";
 
 
/* Characters which mean that a number is a floating point constant,
/* Characters which mean that a number is a floating point constant,
   as in 0d1.0.  */
   as in 0d1.0.  */
const char FLT_CHARS[] = "dD";
const char FLT_CHARS[] = "dD";


const relax_typeS md_relax_table[] =
const relax_typeS md_relax_table[] =
 {
 {
  /* bCC relaxing  */
  /* bCC relaxing  */
  {0x81, -0x7e, 2, 1},
  {0x81, -0x7e, 2, 1},
  {0x8004, -0x7ffb, 5, 2},
  {0x8004, -0x7ffb, 5, 2},
  {0x800006, -0x7ffff9, 7, 0},
  {0x800006, -0x7ffff9, 7, 0},
  /* bCCx relaxing  */
  /* bCCx relaxing  */
  {0x81, -0x7e, 3, 4},
  {0x81, -0x7e, 3, 4},
  {0x8004, -0x7ffb, 6, 5},
  {0x8004, -0x7ffb, 6, 5},
  {0x800006, -0x7ffff9, 8, 0},
  {0x800006, -0x7ffff9, 8, 0},
  /* jsr relaxing  */
  /* jsr relaxing  */
  {0x8004, -0x7ffb, 3, 7},
  {0x8004, -0x7ffb, 3, 7},
  {0x800006, -0x7ffff9, 5, 0},
  {0x800006, -0x7ffff9, 5, 0},
  /* jmp relaxing  */
  /* jmp relaxing  */
  {0x81, -0x7e, 2, 9},
  {0x81, -0x7e, 2, 9},
  {0x8004, -0x7ffb, 3, 10},
  {0x8004, -0x7ffb, 3, 10},
  {0x800006, -0x7ffff9, 5, 0},
  {0x800006, -0x7ffff9, 5, 0},
 
 
};
};
 
 
 
 
/* Fixups.  */
/* Fixups.  */
#define MAX_INSN_FIXUPS 5
#define MAX_INSN_FIXUPS 5
 
 
struct mn10200_fixup
struct mn10200_fixup
{
{
  expressionS exp;
  expressionS exp;
  int opindex;
  int opindex;
  bfd_reloc_code_real_type reloc;
  bfd_reloc_code_real_type reloc;
};
};
 
 
struct mn10200_fixup fixups[MAX_INSN_FIXUPS];
struct mn10200_fixup fixups[MAX_INSN_FIXUPS];
static int fc;
static int fc;


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);
 
 
/* The target specific pseudo-ops which we support.  */
/* The target specific pseudo-ops which we support.  */
const pseudo_typeS md_pseudo_table[] =
const pseudo_typeS md_pseudo_table[] =
{
{
  { NULL,       NULL,           0 }
  { NULL,       NULL,           0 }
};
};
 
 
/* Opcode hash table.  */
/* Opcode hash table.  */
static struct hash_control *mn10200_hash;
static struct hash_control *mn10200_hash;
 
 
/* This table is sorted. Suitable for searching by a binary search.  */
/* This table is sorted. Suitable for searching by a binary search.  */
static const struct reg_name data_registers[] =
static const struct reg_name data_registers[] =
{
{
  { "d0", 0 },
  { "d0", 0 },
  { "d1", 1 },
  { "d1", 1 },
  { "d2", 2 },
  { "d2", 2 },
  { "d3", 3 },
  { "d3", 3 },
};
};
#define DATA_REG_NAME_CNT                               \
#define DATA_REG_NAME_CNT                               \
  (sizeof (data_registers) / sizeof (struct reg_name))
  (sizeof (data_registers) / sizeof (struct reg_name))
 
 
static const struct reg_name address_registers[] =
static const struct reg_name address_registers[] =
{
{
  { "a0", 0 },
  { "a0", 0 },
  { "a1", 1 },
  { "a1", 1 },
  { "a2", 2 },
  { "a2", 2 },
  { "a3", 3 },
  { "a3", 3 },
};
};
#define ADDRESS_REG_NAME_CNT                                    \
#define ADDRESS_REG_NAME_CNT                                    \
  (sizeof (address_registers) / sizeof (struct reg_name))
  (sizeof (address_registers) / sizeof (struct reg_name))
 
 
static const struct reg_name other_registers[] =
static const struct reg_name other_registers[] =
{
{
  { "mdr", 0 },
  { "mdr", 0 },
  { "psw", 0 },
  { "psw", 0 },
};
};
#define OTHER_REG_NAME_CNT                              \
#define OTHER_REG_NAME_CNT                              \
  (sizeof (other_registers) / sizeof (struct reg_name))
  (sizeof (other_registers) / sizeof (struct reg_name))
 
 
/* reg_name_search does a binary search of the given register table
/* reg_name_search does a binary search of the given register table
   to see if "name" is a valid regiter name.  Returns the register
   to see if "name" is a valid regiter name.  Returns the register
   number from the array on success, or -1 on failure.  */
   number from the array on success, or -1 on failure.  */
 
 
static int
static int
reg_name_search (const struct reg_name *regs,
reg_name_search (const struct reg_name *regs,
                 int regcount,
                 int regcount,
                 const char *name)
                 const char *name)
{
{
  int middle, low, high;
  int middle, low, high;
  int cmp;
  int cmp;
 
 
  low = 0;
  low = 0;
  high = regcount - 1;
  high = regcount - 1;
 
 
  do
  do
    {
    {
      middle = (low + high) / 2;
      middle = (low + high) / 2;
      cmp = strcasecmp (name, regs[middle].name);
      cmp = strcasecmp (name, regs[middle].name);
      if (cmp < 0)
      if (cmp < 0)
        high = middle - 1;
        high = middle - 1;
      else if (cmp > 0)
      else if (cmp > 0)
        low = middle + 1;
        low = middle + 1;
      else
      else
        return regs[middle].value;
        return regs[middle].value;
    }
    }
  while (low <= high);
  while (low <= high);
  return -1;
  return -1;
}
}
 
 
/* Summary of register_name().
/* Summary of register_name().
 
 
   in: Input_line_pointer points to 1st char of operand.
   in: Input_line_pointer points to 1st char of operand.
 
 
   out: An expressionS.
   out: An expressionS.
        The operand may have been a register: in this case, X_op == O_register,
        The operand may have been a register: in this case, X_op == O_register,
        X_add_number is set to the register number, and truth is returned.
        X_add_number is set to the register number, and truth is returned.
        Input_line_pointer->(next non-blank) char after operand, or is in
        Input_line_pointer->(next non-blank) char after operand, or is in
        its original state.  */
        its original state.  */
 
 
static bfd_boolean
static bfd_boolean
data_register_name (expressionS *expressionP)
data_register_name (expressionS *expressionP)
{
{
  int reg_number;
  int reg_number;
  char *name;
  char *name;
  char *start;
  char *start;
  char c;
  char c;
 
 
  /* Find the spelling of the operand.  */
  /* Find the spelling of the operand.  */
  start = name = input_line_pointer;
  start = name = input_line_pointer;
 
 
  c = get_symbol_end ();
  c = get_symbol_end ();
  reg_number = reg_name_search (data_registers, DATA_REG_NAME_CNT, name);
  reg_number = reg_name_search (data_registers, DATA_REG_NAME_CNT, name);
 
 
  /* Put back the delimiting char.  */
  /* Put back the delimiting char.  */
  *input_line_pointer = c;
  *input_line_pointer = c;
 
 
  /* Look to see if it's in the register table.  */
  /* Look to see if it's in the register table.  */
  if (reg_number >= 0)
  if (reg_number >= 0)
    {
    {
      expressionP->X_op = O_register;
      expressionP->X_op = O_register;
      expressionP->X_add_number = reg_number;
      expressionP->X_add_number = reg_number;
 
 
      /* Make the rest nice.  */
      /* Make the rest nice.  */
      expressionP->X_add_symbol = NULL;
      expressionP->X_add_symbol = NULL;
      expressionP->X_op_symbol = NULL;
      expressionP->X_op_symbol = NULL;
 
 
      return TRUE;
      return TRUE;
    }
    }
 
 
  /* Reset the line as if we had not done anything.  */
  /* Reset the line as if we had not done anything.  */
  input_line_pointer = start;
  input_line_pointer = start;
  return FALSE;
  return FALSE;
}
}
 
 
/* Summary of register_name().
/* Summary of register_name().
 
 
   in: Input_line_pointer points to 1st char of operand.
   in: Input_line_pointer points to 1st char of operand.
 
 
   out: An expressionS.
   out: An expressionS.
        The operand may have been a register: in this case, X_op == O_register,
        The operand may have been a register: in this case, X_op == O_register,
        X_add_number is set to the register number, and truth is returned.
        X_add_number is set to the register number, and truth is returned.
        Input_line_pointer->(next non-blank) char after operand, or is in
        Input_line_pointer->(next non-blank) char after operand, or is in
        its original state.  */
        its original state.  */
 
 
static bfd_boolean
static bfd_boolean
address_register_name (expressionS *expressionP)
address_register_name (expressionS *expressionP)
{
{
  int reg_number;
  int reg_number;
  char *name;
  char *name;
  char *start;
  char *start;
  char c;
  char c;
 
 
  /* Find the spelling of the operand.  */
  /* Find the spelling of the operand.  */
  start = name = input_line_pointer;
  start = name = input_line_pointer;
 
 
  c = get_symbol_end ();
  c = get_symbol_end ();
  reg_number = reg_name_search (address_registers, ADDRESS_REG_NAME_CNT, name);
  reg_number = reg_name_search (address_registers, ADDRESS_REG_NAME_CNT, name);
 
 
  /* Put back the delimiting char.  */
  /* Put back the delimiting char.  */
  *input_line_pointer = c;
  *input_line_pointer = c;
 
 
  /* Look to see if it's in the register table.  */
  /* Look to see if it's in the register table.  */
  if (reg_number >= 0)
  if (reg_number >= 0)
    {
    {
      expressionP->X_op = O_register;
      expressionP->X_op = O_register;
      expressionP->X_add_number = reg_number;
      expressionP->X_add_number = reg_number;
 
 
      /* Make the rest nice.  */
      /* Make the rest nice.  */
      expressionP->X_add_symbol = NULL;
      expressionP->X_add_symbol = NULL;
      expressionP->X_op_symbol = NULL;
      expressionP->X_op_symbol = NULL;
 
 
      return TRUE;
      return TRUE;
    }
    }
 
 
  /* Reset the line as if we had not done anything.  */
  /* Reset the line as if we had not done anything.  */
  input_line_pointer = start;
  input_line_pointer = start;
  return FALSE;
  return FALSE;
}
}
 
 
/* Summary of register_name().
/* Summary of register_name().
 
 
   in: Input_line_pointer points to 1st char of operand.
   in: Input_line_pointer points to 1st char of operand.
 
 
   out: An expressionS.
   out: An expressionS.
        The operand may have been a register: in this case, X_op == O_register,
        The operand may have been a register: in this case, X_op == O_register,
        X_add_number is set to the register number, and truth is returned.
        X_add_number is set to the register number, and truth is returned.
        Input_line_pointer->(next non-blank) char after operand, or is in
        Input_line_pointer->(next non-blank) char after operand, or is in
        its original state.  */
        its original state.  */
 
 
static bfd_boolean
static bfd_boolean
other_register_name (expressionS *expressionP)
other_register_name (expressionS *expressionP)
{
{
  int reg_number;
  int reg_number;
  char *name;
  char *name;
  char *start;
  char *start;
  char c;
  char c;
 
 
  /* Find the spelling of the operand.  */
  /* Find the spelling of the operand.  */
  start = name = input_line_pointer;
  start = name = input_line_pointer;
 
 
  c = get_symbol_end ();
  c = get_symbol_end ();
  reg_number = reg_name_search (other_registers, OTHER_REG_NAME_CNT, name);
  reg_number = reg_name_search (other_registers, OTHER_REG_NAME_CNT, name);
 
 
  /* Put back the delimiting char.  */
  /* Put back the delimiting char.  */
  *input_line_pointer = c;
  *input_line_pointer = c;
 
 
  /* Look to see if it's in the register table.  */
  /* Look to see if it's in the register table.  */
  if (reg_number >= 0)
  if (reg_number >= 0)
    {
    {
      expressionP->X_op = O_register;
      expressionP->X_op = O_register;
      expressionP->X_add_number = reg_number;
      expressionP->X_add_number = reg_number;
 
 
      /* Make the rest nice.  */
      /* Make the rest nice.  */
      expressionP->X_add_symbol = NULL;
      expressionP->X_add_symbol = NULL;
      expressionP->X_op_symbol = NULL;
      expressionP->X_op_symbol = NULL;
 
 
      return TRUE;
      return TRUE;
    }
    }
 
 
  /* Reset the line as if we had not done anything.  */
  /* Reset the line as if we had not done anything.  */
  input_line_pointer = start;
  input_line_pointer = start;
  return FALSE;
  return FALSE;
}
}
 
 
void
void
md_show_usage (FILE *stream)
md_show_usage (FILE *stream)
{
{
  fprintf (stream, _("MN10200 options:\n\
  fprintf (stream, _("MN10200 options:\n\
none yet\n"));
none yet\n"));
}
}
 
 
int
int
md_parse_option (int c ATTRIBUTE_UNUSED,
md_parse_option (int c ATTRIBUTE_UNUSED,
                 char *arg ATTRIBUTE_UNUSED)
                 char *arg ATTRIBUTE_UNUSED)
{
{
  return 0;
  return 0;
}
}
 
 
symbolS *
symbolS *
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
{
{
  return 0;
  return 0;
}
}
 
 
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, FALSE);
  return ieee_md_atof (type, litp, sizep, FALSE);
}
}
 
 
void
void
md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
                 asection *sec,
                 asection *sec,
                 fragS *fragP)
                 fragS *fragP)
{
{
  static unsigned long label_count = 0;
  static unsigned long label_count = 0;
  char buf[40];
  char buf[40];
 
 
  subseg_change (sec, 0);
  subseg_change (sec, 0);
  if (fragP->fr_subtype == 0)
  if (fragP->fr_subtype == 0)
    {
    {
      fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
      fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
      fragP->fr_var = 0;
      fragP->fr_var = 0;
      fragP->fr_fix += 2;
      fragP->fr_fix += 2;
    }
    }
  else if (fragP->fr_subtype == 1)
  else if (fragP->fr_subtype == 1)
    {
    {
      /* Reverse the condition of the first branch.  */
      /* Reverse the condition of the first branch.  */
      int offset = fragP->fr_fix;
      int offset = fragP->fr_fix;
      int opcode = fragP->fr_literal[offset] & 0xff;
      int opcode = fragP->fr_literal[offset] & 0xff;
 
 
      switch (opcode)
      switch (opcode)
        {
        {
        case 0xe8:
        case 0xe8:
          opcode = 0xe9;
          opcode = 0xe9;
          break;
          break;
        case 0xe9:
        case 0xe9:
          opcode = 0xe8;
          opcode = 0xe8;
          break;
          break;
        case 0xe0:
        case 0xe0:
          opcode = 0xe2;
          opcode = 0xe2;
          break;
          break;
        case 0xe2:
        case 0xe2:
          opcode = 0xe0;
          opcode = 0xe0;
          break;
          break;
        case 0xe3:
        case 0xe3:
          opcode = 0xe1;
          opcode = 0xe1;
          break;
          break;
        case 0xe1:
        case 0xe1:
          opcode = 0xe3;
          opcode = 0xe3;
          break;
          break;
        case 0xe4:
        case 0xe4:
          opcode = 0xe6;
          opcode = 0xe6;
          break;
          break;
        case 0xe6:
        case 0xe6:
          opcode = 0xe4;
          opcode = 0xe4;
          break;
          break;
        case 0xe7:
        case 0xe7:
          opcode = 0xe5;
          opcode = 0xe5;
          break;
          break;
        case 0xe5:
        case 0xe5:
          opcode = 0xe7;
          opcode = 0xe7;
          break;
          break;
        default:
        default:
          abort ();
          abort ();
        }
        }
      fragP->fr_literal[offset] = opcode;
      fragP->fr_literal[offset] = opcode;
 
 
      /* Create a fixup for the reversed conditional branch.  */
      /* Create a fixup for the reversed conditional branch.  */
      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
      fix_new (fragP, fragP->fr_fix + 1, 1,
      fix_new (fragP, fragP->fr_fix + 1, 1,
               symbol_new (buf, sec, 0, fragP->fr_next),
               symbol_new (buf, sec, 0, fragP->fr_next),
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
 
 
      /* Now create the unconditional branch + fixup to the
      /* Now create the unconditional branch + fixup to the
         final target.  */
         final target.  */
      fragP->fr_literal[offset + 2] = 0xfc;
      fragP->fr_literal[offset + 2] = 0xfc;
      fix_new (fragP, fragP->fr_fix + 3, 2, fragP->fr_symbol,
      fix_new (fragP, fragP->fr_fix + 3, 2, fragP->fr_symbol,
               fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
      fragP->fr_var = 0;
      fragP->fr_var = 0;
      fragP->fr_fix += 5;
      fragP->fr_fix += 5;
    }
    }
  else if (fragP->fr_subtype == 2)
  else if (fragP->fr_subtype == 2)
    {
    {
      /* Reverse the condition of the first branch.  */
      /* Reverse the condition of the first branch.  */
      int offset = fragP->fr_fix;
      int offset = fragP->fr_fix;
      int opcode = fragP->fr_literal[offset] & 0xff;
      int opcode = fragP->fr_literal[offset] & 0xff;
 
 
      switch (opcode)
      switch (opcode)
        {
        {
        case 0xe8:
        case 0xe8:
          opcode = 0xe9;
          opcode = 0xe9;
          break;
          break;
        case 0xe9:
        case 0xe9:
          opcode = 0xe8;
          opcode = 0xe8;
          break;
          break;
        case 0xe0:
        case 0xe0:
          opcode = 0xe2;
          opcode = 0xe2;
          break;
          break;
        case 0xe2:
        case 0xe2:
          opcode = 0xe0;
          opcode = 0xe0;
          break;
          break;
        case 0xe3:
        case 0xe3:
          opcode = 0xe1;
          opcode = 0xe1;
          break;
          break;
        case 0xe1:
        case 0xe1:
          opcode = 0xe3;
          opcode = 0xe3;
          break;
          break;
        case 0xe4:
        case 0xe4:
          opcode = 0xe6;
          opcode = 0xe6;
          break;
          break;
        case 0xe6:
        case 0xe6:
          opcode = 0xe4;
          opcode = 0xe4;
          break;
          break;
        case 0xe7:
        case 0xe7:
          opcode = 0xe5;
          opcode = 0xe5;
          break;
          break;
        case 0xe5:
        case 0xe5:
          opcode = 0xe7;
          opcode = 0xe7;
          break;
          break;
        default:
        default:
          abort ();
          abort ();
        }
        }
      fragP->fr_literal[offset] = opcode;
      fragP->fr_literal[offset] = opcode;
 
 
      /* Create a fixup for the reversed conditional branch.  */
      /* Create a fixup for the reversed conditional branch.  */
      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
      fix_new (fragP, fragP->fr_fix + 1, 1,
      fix_new (fragP, fragP->fr_fix + 1, 1,
               symbol_new (buf, sec, 0, fragP->fr_next),
               symbol_new (buf, sec, 0, fragP->fr_next),
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
 
 
      /* Now create the unconditional branch + fixup to the
      /* Now create the unconditional branch + fixup to the
         final target.  */
         final target.  */
      fragP->fr_literal[offset + 2] = 0xf4;
      fragP->fr_literal[offset + 2] = 0xf4;
      fragP->fr_literal[offset + 3] = 0xe0;
      fragP->fr_literal[offset + 3] = 0xe0;
      fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol,
      fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol,
               fragP->fr_offset, 1, BFD_RELOC_24_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_24_PCREL);
      fragP->fr_var = 0;
      fragP->fr_var = 0;
      fragP->fr_fix += 7;
      fragP->fr_fix += 7;
    }
    }
  else if (fragP->fr_subtype == 3)
  else if (fragP->fr_subtype == 3)
    {
    {
      fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol,
      fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol,
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
      fragP->fr_var = 0;
      fragP->fr_var = 0;
      fragP->fr_fix += 3;
      fragP->fr_fix += 3;
    }
    }
  else if (fragP->fr_subtype == 4)
  else if (fragP->fr_subtype == 4)
    {
    {
      /* Reverse the condition of the first branch.  */
      /* Reverse the condition of the first branch.  */
      int offset = fragP->fr_fix;
      int offset = fragP->fr_fix;
      int opcode = fragP->fr_literal[offset + 1] & 0xff;
      int opcode = fragP->fr_literal[offset + 1] & 0xff;
 
 
      switch (opcode)
      switch (opcode)
        {
        {
        case 0xfc:
        case 0xfc:
          opcode = 0xfd;
          opcode = 0xfd;
          break;
          break;
        case 0xfd:
        case 0xfd:
          opcode = 0xfc;
          opcode = 0xfc;
          break;
          break;
        case 0xfe:
        case 0xfe:
          opcode = 0xff;
          opcode = 0xff;
          break;
          break;
        case 0xff:
        case 0xff:
          opcode = 0xfe;
          opcode = 0xfe;
        case 0xe8:
        case 0xe8:
          opcode = 0xe9;
          opcode = 0xe9;
          break;
          break;
        case 0xe9:
        case 0xe9:
          opcode = 0xe8;
          opcode = 0xe8;
          break;
          break;
        case 0xe0:
        case 0xe0:
          opcode = 0xe2;
          opcode = 0xe2;
          break;
          break;
        case 0xe2:
        case 0xe2:
          opcode = 0xe0;
          opcode = 0xe0;
          break;
          break;
        case 0xe3:
        case 0xe3:
          opcode = 0xe1;
          opcode = 0xe1;
          break;
          break;
        case 0xe1:
        case 0xe1:
          opcode = 0xe3;
          opcode = 0xe3;
          break;
          break;
        case 0xe4:
        case 0xe4:
          opcode = 0xe6;
          opcode = 0xe6;
          break;
          break;
        case 0xe6:
        case 0xe6:
          opcode = 0xe4;
          opcode = 0xe4;
          break;
          break;
        case 0xe7:
        case 0xe7:
          opcode = 0xe5;
          opcode = 0xe5;
          break;
          break;
        case 0xe5:
        case 0xe5:
          opcode = 0xe7;
          opcode = 0xe7;
          break;
          break;
        case 0xec:
        case 0xec:
          opcode = 0xed;
          opcode = 0xed;
          break;
          break;
        case 0xed:
        case 0xed:
          opcode = 0xec;
          opcode = 0xec;
          break;
          break;
        case 0xee:
        case 0xee:
          opcode = 0xef;
          opcode = 0xef;
          break;
          break;
        case 0xef:
        case 0xef:
          opcode = 0xee;
          opcode = 0xee;
          break;
          break;
        default:
        default:
          abort ();
          abort ();
        }
        }
      fragP->fr_literal[offset + 1] = opcode;
      fragP->fr_literal[offset + 1] = opcode;
 
 
      /* Create a fixup for the reversed conditional branch.  */
      /* Create a fixup for the reversed conditional branch.  */
      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
      fix_new (fragP, fragP->fr_fix + 2, 1,
      fix_new (fragP, fragP->fr_fix + 2, 1,
               symbol_new (buf, sec, 0, fragP->fr_next),
               symbol_new (buf, sec, 0, fragP->fr_next),
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
 
 
      /* Now create the unconditional branch + fixup to the
      /* Now create the unconditional branch + fixup to the
         final target.  */
         final target.  */
      fragP->fr_literal[offset + 3] = 0xfc;
      fragP->fr_literal[offset + 3] = 0xfc;
      fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
      fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
               fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
      fragP->fr_var = 0;
      fragP->fr_var = 0;
      fragP->fr_fix += 6;
      fragP->fr_fix += 6;
    }
    }
  else if (fragP->fr_subtype == 5)
  else if (fragP->fr_subtype == 5)
    {
    {
      /* Reverse the condition of the first branch.  */
      /* Reverse the condition of the first branch.  */
      int offset = fragP->fr_fix;
      int offset = fragP->fr_fix;
      int opcode = fragP->fr_literal[offset + 1] & 0xff;
      int opcode = fragP->fr_literal[offset + 1] & 0xff;
 
 
      switch (opcode)
      switch (opcode)
        {
        {
        case 0xfc:
        case 0xfc:
          opcode = 0xfd;
          opcode = 0xfd;
          break;
          break;
        case 0xfd:
        case 0xfd:
          opcode = 0xfc;
          opcode = 0xfc;
          break;
          break;
        case 0xfe:
        case 0xfe:
          opcode = 0xff;
          opcode = 0xff;
          break;
          break;
        case 0xff:
        case 0xff:
          opcode = 0xfe;
          opcode = 0xfe;
        case 0xe8:
        case 0xe8:
          opcode = 0xe9;
          opcode = 0xe9;
          break;
          break;
        case 0xe9:
        case 0xe9:
          opcode = 0xe8;
          opcode = 0xe8;
          break;
          break;
        case 0xe0:
        case 0xe0:
          opcode = 0xe2;
          opcode = 0xe2;
          break;
          break;
        case 0xe2:
        case 0xe2:
          opcode = 0xe0;
          opcode = 0xe0;
          break;
          break;
        case 0xe3:
        case 0xe3:
          opcode = 0xe1;
          opcode = 0xe1;
          break;
          break;
        case 0xe1:
        case 0xe1:
          opcode = 0xe3;
          opcode = 0xe3;
          break;
          break;
        case 0xe4:
        case 0xe4:
          opcode = 0xe6;
          opcode = 0xe6;
          break;
          break;
        case 0xe6:
        case 0xe6:
          opcode = 0xe4;
          opcode = 0xe4;
          break;
          break;
        case 0xe7:
        case 0xe7:
          opcode = 0xe5;
          opcode = 0xe5;
          break;
          break;
        case 0xe5:
        case 0xe5:
          opcode = 0xe7;
          opcode = 0xe7;
          break;
          break;
        case 0xec:
        case 0xec:
          opcode = 0xed;
          opcode = 0xed;
          break;
          break;
        case 0xed:
        case 0xed:
          opcode = 0xec;
          opcode = 0xec;
          break;
          break;
        case 0xee:
        case 0xee:
          opcode = 0xef;
          opcode = 0xef;
          break;
          break;
        case 0xef:
        case 0xef:
          opcode = 0xee;
          opcode = 0xee;
          break;
          break;
        default:
        default:
          abort ();
          abort ();
        }
        }
      fragP->fr_literal[offset + 1] = opcode;
      fragP->fr_literal[offset + 1] = opcode;
 
 
      /* Create a fixup for the reversed conditional branch.  */
      /* Create a fixup for the reversed conditional branch.  */
      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
      fix_new (fragP, fragP->fr_fix + 2, 1,
      fix_new (fragP, fragP->fr_fix + 2, 1,
               symbol_new (buf, sec, 0, fragP->fr_next),
               symbol_new (buf, sec, 0, fragP->fr_next),
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
 
 
      /* Now create the unconditional branch + fixup to the
      /* Now create the unconditional branch + fixup to the
         final target.  */
         final target.  */
      fragP->fr_literal[offset + 3] = 0xf4;
      fragP->fr_literal[offset + 3] = 0xf4;
      fragP->fr_literal[offset + 4] = 0xe0;
      fragP->fr_literal[offset + 4] = 0xe0;
      fix_new (fragP, fragP->fr_fix + 5, 4, fragP->fr_symbol,
      fix_new (fragP, fragP->fr_fix + 5, 4, fragP->fr_symbol,
               fragP->fr_offset, 1, BFD_RELOC_24_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_24_PCREL);
      fragP->fr_var = 0;
      fragP->fr_var = 0;
      fragP->fr_fix += 8;
      fragP->fr_fix += 8;
    }
    }
  else if (fragP->fr_subtype == 6)
  else if (fragP->fr_subtype == 6)
    {
    {
      fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
      fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
               fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
      fragP->fr_var = 0;
      fragP->fr_var = 0;
      fragP->fr_fix += 3;
      fragP->fr_fix += 3;
    }
    }
  else if (fragP->fr_subtype == 7)
  else if (fragP->fr_subtype == 7)
    {
    {
      int offset = fragP->fr_fix;
      int offset = fragP->fr_fix;
      fragP->fr_literal[offset] = 0xf4;
      fragP->fr_literal[offset] = 0xf4;
      fragP->fr_literal[offset + 1] = 0xe1;
      fragP->fr_literal[offset + 1] = 0xe1;
 
 
      fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
      fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
               fragP->fr_offset, 1, BFD_RELOC_24_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_24_PCREL);
      fragP->fr_var = 0;
      fragP->fr_var = 0;
      fragP->fr_fix += 5;
      fragP->fr_fix += 5;
    }
    }
  else if (fragP->fr_subtype == 8)
  else if (fragP->fr_subtype == 8)
    {
    {
      fragP->fr_literal[fragP->fr_fix] = 0xea;
      fragP->fr_literal[fragP->fr_fix] = 0xea;
      fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
      fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
      fragP->fr_var = 0;
      fragP->fr_var = 0;
      fragP->fr_fix += 2;
      fragP->fr_fix += 2;
    }
    }
  else if (fragP->fr_subtype == 9)
  else if (fragP->fr_subtype == 9)
    {
    {
      int offset = fragP->fr_fix;
      int offset = fragP->fr_fix;
      fragP->fr_literal[offset] = 0xfc;
      fragP->fr_literal[offset] = 0xfc;
 
 
      fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
      fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
               fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
      fragP->fr_var = 0;
      fragP->fr_var = 0;
      fragP->fr_fix += 3;
      fragP->fr_fix += 3;
    }
    }
  else if (fragP->fr_subtype == 10)
  else if (fragP->fr_subtype == 10)
    {
    {
      int offset = fragP->fr_fix;
      int offset = fragP->fr_fix;
      fragP->fr_literal[offset] = 0xf4;
      fragP->fr_literal[offset] = 0xf4;
      fragP->fr_literal[offset + 1] = 0xe0;
      fragP->fr_literal[offset + 1] = 0xe0;
 
 
      fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
      fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
               fragP->fr_offset, 1, BFD_RELOC_24_PCREL);
               fragP->fr_offset, 1, BFD_RELOC_24_PCREL);
      fragP->fr_var = 0;
      fragP->fr_var = 0;
      fragP->fr_fix += 5;
      fragP->fr_fix += 5;
    }
    }
  else
  else
    abort ();
    abort ();
}
}
 
 
valueT
valueT
md_section_align (asection *seg, valueT addr)
md_section_align (asection *seg, valueT addr)
{
{
  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));
}
}
 
 
void
void
md_begin (void)
md_begin (void)
{
{
  char *prev_name = "";
  char *prev_name = "";
  register const struct mn10200_opcode *op;
  register const struct mn10200_opcode *op;
 
 
  mn10200_hash = hash_new ();
  mn10200_hash = hash_new ();
 
 
  /* Insert unique names into hash table.  The MN10200 instruction set
  /* Insert unique names into hash table.  The MN10200 instruction set
     has many identical opcode names that have different opcodes based
     has many identical opcode names that have different opcodes based
     on the operands.  This hash table then provides a quick index to
     on the operands.  This hash table then provides a quick index to
     the first opcode with a particular name in the opcode table.  */
     the first opcode with a particular name in the opcode table.  */
 
 
  op = mn10200_opcodes;
  op = mn10200_opcodes;
  while (op->name)
  while (op->name)
    {
    {
      if (strcmp (prev_name, op->name))
      if (strcmp (prev_name, op->name))
        {
        {
          prev_name = (char *) op->name;
          prev_name = (char *) op->name;
          hash_insert (mn10200_hash, op->name, (char *) op);
          hash_insert (mn10200_hash, op->name, (char *) op);
        }
        }
      op++;
      op++;
    }
    }
 
 
  /* This is both a simplification (we don't have to write md_apply_fix)
  /* This is both a simplification (we don't have to write md_apply_fix)
     and support for future optimizations (branch shortening and similar
     and support for future optimizations (branch shortening and similar
     stuff in the linker.  */
     stuff in the linker.  */
  linkrelax = 1;
  linkrelax = 1;
}
}
 
 
static unsigned long
static unsigned long
check_operand (unsigned long insn ATTRIBUTE_UNUSED,
check_operand (unsigned long insn ATTRIBUTE_UNUSED,
               const struct mn10200_operand *operand,
               const struct mn10200_operand *operand,
               offsetT val)
               offsetT val)
{
{
  /* No need to check 24bit or 32bit operands for a bit.  */
  /* No need to check 24bit or 32bit operands for a bit.  */
  if (operand->bits < 24
  if (operand->bits < 24
      && (operand->flags & MN10200_OPERAND_NOCHECK) == 0)
      && (operand->flags & MN10200_OPERAND_NOCHECK) == 0)
    {
    {
      long min, max;
      long min, max;
      offsetT test;
      offsetT test;
 
 
      if ((operand->flags & MN10200_OPERAND_SIGNED) != 0)
      if ((operand->flags & MN10200_OPERAND_SIGNED) != 0)
        {
        {
          max = (1 << (operand->bits - 1)) - 1;
          max = (1 << (operand->bits - 1)) - 1;
          min = - (1 << (operand->bits - 1));
          min = - (1 << (operand->bits - 1));
        }
        }
      else
      else
        {
        {
          max = (1 << operand->bits) - 1;
          max = (1 << operand->bits) - 1;
          min = 0;
          min = 0;
        }
        }
 
 
      test = val;
      test = val;
 
 
      if (test < (offsetT) min || test > (offsetT) max)
      if (test < (offsetT) min || test > (offsetT) max)
        return 0;
        return 0;
      else
      else
        return 1;
        return 1;
    }
    }
  return 1;
  return 1;
}
}
/* If while processing a fixup, a reloc really needs to be created
/* If while processing a fixup, a reloc really needs to be created
   Then it is done here.  */
   Then it is done here.  */
 
 
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));
 
 
  if (fixp->fx_subsy != NULL)
  if (fixp->fx_subsy != NULL)
    {
    {
      if (S_GET_SEGMENT (fixp->fx_addsy) == S_GET_SEGMENT (fixp->fx_subsy)
      if (S_GET_SEGMENT (fixp->fx_addsy) == S_GET_SEGMENT (fixp->fx_subsy)
          && S_IS_DEFINED (fixp->fx_subsy))
          && S_IS_DEFINED (fixp->fx_subsy))
        {
        {
          fixp->fx_offset -= S_GET_VALUE (fixp->fx_subsy);
          fixp->fx_offset -= S_GET_VALUE (fixp->fx_subsy);
          fixp->fx_subsy = NULL;
          fixp->fx_subsy = NULL;
        }
        }
      else
      else
        /* FIXME: We should try more ways to resolve difference expressions
        /* FIXME: We should try more ways to resolve difference expressions
           here.  At least this is better than silently ignoring the
           here.  At least this is better than silently ignoring the
           subtrahend.  */
           subtrahend.  */
        as_bad_where (fixp->fx_file, fixp->fx_line,
        as_bad_where (fixp->fx_file, fixp->fx_line,
                      _("can't resolve `%s' {%s section} - `%s' {%s section}"),
                      _("can't resolve `%s' {%s section} - `%s' {%s section}"),
                      fixp->fx_addsy ? S_GET_NAME (fixp->fx_addsy) : "0",
                      fixp->fx_addsy ? S_GET_NAME (fixp->fx_addsy) : "0",
                      segment_name (fixp->fx_addsy
                      segment_name (fixp->fx_addsy
                                    ? S_GET_SEGMENT (fixp->fx_addsy)
                                    ? S_GET_SEGMENT (fixp->fx_addsy)
                                    : absolute_section),
                                    : absolute_section),
                      S_GET_NAME (fixp->fx_subsy),
                      S_GET_NAME (fixp->fx_subsy),
                      segment_name (S_GET_SEGMENT (fixp->fx_addsy)));
                      segment_name (S_GET_SEGMENT (fixp->fx_addsy)));
    }
    }
 
 
  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 == NULL)
  if (reloc->howto == 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;
    }
    }
  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
  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->addend = fixp->fx_offset;
  reloc->addend = fixp->fx_offset;
  return reloc;
  return reloc;
}
}
 
 
int
int
md_estimate_size_before_relax (fragS *fragp, asection *seg)
md_estimate_size_before_relax (fragS *fragp, asection *seg)
{
{
  if (fragp->fr_subtype == 6
  if (fragp->fr_subtype == 6
      && (!S_IS_DEFINED (fragp->fr_symbol)
      && (!S_IS_DEFINED (fragp->fr_symbol)
          || seg != S_GET_SEGMENT (fragp->fr_symbol)))
          || seg != S_GET_SEGMENT (fragp->fr_symbol)))
    fragp->fr_subtype = 7;
    fragp->fr_subtype = 7;
  else if (fragp->fr_subtype == 8
  else if (fragp->fr_subtype == 8
           && (!S_IS_DEFINED (fragp->fr_symbol)
           && (!S_IS_DEFINED (fragp->fr_symbol)
               || seg != S_GET_SEGMENT (fragp->fr_symbol)))
               || seg != S_GET_SEGMENT (fragp->fr_symbol)))
    fragp->fr_subtype = 10;
    fragp->fr_subtype = 10;
 
 
  if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
  if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
    abort ();
    abort ();
 
 
  return md_relax_table[fragp->fr_subtype].rlx_length;
  return md_relax_table[fragp->fr_subtype].rlx_length;
}
}
 
 
long
long
md_pcrel_from (fixS *fixp)
md_pcrel_from (fixS *fixp)
{
{
  return fixp->fx_frag->fr_address;
  return fixp->fx_frag->fr_address;
}
}
 
 
void
void
md_apply_fix (fixS * fixP, valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED)
md_apply_fix (fixS * fixP, valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED)
{
{
  /* We shouldn't ever get here because linkrelax is nonzero.  */
  /* We shouldn't ever get here because linkrelax is nonzero.  */
  abort ();
  abort ();
  fixP->fx_done = 1;
  fixP->fx_done = 1;
}
}
 
 
/* Insert an operand value into an instruction.  */
/* Insert an operand value into an instruction.  */
 
 
static void
static void
mn10200_insert_operand (unsigned long *insnp,
mn10200_insert_operand (unsigned long *insnp,
                        unsigned long *extensionp,
                        unsigned long *extensionp,
                        const struct mn10200_operand *operand,
                        const struct mn10200_operand *operand,
                        offsetT val,
                        offsetT val,
                        char *file,
                        char *file,
                        unsigned int line,
                        unsigned int line,
                        unsigned int shift)
                        unsigned int shift)
{
{
  /* No need to check 24 or 32bit operands for a bit.  */
  /* No need to check 24 or 32bit operands for a bit.  */
  if (operand->bits < 24
  if (operand->bits < 24
      && (operand->flags & MN10200_OPERAND_NOCHECK) == 0)
      && (operand->flags & MN10200_OPERAND_NOCHECK) == 0)
    {
    {
      long min, max;
      long min, max;
      offsetT test;
      offsetT test;
 
 
      if ((operand->flags & MN10200_OPERAND_SIGNED) != 0)
      if ((operand->flags & MN10200_OPERAND_SIGNED) != 0)
        {
        {
          max = (1 << (operand->bits - 1)) - 1;
          max = (1 << (operand->bits - 1)) - 1;
          min = - (1 << (operand->bits - 1));
          min = - (1 << (operand->bits - 1));
        }
        }
      else
      else
        {
        {
          max = (1 << operand->bits) - 1;
          max = (1 << operand->bits) - 1;
          min = 0;
          min = 0;
        }
        }
 
 
      test = val;
      test = val;
 
 
      if (test < (offsetT) min || test > (offsetT) max)
      if (test < (offsetT) min || test > (offsetT) max)
        as_warn_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line);
        as_warn_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line);
    }
    }
 
 
  if ((operand->flags & MN10200_OPERAND_EXTENDED) == 0)
  if ((operand->flags & MN10200_OPERAND_EXTENDED) == 0)
    {
    {
      *insnp |= (((long) val & ((1 << operand->bits) - 1))
      *insnp |= (((long) val & ((1 << operand->bits) - 1))
                 << (operand->shift + shift));
                 << (operand->shift + shift));
 
 
      if ((operand->flags & MN10200_OPERAND_REPEATED) != 0)
      if ((operand->flags & MN10200_OPERAND_REPEATED) != 0)
        *insnp |= (((long) val & ((1 << operand->bits) - 1))
        *insnp |= (((long) val & ((1 << operand->bits) - 1))
                   << (operand->shift + shift + 2));
                   << (operand->shift + shift + 2));
    }
    }
  else
  else
    {
    {
      *extensionp |= (val >> 16) & 0xff;
      *extensionp |= (val >> 16) & 0xff;
      *insnp |= val & 0xffff;
      *insnp |= val & 0xffff;
    }
    }
}
}
 
 
void
void
md_assemble (char *str)
md_assemble (char *str)
{
{
  char *s;
  char *s;
  struct mn10200_opcode *opcode;
  struct mn10200_opcode *opcode;
  struct mn10200_opcode *next_opcode;
  struct mn10200_opcode *next_opcode;
  const unsigned char *opindex_ptr;
  const unsigned char *opindex_ptr;
  int next_opindex, relaxable;
  int next_opindex, relaxable;
  unsigned long insn, extension, size = 0;
  unsigned long insn, extension, size = 0;
  char *f;
  char *f;
  int i;
  int i;
  int match;
  int match;
 
 
  /* Get the opcode.  */
  /* Get the opcode.  */
  for (s = str; *s != '\0' && !ISSPACE (*s); s++)
  for (s = str; *s != '\0' && !ISSPACE (*s); s++)
    ;
    ;
  if (*s != '\0')
  if (*s != '\0')
    *s++ = '\0';
    *s++ = '\0';
 
 
  /* Find the first opcode with the proper name.  */
  /* Find the first opcode with the proper name.  */
  opcode = (struct mn10200_opcode *) hash_find (mn10200_hash, str);
  opcode = (struct mn10200_opcode *) hash_find (mn10200_hash, str);
  if (opcode == NULL)
  if (opcode == NULL)
    {
    {
      as_bad (_("Unrecognized opcode: `%s'"), str);
      as_bad (_("Unrecognized opcode: `%s'"), str);
      return;
      return;
    }
    }
 
 
  str = s;
  str = s;
  while (ISSPACE (*str))
  while (ISSPACE (*str))
    ++str;
    ++str;
 
 
  input_line_pointer = str;
  input_line_pointer = str;
 
 
  for (;;)
  for (;;)
    {
    {
      const char *errmsg = NULL;
      const char *errmsg = NULL;
      int op_idx;
      int op_idx;
      char *hold;
      char *hold;
      int extra_shift = 0;
      int extra_shift = 0;
 
 
      relaxable = 0;
      relaxable = 0;
      fc = 0;
      fc = 0;
      match = 0;
      match = 0;
      next_opindex = 0;
      next_opindex = 0;
      insn = opcode->opcode;
      insn = opcode->opcode;
      extension = 0;
      extension = 0;
      for (op_idx = 1, opindex_ptr = opcode->operands;
      for (op_idx = 1, opindex_ptr = opcode->operands;
           *opindex_ptr != 0;
           *opindex_ptr != 0;
           opindex_ptr++, op_idx++)
           opindex_ptr++, op_idx++)
        {
        {
          const struct mn10200_operand *operand;
          const struct mn10200_operand *operand;
          expressionS ex;
          expressionS ex;
 
 
          if (next_opindex == 0)
          if (next_opindex == 0)
            {
            {
              operand = &mn10200_operands[*opindex_ptr];
              operand = &mn10200_operands[*opindex_ptr];
            }
            }
          else
          else
            {
            {
              operand = &mn10200_operands[next_opindex];
              operand = &mn10200_operands[next_opindex];
              next_opindex = 0;
              next_opindex = 0;
            }
            }
 
 
          errmsg = NULL;
          errmsg = NULL;
 
 
          while (*str == ' ' || *str == ',')
          while (*str == ' ' || *str == ',')
            ++str;
            ++str;
 
 
          if (operand->flags & MN10200_OPERAND_RELAX)
          if (operand->flags & MN10200_OPERAND_RELAX)
            relaxable = 1;
            relaxable = 1;
 
 
          /* Gather the operand.  */
          /* Gather the operand.  */
          hold = input_line_pointer;
          hold = input_line_pointer;
          input_line_pointer = str;
          input_line_pointer = str;
 
 
          if (operand->flags & MN10200_OPERAND_PAREN)
          if (operand->flags & MN10200_OPERAND_PAREN)
            {
            {
              if (*input_line_pointer != ')' && *input_line_pointer != '(')
              if (*input_line_pointer != ')' && *input_line_pointer != '(')
                {
                {
                  input_line_pointer = hold;
                  input_line_pointer = hold;
                  str = hold;
                  str = hold;
                  goto error;
                  goto error;
                }
                }
              input_line_pointer++;
              input_line_pointer++;
              goto keep_going;
              goto keep_going;
            }
            }
          /* See if we can match the operands.  */
          /* See if we can match the operands.  */
          else if (operand->flags & MN10200_OPERAND_DREG)
          else if (operand->flags & MN10200_OPERAND_DREG)
            {
            {
              if (!data_register_name (&ex))
              if (!data_register_name (&ex))
                {
                {
                  input_line_pointer = hold;
                  input_line_pointer = hold;
                  str = hold;
                  str = hold;
                  goto error;
                  goto error;
                }
                }
            }
            }
          else if (operand->flags & MN10200_OPERAND_AREG)
          else if (operand->flags & MN10200_OPERAND_AREG)
            {
            {
              if (!address_register_name (&ex))
              if (!address_register_name (&ex))
                {
                {
                  input_line_pointer = hold;
                  input_line_pointer = hold;
                  str = hold;
                  str = hold;
                  goto error;
                  goto error;
                }
                }
            }
            }
          else if (operand->flags & MN10200_OPERAND_PSW)
          else if (operand->flags & MN10200_OPERAND_PSW)
            {
            {
              char *start = input_line_pointer;
              char *start = input_line_pointer;
              char c = get_symbol_end ();
              char c = get_symbol_end ();
 
 
              if (strcmp (start, "psw") != 0)
              if (strcmp (start, "psw") != 0)
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  input_line_pointer = hold;
                  input_line_pointer = hold;
                  str = hold;
                  str = hold;
                  goto error;
                  goto error;
                }
                }
              *input_line_pointer = c;
              *input_line_pointer = c;
              goto keep_going;
              goto keep_going;
            }
            }
          else if (operand->flags & MN10200_OPERAND_MDR)
          else if (operand->flags & MN10200_OPERAND_MDR)
            {
            {
              char *start = input_line_pointer;
              char *start = input_line_pointer;
              char c = get_symbol_end ();
              char c = get_symbol_end ();
 
 
              if (strcmp (start, "mdr") != 0)
              if (strcmp (start, "mdr") != 0)
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  input_line_pointer = hold;
                  input_line_pointer = hold;
                  str = hold;
                  str = hold;
                  goto error;
                  goto error;
                }
                }
              *input_line_pointer = c;
              *input_line_pointer = c;
              goto keep_going;
              goto keep_going;
            }
            }
          else if (data_register_name (&ex))
          else if (data_register_name (&ex))
            {
            {
              input_line_pointer = hold;
              input_line_pointer = hold;
              str = hold;
              str = hold;
              goto error;
              goto error;
            }
            }
          else if (address_register_name (&ex))
          else if (address_register_name (&ex))
            {
            {
              input_line_pointer = hold;
              input_line_pointer = hold;
              str = hold;
              str = hold;
              goto error;
              goto error;
            }
            }
          else if (other_register_name (&ex))
          else if (other_register_name (&ex))
            {
            {
              input_line_pointer = hold;
              input_line_pointer = hold;
              str = hold;
              str = hold;
              goto error;
              goto error;
            }
            }
          else if (*str == ')' || *str == '(')
          else if (*str == ')' || *str == '(')
            {
            {
              input_line_pointer = hold;
              input_line_pointer = hold;
              str = hold;
              str = hold;
              goto error;
              goto error;
            }
            }
          else
          else
            {
            {
              expression (&ex);
              expression (&ex);
            }
            }
 
 
          switch (ex.X_op)
          switch (ex.X_op)
            {
            {
            case O_illegal:
            case O_illegal:
              errmsg = _("illegal operand");
              errmsg = _("illegal operand");
              goto error;
              goto error;
            case O_absent:
            case O_absent:
              errmsg = _("missing operand");
              errmsg = _("missing operand");
              goto error;
              goto error;
            case O_register:
            case O_register:
              if ((operand->flags
              if ((operand->flags
                   & (MN10200_OPERAND_DREG | MN10200_OPERAND_AREG)) == 0)
                   & (MN10200_OPERAND_DREG | MN10200_OPERAND_AREG)) == 0)
                {
                {
                  input_line_pointer = hold;
                  input_line_pointer = hold;
                  str = hold;
                  str = hold;
                  goto error;
                  goto error;
                }
                }
 
 
              if (opcode->format == FMT_2 || opcode->format == FMT_5)
              if (opcode->format == FMT_2 || opcode->format == FMT_5)
                extra_shift = 8;
                extra_shift = 8;
              else if (opcode->format == FMT_3 || opcode->format == FMT_6
              else if (opcode->format == FMT_3 || opcode->format == FMT_6
                       || opcode->format == FMT_7)
                       || opcode->format == FMT_7)
                extra_shift = 16;
                extra_shift = 16;
              else
              else
                extra_shift = 0;
                extra_shift = 0;
 
 
              mn10200_insert_operand (&insn, &extension, operand,
              mn10200_insert_operand (&insn, &extension, operand,
                                      ex.X_add_number, NULL,
                                      ex.X_add_number, NULL,
                                      0, extra_shift);
                                      0, extra_shift);
 
 
              break;
              break;
 
 
            case O_constant:
            case O_constant:
              /* If this operand can be promoted, and it doesn't
              /* If this operand can be promoted, and it doesn't
                 fit into the allocated bitfield for this insn,
                 fit into the allocated bitfield for this insn,
                 then promote it (ie this opcode does not match).  */
                 then promote it (ie this opcode does not match).  */
              if (operand->flags
              if (operand->flags
                  & (MN10200_OPERAND_PROMOTE | MN10200_OPERAND_RELAX)
                  & (MN10200_OPERAND_PROMOTE | MN10200_OPERAND_RELAX)
                  && !check_operand (insn, operand, ex.X_add_number))
                  && !check_operand (insn, operand, ex.X_add_number))
                {
                {
                  input_line_pointer = hold;
                  input_line_pointer = hold;
                  str = hold;
                  str = hold;
                  goto error;
                  goto error;
                }
                }
 
 
              mn10200_insert_operand (&insn, &extension, operand,
              mn10200_insert_operand (&insn, &extension, operand,
                                      ex.X_add_number, NULL,
                                      ex.X_add_number, NULL,
                                      0, 0);
                                      0, 0);
              break;
              break;
 
 
            default:
            default:
              /* If this operand can be promoted, then this opcode didn't
              /* If this operand can be promoted, then this opcode didn't
                 match since we can't know if it needed promotion!  */
                 match since we can't know if it needed promotion!  */
              if (operand->flags & MN10200_OPERAND_PROMOTE)
              if (operand->flags & MN10200_OPERAND_PROMOTE)
                {
                {
                  input_line_pointer = hold;
                  input_line_pointer = hold;
                  str = hold;
                  str = hold;
                  goto error;
                  goto error;
                }
                }
 
 
              /* We need to generate a fixup for this expression.  */
              /* We need to generate a fixup for this expression.  */
              if (fc >= MAX_INSN_FIXUPS)
              if (fc >= MAX_INSN_FIXUPS)
                as_fatal (_("too many fixups"));
                as_fatal (_("too many fixups"));
              fixups[fc].exp = ex;
              fixups[fc].exp = ex;
              fixups[fc].opindex = *opindex_ptr;
              fixups[fc].opindex = *opindex_ptr;
              fixups[fc].reloc = BFD_RELOC_UNUSED;
              fixups[fc].reloc = BFD_RELOC_UNUSED;
              ++fc;
              ++fc;
              break;
              break;
            }
            }
 
 
keep_going:
keep_going:
          str = input_line_pointer;
          str = input_line_pointer;
          input_line_pointer = hold;
          input_line_pointer = hold;
 
 
          while (*str == ' ' || *str == ',')
          while (*str == ' ' || *str == ',')
            ++str;
            ++str;
 
 
        }
        }
 
 
      /* Make sure we used all the operands!  */
      /* Make sure we used all the operands!  */
      if (*str != ',')
      if (*str != ',')
        match = 1;
        match = 1;
 
 
    error:
    error:
      if (match == 0)
      if (match == 0)
        {
        {
          next_opcode = opcode + 1;
          next_opcode = opcode + 1;
          if (!strcmp (next_opcode->name, opcode->name))
          if (!strcmp (next_opcode->name, opcode->name))
            {
            {
              opcode = next_opcode;
              opcode = next_opcode;
              continue;
              continue;
            }
            }
 
 
          as_bad ("%s", errmsg);
          as_bad ("%s", errmsg);
          return;
          return;
        }
        }
      break;
      break;
    }
    }
 
 
  while (ISSPACE (*str))
  while (ISSPACE (*str))
    ++str;
    ++str;
 
 
  if (*str != '\0')
  if (*str != '\0')
    as_bad (_("junk at end of line: `%s'"), str);
    as_bad (_("junk at end of line: `%s'"), str);
 
 
  input_line_pointer = str;
  input_line_pointer = str;
 
 
  if (opcode->format == FMT_1)
  if (opcode->format == FMT_1)
    size = 1;
    size = 1;
  else if (opcode->format == FMT_2 || opcode->format == FMT_4)
  else if (opcode->format == FMT_2 || opcode->format == FMT_4)
    size = 2;
    size = 2;
  else if (opcode->format == FMT_3 || opcode->format == FMT_5)
  else if (opcode->format == FMT_3 || opcode->format == FMT_5)
    size = 3;
    size = 3;
  else if (opcode->format == FMT_6)
  else if (opcode->format == FMT_6)
    size = 4;
    size = 4;
  else if (opcode->format == FMT_7)
  else if (opcode->format == FMT_7)
    size = 5;
    size = 5;
  else
  else
    abort ();
    abort ();
 
 
  /* Write out the instruction.  */
  /* Write out the instruction.  */
  if (relaxable && fc > 0)
  if (relaxable && fc > 0)
    {
    {
      /* On a 64-bit host the size of an 'int' is not the same
      /* On a 64-bit host the size of an 'int' is not the same
         as the size of a pointer, so we need a union to convert
         as the size of a pointer, so we need a union to convert
         the opindex field of the fr_cgen structure into a char *
         the opindex field of the fr_cgen structure into a char *
         so that it can be stored in the frag.  We do not have
         so that it can be stored in the frag.  We do not have
         to worry about loosing accuracy as we are not going to
         to worry about loosing accuracy as we are not going to
         be even close to the 32bit limit of the int.  */
         be even close to the 32bit limit of the int.  */
      union
      union
      {
      {
        int opindex;
        int opindex;
        char * ptr;
        char * ptr;
      }
      }
      opindex_converter;
      opindex_converter;
      int type;
      int type;
 
 
      /* bCC  */
      /* bCC  */
      if (size == 2 && opcode->opcode != 0xfc0000)
      if (size == 2 && opcode->opcode != 0xfc0000)
        {
        {
          /* Handle bra specially.  Basically treat it like jmp so
          /* Handle bra specially.  Basically treat it like jmp so
             that we automatically handle 8, 16 and 32 bit offsets
             that we automatically handle 8, 16 and 32 bit offsets
             correctly as well as jumps to an undefined address.
             correctly as well as jumps to an undefined address.
 
 
             It is also important to not treat it like other bCC
             It is also important to not treat it like other bCC
             instructions since the long forms of bra is different
             instructions since the long forms of bra is different
             from other bCC instructions.  */
             from other bCC instructions.  */
          if (opcode->opcode == 0xea00)
          if (opcode->opcode == 0xea00)
            type = 8;
            type = 8;
          else
          else
            type = 0;
            type = 0;
        }
        }
      /* jsr  */
      /* jsr  */
      else if (size == 3 && opcode->opcode == 0xfd0000)
      else if (size == 3 && opcode->opcode == 0xfd0000)
        type = 6;
        type = 6;
      /* jmp  */
      /* jmp  */
      else if (size == 3 && opcode->opcode == 0xfc0000)
      else if (size == 3 && opcode->opcode == 0xfc0000)
        type = 8;
        type = 8;
      /* bCCx  */
      /* bCCx  */
      else
      else
        type = 3;
        type = 3;
 
 
      opindex_converter.opindex = fixups[0].opindex;
      opindex_converter.opindex = fixups[0].opindex;
      f = frag_var (rs_machine_dependent, 8, 8 - size, type,
      f = frag_var (rs_machine_dependent, 8, 8 - size, type,
                    fixups[0].exp.X_add_symbol,
                    fixups[0].exp.X_add_symbol,
                    fixups[0].exp.X_add_number,
                    fixups[0].exp.X_add_number,
                    opindex_converter.ptr);
                    opindex_converter.ptr);
      number_to_chars_bigendian (f, insn, size);
      number_to_chars_bigendian (f, insn, size);
      if (8 - size > 4)
      if (8 - size > 4)
        {
        {
          number_to_chars_bigendian (f + size, 0, 4);
          number_to_chars_bigendian (f + size, 0, 4);
          number_to_chars_bigendian (f + size + 4, 0, 8 - size - 4);
          number_to_chars_bigendian (f + size + 4, 0, 8 - size - 4);
        }
        }
      else
      else
        number_to_chars_bigendian (f + size, 0, 8 - size);
        number_to_chars_bigendian (f + size, 0, 8 - size);
    }
    }
  else
  else
    {
    {
      f = frag_more (size);
      f = frag_more (size);
 
 
      /* Oh, what a mess.  The instruction is in big endian format, but
      /* Oh, what a mess.  The instruction is in big endian format, but
         16 and 24bit immediates are little endian!  */
         16 and 24bit immediates are little endian!  */
      if (opcode->format == FMT_3)
      if (opcode->format == FMT_3)
        {
        {
          number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1);
          number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1);
          number_to_chars_littleendian (f + 1, insn & 0xffff, 2);
          number_to_chars_littleendian (f + 1, insn & 0xffff, 2);
        }
        }
      else if (opcode->format == FMT_6)
      else if (opcode->format == FMT_6)
        {
        {
          number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
          number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
          number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
          number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
        }
        }
      else if (opcode->format == FMT_7)
      else if (opcode->format == FMT_7)
        {
        {
          number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
          number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
          number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
          number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
          number_to_chars_littleendian (f + 4, extension & 0xff, 1);
          number_to_chars_littleendian (f + 4, extension & 0xff, 1);
        }
        }
      else
      else
        number_to_chars_bigendian (f, insn, size > 4 ? 4 : size);
        number_to_chars_bigendian (f, insn, size > 4 ? 4 : size);
 
 
      /* Create any fixups.  */
      /* Create any fixups.  */
      for (i = 0; i < fc; i++)
      for (i = 0; i < fc; i++)
        {
        {
          const struct mn10200_operand *operand;
          const struct mn10200_operand *operand;
 
 
          operand = &mn10200_operands[fixups[i].opindex];
          operand = &mn10200_operands[fixups[i].opindex];
          if (fixups[i].reloc != BFD_RELOC_UNUSED)
          if (fixups[i].reloc != BFD_RELOC_UNUSED)
            {
            {
              reloc_howto_type *reloc_howto;
              reloc_howto_type *reloc_howto;
              int size;
              int size;
              int offset;
              int offset;
              fixS *fixP;
              fixS *fixP;
 
 
              reloc_howto = bfd_reloc_type_lookup (stdoutput,
              reloc_howto = bfd_reloc_type_lookup (stdoutput,
                                                   fixups[i].reloc);
                                                   fixups[i].reloc);
 
 
              if (!reloc_howto)
              if (!reloc_howto)
                abort ();
                abort ();
 
 
              size = bfd_get_reloc_size (reloc_howto);
              size = bfd_get_reloc_size (reloc_howto);
 
 
              if (size < 1 || size > 4)
              if (size < 1 || size > 4)
                abort ();
                abort ();
 
 
              offset = 4 - size;
              offset = 4 - size;
              fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
              fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
                                  size,
                                  size,
                                  &fixups[i].exp,
                                  &fixups[i].exp,
                                  reloc_howto->pc_relative,
                                  reloc_howto->pc_relative,
                                  fixups[i].reloc);
                                  fixups[i].reloc);
 
 
              /* PC-relative offsets are from the first byte of the
              /* PC-relative offsets are from the first byte of the
                 next instruction, not from the start of the current
                 next instruction, not from the start of the current
                 instruction.  */
                 instruction.  */
              if (reloc_howto->pc_relative)
              if (reloc_howto->pc_relative)
                fixP->fx_offset += size;
                fixP->fx_offset += size;
            }
            }
          else
          else
            {
            {
              int reloc, pcrel, reloc_size, offset;
              int reloc, pcrel, reloc_size, offset;
              fixS *fixP;
              fixS *fixP;
 
 
              reloc = BFD_RELOC_NONE;
              reloc = BFD_RELOC_NONE;
              /* How big is the reloc?  Remember SPLIT relocs are
              /* How big is the reloc?  Remember SPLIT relocs are
                 implicitly 32bits.  */
                 implicitly 32bits.  */
              reloc_size = operand->bits;
              reloc_size = operand->bits;
 
 
              offset = size - reloc_size / 8;
              offset = size - reloc_size / 8;
 
 
              /* Is the reloc pc-relative?  */
              /* Is the reloc pc-relative?  */
              pcrel = (operand->flags & MN10200_OPERAND_PCREL) != 0;
              pcrel = (operand->flags & MN10200_OPERAND_PCREL) != 0;
 
 
              /* Choose a proper BFD relocation type.  */
              /* Choose a proper BFD relocation type.  */
              if (pcrel)
              if (pcrel)
                {
                {
                  if (reloc_size == 8)
                  if (reloc_size == 8)
                    reloc = BFD_RELOC_8_PCREL;
                    reloc = BFD_RELOC_8_PCREL;
                  else if (reloc_size == 24)
                  else if (reloc_size == 24)
                    reloc = BFD_RELOC_24_PCREL;
                    reloc = BFD_RELOC_24_PCREL;
                  else
                  else
                    abort ();
                    abort ();
                }
                }
              else
              else
                {
                {
                  if (reloc_size == 32)
                  if (reloc_size == 32)
                    reloc = BFD_RELOC_32;
                    reloc = BFD_RELOC_32;
                  else if (reloc_size == 16)
                  else if (reloc_size == 16)
                    reloc = BFD_RELOC_16;
                    reloc = BFD_RELOC_16;
                  else if (reloc_size == 8)
                  else if (reloc_size == 8)
                    reloc = BFD_RELOC_8;
                    reloc = BFD_RELOC_8;
                  else if (reloc_size == 24)
                  else if (reloc_size == 24)
                    reloc = BFD_RELOC_24;
                    reloc = BFD_RELOC_24;
                  else
                  else
                    abort ();
                    abort ();
                }
                }
 
 
              /* Convert the size of the reloc into what fix_new_exp
              /* Convert the size of the reloc into what fix_new_exp
                 wants.  */
                 wants.  */
              reloc_size = reloc_size / 8;
              reloc_size = reloc_size / 8;
              if (reloc_size == 8)
              if (reloc_size == 8)
                reloc_size = 0;
                reloc_size = 0;
              else if (reloc_size == 16)
              else if (reloc_size == 16)
                reloc_size = 1;
                reloc_size = 1;
              else if (reloc_size == 32 || reloc_size == 24)
              else if (reloc_size == 32 || reloc_size == 24)
                reloc_size = 2;
                reloc_size = 2;
 
 
              fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
              fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
                                  reloc_size, &fixups[i].exp, pcrel,
                                  reloc_size, &fixups[i].exp, pcrel,
                                  ((bfd_reloc_code_real_type) reloc));
                                  ((bfd_reloc_code_real_type) reloc));
 
 
              /* PC-relative offsets are from the first byte of the
              /* PC-relative offsets are from the first byte of the
                 next instruction, not from the start of the current
                 next instruction, not from the start of the current
                 instruction.  */
                 instruction.  */
              if (pcrel)
              if (pcrel)
                fixP->fx_offset += size;
                fixP->fx_offset += size;
            }
            }
        }
        }
    }
    }
}
}
 
 
 
 

powered by: WebSVN 2.1.0

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