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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [binutils-2.18.50/] [gas/] [config/] [tc-mcore.c] - Diff between revs 156 and 816

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

Rev 156 Rev 816
/* tc-mcore.c -- Assemble code for M*Core
/* tc-mcore.c -- Assemble code for M*Core
   Copyright 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007
   Copyright 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007
   Free Software Foundation, Inc.
   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 the Free
   along with GAS; see the file COPYING.  If not, write to the Free
   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
   02110-1301, USA.  */
   02110-1301, USA.  */
 
 
#include "as.h"
#include "as.h"
#include "subsegs.h"
#include "subsegs.h"
#define DEFINE_TABLE
#define DEFINE_TABLE
#include "../opcodes/mcore-opc.h"
#include "../opcodes/mcore-opc.h"
#include "safe-ctype.h"
#include "safe-ctype.h"
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
#include "elf/mcore.h"
#include "elf/mcore.h"
#endif
#endif
 
 
#ifndef streq
#ifndef streq
#define streq(a,b) (strcmp (a, b) == 0)
#define streq(a,b) (strcmp (a, b) == 0)
#endif
#endif
 
 
/* Forward declarations for dumb compilers.  */
/* Forward declarations for dumb compilers.  */
 
 
/* Several places in this file insert raw instructions into the
/* Several places in this file insert raw instructions into the
   object. They should use MCORE_INST_XXX macros to get the opcodes
   object. They should use MCORE_INST_XXX macros to get the opcodes
   and then use these two macros to crack the MCORE_INST value into
   and then use these two macros to crack the MCORE_INST value into
   the appropriate byte values.  */
   the appropriate byte values.  */
#define INST_BYTE0(x)  (target_big_endian ? (((x) >> 8) & 0xFF) : ((x) & 0xFF))
#define INST_BYTE0(x)  (target_big_endian ? (((x) >> 8) & 0xFF) : ((x) & 0xFF))
#define INST_BYTE1(x)  (target_big_endian ? ((x) & 0xFF) : (((x) >> 8) & 0xFF))
#define INST_BYTE1(x)  (target_big_endian ? ((x) & 0xFF) : (((x) >> 8) & 0xFF))
 
 
const char comment_chars[] = "#/";
const char comment_chars[] = "#/";
const char line_separator_chars[] = ";";
const char line_separator_chars[] = ";";
const char line_comment_chars[] = "#/";
const char line_comment_chars[] = "#/";
 
 
static int do_jsri2bsr = 0;      /* Change here from 1 by Cruess 19 August 97.  */
static int do_jsri2bsr = 0;      /* Change here from 1 by Cruess 19 August 97.  */
static int sifilter_mode = 0;
static int sifilter_mode = 0;
 
 
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";
 
 
#define C(what,length) (((what) << 2) + (length))
#define C(what,length) (((what) << 2) + (length))
#define GET_WHAT(x)    ((x >> 2))
#define GET_WHAT(x)    ((x >> 2))
 
 
/* These are the two types of relaxable instruction.  */
/* These are the two types of relaxable instruction.  */
#define COND_JUMP  1
#define COND_JUMP  1
#define UNCD_JUMP  2
#define UNCD_JUMP  2
 
 
#define UNDEF_DISP      0
#define UNDEF_DISP      0
#define DISP12          1
#define DISP12          1
#define DISP32          2
#define DISP32          2
#define UNDEF_WORD_DISP 3
#define UNDEF_WORD_DISP 3
 
 
#define C12_LEN         2
#define C12_LEN         2
#define C32_LEN        10       /* Allow for align.  */
#define C32_LEN        10       /* Allow for align.  */
#define U12_LEN         2
#define U12_LEN         2
#define U32_LEN         8       /* Allow for align.  */
#define U32_LEN         8       /* Allow for align.  */
 
 
typedef enum
typedef enum
{
{
  M210,
  M210,
  M340
  M340
}
}
cpu_type;
cpu_type;
 
 
cpu_type cpu = M340;
cpu_type cpu = M340;
 
 
/* Initialize the relax table.  */
/* Initialize the relax table.  */
const relax_typeS md_relax_table[] =
const relax_typeS md_relax_table[] =
{
{
  {    0,     0, 0,          0 },
  {    0,     0, 0,          0 },
  {    0,     0, 0,          0 },
  {    0,     0, 0,          0 },
  {    0,     0, 0,          0 },
  {    0,     0, 0,          0 },
  {    0,     0, 0,          0 },
  {    0,     0, 0,          0 },
 
 
  /* COND_JUMP */
  /* COND_JUMP */
  {    0,     0, 0,          0 },                     /* UNDEF_DISP */
  {    0,     0, 0,          0 },                     /* UNDEF_DISP */
  { 2048, -2046, C12_LEN, C(COND_JUMP, DISP32) }, /* DISP12 */
  { 2048, -2046, C12_LEN, C(COND_JUMP, DISP32) }, /* DISP12 */
  {    0,     0, C32_LEN, 0 },                       /* DISP32 */
  {    0,     0, C32_LEN, 0 },                       /* DISP32 */
  {    0,     0, C32_LEN, 0 },                       /* UNDEF_WORD_DISP */
  {    0,     0, C32_LEN, 0 },                       /* UNDEF_WORD_DISP */
 
 
  /* UNCD_JUMP */
  /* UNCD_JUMP */
  {    0,     0, 0,          0 },                     /* UNDEF_DISP */
  {    0,     0, 0,          0 },                     /* UNDEF_DISP */
  { 2048, -2046, U12_LEN, C(UNCD_JUMP, DISP32) }, /* DISP12 */
  { 2048, -2046, U12_LEN, C(UNCD_JUMP, DISP32) }, /* DISP12 */
  {    0,     0, U32_LEN, 0 },                       /* DISP32 */
  {    0,     0, U32_LEN, 0 },                       /* DISP32 */
  {    0,     0, U32_LEN, 0 }                        /* UNDEF_WORD_DISP */
  {    0,     0, U32_LEN, 0 }                        /* UNDEF_WORD_DISP */
 
 
};
};
 
 
/* Literal pool data structures.  */
/* Literal pool data structures.  */
struct literal
struct literal
{
{
  unsigned short  refcnt;
  unsigned short  refcnt;
  unsigned char   ispcrel;
  unsigned char   ispcrel;
  unsigned char   unused;
  unsigned char   unused;
  expressionS     e;
  expressionS     e;
};
};
 
 
#define MAX_POOL_SIZE   (1024/4)
#define MAX_POOL_SIZE   (1024/4)
static struct literal litpool [MAX_POOL_SIZE];
static struct literal litpool [MAX_POOL_SIZE];
static unsigned poolsize;
static unsigned poolsize;
static unsigned poolnumber;
static unsigned poolnumber;
static unsigned long poolspan;
static unsigned long poolspan;
 
 
/* SPANPANIC: the point at which we get too scared and force a dump
/* SPANPANIC: the point at which we get too scared and force a dump
   of the literal pool, and perhaps put a branch in place.
   of the literal pool, and perhaps put a branch in place.
   Calculated as:
   Calculated as:
                 1024   span of lrw/jmpi/jsri insn (actually span+1)
                 1024   span of lrw/jmpi/jsri insn (actually span+1)
                -2      possible alignment at the insn.
                -2      possible alignment at the insn.
                -2      possible alignment to get the table aligned.
                -2      possible alignment to get the table aligned.
                -2      an inserted branch around the table.
                -2      an inserted branch around the table.
             == 1018
             == 1018
   at 1018, we might be in trouble.
   at 1018, we might be in trouble.
   -- so we have to be smaller than 1018 and since we deal with 2-byte
   -- so we have to be smaller than 1018 and since we deal with 2-byte
   instructions, the next good choice is 1016.
   instructions, the next good choice is 1016.
   -- Note we have a test case that fails when we've got 1018 here.  */
   -- Note we have a test case that fails when we've got 1018 here.  */
#define SPANPANIC       (1016)          /* 1024 - 1 entry - 2 byte rounding.  */
#define SPANPANIC       (1016)          /* 1024 - 1 entry - 2 byte rounding.  */
#define SPANCLOSE       (900)
#define SPANCLOSE       (900)
#define SPANEXIT        (600)
#define SPANEXIT        (600)
static symbolS * poolsym;               /* Label for current pool.  */
static symbolS * poolsym;               /* Label for current pool.  */
static char poolname[8];
static char poolname[8];
static struct hash_control * opcode_hash_control;       /* Opcode mnemonics.  */
static struct hash_control * opcode_hash_control;       /* Opcode mnemonics.  */
 
 
#define POOL_END_LABEL   ".LE"
#define POOL_END_LABEL   ".LE"
#define POOL_START_LABEL ".LS"
#define POOL_START_LABEL ".LS"
 
 
static void
static void
make_name (char * s, char * p, int n)
make_name (char * s, char * p, int n)
{
{
  static const char hex[] = "0123456789ABCDEF";
  static const char hex[] = "0123456789ABCDEF";
 
 
  s[0] = p[0];
  s[0] = p[0];
  s[1] = p[1];
  s[1] = p[1];
  s[2] = p[2];
  s[2] = p[2];
  s[3] = hex[(n >> 12) & 0xF];
  s[3] = hex[(n >> 12) & 0xF];
  s[4] = hex[(n >>  8) & 0xF];
  s[4] = hex[(n >>  8) & 0xF];
  s[5] = hex[(n >>  4) & 0xF];
  s[5] = hex[(n >>  4) & 0xF];
  s[6] = hex[(n)       & 0xF];
  s[6] = hex[(n)       & 0xF];
  s[7] = 0;
  s[7] = 0;
}
}
 
 
static void
static void
dump_literals (int isforce)
dump_literals (int isforce)
{
{
  unsigned int i;
  unsigned int i;
  struct literal * p;
  struct literal * p;
  symbolS * brarsym = NULL;
  symbolS * brarsym = NULL;
 
 
  if (poolsize == 0)
  if (poolsize == 0)
    return;
    return;
 
 
  /* Must we branch around the literal table?  */
  /* Must we branch around the literal table?  */
  if (isforce)
  if (isforce)
    {
    {
      char * output;
      char * output;
      char brarname[8];
      char brarname[8];
 
 
      make_name (brarname, POOL_END_LABEL, poolnumber);
      make_name (brarname, POOL_END_LABEL, poolnumber);
 
 
      brarsym = symbol_make (brarname);
      brarsym = symbol_make (brarname);
 
 
      symbol_table_insert (brarsym);
      symbol_table_insert (brarsym);
 
 
      output = frag_var (rs_machine_dependent,
      output = frag_var (rs_machine_dependent,
                         md_relax_table[C (UNCD_JUMP, DISP32)].rlx_length,
                         md_relax_table[C (UNCD_JUMP, DISP32)].rlx_length,
                         md_relax_table[C (UNCD_JUMP, DISP12)].rlx_length,
                         md_relax_table[C (UNCD_JUMP, DISP12)].rlx_length,
                         C (UNCD_JUMP, 0), brarsym, 0, 0);
                         C (UNCD_JUMP, 0), brarsym, 0, 0);
      output[0] = INST_BYTE0 (MCORE_INST_BR);    /* br .+xxx */
      output[0] = INST_BYTE0 (MCORE_INST_BR);    /* br .+xxx */
      output[1] = INST_BYTE1 (MCORE_INST_BR);
      output[1] = INST_BYTE1 (MCORE_INST_BR);
    }
    }
 
 
  /* Make sure that the section is sufficiently aligned and that
  /* Make sure that the section is sufficiently aligned and that
     the literal table is aligned within it.  */
     the literal table is aligned within it.  */
  record_alignment (now_seg, 2);
  record_alignment (now_seg, 2);
  frag_align (2, 0, 0);
  frag_align (2, 0, 0);
 
 
  colon (S_GET_NAME (poolsym));
  colon (S_GET_NAME (poolsym));
 
 
  for (i = 0, p = litpool; i < poolsize; i++, p++)
  for (i = 0, p = litpool; i < poolsize; i++, p++)
    emit_expr (& p->e, 4);
    emit_expr (& p->e, 4);
 
 
  if (brarsym != NULL)
  if (brarsym != NULL)
    colon (S_GET_NAME (brarsym));
    colon (S_GET_NAME (brarsym));
 
 
   poolsize = 0;
   poolsize = 0;
}
}
 
 
static void
static void
mcore_s_literals (int ignore ATTRIBUTE_UNUSED)
mcore_s_literals (int ignore ATTRIBUTE_UNUSED)
{
{
  dump_literals (0);
  dump_literals (0);
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Perform FUNC (ARG), and track number of bytes added to frag.  */
/* Perform FUNC (ARG), and track number of bytes added to frag.  */
 
 
static void
static void
mcore_pool_count (void (*func) (int), int arg)
mcore_pool_count (void (*func) (int), int arg)
{
{
  const fragS *curr_frag = frag_now;
  const fragS *curr_frag = frag_now;
  offsetT added = -frag_now_fix_octets ();
  offsetT added = -frag_now_fix_octets ();
 
 
  (*func) (arg);
  (*func) (arg);
 
 
  while (curr_frag != frag_now)
  while (curr_frag != frag_now)
    {
    {
      added += curr_frag->fr_fix;
      added += curr_frag->fr_fix;
      curr_frag = curr_frag->fr_next;
      curr_frag = curr_frag->fr_next;
    }
    }
 
 
  added += frag_now_fix_octets ();
  added += frag_now_fix_octets ();
  poolspan += added;
  poolspan += added;
}
}
 
 
static void
static void
check_literals (int kind, int offset)
check_literals (int kind, int offset)
{
{
  poolspan += offset;
  poolspan += offset;
 
 
  /* SPANCLOSE and SPANEXIT are smaller numbers than SPANPANIC.
  /* SPANCLOSE and SPANEXIT are smaller numbers than SPANPANIC.
     SPANPANIC means that we must dump now.
     SPANPANIC means that we must dump now.
     kind == 0 is any old instruction.
     kind == 0 is any old instruction.
     kind  > 0 means we just had a control transfer instruction.
     kind  > 0 means we just had a control transfer instruction.
     kind == 1 means within a function
     kind == 1 means within a function
     kind == 2 means we just left a function
     kind == 2 means we just left a function
 
 
     The dump_literals (1) call inserts a branch around the table, so
     The dump_literals (1) call inserts a branch around the table, so
     we first look to see if its a situation where we won't have to
     we first look to see if its a situation where we won't have to
     insert a branch (e.g., the previous instruction was an unconditional
     insert a branch (e.g., the previous instruction was an unconditional
     branch).
     branch).
 
 
     SPANPANIC is the point where we must dump a single-entry pool.
     SPANPANIC is the point where we must dump a single-entry pool.
     it accounts for alignments and an inserted branch.
     it accounts for alignments and an inserted branch.
     the 'poolsize*2' accounts for the scenario where we do:
     the 'poolsize*2' accounts for the scenario where we do:
       lrw r1,lit1; lrw r2,lit2; lrw r3,lit3
       lrw r1,lit1; lrw r2,lit2; lrw r3,lit3
     Note that the 'lit2' reference is 2 bytes further along
     Note that the 'lit2' reference is 2 bytes further along
     but the literal it references will be 4 bytes further along,
     but the literal it references will be 4 bytes further along,
     so we must consider the poolsize into this equation.
     so we must consider the poolsize into this equation.
     This is slightly over-cautious, but guarantees that we won't
     This is slightly over-cautious, but guarantees that we won't
     panic because a relocation is too distant.  */
     panic because a relocation is too distant.  */
 
 
  if (poolspan > SPANCLOSE && kind > 0)
  if (poolspan > SPANCLOSE && kind > 0)
    dump_literals (0);
    dump_literals (0);
  else if (poolspan > SPANEXIT && kind > 1)
  else if (poolspan > SPANEXIT && kind > 1)
    dump_literals (0);
    dump_literals (0);
  else if (poolspan >= (SPANPANIC - poolsize * 2))
  else if (poolspan >= (SPANPANIC - poolsize * 2))
    dump_literals (1);
    dump_literals (1);
}
}
 
 
static void
static void
mcore_cons (int nbytes)
mcore_cons (int nbytes)
{
{
  if (now_seg == text_section)
  if (now_seg == text_section)
    mcore_pool_count (cons, nbytes);
    mcore_pool_count (cons, nbytes);
  else
  else
    cons (nbytes);
    cons (nbytes);
 
 
  /* In theory we ought to call check_literals (2,0) here in case
  /* In theory we ought to call check_literals (2,0) here in case
     we need to dump the literal table.  We cannot do this however,
     we need to dump the literal table.  We cannot do this however,
     as the directives that we are intercepting may be being used
     as the directives that we are intercepting may be being used
     to build a switch table, and we must not interfere with its
     to build a switch table, and we must not interfere with its
     contents.  Instead we cross our fingers and pray...  */
     contents.  Instead we cross our fingers and pray...  */
}
}
 
 
static void
static void
mcore_float_cons (int float_type)
mcore_float_cons (int float_type)
{
{
  if (now_seg == text_section)
  if (now_seg == text_section)
    mcore_pool_count (float_cons, float_type);
    mcore_pool_count (float_cons, float_type);
  else
  else
    float_cons (float_type);
    float_cons (float_type);
 
 
  /* See the comment in mcore_cons () about calling check_literals.
  /* See the comment in mcore_cons () about calling check_literals.
     It is unlikely that a switch table will be constructed using
     It is unlikely that a switch table will be constructed using
     floating point values, but it is still likely that an indexed
     floating point values, but it is still likely that an indexed
     table of floating point constants is being created by these
     table of floating point constants is being created by these
     directives, so again we must not interfere with their placement.  */
     directives, so again we must not interfere with their placement.  */
}
}
 
 
static void
static void
mcore_stringer (int append_zero)
mcore_stringer (int append_zero)
{
{
  if (now_seg == text_section)
  if (now_seg == text_section)
    mcore_pool_count (stringer, append_zero);
    mcore_pool_count (stringer, append_zero);
  else
  else
    stringer (append_zero);
    stringer (append_zero);
 
 
  /* We call check_literals here in case a large number of strings are
  /* We call check_literals here in case a large number of strings are
     being placed into the text section with a sequence of stringer
     being placed into the text section with a sequence of stringer
     directives.  In theory we could be upsetting something if these
     directives.  In theory we could be upsetting something if these
     strings are actually in an indexed table instead of referenced by
     strings are actually in an indexed table instead of referenced by
     individual labels.  Let us hope that that never happens.  */
     individual labels.  Let us hope that that never happens.  */
  check_literals (2, 0);
  check_literals (2, 0);
}
}
 
 
static void
static void
mcore_fill (int unused)
mcore_fill (int unused)
{
{
  if (now_seg == text_section)
  if (now_seg == text_section)
    mcore_pool_count (s_fill, unused);
    mcore_pool_count (s_fill, unused);
  else
  else
    s_fill (unused);
    s_fill (unused);
 
 
  check_literals (2, 0);
  check_literals (2, 0);
}
}
 
 
/* Handle the section changing pseudo-ops.  These call through to the
/* Handle the section changing pseudo-ops.  These call through to the
   normal implementations, but they dump the literal pool first.  */
   normal implementations, but they dump the literal pool first.  */
 
 
static void
static void
mcore_s_text (int ignore)
mcore_s_text (int ignore)
{
{
  dump_literals (0);
  dump_literals (0);
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  obj_elf_text (ignore);
  obj_elf_text (ignore);
#else
#else
  s_text (ignore);
  s_text (ignore);
#endif
#endif
}
}
 
 
static void
static void
mcore_s_data (int ignore)
mcore_s_data (int ignore)
{
{
  dump_literals (0);
  dump_literals (0);
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  obj_elf_data (ignore);
  obj_elf_data (ignore);
#else
#else
  s_data (ignore);
  s_data (ignore);
#endif
#endif
}
}
 
 
static void
static void
mcore_s_section (int ignore)
mcore_s_section (int ignore)
{
{
  /* Scan forwards to find the name of the section.  If the section
  /* Scan forwards to find the name of the section.  If the section
     being switched to is ".line" then this is a DWARF1 debug section
     being switched to is ".line" then this is a DWARF1 debug section
     which is arbitrarily placed inside generated code.  In this case
     which is arbitrarily placed inside generated code.  In this case
     do not dump the literal pool because it is a) inefficient and
     do not dump the literal pool because it is a) inefficient and
     b) would require the generation of extra code to jump around the
     b) would require the generation of extra code to jump around the
     pool.  */
     pool.  */
  char * ilp = input_line_pointer;
  char * ilp = input_line_pointer;
 
 
  while (*ilp != 0 && ISSPACE (*ilp))
  while (*ilp != 0 && ISSPACE (*ilp))
    ++ ilp;
    ++ ilp;
 
 
  if (strncmp (ilp, ".line", 5) == 0
  if (strncmp (ilp, ".line", 5) == 0
      && (ISSPACE (ilp[5]) || *ilp == '\n' || *ilp == '\r'))
      && (ISSPACE (ilp[5]) || *ilp == '\n' || *ilp == '\r'))
    ;
    ;
  else
  else
    dump_literals (0);
    dump_literals (0);
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  obj_elf_section (ignore);
  obj_elf_section (ignore);
#endif
#endif
#ifdef OBJ_COFF
#ifdef OBJ_COFF
  obj_coff_section (ignore);
  obj_coff_section (ignore);
#endif
#endif
}
}
 
 
static void
static void
mcore_s_bss (int needs_align)
mcore_s_bss (int needs_align)
{
{
  dump_literals (0);
  dump_literals (0);
 
 
  s_lcomm_bytes (needs_align);
  s_lcomm_bytes (needs_align);
}
}
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
static void
static void
mcore_s_comm (int needs_align)
mcore_s_comm (int needs_align)
{
{
  dump_literals (0);
  dump_literals (0);
 
 
  obj_elf_common (needs_align);
  obj_elf_common (needs_align);
}
}
#endif
#endif
 
 
/* This table describes all the machine specific pseudo-ops the assembler
/* This table describes all the machine specific pseudo-ops the assembler
   has to support.  The fields are:
   has to support.  The fields are:
     Pseudo-op name without dot
     Pseudo-op name without dot
     Function to call to execute this pseudo-op
     Function to call to execute this pseudo-op
     Integer arg to pass to the function.   */
     Integer arg to pass to the function.   */
const pseudo_typeS md_pseudo_table[] =
const pseudo_typeS md_pseudo_table[] =
{
{
  { "export",   s_globl,          0 },
  { "export",   s_globl,          0 },
  { "import",   s_ignore,         0 },
  { "import",   s_ignore,         0 },
  { "literals", mcore_s_literals, 0 },
  { "literals", mcore_s_literals, 0 },
  { "page",     listing_eject,    0 },
  { "page",     listing_eject,    0 },
 
 
  /* The following are to intercept the placement of data into the text
  /* The following are to intercept the placement of data into the text
     section (eg addresses for a switch table), so that the space they
     section (eg addresses for a switch table), so that the space they
     occupy can be taken into account when deciding whether or not to
     occupy can be taken into account when deciding whether or not to
     dump the current literal pool.
     dump the current literal pool.
     XXX - currently we do not cope with the .space and .dcb.d directives.  */
     XXX - currently we do not cope with the .space and .dcb.d directives.  */
  { "ascii",    mcore_stringer,       8 + 0 },
  { "ascii",    mcore_stringer,       8 + 0 },
  { "asciz",    mcore_stringer,       8 + 1 },
  { "asciz",    mcore_stringer,       8 + 1 },
  { "byte",     mcore_cons,           1 },
  { "byte",     mcore_cons,           1 },
  { "dc",       mcore_cons,           2 },
  { "dc",       mcore_cons,           2 },
  { "dc.b",     mcore_cons,           1 },
  { "dc.b",     mcore_cons,           1 },
  { "dc.d",     mcore_float_cons,    'd'},
  { "dc.d",     mcore_float_cons,    'd'},
  { "dc.l",     mcore_cons,           4 },
  { "dc.l",     mcore_cons,           4 },
  { "dc.s",     mcore_float_cons,    'f'},
  { "dc.s",     mcore_float_cons,    'f'},
  { "dc.w",     mcore_cons,           2 },
  { "dc.w",     mcore_cons,           2 },
  { "dc.x",     mcore_float_cons,    'x'},
  { "dc.x",     mcore_float_cons,    'x'},
  { "double",   mcore_float_cons,    'd'},
  { "double",   mcore_float_cons,    'd'},
  { "float",    mcore_float_cons,    'f'},
  { "float",    mcore_float_cons,    'f'},
  { "hword",    mcore_cons,           2 },
  { "hword",    mcore_cons,           2 },
  { "int",      mcore_cons,           4 },
  { "int",      mcore_cons,           4 },
  { "long",     mcore_cons,           4 },
  { "long",     mcore_cons,           4 },
  { "octa",     mcore_cons,          16 },
  { "octa",     mcore_cons,          16 },
  { "quad",     mcore_cons,           8 },
  { "quad",     mcore_cons,           8 },
  { "short",    mcore_cons,           2 },
  { "short",    mcore_cons,           2 },
  { "single",   mcore_float_cons,    'f'},
  { "single",   mcore_float_cons,    'f'},
  { "string",   mcore_stringer,       8 + 1 },
  { "string",   mcore_stringer,       8 + 1 },
  { "word",     mcore_cons,           2 },
  { "word",     mcore_cons,           2 },
  { "fill",     mcore_fill,           0 },
  { "fill",     mcore_fill,           0 },
 
 
  /* Allow for the effect of section changes.  */
  /* Allow for the effect of section changes.  */
  { "text",      mcore_s_text,    0 },
  { "text",      mcore_s_text,    0 },
  { "data",      mcore_s_data,    0 },
  { "data",      mcore_s_data,    0 },
  { "bss",       mcore_s_bss,     1 },
  { "bss",       mcore_s_bss,     1 },
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  { "comm",      mcore_s_comm,    0 },
  { "comm",      mcore_s_comm,    0 },
#endif
#endif
  { "section",   mcore_s_section, 0 },
  { "section",   mcore_s_section, 0 },
  { "section.s", mcore_s_section, 0 },
  { "section.s", mcore_s_section, 0 },
  { "sect",      mcore_s_section, 0 },
  { "sect",      mcore_s_section, 0 },
  { "sect.s",    mcore_s_section, 0 },
  { "sect.s",    mcore_s_section, 0 },
 
 
  { 0,          0,                0 }
  { 0,          0,                0 }
};
};
 
 
/* This function is called once, at assembler startup time.  This should
/* This function is called once, at assembler startup time.  This should
   set up all the tables, etc that the MD part of the assembler needs.  */
   set up all the tables, etc that the MD part of the assembler needs.  */
 
 
void
void
md_begin (void)
md_begin (void)
{
{
  const mcore_opcode_info * opcode;
  const mcore_opcode_info * opcode;
  char * prev_name = "";
  char * prev_name = "";
 
 
  opcode_hash_control = hash_new ();
  opcode_hash_control = hash_new ();
 
 
  /* Insert unique names into hash table.  */
  /* Insert unique names into hash table.  */
  for (opcode = mcore_table; opcode->name; opcode ++)
  for (opcode = mcore_table; opcode->name; opcode ++)
    {
    {
      if (! streq (prev_name, opcode->name))
      if (! streq (prev_name, opcode->name))
        {
        {
          prev_name = opcode->name;
          prev_name = opcode->name;
          hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
          hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
        }
        }
    }
    }
}
}
 
 
/* Get a log2(val).  */
/* Get a log2(val).  */
 
 
static int
static int
mylog2 (unsigned int val)
mylog2 (unsigned int val)
{
{
  int log = -1;
  int log = -1;
 
 
  while (val != 0)
  while (val != 0)
      {
      {
        log ++;
        log ++;
        val >>= 1;
        val >>= 1;
      }
      }
 
 
  return log;
  return log;
}
}
 
 
/* Try to parse a reg name.  */
/* Try to parse a reg name.  */
 
 
static char *
static char *
parse_reg (char * s, unsigned * reg)
parse_reg (char * s, unsigned * reg)
{
{
  /* Strip leading whitespace.  */
  /* Strip leading whitespace.  */
  while (ISSPACE (* s))
  while (ISSPACE (* s))
    ++ s;
    ++ s;
 
 
  if (TOLOWER (s[0]) == 'r')
  if (TOLOWER (s[0]) == 'r')
    {
    {
      if (s[1] == '1' && s[2] >= '0' && s[2] <= '5')
      if (s[1] == '1' && s[2] >= '0' && s[2] <= '5')
        {
        {
          *reg = 10 + s[2] - '0';
          *reg = 10 + s[2] - '0';
          return s + 3;
          return s + 3;
        }
        }
 
 
      if (s[1] >= '0' && s[1] <= '9')
      if (s[1] >= '0' && s[1] <= '9')
        {
        {
          *reg = s[1] - '0';
          *reg = s[1] - '0';
          return s + 2;
          return s + 2;
        }
        }
    }
    }
  else if (   TOLOWER (s[0]) == 's'
  else if (   TOLOWER (s[0]) == 's'
           && TOLOWER (s[1]) == 'p'
           && TOLOWER (s[1]) == 'p'
           && ! ISALNUM (s[2]))
           && ! ISALNUM (s[2]))
    {
    {
      * reg = 0;
      * reg = 0;
      return s + 2;
      return s + 2;
    }
    }
 
 
  as_bad (_("register expected, but saw '%.6s'"), s);
  as_bad (_("register expected, but saw '%.6s'"), s);
  return s;
  return s;
}
}
 
 
static struct Cregs
static struct Cregs
{
{
  char * name;
  char * name;
  unsigned int crnum;
  unsigned int crnum;
}
}
cregs[] =
cregs[] =
{
{
  { "psr",       0},
  { "psr",       0},
  { "vbr",       1},
  { "vbr",       1},
  { "epsr",      2},
  { "epsr",      2},
  { "fpsr",      3},
  { "fpsr",      3},
  { "epc",       4},
  { "epc",       4},
  { "fpc",       5},
  { "fpc",       5},
  { "ss0",       6},
  { "ss0",       6},
  { "ss1",       7},
  { "ss1",       7},
  { "ss2",       8},
  { "ss2",       8},
  { "ss3",       9},
  { "ss3",       9},
  { "ss4",      10},
  { "ss4",      10},
  { "gcr",      11},
  { "gcr",      11},
  { "gsr",      12},
  { "gsr",      12},
  { "",          0}
  { "",          0}
};
};
 
 
static char *
static char *
parse_creg (char * s, unsigned * reg)
parse_creg (char * s, unsigned * reg)
{
{
  int i;
  int i;
 
 
  /* Strip leading whitespace.  */
  /* Strip leading whitespace.  */
  while (ISSPACE (* s))
  while (ISSPACE (* s))
    ++s;
    ++s;
 
 
  if ((TOLOWER (s[0]) == 'c' && TOLOWER (s[1]) == 'r'))
  if ((TOLOWER (s[0]) == 'c' && TOLOWER (s[1]) == 'r'))
    {
    {
      if (s[2] == '3' && s[3] >= '0' && s[3] <= '1')
      if (s[2] == '3' && s[3] >= '0' && s[3] <= '1')
        {
        {
          *reg = 30 + s[3] - '0';
          *reg = 30 + s[3] - '0';
          return s + 4;
          return s + 4;
        }
        }
 
 
      if (s[2] == '2' && s[3] >= '0' && s[3] <= '9')
      if (s[2] == '2' && s[3] >= '0' && s[3] <= '9')
        {
        {
          *reg = 20 + s[3] - '0';
          *reg = 20 + s[3] - '0';
          return s + 4;
          return s + 4;
        }
        }
 
 
      if (s[2] == '1' && s[3] >= '0' && s[3] <= '9')
      if (s[2] == '1' && s[3] >= '0' && s[3] <= '9')
        {
        {
          *reg = 10 + s[3] - '0';
          *reg = 10 + s[3] - '0';
          return s + 4;
          return s + 4;
        }
        }
 
 
      if (s[2] >= '0' && s[2] <= '9')
      if (s[2] >= '0' && s[2] <= '9')
        {
        {
          *reg = s[2] - '0';
          *reg = s[2] - '0';
          return s + 3;
          return s + 3;
        }
        }
    }
    }
 
 
  /* Look at alternate creg names before giving error.  */
  /* Look at alternate creg names before giving error.  */
  for (i = 0; cregs[i].name[0] != '\0'; i++)
  for (i = 0; cregs[i].name[0] != '\0'; i++)
    {
    {
      char buf [10];
      char buf [10];
      int  length;
      int  length;
      int  j;
      int  j;
 
 
      length = strlen (cregs[i].name);
      length = strlen (cregs[i].name);
 
 
      for (j = 0; j < length; j++)
      for (j = 0; j < length; j++)
        buf[j] = TOLOWER (s[j]);
        buf[j] = TOLOWER (s[j]);
 
 
      if (strncmp (cregs[i].name, buf, length) == 0)
      if (strncmp (cregs[i].name, buf, length) == 0)
        {
        {
          *reg = cregs[i].crnum;
          *reg = cregs[i].crnum;
          return s + length;
          return s + length;
        }
        }
    }
    }
 
 
  as_bad (_("control register expected, but saw '%.6s'"), s);
  as_bad (_("control register expected, but saw '%.6s'"), s);
 
 
  return s;
  return s;
}
}
 
 
static char *
static char *
parse_psrmod (char * s, unsigned * reg)
parse_psrmod (char * s, unsigned * reg)
{
{
  int  i;
  int  i;
  char buf[10];
  char buf[10];
  static struct psrmods
  static struct psrmods
  {
  {
    char *       name;
    char *       name;
    unsigned int value;
    unsigned int value;
  }
  }
  psrmods[] =
  psrmods[] =
  {
  {
    { "ie", 1 },
    { "ie", 1 },
    { "fe", 2 },
    { "fe", 2 },
    { "ee", 4 },
    { "ee", 4 },
    { "af", 8 } /* Really 0 and non-combinable.  */
    { "af", 8 } /* Really 0 and non-combinable.  */
  };
  };
 
 
  for (i = 0; i < 2; i++)
  for (i = 0; i < 2; i++)
    buf[i] = TOLOWER (s[i]);
    buf[i] = TOLOWER (s[i]);
 
 
  for (i = sizeof (psrmods) / sizeof (psrmods[0]); i--;)
  for (i = sizeof (psrmods) / sizeof (psrmods[0]); i--;)
    {
    {
      if (! strncmp (psrmods[i].name, buf, 2))
      if (! strncmp (psrmods[i].name, buf, 2))
        {
        {
          * reg = psrmods[i].value;
          * reg = psrmods[i].value;
 
 
          return s + 2;
          return s + 2;
        }
        }
    }
    }
 
 
  as_bad (_("bad/missing psr specifier"));
  as_bad (_("bad/missing psr specifier"));
 
 
  * reg = 0;
  * reg = 0;
 
 
  return s;
  return s;
}
}
 
 
static char *
static char *
parse_exp (char * s, expressionS * e)
parse_exp (char * s, expressionS * e)
{
{
  char * save;
  char * save;
  char * new;
  char * new;
 
 
  /* Skip whitespace.  */
  /* Skip whitespace.  */
  while (ISSPACE (* s))
  while (ISSPACE (* s))
    ++ s;
    ++ s;
 
 
  save = input_line_pointer;
  save = input_line_pointer;
  input_line_pointer = s;
  input_line_pointer = s;
 
 
  expression (e);
  expression (e);
 
 
  if (e->X_op == O_absent)
  if (e->X_op == O_absent)
    as_bad (_("missing operand"));
    as_bad (_("missing operand"));
 
 
  new = input_line_pointer;
  new = input_line_pointer;
  input_line_pointer = save;
  input_line_pointer = save;
 
 
  return new;
  return new;
}
}
 
 
static int
static int
enter_literal (expressionS * e, int ispcrel)
enter_literal (expressionS * e, int ispcrel)
{
{
  unsigned int i;
  unsigned int i;
  struct literal * p;
  struct literal * p;
 
 
  if (poolsize >= MAX_POOL_SIZE - 2)
  if (poolsize >= MAX_POOL_SIZE - 2)
    /* The literal pool is as full as we can handle. We have
    /* The literal pool is as full as we can handle. We have
       to be 2 entries shy of the 1024/4=256 entries because we
       to be 2 entries shy of the 1024/4=256 entries because we
       have to allow for the branch (2 bytes) and the alignment
       have to allow for the branch (2 bytes) and the alignment
       (2 bytes before the first insn referencing the pool and
       (2 bytes before the first insn referencing the pool and
       2 bytes before the pool itself) == 6 bytes, rounds up
       2 bytes before the pool itself) == 6 bytes, rounds up
       to 2 entries.  */
       to 2 entries.  */
    dump_literals (1);
    dump_literals (1);
 
 
  if (poolsize == 0)
  if (poolsize == 0)
    {
    {
      /* Create new literal pool.  */
      /* Create new literal pool.  */
      if (++ poolnumber > 0xFFFF)
      if (++ poolnumber > 0xFFFF)
        as_fatal (_("more than 65K literal pools"));
        as_fatal (_("more than 65K literal pools"));
 
 
      make_name (poolname, POOL_START_LABEL, poolnumber);
      make_name (poolname, POOL_START_LABEL, poolnumber);
      poolsym = symbol_make (poolname);
      poolsym = symbol_make (poolname);
      symbol_table_insert (poolsym);
      symbol_table_insert (poolsym);
      poolspan = 0;
      poolspan = 0;
    }
    }
 
 
  /* Search pool for value so we don't have duplicates.  */
  /* Search pool for value so we don't have duplicates.  */
  for (p = litpool, i = 0; i < poolsize; i++, p++)
  for (p = litpool, i = 0; i < poolsize; i++, p++)
    {
    {
      if (e->X_op == p->e.X_op
      if (e->X_op == p->e.X_op
          && e->X_add_symbol == p->e.X_add_symbol
          && e->X_add_symbol == p->e.X_add_symbol
          && e->X_add_number == p->e.X_add_number
          && e->X_add_number == p->e.X_add_number
          && ispcrel == p->ispcrel)
          && ispcrel == p->ispcrel)
        {
        {
          p->refcnt ++;
          p->refcnt ++;
          return i;
          return i;
        }
        }
    }
    }
 
 
  p->refcnt  = 1;
  p->refcnt  = 1;
  p->ispcrel = ispcrel;
  p->ispcrel = ispcrel;
  p->e       = * e;
  p->e       = * e;
 
 
  poolsize ++;
  poolsize ++;
 
 
  return i;
  return i;
}
}
 
 
/* Parse a literal specification. -- either new or old syntax.
/* Parse a literal specification. -- either new or old syntax.
   old syntax: the user supplies the label and places the literal.
   old syntax: the user supplies the label and places the literal.
   new syntax: we put it into the literal pool.  */
   new syntax: we put it into the literal pool.  */
 
 
static char *
static char *
parse_rt (char * s,
parse_rt (char * s,
          char ** outputp,
          char ** outputp,
          int ispcrel,
          int ispcrel,
          expressionS * ep)
          expressionS * ep)
{
{
  expressionS e;
  expressionS e;
  int n;
  int n;
 
 
  if (ep)
  if (ep)
    /* Indicate nothing there.  */
    /* Indicate nothing there.  */
    ep->X_op = O_absent;
    ep->X_op = O_absent;
 
 
  if (*s == '[')
  if (*s == '[')
    {
    {
      s = parse_exp (s + 1, & e);
      s = parse_exp (s + 1, & e);
 
 
      if (*s == ']')
      if (*s == ']')
        s++;
        s++;
      else
      else
        as_bad (_("missing ']'"));
        as_bad (_("missing ']'"));
    }
    }
  else
  else
    {
    {
      s = parse_exp (s, & e);
      s = parse_exp (s, & e);
 
 
      n = enter_literal (& e, ispcrel);
      n = enter_literal (& e, ispcrel);
 
 
      if (ep)
      if (ep)
        *ep = e;
        *ep = e;
 
 
      /* Create a reference to pool entry.  */
      /* Create a reference to pool entry.  */
      e.X_op         = O_symbol;
      e.X_op         = O_symbol;
      e.X_add_symbol = poolsym;
      e.X_add_symbol = poolsym;
      e.X_add_number = n << 2;
      e.X_add_number = n << 2;
    }
    }
 
 
  * outputp = frag_more (2);
  * outputp = frag_more (2);
 
 
  fix_new_exp (frag_now, (*outputp) - frag_now->fr_literal, 2, & e, 1,
  fix_new_exp (frag_now, (*outputp) - frag_now->fr_literal, 2, & e, 1,
               BFD_RELOC_MCORE_PCREL_IMM8BY4);
               BFD_RELOC_MCORE_PCREL_IMM8BY4);
 
 
  return s;
  return s;
}
}
 
 
static char *
static char *
parse_imm (char * s,
parse_imm (char * s,
           unsigned * val,
           unsigned * val,
           unsigned min,
           unsigned min,
           unsigned max)
           unsigned max)
{
{
  char * new;
  char * new;
  expressionS e;
  expressionS e;
 
 
  new = parse_exp (s, & e);
  new = parse_exp (s, & e);
 
 
  if (e.X_op == O_absent)
  if (e.X_op == O_absent)
    ; /* An error message has already been emitted.  */
    ; /* An error message has already been emitted.  */
  else if (e.X_op != O_constant)
  else if (e.X_op != O_constant)
    as_bad (_("operand must be a constant"));
    as_bad (_("operand must be a constant"));
  else if ((addressT) e.X_add_number < min || (addressT) e.X_add_number > max)
  else if ((addressT) e.X_add_number < min || (addressT) e.X_add_number > max)
    as_bad (_("operand must be absolute in range %u..%u, not %ld"),
    as_bad (_("operand must be absolute in range %u..%u, not %ld"),
            min, max, (long) e.X_add_number);
            min, max, (long) e.X_add_number);
 
 
  * val = e.X_add_number;
  * val = e.X_add_number;
 
 
  return new;
  return new;
}
}
 
 
static char *
static char *
parse_mem (char * s,
parse_mem (char * s,
           unsigned * reg,
           unsigned * reg,
           unsigned * off,
           unsigned * off,
           unsigned siz)
           unsigned siz)
{
{
  * off = 0;
  * off = 0;
 
 
  while (ISSPACE (* s))
  while (ISSPACE (* s))
    ++ s;
    ++ s;
 
 
  if (* s == '(')
  if (* s == '(')
    {
    {
      s = parse_reg (s + 1, reg);
      s = parse_reg (s + 1, reg);
 
 
      while (ISSPACE (* s))
      while (ISSPACE (* s))
        ++ s;
        ++ s;
 
 
      if (* s == ',')
      if (* s == ',')
        {
        {
          s = parse_imm (s + 1, off, 0, 63);
          s = parse_imm (s + 1, off, 0, 63);
 
 
          if (siz > 1)
          if (siz > 1)
            {
            {
              if (siz > 2)
              if (siz > 2)
                {
                {
                  if (* off & 0x3)
                  if (* off & 0x3)
                    as_bad (_("operand must be a multiple of 4"));
                    as_bad (_("operand must be a multiple of 4"));
 
 
                  * off >>= 2;
                  * off >>= 2;
                }
                }
              else
              else
                {
                {
                  if (* off & 0x1)
                  if (* off & 0x1)
                    as_bad (_("operand must be a multiple of 2"));
                    as_bad (_("operand must be a multiple of 2"));
 
 
                  * off >>= 1;
                  * off >>= 1;
                }
                }
            }
            }
        }
        }
 
 
      while (ISSPACE (* s))
      while (ISSPACE (* s))
        ++ s;
        ++ s;
 
 
      if (* s == ')')
      if (* s == ')')
        s ++;
        s ++;
    }
    }
  else
  else
    as_bad (_("base register expected"));
    as_bad (_("base register expected"));
 
 
  return s;
  return s;
}
}
 
 
/* This is the guts of the machine-dependent assembler.  STR points to a
/* This is the guts of the machine-dependent assembler.  STR points to a
   machine dependent instruction.  This function is supposed to emit
   machine dependent instruction.  This function is supposed to emit
   the frags/bytes it assembles to.  */
   the frags/bytes it assembles to.  */
 
 
void
void
md_assemble (char * str)
md_assemble (char * str)
{
{
  char * op_start;
  char * op_start;
  char * op_end;
  char * op_end;
  mcore_opcode_info * opcode;
  mcore_opcode_info * opcode;
  char * output;
  char * output;
  int nlen = 0;
  int nlen = 0;
  unsigned short inst;
  unsigned short inst;
  unsigned reg;
  unsigned reg;
  unsigned off;
  unsigned off;
  unsigned isize;
  unsigned isize;
  expressionS e;
  expressionS e;
  char name[20];
  char name[20];
 
 
  /* Drop leading whitespace.  */
  /* Drop leading whitespace.  */
  while (ISSPACE (* str))
  while (ISSPACE (* str))
    str ++;
    str ++;
 
 
  /* Find the op code end.  */
  /* Find the op code end.  */
  for (op_start = op_end = str;
  for (op_start = op_end = str;
       nlen < 20 && !is_end_of_line [(unsigned char) *op_end] && *op_end != ' ';
       nlen < 20 && !is_end_of_line [(unsigned char) *op_end] && *op_end != ' ';
       op_end++)
       op_end++)
    {
    {
      name[nlen] = op_start[nlen];
      name[nlen] = op_start[nlen];
      nlen++;
      nlen++;
    }
    }
 
 
  name [nlen] = 0;
  name [nlen] = 0;
 
 
  if (nlen == 0)
  if (nlen == 0)
    {
    {
      as_bad (_("can't find opcode "));
      as_bad (_("can't find opcode "));
      return;
      return;
    }
    }
 
 
  opcode = (mcore_opcode_info *) hash_find (opcode_hash_control, name);
  opcode = (mcore_opcode_info *) hash_find (opcode_hash_control, name);
  if (opcode == NULL)
  if (opcode == NULL)
    {
    {
      as_bad (_("unknown opcode \"%s\""), name);
      as_bad (_("unknown opcode \"%s\""), name);
      return;
      return;
    }
    }
 
 
  inst = opcode->inst;
  inst = opcode->inst;
  isize = 2;
  isize = 2;
 
 
  switch (opcode->opclass)
  switch (opcode->opclass)
    {
    {
    case O0:
    case O0:
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case OT:
    case OT:
      op_end = parse_imm (op_end + 1, & reg, 0, 3);
      op_end = parse_imm (op_end + 1, & reg, 0, 3);
      inst |= reg;
      inst |= reg;
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case O1:
    case O1:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case JMP:
    case JMP:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
      output = frag_more (2);
      output = frag_more (2);
      /* In a sifilter mode, we emit this insn 2 times,
      /* In a sifilter mode, we emit this insn 2 times,
         fixes problem of an interrupt during a jmp..  */
         fixes problem of an interrupt during a jmp..  */
      if (sifilter_mode)
      if (sifilter_mode)
        {
        {
          output[0] = INST_BYTE0 (inst);
          output[0] = INST_BYTE0 (inst);
          output[1] = INST_BYTE1 (inst);
          output[1] = INST_BYTE1 (inst);
          output = frag_more (2);
          output = frag_more (2);
        }
        }
      break;
      break;
 
 
    case JSR:
    case JSR:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
 
 
      if (reg == 15)
      if (reg == 15)
        as_bad (_("invalid register: r15 illegal"));
        as_bad (_("invalid register: r15 illegal"));
 
 
      inst |= reg;
      inst |= reg;
      output = frag_more (2);
      output = frag_more (2);
 
 
      if (sifilter_mode)
      if (sifilter_mode)
        {
        {
          /* Replace with:  bsr .+2 ; addi r15,6; jmp rx ; jmp rx.  */
          /* Replace with:  bsr .+2 ; addi r15,6; jmp rx ; jmp rx.  */
          inst = MCORE_INST_BSR;        /* With 0 displacement.  */
          inst = MCORE_INST_BSR;        /* With 0 displacement.  */
          output[0] = INST_BYTE0 (inst);
          output[0] = INST_BYTE0 (inst);
          output[1] = INST_BYTE1 (inst);
          output[1] = INST_BYTE1 (inst);
 
 
          output = frag_more (2);
          output = frag_more (2);
          inst = MCORE_INST_ADDI;
          inst = MCORE_INST_ADDI;
          inst |= 15;                   /* addi r15,6  */
          inst |= 15;                   /* addi r15,6  */
          inst |= (6 - 1) << 4;         /* Over the jmp's.  */
          inst |= (6 - 1) << 4;         /* Over the jmp's.  */
          output[0] = INST_BYTE0 (inst);
          output[0] = INST_BYTE0 (inst);
          output[1] = INST_BYTE1 (inst);
          output[1] = INST_BYTE1 (inst);
 
 
          output = frag_more (2);
          output = frag_more (2);
          inst = MCORE_INST_JMP | reg;
          inst = MCORE_INST_JMP | reg;
          output[0] = INST_BYTE0 (inst);
          output[0] = INST_BYTE0 (inst);
          output[1] = INST_BYTE1 (inst);
          output[1] = INST_BYTE1 (inst);
 
 
          /* 2nd emitted in fallthrough.  */
          /* 2nd emitted in fallthrough.  */
          output = frag_more (2);
          output = frag_more (2);
        }
        }
      break;
      break;
 
 
    case OC:
    case OC:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (*op_end == ',')
      if (*op_end == ',')
        {
        {
          op_end = parse_creg (op_end + 1, & reg);
          op_end = parse_creg (op_end + 1, & reg);
          inst |= reg << 4;
          inst |= reg << 4;
        }
        }
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case MULSH:
    case MULSH:
      if (cpu == M210)
      if (cpu == M210)
        {
        {
          as_bad (_("M340 specific opcode used when assembling for M210"));
          as_bad (_("M340 specific opcode used when assembling for M210"));
          break;
          break;
        }
        }
      /* drop through...  */
      /* drop through...  */
    case O2:
    case O2:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_reg (op_end + 1, & reg);
          op_end = parse_reg (op_end + 1, & reg);
          inst |= reg << 4;
          inst |= reg << 4;
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case X1:
    case X1:
      /* Handle both syntax-> xtrb- r1,rx OR xtrb- rx.  */
      /* Handle both syntax-> xtrb- r1,rx OR xtrb- rx.  */
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')      /* xtrb- r1,rx.  */
      if (* op_end == ',')      /* xtrb- r1,rx.  */
        {
        {
          if (reg != 1)
          if (reg != 1)
            as_bad (_("destination register must be r1"));
            as_bad (_("destination register must be r1"));
 
 
          op_end = parse_reg (op_end + 1, & reg);
          op_end = parse_reg (op_end + 1, & reg);
        }
        }
 
 
      inst |= reg;
      inst |= reg;
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case O1R1:  /* div- rx,r1.  */
    case O1R1:  /* div- rx,r1.  */
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_reg (op_end + 1, & reg);
          op_end = parse_reg (op_end + 1, & reg);
          if (reg != 1)
          if (reg != 1)
            as_bad (_("source register must be r1"));
            as_bad (_("source register must be r1"));
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case OI:
    case OI:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_imm (op_end + 1, & reg, 1, 32);
          op_end = parse_imm (op_end + 1, & reg, 1, 32);
          inst |= (reg - 1) << 4;
          inst |= (reg - 1) << 4;
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case OB:
    case OB:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_imm (op_end + 1, & reg, 0, 31);
          op_end = parse_imm (op_end + 1, & reg, 0, 31);
          inst |= reg << 4;
          inst |= reg << 4;
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case OB2:
    case OB2:
      /* Like OB, but arg is 2^n instead of n.  */
      /* Like OB, but arg is 2^n instead of n.  */
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_imm (op_end + 1, & reg, 1, 1 << 31);
          op_end = parse_imm (op_end + 1, & reg, 1, 1 << 31);
          /* Further restrict the immediate to a power of two.  */
          /* Further restrict the immediate to a power of two.  */
          if ((reg & (reg - 1)) == 0)
          if ((reg & (reg - 1)) == 0)
            reg = mylog2 (reg);
            reg = mylog2 (reg);
          else
          else
            {
            {
              reg = 0;
              reg = 0;
              as_bad (_("immediate is not a power of two"));
              as_bad (_("immediate is not a power of two"));
            }
            }
          inst |= (reg) << 4;
          inst |= (reg) << 4;
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case OBRa:  /* Specific for bgeni: imm of 0->6 translate to movi.  */
    case OBRa:  /* Specific for bgeni: imm of 0->6 translate to movi.  */
    case OBRb:
    case OBRb:
    case OBRc:
    case OBRc:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_imm (op_end + 1, & reg, 0, 31);
          op_end = parse_imm (op_end + 1, & reg, 0, 31);
          /* Immediate values of 0 -> 6 translate to movi.  */
          /* Immediate values of 0 -> 6 translate to movi.  */
          if (reg <= 6)
          if (reg <= 6)
            {
            {
              inst = (inst & 0xF) | MCORE_INST_BGENI_ALT;
              inst = (inst & 0xF) | MCORE_INST_BGENI_ALT;
              reg = 0x1 << reg;
              reg = 0x1 << reg;
              as_warn (_("translating bgeni to movi"));
              as_warn (_("translating bgeni to movi"));
            }
            }
          inst &= ~ 0x01f0;
          inst &= ~ 0x01f0;
          inst |= reg << 4;
          inst |= reg << 4;
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case OBR2:  /* Like OBR, but arg is 2^n instead of n.  */
    case OBR2:  /* Like OBR, but arg is 2^n instead of n.  */
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_imm (op_end + 1, & reg, 1, 1 << 31);
          op_end = parse_imm (op_end + 1, & reg, 1, 1 << 31);
 
 
          /* Further restrict the immediate to a power of two.  */
          /* Further restrict the immediate to a power of two.  */
          if ((reg & (reg - 1)) == 0)
          if ((reg & (reg - 1)) == 0)
            reg = mylog2 (reg);
            reg = mylog2 (reg);
          else
          else
            {
            {
              reg = 0;
              reg = 0;
              as_bad (_("immediate is not a power of two"));
              as_bad (_("immediate is not a power of two"));
            }
            }
 
 
          /* Immediate values of 0 -> 6 translate to movi.  */
          /* Immediate values of 0 -> 6 translate to movi.  */
          if (reg <= 6)
          if (reg <= 6)
            {
            {
              inst = (inst & 0xF) | MCORE_INST_BGENI_ALT;
              inst = (inst & 0xF) | MCORE_INST_BGENI_ALT;
              reg = 0x1 << reg;
              reg = 0x1 << reg;
              as_warn (_("translating mgeni to movi"));
              as_warn (_("translating mgeni to movi"));
            }
            }
 
 
          inst |= reg << 4;
          inst |= reg << 4;
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case OMa:   /* Specific for bmaski: imm 1->7 translate to movi.  */
    case OMa:   /* Specific for bmaski: imm 1->7 translate to movi.  */
    case OMb:
    case OMb:
    case OMc:
    case OMc:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_imm (op_end + 1, & reg, 1, 32);
          op_end = parse_imm (op_end + 1, & reg, 1, 32);
 
 
          /* Immediate values of 1 -> 7 translate to movi.  */
          /* Immediate values of 1 -> 7 translate to movi.  */
          if (reg <= 7)
          if (reg <= 7)
            {
            {
              inst = (inst & 0xF) | MCORE_INST_BMASKI_ALT;
              inst = (inst & 0xF) | MCORE_INST_BMASKI_ALT;
              reg = (0x1 << reg) - 1;
              reg = (0x1 << reg) - 1;
              inst |= reg << 4;
              inst |= reg << 4;
 
 
              as_warn (_("translating bmaski to movi"));
              as_warn (_("translating bmaski to movi"));
            }
            }
          else
          else
            {
            {
              inst &= ~ 0x01F0;
              inst &= ~ 0x01F0;
              inst |= (reg & 0x1F) << 4;
              inst |= (reg & 0x1F) << 4;
            }
            }
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case SI:
    case SI:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_imm (op_end + 1, & reg, 1, 31);
          op_end = parse_imm (op_end + 1, & reg, 1, 31);
          inst |= reg << 4;
          inst |= reg << 4;
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case I7:
    case I7:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_imm (op_end + 1, & reg, 0, 0x7F);
          op_end = parse_imm (op_end + 1, & reg, 0, 0x7F);
          inst |= reg << 4;
          inst |= reg << 4;
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case LS:
    case LS:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg << 8;
      inst |= reg << 8;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          int size;
          int size;
 
 
          if ((inst & 0x6000) == 0)
          if ((inst & 0x6000) == 0)
            size = 4;
            size = 4;
          else if ((inst & 0x6000) == 0x4000)
          else if ((inst & 0x6000) == 0x4000)
            size = 2;
            size = 2;
          else if ((inst & 0x6000) == 0x2000)
          else if ((inst & 0x6000) == 0x2000)
            size = 1;
            size = 1;
          else
          else
            abort ();
            abort ();
 
 
          op_end = parse_mem (op_end + 1, & reg, & off, size);
          op_end = parse_mem (op_end + 1, & reg, & off, size);
 
 
          if (off > 16)
          if (off > 16)
            as_bad (_("displacement too large (%d)"), off);
            as_bad (_("displacement too large (%d)"), off);
          else
          else
            inst |= (reg) | (off << 4);
            inst |= (reg) | (off << 4);
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case LR:
    case LR:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
 
 
      if (reg == 0 || reg == 15)
      if (reg == 0 || reg == 15)
        as_bad (_("Invalid register: r0 and r15 illegal"));
        as_bad (_("Invalid register: r0 and r15 illegal"));
 
 
      inst |= (reg << 8);
      inst |= (reg << 8);
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          /* parse_rt calls frag_more() for us.  */
          /* parse_rt calls frag_more() for us.  */
          input_line_pointer = parse_rt (op_end + 1, & output, 0, 0);
          input_line_pointer = parse_rt (op_end + 1, & output, 0, 0);
          op_end = input_line_pointer;
          op_end = input_line_pointer;
        }
        }
      else
      else
        {
        {
          as_bad (_("second operand missing"));
          as_bad (_("second operand missing"));
          output = frag_more (2);               /* save its space */
          output = frag_more (2);               /* save its space */
        }
        }
      break;
      break;
 
 
    case LJ:
    case LJ:
      input_line_pointer = parse_rt (op_end + 1, & output, 1, 0);
      input_line_pointer = parse_rt (op_end + 1, & output, 1, 0);
      /* parse_rt() calls frag_more() for us.  */
      /* parse_rt() calls frag_more() for us.  */
      op_end = input_line_pointer;
      op_end = input_line_pointer;
      break;
      break;
 
 
    case RM:
    case RM:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
 
 
      if (reg == 0 || reg == 15)
      if (reg == 0 || reg == 15)
        as_bad (_("bad starting register: r0 and r15 invalid"));
        as_bad (_("bad starting register: r0 and r15 invalid"));
 
 
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == '-')
      if (* op_end == '-')
        {
        {
          op_end = parse_reg (op_end + 1, & reg);
          op_end = parse_reg (op_end + 1, & reg);
 
 
          if (reg != 15)
          if (reg != 15)
            as_bad (_("ending register must be r15"));
            as_bad (_("ending register must be r15"));
 
 
          /* Skip whitespace.  */
          /* Skip whitespace.  */
          while (ISSPACE (* op_end))
          while (ISSPACE (* op_end))
            ++ op_end;
            ++ op_end;
        }
        }
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end ++;
          op_end ++;
 
 
          /* Skip whitespace.  */
          /* Skip whitespace.  */
          while (ISSPACE (* op_end))
          while (ISSPACE (* op_end))
            ++ op_end;
            ++ op_end;
 
 
          if (* op_end == '(')
          if (* op_end == '(')
            {
            {
              op_end = parse_reg (op_end + 1, & reg);
              op_end = parse_reg (op_end + 1, & reg);
 
 
              if (reg != 0)
              if (reg != 0)
                as_bad (_("bad base register: must be r0"));
                as_bad (_("bad base register: must be r0"));
 
 
              if (* op_end == ')')
              if (* op_end == ')')
                op_end ++;
                op_end ++;
            }
            }
          else
          else
            as_bad (_("base register expected"));
            as_bad (_("base register expected"));
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case RQ:
    case RQ:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
 
 
      if (reg != 4)
      if (reg != 4)
        as_fatal (_("first register must be r4"));
        as_fatal (_("first register must be r4"));
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == '-')
      if (* op_end == '-')
        {
        {
          op_end = parse_reg (op_end + 1, & reg);
          op_end = parse_reg (op_end + 1, & reg);
 
 
          if (reg != 7)
          if (reg != 7)
            as_fatal (_("last register must be r7"));
            as_fatal (_("last register must be r7"));
 
 
          /* Skip whitespace.  */
          /* Skip whitespace.  */
          while (ISSPACE (* op_end))
          while (ISSPACE (* op_end))
            ++ op_end;
            ++ op_end;
 
 
          if (* op_end == ',')
          if (* op_end == ',')
            {
            {
              op_end ++;
              op_end ++;
 
 
              /* Skip whitespace.  */
              /* Skip whitespace.  */
              while (ISSPACE (* op_end))
              while (ISSPACE (* op_end))
                ++ op_end;
                ++ op_end;
 
 
              if (* op_end == '(')
              if (* op_end == '(')
                {
                {
                  op_end = parse_reg (op_end + 1, & reg);
                  op_end = parse_reg (op_end + 1, & reg);
 
 
                  if (reg >= 4 && reg <= 7)
                  if (reg >= 4 && reg <= 7)
                    as_fatal ("base register cannot be r4, r5, r6, or r7");
                    as_fatal ("base register cannot be r4, r5, r6, or r7");
 
 
                  inst |= reg;
                  inst |= reg;
 
 
                  /* Skip whitespace.  */
                  /* Skip whitespace.  */
                  while (ISSPACE (* op_end))
                  while (ISSPACE (* op_end))
                    ++ op_end;
                    ++ op_end;
 
 
                  if (* op_end == ')')
                  if (* op_end == ')')
                    op_end ++;
                    op_end ++;
                }
                }
              else
              else
                as_bad (_("base register expected"));
                as_bad (_("base register expected"));
            }
            }
          else
          else
            as_bad (_("second operand missing"));
            as_bad (_("second operand missing"));
        }
        }
      else
      else
        as_bad (_("reg-reg expected"));
        as_bad (_("reg-reg expected"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case BR:
    case BR:
      input_line_pointer = parse_exp (op_end + 1, & e);
      input_line_pointer = parse_exp (op_end + 1, & e);
      op_end = input_line_pointer;
      op_end = input_line_pointer;
 
 
      output = frag_more (2);
      output = frag_more (2);
 
 
      fix_new_exp (frag_now, output-frag_now->fr_literal,
      fix_new_exp (frag_now, output-frag_now->fr_literal,
                   2, & e, 1, BFD_RELOC_MCORE_PCREL_IMM11BY2);
                   2, & e, 1, BFD_RELOC_MCORE_PCREL_IMM11BY2);
      break;
      break;
 
 
    case BL:
    case BL:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg << 4;
      inst |= reg << 4;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_exp (op_end + 1, & e);
          op_end = parse_exp (op_end + 1, & e);
          output = frag_more (2);
          output = frag_more (2);
 
 
          fix_new_exp (frag_now, output-frag_now->fr_literal,
          fix_new_exp (frag_now, output-frag_now->fr_literal,
                       2, & e, 1, BFD_RELOC_MCORE_PCREL_IMM4BY2);
                       2, & e, 1, BFD_RELOC_MCORE_PCREL_IMM4BY2);
        }
        }
      else
      else
        {
        {
          as_bad (_("second operand missing"));
          as_bad (_("second operand missing"));
          output = frag_more (2);
          output = frag_more (2);
        }
        }
      break;
      break;
 
 
    case JC:
    case JC:
      input_line_pointer = parse_exp (op_end + 1, & e);
      input_line_pointer = parse_exp (op_end + 1, & e);
      op_end = input_line_pointer;
      op_end = input_line_pointer;
 
 
      output = frag_var (rs_machine_dependent,
      output = frag_var (rs_machine_dependent,
                         md_relax_table[C (COND_JUMP, DISP32)].rlx_length,
                         md_relax_table[C (COND_JUMP, DISP32)].rlx_length,
                         md_relax_table[C (COND_JUMP, DISP12)].rlx_length,
                         md_relax_table[C (COND_JUMP, DISP12)].rlx_length,
                         C (COND_JUMP, 0), e.X_add_symbol, e.X_add_number, 0);
                         C (COND_JUMP, 0), e.X_add_symbol, e.X_add_number, 0);
      isize = C32_LEN;
      isize = C32_LEN;
      break;
      break;
 
 
    case JU:
    case JU:
      input_line_pointer = parse_exp (op_end + 1, & e);
      input_line_pointer = parse_exp (op_end + 1, & e);
      op_end = input_line_pointer;
      op_end = input_line_pointer;
 
 
      output = frag_var (rs_machine_dependent,
      output = frag_var (rs_machine_dependent,
                         md_relax_table[C (UNCD_JUMP, DISP32)].rlx_length,
                         md_relax_table[C (UNCD_JUMP, DISP32)].rlx_length,
                         md_relax_table[C (UNCD_JUMP, DISP12)].rlx_length,
                         md_relax_table[C (UNCD_JUMP, DISP12)].rlx_length,
                         C (UNCD_JUMP, 0), e.X_add_symbol, e.X_add_number, 0);
                         C (UNCD_JUMP, 0), e.X_add_symbol, e.X_add_number, 0);
      isize = U32_LEN;
      isize = U32_LEN;
      break;
      break;
 
 
    case JL:
    case JL:
      inst = MCORE_INST_JSRI;           /* jsri */
      inst = MCORE_INST_JSRI;           /* jsri */
      input_line_pointer = parse_rt (op_end + 1, & output, 1, & e);
      input_line_pointer = parse_rt (op_end + 1, & output, 1, & e);
      /* parse_rt() calls frag_more for us.  */
      /* parse_rt() calls frag_more for us.  */
      op_end = input_line_pointer;
      op_end = input_line_pointer;
 
 
      /* Only do this if we know how to do it ...  */
      /* Only do this if we know how to do it ...  */
      if (e.X_op != O_absent && do_jsri2bsr)
      if (e.X_op != O_absent && do_jsri2bsr)
        {
        {
          /* Look at adding the R_PCREL_JSRIMM11BY2.  */
          /* Look at adding the R_PCREL_JSRIMM11BY2.  */
          fix_new_exp (frag_now, output-frag_now->fr_literal,
          fix_new_exp (frag_now, output-frag_now->fr_literal,
                       2, & e, 1, BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2);
                       2, & e, 1, BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2);
        }
        }
      break;
      break;
 
 
    case RSI:
    case RSI:
      /* SI, but imm becomes 32-imm.  */
      /* SI, but imm becomes 32-imm.  */
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_imm (op_end + 1, & reg, 1, 31);
          op_end = parse_imm (op_end + 1, & reg, 1, 31);
 
 
          reg = 32 - reg;
          reg = 32 - reg;
          inst |= reg << 4;
          inst |= reg << 4;
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case DO21:                  /* O2, dup rd, lit must be 1 */
    case DO21:                  /* O2, dup rd, lit must be 1 */
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
      inst |= reg << 4;
      inst |= reg << 4;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_imm (op_end + 1, & reg, 1, 31);
          op_end = parse_imm (op_end + 1, & reg, 1, 31);
 
 
          if (reg != 1)
          if (reg != 1)
            as_bad (_("second operand must be 1"));
            as_bad (_("second operand must be 1"));
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case SIa:
    case SIa:
      op_end = parse_reg (op_end + 1, & reg);
      op_end = parse_reg (op_end + 1, & reg);
      inst |= reg;
      inst |= reg;
 
 
      /* Skip whitespace.  */
      /* Skip whitespace.  */
      while (ISSPACE (* op_end))
      while (ISSPACE (* op_end))
        ++ op_end;
        ++ op_end;
 
 
      if (* op_end == ',')
      if (* op_end == ',')
        {
        {
          op_end = parse_imm (op_end + 1, & reg, 1, 31);
          op_end = parse_imm (op_end + 1, & reg, 1, 31);
 
 
          if (reg == 0)
          if (reg == 0)
            as_bad (_("zero used as immediate value"));
            as_bad (_("zero used as immediate value"));
 
 
          inst |= reg << 4;
          inst |= reg << 4;
        }
        }
      else
      else
        as_bad (_("second operand missing"));
        as_bad (_("second operand missing"));
 
 
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    case OPSR:
    case OPSR:
      if (cpu == M210)
      if (cpu == M210)
        {
        {
          as_bad (_("M340 specific opcode used when assembling for M210"));
          as_bad (_("M340 specific opcode used when assembling for M210"));
          break;
          break;
        }
        }
 
 
      op_end = parse_psrmod (op_end + 1, & reg);
      op_end = parse_psrmod (op_end + 1, & reg);
 
 
      /* Look for further selectors.  */
      /* Look for further selectors.  */
      while (* op_end == ',')
      while (* op_end == ',')
        {
        {
          unsigned value;
          unsigned value;
 
 
          op_end = parse_psrmod (op_end + 1, & value);
          op_end = parse_psrmod (op_end + 1, & value);
 
 
          if (value & reg)
          if (value & reg)
            as_bad (_("duplicated psr bit specifier"));
            as_bad (_("duplicated psr bit specifier"));
 
 
          reg |= value;
          reg |= value;
        }
        }
 
 
      if (reg > 8)
      if (reg > 8)
        as_bad (_("`af' must appear alone"));
        as_bad (_("`af' must appear alone"));
 
 
      inst |= (reg & 0x7);
      inst |= (reg & 0x7);
      output = frag_more (2);
      output = frag_more (2);
      break;
      break;
 
 
    default:
    default:
      as_bad (_("unimplemented opcode \"%s\""), name);
      as_bad (_("unimplemented opcode \"%s\""), name);
    }
    }
 
 
  /* Drop whitespace after all the operands have been parsed.  */
  /* Drop whitespace after all the operands have been parsed.  */
  while (ISSPACE (* op_end))
  while (ISSPACE (* op_end))
    op_end ++;
    op_end ++;
 
 
  /* Give warning message if the insn has more operands than required.  */
  /* Give warning message if the insn has more operands than required.  */
  if (strcmp (op_end, opcode->name) && strcmp (op_end, ""))
  if (strcmp (op_end, opcode->name) && strcmp (op_end, ""))
    as_warn (_("ignoring operands: %s "), op_end);
    as_warn (_("ignoring operands: %s "), op_end);
 
 
  output[0] = INST_BYTE0 (inst);
  output[0] = INST_BYTE0 (inst);
  output[1] = INST_BYTE1 (inst);
  output[1] = INST_BYTE1 (inst);
 
 
  check_literals (opcode->transfer, isize);
  check_literals (opcode->transfer, isize);
}
}
 
 
symbolS *
symbolS *
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
{
{
  return 0;
  return 0;
}
}
 
 
void
void
md_mcore_end (void)
md_mcore_end (void)
{
{
  dump_literals (0);
  dump_literals (0);
  subseg_set (text_section, 0);
  subseg_set (text_section, 0);
}
}
 
 
/* Various routines to kill one day.  */
/* Various routines to kill one day.  */
 
 
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, target_big_endian);
  return ieee_md_atof (type, litP, sizeP, target_big_endian);
}
}


const char * md_shortopts = "";
const char * md_shortopts = "";
 
 
enum options
enum options
{
{
  OPTION_JSRI2BSR_ON = OPTION_MD_BASE,
  OPTION_JSRI2BSR_ON = OPTION_MD_BASE,
  OPTION_JSRI2BSR_OFF,
  OPTION_JSRI2BSR_OFF,
  OPTION_SIFILTER_ON,
  OPTION_SIFILTER_ON,
  OPTION_SIFILTER_OFF,
  OPTION_SIFILTER_OFF,
  OPTION_CPU,
  OPTION_CPU,
  OPTION_EB,
  OPTION_EB,
  OPTION_EL,
  OPTION_EL,
};
};
 
 
struct option md_longopts[] =
struct option md_longopts[] =
{
{
  { "no-jsri2bsr", no_argument, NULL, OPTION_JSRI2BSR_OFF},
  { "no-jsri2bsr", no_argument, NULL, OPTION_JSRI2BSR_OFF},
  { "jsri2bsr",    no_argument, NULL, OPTION_JSRI2BSR_ON},
  { "jsri2bsr",    no_argument, NULL, OPTION_JSRI2BSR_ON},
  { "sifilter",    no_argument, NULL, OPTION_SIFILTER_ON},
  { "sifilter",    no_argument, NULL, OPTION_SIFILTER_ON},
  { "no-sifilter", no_argument, NULL, OPTION_SIFILTER_OFF},
  { "no-sifilter", no_argument, NULL, OPTION_SIFILTER_OFF},
  { "cpu",         required_argument, NULL, OPTION_CPU},
  { "cpu",         required_argument, NULL, OPTION_CPU},
  { "EB",          no_argument, NULL, OPTION_EB},
  { "EB",          no_argument, NULL, OPTION_EB},
  { "EL",          no_argument, NULL, OPTION_EL},
  { "EL",          no_argument, NULL, OPTION_EL},
  { 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, char * arg)
md_parse_option (int c, char * arg)
{
{
  switch (c)
  switch (c)
    {
    {
    case OPTION_CPU:
    case OPTION_CPU:
      if (streq (arg, "210"))
      if (streq (arg, "210"))
        {
        {
          cpu = M210;
          cpu = M210;
          target_big_endian = 1;
          target_big_endian = 1;
        }
        }
      else if (streq (arg, "340"))
      else if (streq (arg, "340"))
        cpu = M340;
        cpu = M340;
      else
      else
        as_warn (_("unrecognised cpu type '%s'"), arg);
        as_warn (_("unrecognised cpu type '%s'"), arg);
      break;
      break;
 
 
    case OPTION_EB: target_big_endian = 1; break;
    case OPTION_EB: target_big_endian = 1; break;
    case OPTION_EL: target_big_endian = 0; cpu = M340; break;
    case OPTION_EL: target_big_endian = 0; cpu = M340; break;
    case OPTION_JSRI2BSR_ON:  do_jsri2bsr = 1;   break;
    case OPTION_JSRI2BSR_ON:  do_jsri2bsr = 1;   break;
    case OPTION_JSRI2BSR_OFF: do_jsri2bsr = 0;   break;
    case OPTION_JSRI2BSR_OFF: do_jsri2bsr = 0;   break;
    case OPTION_SIFILTER_ON:  sifilter_mode = 1; break;
    case OPTION_SIFILTER_ON:  sifilter_mode = 1; break;
    case OPTION_SIFILTER_OFF: sifilter_mode = 0; break;
    case OPTION_SIFILTER_OFF: sifilter_mode = 0; break;
    default:                  return 0;
    default:                  return 0;
    }
    }
 
 
  return 1;
  return 1;
}
}
 
 
void
void
md_show_usage (FILE * stream)
md_show_usage (FILE * stream)
{
{
  fprintf (stream, _("\
  fprintf (stream, _("\
MCORE specific options:\n\
MCORE specific options:\n\
  -{no-}jsri2bsr          {dis}able jsri to bsr transformation (def: dis)\n\
  -{no-}jsri2bsr          {dis}able jsri to bsr transformation (def: dis)\n\
  -{no-}sifilter          {dis}able silicon filter behavior (def: dis)\n\
  -{no-}sifilter          {dis}able silicon filter behavior (def: dis)\n\
  -cpu=[210|340]          select CPU type\n\
  -cpu=[210|340]          select CPU type\n\
  -EB                     assemble for a big endian system (default)\n\
  -EB                     assemble for a big endian system (default)\n\
  -EL                     assemble for a little endian system\n"));
  -EL                     assemble for a little endian system\n"));
}
}


int md_short_jump_size;
int md_short_jump_size;
 
 
void
void
md_create_short_jump (char * ptr ATTRIBUTE_UNUSED,
md_create_short_jump (char * ptr ATTRIBUTE_UNUSED,
                      addressT from_Nddr ATTRIBUTE_UNUSED,
                      addressT from_Nddr ATTRIBUTE_UNUSED,
                      addressT to_Nddr ATTRIBUTE_UNUSED,
                      addressT to_Nddr ATTRIBUTE_UNUSED,
                      fragS * frag ATTRIBUTE_UNUSED,
                      fragS * frag ATTRIBUTE_UNUSED,
                      symbolS * to_symbol ATTRIBUTE_UNUSED)
                      symbolS * to_symbol ATTRIBUTE_UNUSED)
{
{
  as_fatal (_("failed sanity check: short_jump"));
  as_fatal (_("failed sanity check: short_jump"));
}
}
 
 
void
void
md_create_long_jump (char * ptr ATTRIBUTE_UNUSED,
md_create_long_jump (char * ptr ATTRIBUTE_UNUSED,
                     addressT from_Nddr ATTRIBUTE_UNUSED,
                     addressT from_Nddr ATTRIBUTE_UNUSED,
                     addressT to_Nddr ATTRIBUTE_UNUSED,
                     addressT to_Nddr ATTRIBUTE_UNUSED,
                     fragS * frag ATTRIBUTE_UNUSED,
                     fragS * frag ATTRIBUTE_UNUSED,
                     symbolS * to_symbol ATTRIBUTE_UNUSED)
                     symbolS * to_symbol ATTRIBUTE_UNUSED)
{
{
  as_fatal (_("failed sanity check: long_jump"));
  as_fatal (_("failed sanity check: long_jump"));
}
}
 
 
/* Called after relaxing, change the frags so they know how big they are.  */
/* Called after relaxing, change the frags so they know how big they are.  */
 
 
void
void
md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
                 segT sec ATTRIBUTE_UNUSED,
                 segT sec ATTRIBUTE_UNUSED,
                 fragS * fragP)
                 fragS * fragP)
{
{
  char *buffer;
  char *buffer;
  int targ_addr = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
  int targ_addr = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
 
 
  buffer = fragP->fr_fix + fragP->fr_literal;
  buffer = fragP->fr_fix + fragP->fr_literal;
 
 
  switch (fragP->fr_subtype)
  switch (fragP->fr_subtype)
    {
    {
    case C (COND_JUMP, DISP12):
    case C (COND_JUMP, DISP12):
    case C (UNCD_JUMP, DISP12):
    case C (UNCD_JUMP, DISP12):
      {
      {
        /* Get the address of the end of the instruction.  */
        /* Get the address of the end of the instruction.  */
        int next_inst = fragP->fr_fix + fragP->fr_address + 2;
        int next_inst = fragP->fr_fix + fragP->fr_address + 2;
        unsigned char t0;
        unsigned char t0;
        int disp = targ_addr - next_inst;
        int disp = targ_addr - next_inst;
 
 
        if (disp & 1)
        if (disp & 1)
          as_bad (_("odd displacement at %x"), next_inst - 2);
          as_bad (_("odd displacement at %x"), next_inst - 2);
 
 
        disp >>= 1;
        disp >>= 1;
 
 
        if (! target_big_endian)
        if (! target_big_endian)
          {
          {
            t0 = buffer[1] & 0xF8;
            t0 = buffer[1] & 0xF8;
 
 
            md_number_to_chars (buffer, disp, 2);
            md_number_to_chars (buffer, disp, 2);
 
 
            buffer[1] = (buffer[1] & 0x07) | t0;
            buffer[1] = (buffer[1] & 0x07) | t0;
          }
          }
        else
        else
          {
          {
            t0 = buffer[0] & 0xF8;
            t0 = buffer[0] & 0xF8;
 
 
            md_number_to_chars (buffer, disp, 2);
            md_number_to_chars (buffer, disp, 2);
 
 
            buffer[0] = (buffer[0] & 0x07) | t0;
            buffer[0] = (buffer[0] & 0x07) | t0;
          }
          }
 
 
        fragP->fr_fix += 2;
        fragP->fr_fix += 2;
      }
      }
      break;
      break;
 
 
    case C (COND_JUMP, DISP32):
    case C (COND_JUMP, DISP32):
    case C (COND_JUMP, UNDEF_WORD_DISP):
    case C (COND_JUMP, UNDEF_WORD_DISP):
      {
      {
        /* A conditional branch wont fit into 12 bits so:
        /* A conditional branch wont fit into 12 bits so:
                b!cond  1f
                b!cond  1f
                jmpi    0f
                jmpi    0f
                .align 2
                .align 2
           0:   .long disp
           0:   .long disp
           1:
           1:
 
 
           If the b!cond is 4 byte aligned, the literal which would
           If the b!cond is 4 byte aligned, the literal which would
           go at x+4 will also be aligned.  */
           go at x+4 will also be aligned.  */
        int first_inst = fragP->fr_fix + fragP->fr_address;
        int first_inst = fragP->fr_fix + fragP->fr_address;
        int needpad = (first_inst & 3);
        int needpad = (first_inst & 3);
 
 
        if (! target_big_endian)
        if (! target_big_endian)
          buffer[1] ^= 0x08;
          buffer[1] ^= 0x08;
        else
        else
          buffer[0] ^= 0x08;     /* Toggle T/F bit.  */
          buffer[0] ^= 0x08;     /* Toggle T/F bit.  */
 
 
        buffer[2] = INST_BYTE0 (MCORE_INST_JMPI);       /* Build jmpi.  */
        buffer[2] = INST_BYTE0 (MCORE_INST_JMPI);       /* Build jmpi.  */
        buffer[3] = INST_BYTE1 (MCORE_INST_JMPI);
        buffer[3] = INST_BYTE1 (MCORE_INST_JMPI);
 
 
        if (needpad)
        if (needpad)
          {
          {
            if (! target_big_endian)
            if (! target_big_endian)
              {
              {
                buffer[0] = 4;   /* Branch over jmpi, pad, and ptr.  */
                buffer[0] = 4;   /* Branch over jmpi, pad, and ptr.  */
                buffer[2] = 1;  /* Jmpi offset of 1 gets the pointer.  */
                buffer[2] = 1;  /* Jmpi offset of 1 gets the pointer.  */
              }
              }
            else
            else
              {
              {
                buffer[1] = 4;  /* Branch over jmpi, pad, and ptr.  */
                buffer[1] = 4;  /* Branch over jmpi, pad, and ptr.  */
                buffer[3] = 1;  /* Jmpi offset of 1 gets the pointer.  */
                buffer[3] = 1;  /* Jmpi offset of 1 gets the pointer.  */
              }
              }
 
 
            buffer[4] = 0;       /* Alignment/pad.  */
            buffer[4] = 0;       /* Alignment/pad.  */
            buffer[5] = 0;
            buffer[5] = 0;
            buffer[6] = 0;       /* Space for 32 bit address.  */
            buffer[6] = 0;       /* Space for 32 bit address.  */
            buffer[7] = 0;
            buffer[7] = 0;
            buffer[8] = 0;
            buffer[8] = 0;
            buffer[9] = 0;
            buffer[9] = 0;
 
 
            /* Make reloc for the long disp.  */
            /* Make reloc for the long disp.  */
            fix_new (fragP, fragP->fr_fix + 6, 4,
            fix_new (fragP, fragP->fr_fix + 6, 4,
                     fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_32);
                     fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_32);
 
 
            fragP->fr_fix += C32_LEN;
            fragP->fr_fix += C32_LEN;
          }
          }
        else
        else
          {
          {
            /* See comment below about this given gas' limitations for
            /* See comment below about this given gas' limitations for
               shrinking the fragment. '3' is the amount of code that
               shrinking the fragment. '3' is the amount of code that
               we inserted here, but '4' is right for the space we reserved
               we inserted here, but '4' is right for the space we reserved
               for this fragment.  */
               for this fragment.  */
            if (! target_big_endian)
            if (! target_big_endian)
              {
              {
                buffer[0] = 3;   /* Branch over jmpi, and ptr.  */
                buffer[0] = 3;   /* Branch over jmpi, and ptr.  */
                buffer[2] = 0;   /* Jmpi offset of 0 gets the pointer.  */
                buffer[2] = 0;   /* Jmpi offset of 0 gets the pointer.  */
              }
              }
            else
            else
              {
              {
                buffer[1] = 3;  /* Branch over jmpi, and ptr.  */
                buffer[1] = 3;  /* Branch over jmpi, and ptr.  */
                buffer[3] = 0;   /* Jmpi offset of 0 gets the pointer.  */
                buffer[3] = 0;   /* Jmpi offset of 0 gets the pointer.  */
              }
              }
 
 
            buffer[4] = 0;       /* Space for 32 bit address.  */
            buffer[4] = 0;       /* Space for 32 bit address.  */
            buffer[5] = 0;
            buffer[5] = 0;
            buffer[6] = 0;
            buffer[6] = 0;
            buffer[7] = 0;
            buffer[7] = 0;
 
 
            /* Make reloc for the long disp.  */
            /* Make reloc for the long disp.  */
            fix_new (fragP, fragP->fr_fix + 4, 4,
            fix_new (fragP, fragP->fr_fix + 4, 4,
                     fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_32);
                     fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_32);
            fragP->fr_fix += C32_LEN;
            fragP->fr_fix += C32_LEN;
 
 
            /* Frag is actually shorter (see the other side of this ifdef)
            /* Frag is actually shorter (see the other side of this ifdef)
               but gas isn't prepared for that.  We have to re-adjust
               but gas isn't prepared for that.  We have to re-adjust
               the branch displacement so that it goes beyond the
               the branch displacement so that it goes beyond the
               full length of the fragment, not just what we actually
               full length of the fragment, not just what we actually
               filled in.  */
               filled in.  */
            if (! target_big_endian)
            if (! target_big_endian)
              buffer[0] = 4;     /* Jmpi, ptr, and the 'tail pad'.  */
              buffer[0] = 4;     /* Jmpi, ptr, and the 'tail pad'.  */
            else
            else
              buffer[1] = 4;    /* Jmpi, ptr, and the 'tail pad'.  */
              buffer[1] = 4;    /* Jmpi, ptr, and the 'tail pad'.  */
          }
          }
      }
      }
      break;
      break;
 
 
    case C (UNCD_JUMP, DISP32):
    case C (UNCD_JUMP, DISP32):
    case C (UNCD_JUMP, UNDEF_WORD_DISP):
    case C (UNCD_JUMP, UNDEF_WORD_DISP):
      {
      {
        /* An unconditional branch will not fit in 12 bits, make code which
        /* An unconditional branch will not fit in 12 bits, make code which
           looks like:
           looks like:
                jmpi    0f
                jmpi    0f
                .align 2
                .align 2
             0: .long disp
             0: .long disp
           we need a pad if "first_inst" is 4 byte aligned.
           we need a pad if "first_inst" is 4 byte aligned.
           [because the natural literal place is x + 2].  */
           [because the natural literal place is x + 2].  */
        int first_inst = fragP->fr_fix + fragP->fr_address;
        int first_inst = fragP->fr_fix + fragP->fr_address;
        int needpad = !(first_inst & 3);
        int needpad = !(first_inst & 3);
 
 
        buffer[0] = INST_BYTE0 (MCORE_INST_JMPI);        /* Build jmpi.  */
        buffer[0] = INST_BYTE0 (MCORE_INST_JMPI);        /* Build jmpi.  */
        buffer[1] = INST_BYTE1 (MCORE_INST_JMPI);
        buffer[1] = INST_BYTE1 (MCORE_INST_JMPI);
 
 
        if (needpad)
        if (needpad)
          {
          {
            if (! target_big_endian)
            if (! target_big_endian)
              buffer[0] = 1;     /* Jmpi offset of 1 since padded.  */
              buffer[0] = 1;     /* Jmpi offset of 1 since padded.  */
            else
            else
              buffer[1] = 1;    /* Jmpi offset of 1 since padded.  */
              buffer[1] = 1;    /* Jmpi offset of 1 since padded.  */
            buffer[2] = 0;       /* Alignment.  */
            buffer[2] = 0;       /* Alignment.  */
            buffer[3] = 0;
            buffer[3] = 0;
            buffer[4] = 0;       /* Space for 32 bit address.  */
            buffer[4] = 0;       /* Space for 32 bit address.  */
            buffer[5] = 0;
            buffer[5] = 0;
            buffer[6] = 0;
            buffer[6] = 0;
            buffer[7] = 0;
            buffer[7] = 0;
 
 
            /* Make reloc for the long disp.  */
            /* Make reloc for the long disp.  */
            fix_new (fragP, fragP->fr_fix + 4, 4,
            fix_new (fragP, fragP->fr_fix + 4, 4,
                     fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_32);
                     fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_32);
 
 
            fragP->fr_fix += U32_LEN;
            fragP->fr_fix += U32_LEN;
          }
          }
        else
        else
          {
          {
            if (! target_big_endian)
            if (! target_big_endian)
              buffer[0] = 0;      /* Jmpi offset of 0 if no pad.  */
              buffer[0] = 0;      /* Jmpi offset of 0 if no pad.  */
            else
            else
              buffer[1] = 0;     /* Jmpi offset of 0 if no pad.  */
              buffer[1] = 0;     /* Jmpi offset of 0 if no pad.  */
            buffer[2] = 0;       /* Space for 32 bit address.  */
            buffer[2] = 0;       /* Space for 32 bit address.  */
            buffer[3] = 0;
            buffer[3] = 0;
            buffer[4] = 0;
            buffer[4] = 0;
            buffer[5] = 0;
            buffer[5] = 0;
 
 
            /* Make reloc for the long disp.  */
            /* Make reloc for the long disp.  */
            fix_new (fragP, fragP->fr_fix + 2, 4,
            fix_new (fragP, fragP->fr_fix + 2, 4,
                     fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_32);
                     fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_32);
            fragP->fr_fix += U32_LEN;
            fragP->fr_fix += U32_LEN;
          }
          }
      }
      }
      break;
      break;
 
 
    default:
    default:
      abort ();
      abort ();
    }
    }
}
}
 
 
/* Applies the desired value to the specified location.
/* Applies the desired value to the specified location.
   Also sets up addends for 'rela' type relocations.  */
   Also sets up addends for 'rela' type relocations.  */
 
 
void
void
md_apply_fix (fixS *   fixP,
md_apply_fix (fixS *   fixP,
               valueT * valP,
               valueT * valP,
               segT     segment ATTRIBUTE_UNUSED)
               segT     segment ATTRIBUTE_UNUSED)
{
{
  char *       buf  = fixP->fx_where + fixP->fx_frag->fr_literal;
  char *       buf  = fixP->fx_where + fixP->fx_frag->fr_literal;
  char *       file = fixP->fx_file ? fixP->fx_file : _("unknown");
  char *       file = fixP->fx_file ? fixP->fx_file : _("unknown");
  const char * symname;
  const char * symname;
  /* Note: use offsetT because it is signed, valueT is unsigned.  */
  /* Note: use offsetT because it is signed, valueT is unsigned.  */
  offsetT      val  = *valP;
  offsetT      val  = *valP;
 
 
  symname = fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : _("<unknown>");
  symname = fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : _("<unknown>");
  /* Save this for the addend in the relocation record.  */
  /* Save this for the addend in the relocation record.  */
  fixP->fx_addnumber = val;
  fixP->fx_addnumber = val;
 
 
  if (fixP->fx_addsy != NULL)
  if (fixP->fx_addsy != NULL)
    {
    {
#ifdef OBJ_ELF
#ifdef OBJ_ELF
      /* For ELF we can just return and let the reloc that will be generated
      /* For ELF we can just return and let the reloc that will be generated
         take care of everything.  For COFF we still have to insert 'val'
         take care of everything.  For COFF we still have to insert 'val'
         into the insn since the addend field will be ignored.  */
         into the insn since the addend field will be ignored.  */
      return;
      return;
#endif
#endif
    }
    }
  else
  else
    fixP->fx_done = 1;
    fixP->fx_done = 1;
 
 
  switch (fixP->fx_r_type)
  switch (fixP->fx_r_type)
    {
    {
      /* Second byte of 2 byte opcode.  */
      /* Second byte of 2 byte opcode.  */
    case BFD_RELOC_MCORE_PCREL_IMM11BY2:
    case BFD_RELOC_MCORE_PCREL_IMM11BY2:
      if ((val & 1) != 0)
      if ((val & 1) != 0)
        as_bad_where (file, fixP->fx_line,
        as_bad_where (file, fixP->fx_line,
                      _("odd distance branch (0x%lx bytes)"), (long) val);
                      _("odd distance branch (0x%lx bytes)"), (long) val);
      val /= 2;
      val /= 2;
      if (((val & ~0x3ff) != 0) && ((val | 0x3ff) != -1))
      if (((val & ~0x3ff) != 0) && ((val | 0x3ff) != -1))
        as_bad_where (file, fixP->fx_line,
        as_bad_where (file, fixP->fx_line,
                      _("pcrel for branch to %s too far (0x%lx)"),
                      _("pcrel for branch to %s too far (0x%lx)"),
                      symname, (long) val);
                      symname, (long) val);
      if (target_big_endian)
      if (target_big_endian)
        {
        {
          buf[0] |= ((val >> 8) & 0x7);
          buf[0] |= ((val >> 8) & 0x7);
          buf[1] |= (val & 0xff);
          buf[1] |= (val & 0xff);
        }
        }
      else
      else
        {
        {
          buf[1] |= ((val >> 8) & 0x7);
          buf[1] |= ((val >> 8) & 0x7);
          buf[0] |= (val & 0xff);
          buf[0] |= (val & 0xff);
        }
        }
      break;
      break;
 
 
      /* Lower 8 bits of 2 byte opcode.  */
      /* Lower 8 bits of 2 byte opcode.  */
    case BFD_RELOC_MCORE_PCREL_IMM8BY4:
    case BFD_RELOC_MCORE_PCREL_IMM8BY4:
      val += 3;
      val += 3;
      val /= 4;
      val /= 4;
      if (val & ~0xff)
      if (val & ~0xff)
        as_bad_where (file, fixP->fx_line,
        as_bad_where (file, fixP->fx_line,
                      _("pcrel for lrw/jmpi/jsri to %s too far (0x%lx)"),
                      _("pcrel for lrw/jmpi/jsri to %s too far (0x%lx)"),
                      symname, (long) val);
                      symname, (long) val);
      else if (! target_big_endian)
      else if (! target_big_endian)
        buf[0] |= (val & 0xff);
        buf[0] |= (val & 0xff);
      else
      else
        buf[1] |= (val & 0xff);
        buf[1] |= (val & 0xff);
      break;
      break;
 
 
      /* Loopt instruction.  */
      /* Loopt instruction.  */
    case BFD_RELOC_MCORE_PCREL_IMM4BY2:
    case BFD_RELOC_MCORE_PCREL_IMM4BY2:
      if ((val < -32) || (val > -2))
      if ((val < -32) || (val > -2))
        as_bad_where (file, fixP->fx_line,
        as_bad_where (file, fixP->fx_line,
                      _("pcrel for loopt too far (0x%lx)"), (long) val);
                      _("pcrel for loopt too far (0x%lx)"), (long) val);
      val /= 2;
      val /= 2;
      if (! target_big_endian)
      if (! target_big_endian)
        buf[0] |= (val & 0xf);
        buf[0] |= (val & 0xf);
      else
      else
        buf[1] |= (val & 0xf);
        buf[1] |= (val & 0xf);
      break;
      break;
 
 
    case BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2:
    case BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2:
      /* Conditional linker map jsri to bsr.  */
      /* Conditional linker map jsri to bsr.  */
      /* If its a local target and close enough, fix it.
      /* If its a local target and close enough, fix it.
         NB: >= -2k for backwards bsr; < 2k for forwards...  */
         NB: >= -2k for backwards bsr; < 2k for forwards...  */
      if (fixP->fx_addsy == 0 && val >= -2048  && val < 2048)
      if (fixP->fx_addsy == 0 && val >= -2048  && val < 2048)
        {
        {
          long nval = (val / 2) & 0x7ff;
          long nval = (val / 2) & 0x7ff;
          nval |= MCORE_INST_BSR;
          nval |= MCORE_INST_BSR;
 
 
          /* REPLACE the instruction, don't just modify it.  */
          /* REPLACE the instruction, don't just modify it.  */
          buf[0] = INST_BYTE0 (nval);
          buf[0] = INST_BYTE0 (nval);
          buf[1] = INST_BYTE1 (nval);
          buf[1] = INST_BYTE1 (nval);
        }
        }
      else
      else
        fixP->fx_done = 0;
        fixP->fx_done = 0;
      break;
      break;
 
 
    case BFD_RELOC_MCORE_PCREL_32:
    case BFD_RELOC_MCORE_PCREL_32:
    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;
 
 
    default:
    default:
      if (fixP->fx_addsy != NULL)
      if (fixP->fx_addsy != NULL)
        {
        {
          /* If the fix is an absolute reloc based on a symbol's
          /* If the fix is an absolute reloc based on a symbol's
             address, then it cannot be resolved until the final link.  */
             address, then it cannot be resolved until the final link.  */
          fixP->fx_done = 0;
          fixP->fx_done = 0;
        }
        }
#ifdef OBJ_ELF
#ifdef OBJ_ELF
      else
      else
#endif
#endif
        {
        {
          if (fixP->fx_size == 4)
          if (fixP->fx_size == 4)
            ;
            ;
          else if (fixP->fx_size == 2 && val >= -32768 && val <= 32767)
          else if (fixP->fx_size == 2 && val >= -32768 && val <= 32767)
            ;
            ;
          else if (fixP->fx_size == 1 && val >= -256 && val <= 255)
          else if (fixP->fx_size == 1 && val >= -256 && val <= 255)
            ;
            ;
          else
          else
            abort ();
            abort ();
          md_number_to_chars (buf, val, fixP->fx_size);
          md_number_to_chars (buf, val, fixP->fx_size);
        }
        }
      break;
      break;
    }
    }
}
}
 
 
void
void
md_operand (expressionS * expressionP)
md_operand (expressionS * expressionP)
{
{
  /* Ignore leading hash symbol, if poresent.  */
  /* Ignore leading hash symbol, if poresent.  */
  if (* input_line_pointer == '#')
  if (* input_line_pointer == '#')
    {
    {
      input_line_pointer ++;
      input_line_pointer ++;
      expression (expressionP);
      expression (expressionP);
    }
    }
}
}
 
 
int md_long_jump_size;
int md_long_jump_size;
 
 
/* Called just before address relaxation, return the length
/* Called just before address relaxation, return the length
   by which a fragment must grow to reach it's destination.  */
   by which a fragment must grow to reach it's destination.  */
int
int
md_estimate_size_before_relax (fragS * fragP, segT segment_type)
md_estimate_size_before_relax (fragS * fragP, segT segment_type)
{
{
  switch (fragP->fr_subtype)
  switch (fragP->fr_subtype)
    {
    {
    default:
    default:
      abort ();
      abort ();
 
 
    case C (UNCD_JUMP, UNDEF_DISP):
    case C (UNCD_JUMP, UNDEF_DISP):
      /* Used to be a branch to somewhere which was unknown.  */
      /* Used to be a branch to somewhere which was unknown.  */
      if (!fragP->fr_symbol)
      if (!fragP->fr_symbol)
        fragP->fr_subtype = C (UNCD_JUMP, DISP12);
        fragP->fr_subtype = C (UNCD_JUMP, DISP12);
      else if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
      else if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
        fragP->fr_subtype = C (UNCD_JUMP, DISP12);
        fragP->fr_subtype = C (UNCD_JUMP, DISP12);
      else
      else
        fragP->fr_subtype = C (UNCD_JUMP, UNDEF_WORD_DISP);
        fragP->fr_subtype = C (UNCD_JUMP, UNDEF_WORD_DISP);
      break;
      break;
 
 
    case C (COND_JUMP, UNDEF_DISP):
    case C (COND_JUMP, UNDEF_DISP):
      /* Used to be a branch to somewhere which was unknown.  */
      /* Used to be a branch to somewhere which was unknown.  */
      if (fragP->fr_symbol
      if (fragP->fr_symbol
          && S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
          && S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
        /* Got a symbol and it's defined in this segment, become byte
        /* Got a symbol and it's defined in this segment, become byte
           sized - maybe it will fix up */
           sized - maybe it will fix up */
        fragP->fr_subtype = C (COND_JUMP, DISP12);
        fragP->fr_subtype = C (COND_JUMP, DISP12);
      else if (fragP->fr_symbol)
      else if (fragP->fr_symbol)
        /* Its got a segment, but its not ours, so it will always be long.  */
        /* Its got a segment, but its not ours, so it will always be long.  */
        fragP->fr_subtype = C (COND_JUMP, UNDEF_WORD_DISP);
        fragP->fr_subtype = C (COND_JUMP, UNDEF_WORD_DISP);
      else
      else
        /* We know the abs value.  */
        /* We know the abs value.  */
        fragP->fr_subtype = C (COND_JUMP, DISP12);
        fragP->fr_subtype = C (COND_JUMP, DISP12);
      break;
      break;
 
 
    case C (UNCD_JUMP, DISP12):
    case C (UNCD_JUMP, DISP12):
    case C (UNCD_JUMP, DISP32):
    case C (UNCD_JUMP, DISP32):
    case C (UNCD_JUMP, UNDEF_WORD_DISP):
    case C (UNCD_JUMP, UNDEF_WORD_DISP):
    case C (COND_JUMP, DISP12):
    case C (COND_JUMP, DISP12):
    case C (COND_JUMP, DISP32):
    case C (COND_JUMP, DISP32):
    case C (COND_JUMP, UNDEF_WORD_DISP):
    case C (COND_JUMP, UNDEF_WORD_DISP):
      /* When relaxing a section for the second time, we don't need to
      /* When relaxing a section for the second time, we don't need to
         do anything besides return the current size.  */
         do anything besides return the current size.  */
      break;
      break;
    }
    }
 
 
  return md_relax_table[fragP->fr_subtype].rlx_length;
  return md_relax_table[fragP->fr_subtype].rlx_length;
}
}
 
 
/* Put number into target byte order.  */
/* Put number into target byte order.  */
 
 
void
void
md_number_to_chars (char * ptr, valueT use, int nbytes)
md_number_to_chars (char * ptr, valueT use, int nbytes)
{
{
  if (target_big_endian)
  if (target_big_endian)
    number_to_chars_bigendian (ptr, use, nbytes);
    number_to_chars_bigendian (ptr, use, nbytes);
  else
  else
    number_to_chars_littleendian (ptr, use, nbytes);
    number_to_chars_littleendian (ptr, use, nbytes);
}
}
 
 
/* Round up a section size to the appropriate boundary.  */
/* Round up a section size to the appropriate boundary.  */
 
 
valueT
valueT
md_section_align (segT segment ATTRIBUTE_UNUSED,
md_section_align (segT segment ATTRIBUTE_UNUSED,
                  valueT size)
                  valueT size)
{
{
  /* Byte alignment is fine.  */
  /* Byte alignment is fine.  */
  return size;
  return size;
}
}
 
 
/* The location from which a PC relative jump should be calculated,
/* The location from which a PC relative jump should be calculated,
   given a PC relative reloc.  */
   given a PC relative reloc.  */
 
 
long
long
md_pcrel_from_section (fixS * fixp, segT sec ATTRIBUTE_UNUSED)
md_pcrel_from_section (fixS * fixp, segT sec ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  /* If the symbol is undefined or defined in another section
  /* If the symbol is undefined or defined in another section
     we leave the add number alone for the linker to fix it later.
     we leave the add number alone for the linker to fix it later.
     Only account for the PC pre-bump (which is 2 bytes on the MCore).  */
     Only account for the PC pre-bump (which is 2 bytes on the MCore).  */
  if (fixp->fx_addsy != (symbolS *) NULL
  if (fixp->fx_addsy != (symbolS *) NULL
      && (! S_IS_DEFINED (fixp->fx_addsy)
      && (! S_IS_DEFINED (fixp->fx_addsy)
          || (S_GET_SEGMENT (fixp->fx_addsy) != sec)))
          || (S_GET_SEGMENT (fixp->fx_addsy) != sec)))
 
 
  {
  {
    assert (fixp->fx_size == 2);        /* must be an insn */
    assert (fixp->fx_size == 2);        /* must be an insn */
    return fixp->fx_size;
    return fixp->fx_size;
  }
  }
#endif
#endif
 
 
  /* The case where we are going to resolve things...  */
  /* The case where we are going to resolve things...  */
  return  fixp->fx_size + fixp->fx_where + fixp->fx_frag->fr_address;
  return  fixp->fx_size + fixp->fx_where + fixp->fx_frag->fr_address;
}
}
 
 
#define F(SZ,PCREL)             (((SZ) << 1) + (PCREL))
#define F(SZ,PCREL)             (((SZ) << 1) + (PCREL))
#define MAP(SZ,PCREL,TYPE)      case F (SZ, PCREL): code = (TYPE); break
#define MAP(SZ,PCREL,TYPE)      case F (SZ, PCREL): code = (TYPE); break
 
 
arelent *
arelent *
tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
{
{
  arelent * rel;
  arelent * rel;
  bfd_reloc_code_real_type code;
  bfd_reloc_code_real_type code;
 
 
  switch (fixp->fx_r_type)
  switch (fixp->fx_r_type)
    {
    {
      /* These confuse the size/pcrel macro approach.  */
      /* These confuse the size/pcrel macro approach.  */
    case BFD_RELOC_VTABLE_INHERIT:
    case BFD_RELOC_VTABLE_INHERIT:
    case BFD_RELOC_VTABLE_ENTRY:
    case BFD_RELOC_VTABLE_ENTRY:
    case BFD_RELOC_MCORE_PCREL_IMM4BY2:
    case BFD_RELOC_MCORE_PCREL_IMM4BY2:
    case BFD_RELOC_MCORE_PCREL_IMM8BY4:
    case BFD_RELOC_MCORE_PCREL_IMM8BY4:
    case BFD_RELOC_MCORE_PCREL_IMM11BY2:
    case BFD_RELOC_MCORE_PCREL_IMM11BY2:
    case BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2:
    case BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2:
    case BFD_RELOC_RVA:
    case BFD_RELOC_RVA:
      code = fixp->fx_r_type;
      code = fixp->fx_r_type;
      break;
      break;
 
 
    default:
    default:
      switch (F (fixp->fx_size, fixp->fx_pcrel))
      switch (F (fixp->fx_size, fixp->fx_pcrel))
        {
        {
          MAP (1, 0, BFD_RELOC_8);
          MAP (1, 0, BFD_RELOC_8);
          MAP (2, 0, BFD_RELOC_16);
          MAP (2, 0, BFD_RELOC_16);
          MAP (4, 0, BFD_RELOC_32);
          MAP (4, 0, BFD_RELOC_32);
          MAP (1, 1, BFD_RELOC_8_PCREL);
          MAP (1, 1, BFD_RELOC_8_PCREL);
          MAP (2, 1, BFD_RELOC_16_PCREL);
          MAP (2, 1, BFD_RELOC_16_PCREL);
          MAP (4, 1, BFD_RELOC_32_PCREL);
          MAP (4, 1, BFD_RELOC_32_PCREL);
        default:
        default:
          code = fixp->fx_r_type;
          code = fixp->fx_r_type;
          as_bad (_("Can not do %d byte %srelocation"),
          as_bad (_("Can not do %d byte %srelocation"),
                  fixp->fx_size,
                  fixp->fx_size,
                  fixp->fx_pcrel ? _("pc-relative") : "");
                  fixp->fx_pcrel ? _("pc-relative") : "");
        }
        }
      break;
      break;
  }
  }
 
 
  rel = xmalloc (sizeof (arelent));
  rel = xmalloc (sizeof (arelent));
  rel->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
  rel->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
  *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
  *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
  rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
  rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
  /* Always pass the addend along!  */
  /* Always pass the addend along!  */
  rel->addend = fixp->fx_addnumber;
  rel->addend = fixp->fx_addnumber;
 
 
  rel->howto = bfd_reloc_type_lookup (stdoutput, code);
  rel->howto = bfd_reloc_type_lookup (stdoutput, code);
 
 
  if (rel->howto == NULL)
  if (rel->howto == NULL)
    {
    {
      as_bad_where (fixp->fx_file, fixp->fx_line,
      as_bad_where (fixp->fx_file, fixp->fx_line,
                    _("Cannot represent relocation type %s"),
                    _("Cannot represent relocation type %s"),
                    bfd_get_reloc_code_name (code));
                    bfd_get_reloc_code_name (code));
 
 
      /* Set howto to a garbage value so that we can keep going.  */
      /* Set howto to a garbage value so that we can keep going.  */
      rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
      rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
      assert (rel->howto != NULL);
      assert (rel->howto != NULL);
    }
    }
 
 
  return rel;
  return rel;
}
}
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
/* See whether we need to force a relocation into the output file.
/* See whether we need to force a relocation into the output file.
   This is used to force out switch and PC relative relocations when
   This is used to force out switch and PC relative relocations when
   relaxing.  */
   relaxing.  */
int
int
mcore_force_relocation (fixS * fix)
mcore_force_relocation (fixS * fix)
{
{
  if (fix->fx_r_type == BFD_RELOC_RVA)
  if (fix->fx_r_type == BFD_RELOC_RVA)
    return 1;
    return 1;
 
 
  return generic_force_reloc (fix);
  return generic_force_reloc (fix);
}
}
 
 
/* Return true if the fix can be handled by GAS, false if it must
/* Return true if the fix can be handled by GAS, false if it must
   be passed through to the linker.  */
   be passed through to the linker.  */
 
 
bfd_boolean
bfd_boolean
mcore_fix_adjustable (fixS * fixP)
mcore_fix_adjustable (fixS * fixP)
{
{
  /* We need the symbol name for the VTABLE entries.  */
  /* We need the symbol name for the VTABLE entries.  */
  if (   fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
  if (   fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
    return 0;
    return 0;
 
 
  return 1;
  return 1;
}
}
#endif /* OBJ_ELF */
#endif /* OBJ_ELF */
 
 

powered by: WebSVN 2.1.0

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