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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [binutils-2.20.1/] [gas/] [config/] [tc-z8k.c] - Diff between revs 205 and 816

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

Rev 205 Rev 816
/* tc-z8k.c -- Assemble code for the Zilog Z800n
/* tc-z8k.c -- Assemble code for the Zilog Z800n
   Copyright 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001, 2002, 2003,
   Copyright 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001, 2002, 2003,
   2005, 2006, 2007, 2009  Free Software Foundation, Inc.
   2005, 2006, 2007, 2009  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.  */
 
 
/* Written By Steve Chamberlain <sac@cygnus.com>.  */
/* Written By Steve Chamberlain <sac@cygnus.com>.  */
 
 
#include "as.h"
#include "as.h"
#include "safe-ctype.h"
#include "safe-ctype.h"
#define DEFINE_TABLE
#define DEFINE_TABLE
#include "opcodes/z8k-opc.h"
#include "opcodes/z8k-opc.h"
 
 
const char comment_chars[] = "!";
const char comment_chars[] = "!";
const char line_comment_chars[] = "#";
const char line_comment_chars[] = "#";
const char line_separator_chars[] = ";";
const char line_separator_chars[] = ";";
 
 
extern int machine;
extern int machine;
extern int coff_flags;
extern int coff_flags;
int segmented_mode;
int segmented_mode;
 
 
/* This is non-zero if target was set from the command line.  */
/* This is non-zero if target was set from the command line.  */
static int z8k_target_from_cmdline;
static int z8k_target_from_cmdline;
 
 
static void
static void
s_segm (int segm)
s_segm (int segm)
{
{
  if (segm)
  if (segm)
    {
    {
      segmented_mode = 1;
      segmented_mode = 1;
      bfd_set_arch_mach (stdoutput, TARGET_ARCH, bfd_mach_z8001);
      bfd_set_arch_mach (stdoutput, TARGET_ARCH, bfd_mach_z8001);
    }
    }
  else
  else
    {
    {
      segmented_mode = 0;
      segmented_mode = 0;
      bfd_set_arch_mach (stdoutput, TARGET_ARCH, bfd_mach_z8002);
      bfd_set_arch_mach (stdoutput, TARGET_ARCH, bfd_mach_z8002);
    }
    }
}
}
 
 
static void
static void
even (int ignore ATTRIBUTE_UNUSED)
even (int ignore ATTRIBUTE_UNUSED)
{
{
  frag_align (1, 0, 0);
  frag_align (1, 0, 0);
  record_alignment (now_seg, 1);
  record_alignment (now_seg, 1);
}
}
 
 
static int
static int
tohex (int c)
tohex (int c)
{
{
  if (ISDIGIT (c))
  if (ISDIGIT (c))
    return c - '0';
    return c - '0';
  if (ISLOWER (c))
  if (ISLOWER (c))
    return c - 'a' + 10;
    return c - 'a' + 10;
  return c - 'A' + 10;
  return c - 'A' + 10;
}
}
 
 
static void
static void
sval (int ignore ATTRIBUTE_UNUSED)
sval (int ignore ATTRIBUTE_UNUSED)
{
{
  SKIP_WHITESPACE ();
  SKIP_WHITESPACE ();
  if (*input_line_pointer == '\'')
  if (*input_line_pointer == '\'')
    {
    {
      int c;
      int c;
      input_line_pointer++;
      input_line_pointer++;
      c = *input_line_pointer++;
      c = *input_line_pointer++;
      while (c != '\'')
      while (c != '\'')
        {
        {
          if (c == '%')
          if (c == '%')
            {
            {
              c = (tohex (input_line_pointer[0]) << 4)
              c = (tohex (input_line_pointer[0]) << 4)
                | tohex (input_line_pointer[1]);
                | tohex (input_line_pointer[1]);
              input_line_pointer += 2;
              input_line_pointer += 2;
            }
            }
          FRAG_APPEND_1_CHAR (c);
          FRAG_APPEND_1_CHAR (c);
          c = *input_line_pointer++;
          c = *input_line_pointer++;
        }
        }
      demand_empty_rest_of_line ();
      demand_empty_rest_of_line ();
    }
    }
}
}
 
 
/* 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[] = {
  {"int"    , cons            , 2},
  {"int"    , cons            , 2},
  {"data.b" , cons            , 1},
  {"data.b" , cons            , 1},
  {"data.w" , cons            , 2},
  {"data.w" , cons            , 2},
  {"data.l" , cons            , 4},
  {"data.l" , cons            , 4},
  {"form"   , listing_psize   , 0},
  {"form"   , listing_psize   , 0},
  {"heading", listing_title   , 0},
  {"heading", listing_title   , 0},
  {"import" , s_ignore        , 0},
  {"import" , s_ignore        , 0},
  {"page"   , listing_eject   , 0},
  {"page"   , listing_eject   , 0},
  {"program", s_ignore        , 0},
  {"program", s_ignore        , 0},
  {"z8001"  , s_segm          , 1},
  {"z8001"  , s_segm          , 1},
  {"z8002"  , s_segm          , 0},
  {"z8002"  , s_segm          , 0},
 
 
  {"segm"   , s_segm          , 1},
  {"segm"   , s_segm          , 1},
  {"unsegm" , s_segm          , 0},
  {"unsegm" , s_segm          , 0},
  {"unseg"  , s_segm          , 0},
  {"unseg"  , s_segm          , 0},
  {"name"   , s_app_file      , 0},
  {"name"   , s_app_file      , 0},
  {"global" , s_globl         , 0},
  {"global" , s_globl         , 0},
  {"wval"   , cons            , 2},
  {"wval"   , cons            , 2},
  {"lval"   , cons            , 4},
  {"lval"   , cons            , 4},
  {"bval"   , cons            , 1},
  {"bval"   , cons            , 1},
  {"sval"   , sval            , 0},
  {"sval"   , sval            , 0},
  {"rsect"  , obj_coff_section, 0},
  {"rsect"  , obj_coff_section, 0},
  {"sect"   , obj_coff_section, 0},
  {"sect"   , obj_coff_section, 0},
  {"block"  , s_space         , 0},
  {"block"  , s_space         , 0},
  {"even"   , even            , 0},
  {"even"   , even            , 0},
  {0        , 0               , 0}
  {0        , 0               , 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";
 
 
/* Opcode mnemonics.  */
/* Opcode mnemonics.  */
static struct hash_control *opcode_hash_control;
static struct hash_control *opcode_hash_control;
 
 
void
void
md_begin (void)
md_begin (void)
{
{
  const opcode_entry_type *opcode;
  const opcode_entry_type *opcode;
  int idx = -1;
  int idx = -1;
 
 
  opcode_hash_control = hash_new ();
  opcode_hash_control = hash_new ();
 
 
  for (opcode = z8k_table; opcode->name; opcode++)
  for (opcode = z8k_table; opcode->name; opcode++)
    {
    {
      /* Only enter unique codes into the table.  */
      /* Only enter unique codes into the table.  */
      if (idx != opcode->idx)
      if (idx != opcode->idx)
        hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
        hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
      idx = opcode->idx;
      idx = opcode->idx;
    }
    }
 
 
  /* Default to z8002.  */
  /* Default to z8002.  */
  if (! z8k_target_from_cmdline)
  if (! z8k_target_from_cmdline)
    s_segm (0);
    s_segm (0);
 
 
  /* Insert the pseudo ops, too.  */
  /* Insert the pseudo ops, too.  */
  for (idx = 0; md_pseudo_table[idx].poc_name; idx++)
  for (idx = 0; md_pseudo_table[idx].poc_name; idx++)
    {
    {
      opcode_entry_type *fake_opcode;
      opcode_entry_type *fake_opcode;
      fake_opcode = (opcode_entry_type *) malloc (sizeof (opcode_entry_type));
      fake_opcode = (opcode_entry_type *) malloc (sizeof (opcode_entry_type));
      fake_opcode->name = md_pseudo_table[idx].poc_name;
      fake_opcode->name = md_pseudo_table[idx].poc_name;
      fake_opcode->func = (void *) (md_pseudo_table + idx);
      fake_opcode->func = (void *) (md_pseudo_table + idx);
      fake_opcode->opcode = 250;
      fake_opcode->opcode = 250;
      hash_insert (opcode_hash_control, fake_opcode->name, fake_opcode);
      hash_insert (opcode_hash_control, fake_opcode->name, fake_opcode);
    }
    }
}
}
 
 
typedef struct z8k_op {
typedef struct z8k_op {
  /* CLASS_REG_xxx.  */
  /* CLASS_REG_xxx.  */
  int regsize;
  int regsize;
 
 
  /* 0 .. 15.  */
  /* 0 .. 15.  */
  unsigned int reg;
  unsigned int reg;
 
 
  int mode;
  int mode;
 
 
  /* Any other register associated with the mode.  */
  /* Any other register associated with the mode.  */
  unsigned int x_reg;
  unsigned int x_reg;
 
 
  /* Any expression.  */
  /* Any expression.  */
  expressionS exp;
  expressionS exp;
} op_type;
} op_type;
 
 
static expressionS *da_operand;
static expressionS *da_operand;
static expressionS *imm_operand;
static expressionS *imm_operand;
 
 
static int reg[16];
static int reg[16];
static int the_cc;
static int the_cc;
static int the_ctrl;
static int the_ctrl;
static int the_flags;
static int the_flags;
static int the_interrupt;
static int the_interrupt;
 
 
/* Determine register number.  src points to the ascii number
/* Determine register number.  src points to the ascii number
   (after "rl", "rh", "r", "rr", or "rq").  If a character
   (after "rl", "rh", "r", "rr", or "rq").  If a character
   outside the set of {0,',',')','('} follows the number,
   outside the set of {0,',',')','('} follows the number,
   return NULL to indicate that it's not a valid register
   return NULL to indicate that it's not a valid register
   number.  */
   number.  */
 
 
static char *
static char *
whatreg (unsigned int *reg, char *src)
whatreg (unsigned int *reg, char *src)
{
{
  unsigned int new_reg;
  unsigned int new_reg;
 
 
  /* src[0] is already known to be a digit.  */
  /* src[0] is already known to be a digit.  */
  if (ISDIGIT (src[1]))
  if (ISDIGIT (src[1]))
    {
    {
      new_reg = (src[0] - '0') * 10 + src[1] - '0';
      new_reg = (src[0] - '0') * 10 + src[1] - '0';
      src += 2;
      src += 2;
    }
    }
  else
  else
    {
    {
      new_reg = (src[0] - '0');
      new_reg = (src[0] - '0');
      src += 1;
      src += 1;
    }
    }
 
 
  if (src[0] != 0 && src[0] != ',' && src[0] != '(' && src[0] != ')')
  if (src[0] != 0 && src[0] != ',' && src[0] != '(' && src[0] != ')')
    return NULL;
    return NULL;
 
 
  *reg = new_reg;
  *reg = new_reg;
  return src;
  return src;
}
}
 
 
/* Parse operands
/* Parse operands
 
 
   rh0-rh7, rl0-rl7
   rh0-rh7, rl0-rl7
   r0-r15
   r0-r15
   rr0-rr14
   rr0-rr14
   rq0--rq12
   rq0--rq12
   WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp
   WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp
   r0l,r0h,..r7l,r7h
   r0l,r0h,..r7l,r7h
   @WREG
   @WREG
   @WREG+
   @WREG+
   @-WREG
   @-WREG
   #const
   #const
*/
*/
 
 
/* Try to parse a reg name.  Return a pointer to the first character
/* Try to parse a reg name.  Return a pointer to the first character
   in SRC after the reg name.  */
   in SRC after the reg name.  */
 
 
static char *
static char *
parse_reg (char *src, int *mode, unsigned int *reg)
parse_reg (char *src, int *mode, unsigned int *reg)
{
{
  char *res = NULL;
  char *res = NULL;
  char regno;
  char regno;
 
 
  /* Check for stack pointer "sp" alias.  */
  /* Check for stack pointer "sp" alias.  */
  if ((src[0] == 's' || src[0] == 'S')
  if ((src[0] == 's' || src[0] == 'S')
      && (src[1] == 'p' || src[1] == 'P')
      && (src[1] == 'p' || src[1] == 'P')
      && (src[2] == 0 || src[2] == ','))
      && (src[2] == 0 || src[2] == ','))
    {
    {
      if (segmented_mode)
      if (segmented_mode)
        {
        {
          *mode = CLASS_REG_LONG;
          *mode = CLASS_REG_LONG;
          *reg = 14;
          *reg = 14;
        }
        }
      else
      else
        {
        {
          *mode = CLASS_REG_WORD;
          *mode = CLASS_REG_WORD;
          *reg = 15;
          *reg = 15;
        }
        }
      return src + 2;
      return src + 2;
    }
    }
 
 
  if (src[0] == 'r' || src[0] == 'R')
  if (src[0] == 'r' || src[0] == 'R')
    {
    {
      if (src[1] == 'r' || src[1] == 'R')
      if (src[1] == 'r' || src[1] == 'R')
        {
        {
          if (src[2] < '0' || src[2] > '9')
          if (src[2] < '0' || src[2] > '9')
            return NULL;        /* Assume no register name but a label starting with 'rr'.  */
            return NULL;        /* Assume no register name but a label starting with 'rr'.  */
          *mode = CLASS_REG_LONG;
          *mode = CLASS_REG_LONG;
          res = whatreg (reg, src + 2);
          res = whatreg (reg, src + 2);
          if (res == NULL)
          if (res == NULL)
            return NULL;        /* Not a valid register name.  */
            return NULL;        /* Not a valid register name.  */
          regno = *reg;
          regno = *reg;
          if (regno > 14)
          if (regno > 14)
            as_bad (_("register rr%d out of range"), regno);
            as_bad (_("register rr%d out of range"), regno);
          if (regno & 1)
          if (regno & 1)
            as_bad (_("register rr%d does not exist"), regno);
            as_bad (_("register rr%d does not exist"), regno);
        }
        }
      else if (src[1] == 'h' || src[1] == 'H')
      else if (src[1] == 'h' || src[1] == 'H')
        {
        {
          if (src[2] < '0' || src[2] > '9')
          if (src[2] < '0' || src[2] > '9')
            return NULL;        /* Assume no register name but a label starting with 'rh'.  */
            return NULL;        /* Assume no register name but a label starting with 'rh'.  */
          *mode = CLASS_REG_BYTE;
          *mode = CLASS_REG_BYTE;
          res = whatreg (reg, src + 2);
          res = whatreg (reg, src + 2);
          if (res == NULL)
          if (res == NULL)
            return NULL;        /* Not a valid register name.  */
            return NULL;        /* Not a valid register name.  */
          regno = *reg;
          regno = *reg;
          if (regno > 7)
          if (regno > 7)
            as_bad (_("register rh%d out of range"), regno);
            as_bad (_("register rh%d out of range"), regno);
        }
        }
      else if (src[1] == 'l' || src[1] == 'L')
      else if (src[1] == 'l' || src[1] == 'L')
        {
        {
          if (src[2] < '0' || src[2] > '9')
          if (src[2] < '0' || src[2] > '9')
            return NULL;        /* Assume no register name but a label starting with 'rl'.  */
            return NULL;        /* Assume no register name but a label starting with 'rl'.  */
          *mode = CLASS_REG_BYTE;
          *mode = CLASS_REG_BYTE;
          res = whatreg (reg, src + 2);
          res = whatreg (reg, src + 2);
          if (res == NULL)
          if (res == NULL)
            return NULL;        /* Not a valid register name.  */
            return NULL;        /* Not a valid register name.  */
          regno = *reg;
          regno = *reg;
          if (regno > 7)
          if (regno > 7)
            as_bad (_("register rl%d out of range"), regno);
            as_bad (_("register rl%d out of range"), regno);
          *reg += 8;
          *reg += 8;
        }
        }
      else if (src[1] == 'q' || src[1] == 'Q')
      else if (src[1] == 'q' || src[1] == 'Q')
        {
        {
          if (src[2] < '0' || src[2] > '9')
          if (src[2] < '0' || src[2] > '9')
            return NULL;        /* Assume no register name but a label starting with 'rq'.  */
            return NULL;        /* Assume no register name but a label starting with 'rq'.  */
          *mode = CLASS_REG_QUAD;
          *mode = CLASS_REG_QUAD;
          res = whatreg (reg, src + 2);
          res = whatreg (reg, src + 2);
          if (res == NULL)
          if (res == NULL)
            return NULL;        /* Not a valid register name.  */
            return NULL;        /* Not a valid register name.  */
          regno = *reg;
          regno = *reg;
          if (regno > 12)
          if (regno > 12)
            as_bad (_("register rq%d out of range"), regno);
            as_bad (_("register rq%d out of range"), regno);
          if (regno & 3)
          if (regno & 3)
            as_bad (_("register rq%d does not exist"), regno);
            as_bad (_("register rq%d does not exist"), regno);
        }
        }
      else
      else
        {
        {
          if (src[1] < '0' || src[1] > '9')
          if (src[1] < '0' || src[1] > '9')
            return NULL;        /* Assume no register name but a label starting with 'r'.  */
            return NULL;        /* Assume no register name but a label starting with 'r'.  */
          *mode = CLASS_REG_WORD;
          *mode = CLASS_REG_WORD;
          res = whatreg (reg, src + 1);
          res = whatreg (reg, src + 1);
          if (res == NULL)
          if (res == NULL)
            return NULL;        /* Not a valid register name.  */
            return NULL;        /* Not a valid register name.  */
          regno = *reg;
          regno = *reg;
          if (regno > 15)
          if (regno > 15)
            as_bad (_("register r%d out of range"), regno);
            as_bad (_("register r%d out of range"), regno);
        }
        }
    }
    }
  return res;
  return res;
}
}
 
 
static char *
static char *
parse_exp (char *s, expressionS *op)
parse_exp (char *s, expressionS *op)
{
{
  char *save = input_line_pointer;
  char *save = input_line_pointer;
  char *new_pointer;
  char *new_pointer;
 
 
  input_line_pointer = s;
  input_line_pointer = s;
  expression (op);
  expression (op);
  if (op->X_op == O_absent)
  if (op->X_op == O_absent)
    as_bad (_("missing operand"));
    as_bad (_("missing operand"));
  new_pointer = input_line_pointer;
  new_pointer = input_line_pointer;
  input_line_pointer = save;
  input_line_pointer = save;
  return new_pointer;
  return new_pointer;
}
}
 
 
/* The many forms of operand:
/* The many forms of operand:
 
 
   <rb>
   <rb>
   <r>
   <r>
   <rr>
   <rr>
   <rq>
   <rq>
   @r
   @r
   #exp
   #exp
   exp
   exp
   exp(r)
   exp(r)
   r(#exp)
   r(#exp)
   r(r)
   r(r)
   */
   */
 
 
static char *
static char *
checkfor (char *ptr, char what)
checkfor (char *ptr, char what)
{
{
  if (*ptr == what)
  if (*ptr == what)
    ptr++;
    ptr++;
  else
  else
    as_bad (_("expected %c"), what);
    as_bad (_("expected %c"), what);
 
 
  return ptr;
  return ptr;
}
}
 
 
/* Make sure the mode supplied is the size of a word.  */
/* Make sure the mode supplied is the size of a word.  */
 
 
static void
static void
regword (int mode, char *string)
regword (int mode, char *string)
{
{
  int ok;
  int ok;
 
 
  ok = CLASS_REG_WORD;
  ok = CLASS_REG_WORD;
  if (ok != mode)
  if (ok != mode)
    {
    {
      as_bad (_("register is wrong size for a word %s"), string);
      as_bad (_("register is wrong size for a word %s"), string);
    }
    }
}
}
 
 
/* Make sure the mode supplied is the size of an address.  */
/* Make sure the mode supplied is the size of an address.  */
 
 
static void
static void
regaddr (int mode, char *string)
regaddr (int mode, char *string)
{
{
  int ok;
  int ok;
 
 
  ok = segmented_mode ? CLASS_REG_LONG : CLASS_REG_WORD;
  ok = segmented_mode ? CLASS_REG_LONG : CLASS_REG_WORD;
  if (ok != mode)
  if (ok != mode)
    {
    {
      as_bad (_("register is wrong size for address %s"), string);
      as_bad (_("register is wrong size for address %s"), string);
    }
    }
}
}
 
 
struct ctrl_names {
struct ctrl_names {
  int value;
  int value;
  char *name;
  char *name;
};
};
 
 
static struct ctrl_names ctrl_table[] = {
static struct ctrl_names ctrl_table[] = {
  { 0x1, "flags" },   /* ldctlb only.  */
  { 0x1, "flags" },   /* ldctlb only.  */
  { 0x2, "fcw" },     /* ldctl only.  Applies to all remaining control registers.  */
  { 0x2, "fcw" },     /* ldctl only.  Applies to all remaining control registers.  */
  { 0x3, "refresh" },
  { 0x3, "refresh" },
  { 0x4, "psapseg" },
  { 0x4, "psapseg" },
  { 0x5, "psapoff" },
  { 0x5, "psapoff" },
  { 0x5, "psap" },
  { 0x5, "psap" },
  { 0x6, "nspseg" },
  { 0x6, "nspseg" },
  { 0x7, "nspoff" },
  { 0x7, "nspoff" },
  { 0x7, "nsp" },
  { 0x7, "nsp" },
  { 0  , 0 }
  { 0  , 0 }
};
};
 
 
static void
static void
get_ctrl_operand (char **ptr, struct z8k_op *mode, unsigned int dst ATTRIBUTE_UNUSED)
get_ctrl_operand (char **ptr, struct z8k_op *mode, unsigned int dst ATTRIBUTE_UNUSED)
{
{
  char *src = *ptr;
  char *src = *ptr;
  int i, l;
  int i, l;
 
 
  while (*src == ' ')
  while (*src == ' ')
    src++;
    src++;
 
 
  mode->mode = CLASS_CTRL;
  mode->mode = CLASS_CTRL;
  for (i = 0; ctrl_table[i].name; i++)
  for (i = 0; ctrl_table[i].name; i++)
    {
    {
      l = strlen (ctrl_table[i].name);
      l = strlen (ctrl_table[i].name);
      if (! strncasecmp (ctrl_table[i].name, src, l))
      if (! strncasecmp (ctrl_table[i].name, src, l))
        {
        {
          the_ctrl = ctrl_table[i].value;
          the_ctrl = ctrl_table[i].value;
          if (*(src + l) && *(src + l) != ',')
          if (*(src + l) && *(src + l) != ',')
            break;
            break;
          *ptr = src + l;  /* Valid control name found: "consume" it.  */
          *ptr = src + l;  /* Valid control name found: "consume" it.  */
          return;
          return;
        }
        }
    }
    }
  the_ctrl = 0;
  the_ctrl = 0;
}
}
 
 
struct flag_names {
struct flag_names {
  int value;
  int value;
  char *name;
  char *name;
};
};
 
 
static struct flag_names flag_table[] = {
static struct flag_names flag_table[] = {
  { 0x1, "P" },
  { 0x1, "P" },
  { 0x1, "V" },
  { 0x1, "V" },
  { 0x2, "S" },
  { 0x2, "S" },
  { 0x4, "Z" },
  { 0x4, "Z" },
  { 0x8, "C" },
  { 0x8, "C" },
  { 0x0, "+" },
  { 0x0, "+" },
  { 0x0, "," },
  { 0x0, "," },
  { 0, 0 }
  { 0, 0 }
};
};
 
 
static void
static void
get_flags_operand (char **ptr, struct z8k_op *mode, unsigned int dst ATTRIBUTE_UNUSED)
get_flags_operand (char **ptr, struct z8k_op *mode, unsigned int dst ATTRIBUTE_UNUSED)
{
{
  char *src = *ptr;
  char *src = *ptr;
  char c;
  char c;
  int i;
  int i;
  int j;
  int j;
 
 
  while (*src == ' ')
  while (*src == ' ')
    src++;
    src++;
 
 
  mode->mode = CLASS_FLAGS;
  mode->mode = CLASS_FLAGS;
  the_flags = 0;
  the_flags = 0;
  for (j = 0; j <= 9; j++)
  for (j = 0; j <= 9; j++)
    {
    {
      if (!src[j])
      if (!src[j])
        goto done;
        goto done;
      c = TOUPPER(src[j]);
      c = TOUPPER(src[j]);
      for (i = 0; flag_table[i].name; i++)
      for (i = 0; flag_table[i].name; i++)
        {
        {
          if (flag_table[i].name[0] == c)
          if (flag_table[i].name[0] == c)
            {
            {
              the_flags = the_flags | flag_table[i].value;
              the_flags = the_flags | flag_table[i].value;
              goto match;
              goto match;
            }
            }
        }
        }
      goto done;
      goto done;
    match:
    match:
      ;
      ;
    }
    }
 done:
 done:
  *ptr = src + j;
  *ptr = src + j;
}
}
 
 
struct interrupt_names {
struct interrupt_names {
  int value;
  int value;
  char *name;
  char *name;
};
};
 
 
static struct interrupt_names intr_table[] = {
static struct interrupt_names intr_table[] = {
  { 0x1, "nvi" },
  { 0x1, "nvi" },
  { 0x2, "vi" },
  { 0x2, "vi" },
  { 0x3, "both" },
  { 0x3, "both" },
  { 0x3, "all" },
  { 0x3, "all" },
  { 0, 0 }
  { 0, 0 }
};
};
 
 
static void
static void
get_interrupt_operand (char **ptr, struct z8k_op *mode, unsigned int dst ATTRIBUTE_UNUSED)
get_interrupt_operand (char **ptr, struct z8k_op *mode, unsigned int dst ATTRIBUTE_UNUSED)
{
{
  char *src = *ptr;
  char *src = *ptr;
  int i, l;
  int i, l;
 
 
  while (*src == ' ')
  while (*src == ' ')
    src++;
    src++;
 
 
  mode->mode = CLASS_IMM;
  mode->mode = CLASS_IMM;
  the_interrupt = 0;
  the_interrupt = 0;
 
 
  while (*src)
  while (*src)
    {
    {
      for (i = 0; intr_table[i].name; i++)
      for (i = 0; intr_table[i].name; i++)
        {
        {
          l = strlen (intr_table[i].name);
          l = strlen (intr_table[i].name);
          if (! strncasecmp (intr_table[i].name, src, l))
          if (! strncasecmp (intr_table[i].name, src, l))
            {
            {
              the_interrupt |= intr_table[i].value;
              the_interrupt |= intr_table[i].value;
              if (*(src + l) && *(src + l) != ',')
              if (*(src + l) && *(src + l) != ',')
                {
                {
                  *ptr = src + l;
                  *ptr = src + l;
                invalid:
                invalid:
                  as_bad (_("unknown interrupt %s"), src);
                  as_bad (_("unknown interrupt %s"), src);
                  while (**ptr && ! is_end_of_line[(unsigned char) **ptr])
                  while (**ptr && ! is_end_of_line[(unsigned char) **ptr])
                    (*ptr)++;    /* Consume rest of line.  */
                    (*ptr)++;    /* Consume rest of line.  */
                  return;
                  return;
                }
                }
              src += l;
              src += l;
              if (! *src)
              if (! *src)
                {
                {
                  *ptr = src;
                  *ptr = src;
                  return;
                  return;
                }
                }
            }
            }
        }
        }
      if (*src == ',')
      if (*src == ',')
        src++;
        src++;
      else
      else
        {
        {
          *ptr = src;
          *ptr = src;
          goto invalid;
          goto invalid;
        }
        }
    }
    }
 
 
  /* No interrupt type specified, opcode won't do anything.  */
  /* No interrupt type specified, opcode won't do anything.  */
  as_warn (_("opcode has no effect"));
  as_warn (_("opcode has no effect"));
  the_interrupt = 0x0;
  the_interrupt = 0x0;
}
}
 
 
struct cc_names {
struct cc_names {
  int value;
  int value;
  char *name;
  char *name;
};
};
 
 
static struct cc_names table[] = {
static struct cc_names table[] = {
  { 0x0, "f" },
  { 0x0, "f" },
  { 0x1, "lt" },
  { 0x1, "lt" },
  { 0x2, "le" },
  { 0x2, "le" },
  { 0x3, "ule" },
  { 0x3, "ule" },
  { 0x4, "ov/pe" },
  { 0x4, "ov/pe" },
  { 0x4, "ov" },
  { 0x4, "ov" },
  { 0x4, "pe/ov" },
  { 0x4, "pe/ov" },
  { 0x4, "pe" },
  { 0x4, "pe" },
  { 0x5, "mi" },
  { 0x5, "mi" },
  { 0x6, "eq" },
  { 0x6, "eq" },
  { 0x6, "z" },
  { 0x6, "z" },
  { 0x7, "c/ult" },
  { 0x7, "c/ult" },
  { 0x7, "c" },
  { 0x7, "c" },
  { 0x7, "ult/c" },
  { 0x7, "ult/c" },
  { 0x7, "ult" },
  { 0x7, "ult" },
  { 0x8, "t" },
  { 0x8, "t" },
  { 0x9, "ge" },
  { 0x9, "ge" },
  { 0xa, "gt" },
  { 0xa, "gt" },
  { 0xb, "ugt" },
  { 0xb, "ugt" },
  { 0xc, "nov/po" },
  { 0xc, "nov/po" },
  { 0xc, "nov" },
  { 0xc, "nov" },
  { 0xc, "po/nov" },
  { 0xc, "po/nov" },
  { 0xc, "po" },
  { 0xc, "po" },
  { 0xd, "pl" },
  { 0xd, "pl" },
  { 0xe, "ne" },
  { 0xe, "ne" },
  { 0xe, "nz" },
  { 0xe, "nz" },
  { 0xf, "nc/uge" },
  { 0xf, "nc/uge" },
  { 0xf, "nc" },
  { 0xf, "nc" },
  { 0xf, "uge/nc" },
  { 0xf, "uge/nc" },
  { 0xf, "uge" },
  { 0xf, "uge" },
  { 0  ,  0 }
  { 0  ,  0 }
};
};
 
 
static void
static void
get_cc_operand (char **ptr, struct z8k_op *mode, unsigned int dst ATTRIBUTE_UNUSED)
get_cc_operand (char **ptr, struct z8k_op *mode, unsigned int dst ATTRIBUTE_UNUSED)
{
{
  char *src = *ptr;
  char *src = *ptr;
  int i, l;
  int i, l;
 
 
  while (*src == ' ')
  while (*src == ' ')
    src++;
    src++;
 
 
  mode->mode = CLASS_CC;
  mode->mode = CLASS_CC;
  for (i = 0; table[i].name; i++)
  for (i = 0; table[i].name; i++)
    {
    {
      l = strlen (table[i].name);
      l = strlen (table[i].name);
      if (! strncasecmp (table[i].name, src, l))
      if (! strncasecmp (table[i].name, src, l))
        {
        {
          the_cc = table[i].value;
          the_cc = table[i].value;
          if (*(src + l) && *(src + l) != ',')
          if (*(src + l) && *(src + l) != ',')
            break;
            break;
          *ptr = src + l;  /* Valid cc found: "consume" it.  */
          *ptr = src + l;  /* Valid cc found: "consume" it.  */
          return;
          return;
        }
        }
    }
    }
  the_cc = 0x8;  /* Not recognizing the cc defaults to t.  (Assuming no cc present.)  */
  the_cc = 0x8;  /* Not recognizing the cc defaults to t.  (Assuming no cc present.)  */
}
}
 
 
static void
static void
get_operand (char **ptr, struct z8k_op *mode, unsigned int dst ATTRIBUTE_UNUSED)
get_operand (char **ptr, struct z8k_op *mode, unsigned int dst ATTRIBUTE_UNUSED)
{
{
  char *src = *ptr;
  char *src = *ptr;
  char *end;
  char *end;
 
 
  mode->mode = 0;
  mode->mode = 0;
 
 
  while (*src == ' ')
  while (*src == ' ')
    src++;
    src++;
  if (*src == '#')
  if (*src == '#')
    {
    {
      mode->mode = CLASS_IMM;
      mode->mode = CLASS_IMM;
      imm_operand = &(mode->exp);
      imm_operand = &(mode->exp);
      src = parse_exp (src + 1, &(mode->exp));
      src = parse_exp (src + 1, &(mode->exp));
    }
    }
  else if (*src == '@')
  else if (*src == '@')
    {
    {
      mode->mode = CLASS_IR;
      mode->mode = CLASS_IR;
      src = parse_reg (src + 1, &mode->regsize, &mode->reg);
      src = parse_reg (src + 1, &mode->regsize, &mode->reg);
    }
    }
  else
  else
    {
    {
      unsigned int regn;
      unsigned int regn;
 
 
      end = parse_reg (src, &mode->mode, &regn);
      end = parse_reg (src, &mode->mode, &regn);
 
 
      if (end)
      if (end)
        {
        {
          int nw;
          int nw;
          unsigned int nr;
          unsigned int nr;
 
 
          src = end;
          src = end;
          if (*src == '(')
          if (*src == '(')
            {
            {
              src++;
              src++;
              end = parse_reg (src, &nw, &nr);
              end = parse_reg (src, &nw, &nr);
              if (end)
              if (end)
                {
                {
                  /* Got Ra(Rb).  */
                  /* Got Ra(Rb).  */
                  src = end;
                  src = end;
 
 
                  if (*src != ')')
                  if (*src != ')')
                    as_bad (_("Missing ) in ra(rb)"));
                    as_bad (_("Missing ) in ra(rb)"));
                  else
                  else
                    src++;
                    src++;
 
 
                  regaddr (mode->mode, "ra(rb) ra");
                  regaddr (mode->mode, "ra(rb) ra");
                  mode->mode = CLASS_BX;
                  mode->mode = CLASS_BX;
                  mode->reg = regn;
                  mode->reg = regn;
                  mode->x_reg = nr;
                  mode->x_reg = nr;
                  reg[ARG_RX] = nr;
                  reg[ARG_RX] = nr;
                }
                }
              else
              else
                {
                {
                  /* Got Ra(disp).  */
                  /* Got Ra(disp).  */
                  if (*src == '#')
                  if (*src == '#')
                    src++;
                    src++;
                  src = parse_exp (src, &(mode->exp));
                  src = parse_exp (src, &(mode->exp));
                  src = checkfor (src, ')');
                  src = checkfor (src, ')');
                  mode->mode = CLASS_BA;
                  mode->mode = CLASS_BA;
                  mode->reg = regn;
                  mode->reg = regn;
                  mode->x_reg = 0;
                  mode->x_reg = 0;
                  imm_operand = &(mode->exp);
                  imm_operand = &(mode->exp);
                }
                }
            }
            }
          else
          else
            {
            {
              mode->reg = regn;
              mode->reg = regn;
              mode->x_reg = 0;
              mode->x_reg = 0;
            }
            }
        }
        }
      else
      else
        {
        {
          /* No initial reg.  */
          /* No initial reg.  */
          src = parse_exp (src, &(mode->exp));
          src = parse_exp (src, &(mode->exp));
          if (*src == '(')
          if (*src == '(')
            {
            {
              src++;
              src++;
              end = parse_reg (src, &(mode->mode), &regn);
              end = parse_reg (src, &(mode->mode), &regn);
              regword (mode->mode, "addr(Ra) ra");
              regword (mode->mode, "addr(Ra) ra");
              mode->mode = CLASS_X;
              mode->mode = CLASS_X;
              mode->reg = regn;
              mode->reg = regn;
              mode->x_reg = 0;
              mode->x_reg = 0;
              da_operand = &(mode->exp);
              da_operand = &(mode->exp);
              src = checkfor (end, ')');
              src = checkfor (end, ')');
            }
            }
          else
          else
            {
            {
              /* Just an address.  */
              /* Just an address.  */
              mode->mode = CLASS_DA;
              mode->mode = CLASS_DA;
              mode->reg = 0;
              mode->reg = 0;
              mode->x_reg = 0;
              mode->x_reg = 0;
              da_operand = &(mode->exp);
              da_operand = &(mode->exp);
            }
            }
        }
        }
    }
    }
  *ptr = src;
  *ptr = src;
}
}
 
 
static char *
static char *
get_operands (const opcode_entry_type *opcode, char *op_end, op_type *operand)
get_operands (const opcode_entry_type *opcode, char *op_end, op_type *operand)
{
{
  char *ptr = op_end;
  char *ptr = op_end;
  char *savptr;
  char *savptr;
 
 
  switch (opcode->noperands)
  switch (opcode->noperands)
    {
    {
    case 0:
    case 0:
      operand[0].mode = 0;
      operand[0].mode = 0;
      operand[1].mode = 0;
      operand[1].mode = 0;
      while (*ptr == ' ')
      while (*ptr == ' ')
        ptr++;
        ptr++;
      break;
      break;
 
 
    case 1:
    case 1:
      if (opcode->arg_info[0] == CLASS_CC)
      if (opcode->arg_info[0] == CLASS_CC)
        {
        {
          get_cc_operand (&ptr, operand + 0, 0);
          get_cc_operand (&ptr, operand + 0, 0);
          while (*ptr == ' ')
          while (*ptr == ' ')
            ptr++;
            ptr++;
          if (*ptr && ! is_end_of_line[(unsigned char) *ptr])
          if (*ptr && ! is_end_of_line[(unsigned char) *ptr])
            {
            {
              as_bad (_("invalid condition code '%s'"), ptr);
              as_bad (_("invalid condition code '%s'"), ptr);
              while (*ptr && ! is_end_of_line[(unsigned char) *ptr])
              while (*ptr && ! is_end_of_line[(unsigned char) *ptr])
                ptr++;   /* Consume rest of line.  */
                ptr++;   /* Consume rest of line.  */
            }
            }
        }
        }
      else if (opcode->arg_info[0] == CLASS_FLAGS)
      else if (opcode->arg_info[0] == CLASS_FLAGS)
        {
        {
          get_flags_operand (&ptr, operand + 0, 0);
          get_flags_operand (&ptr, operand + 0, 0);
          while (*ptr == ' ')
          while (*ptr == ' ')
            ptr++;
            ptr++;
          if (*ptr && ! is_end_of_line[(unsigned char) *ptr])
          if (*ptr && ! is_end_of_line[(unsigned char) *ptr])
            {
            {
              as_bad (_("invalid flag '%s'"), ptr);
              as_bad (_("invalid flag '%s'"), ptr);
              while (*ptr && ! is_end_of_line[(unsigned char) *ptr])
              while (*ptr && ! is_end_of_line[(unsigned char) *ptr])
                ptr++;   /* Consume rest of line.  */
                ptr++;   /* Consume rest of line.  */
            }
            }
        }
        }
      else if (opcode->arg_info[0] == (CLASS_IMM + (ARG_IMM2)))
      else if (opcode->arg_info[0] == (CLASS_IMM + (ARG_IMM2)))
        get_interrupt_operand (&ptr, operand + 0, 0);
        get_interrupt_operand (&ptr, operand + 0, 0);
      else
      else
        get_operand (&ptr, operand + 0, 0);
        get_operand (&ptr, operand + 0, 0);
 
 
      operand[1].mode = 0;
      operand[1].mode = 0;
      break;
      break;
 
 
    case 2:
    case 2:
      savptr = ptr;
      savptr = ptr;
      if (opcode->arg_info[0] == CLASS_CC)
      if (opcode->arg_info[0] == CLASS_CC)
        {
        {
          get_cc_operand (&ptr, operand + 0, 0);
          get_cc_operand (&ptr, operand + 0, 0);
          while (*ptr == ' ')
          while (*ptr == ' ')
            ptr++;
            ptr++;
          if (*ptr != ',' && strchr (ptr + 1, ','))
          if (*ptr != ',' && strchr (ptr + 1, ','))
            {
            {
              savptr = ptr;
              savptr = ptr;
              while (*ptr != ',')
              while (*ptr != ',')
                ptr++;
                ptr++;
              *ptr = 0;
              *ptr = 0;
              ptr++;
              ptr++;
              as_bad (_("invalid condition code '%s'"), savptr);
              as_bad (_("invalid condition code '%s'"), savptr);
            }
            }
        }
        }
      else if (opcode->arg_info[0] == CLASS_CTRL)
      else if (opcode->arg_info[0] == CLASS_CTRL)
        {
        {
          get_ctrl_operand (&ptr, operand + 0, 0);
          get_ctrl_operand (&ptr, operand + 0, 0);
 
 
          if (the_ctrl == 0)
          if (the_ctrl == 0)
            {
            {
              ptr = savptr;
              ptr = savptr;
              get_operand (&ptr, operand + 0, 0);
              get_operand (&ptr, operand + 0, 0);
 
 
              if (ptr == 0)
              if (ptr == 0)
                return NULL;
                return NULL;
              if (*ptr == ',')
              if (*ptr == ',')
                ptr++;
                ptr++;
              get_ctrl_operand (&ptr, operand + 1, 1);
              get_ctrl_operand (&ptr, operand + 1, 1);
              if (the_ctrl == 0)
              if (the_ctrl == 0)
                return NULL;
                return NULL;
              return ptr;
              return ptr;
            }
            }
        }
        }
      else
      else
        get_operand (&ptr, operand + 0, 0);
        get_operand (&ptr, operand + 0, 0);
 
 
      if (ptr == 0)
      if (ptr == 0)
        return NULL;
        return NULL;
      if (*ptr == ',')
      if (*ptr == ',')
        ptr++;
        ptr++;
      get_operand (&ptr, operand + 1, 1);
      get_operand (&ptr, operand + 1, 1);
      break;
      break;
 
 
    case 3:
    case 3:
      get_operand (&ptr, operand + 0, 0);
      get_operand (&ptr, operand + 0, 0);
      if (*ptr == ',')
      if (*ptr == ',')
        ptr++;
        ptr++;
      get_operand (&ptr, operand + 1, 1);
      get_operand (&ptr, operand + 1, 1);
      if (*ptr == ',')
      if (*ptr == ',')
        ptr++;
        ptr++;
      get_operand (&ptr, operand + 2, 2);
      get_operand (&ptr, operand + 2, 2);
      break;
      break;
 
 
    case 4:
    case 4:
      get_operand (&ptr, operand + 0, 0);
      get_operand (&ptr, operand + 0, 0);
      if (*ptr == ',')
      if (*ptr == ',')
        ptr++;
        ptr++;
      get_operand (&ptr, operand + 1, 1);
      get_operand (&ptr, operand + 1, 1);
      if (*ptr == ',')
      if (*ptr == ',')
        ptr++;
        ptr++;
      get_operand (&ptr, operand + 2, 2);
      get_operand (&ptr, operand + 2, 2);
      if (*ptr == ',')
      if (*ptr == ',')
        ptr++;
        ptr++;
      get_cc_operand (&ptr, operand + 3, 3);
      get_cc_operand (&ptr, operand + 3, 3);
      break;
      break;
 
 
    default:
    default:
      abort ();
      abort ();
    }
    }
 
 
  return ptr;
  return ptr;
}
}
 
 
/* Passed a pointer to a list of opcodes which use different
/* Passed a pointer to a list of opcodes which use different
   addressing modes.  Return the opcode which matches the opcodes
   addressing modes.  Return the opcode which matches the opcodes
   provided.  */
   provided.  */
 
 
static opcode_entry_type *
static opcode_entry_type *
get_specific (opcode_entry_type *opcode, op_type *operands)
get_specific (opcode_entry_type *opcode, op_type *operands)
{
{
  opcode_entry_type *this_try = opcode;
  opcode_entry_type *this_try = opcode;
  int found = 0;
  int found = 0;
  unsigned int noperands = opcode->noperands;
  unsigned int noperands = opcode->noperands;
 
 
  int this_index = opcode->idx;
  int this_index = opcode->idx;
 
 
  while (this_index == opcode->idx && !found)
  while (this_index == opcode->idx && !found)
    {
    {
      unsigned int i;
      unsigned int i;
 
 
      this_try = opcode++;
      this_try = opcode++;
      for (i = 0; i < noperands; i++)
      for (i = 0; i < noperands; i++)
        {
        {
          unsigned int mode = operands[i].mode;
          unsigned int mode = operands[i].mode;
 
 
          if (((mode & CLASS_MASK) == CLASS_IR) && ((this_try->arg_info[i] & CLASS_MASK) == CLASS_IRO))
          if (((mode & CLASS_MASK) == CLASS_IR) && ((this_try->arg_info[i] & CLASS_MASK) == CLASS_IRO))
            {
            {
              mode = operands[i].mode = (operands[i].mode & ~CLASS_MASK) | CLASS_IRO;
              mode = operands[i].mode = (operands[i].mode & ~CLASS_MASK) | CLASS_IRO;
            }
            }
 
 
          if ((mode & CLASS_MASK) != (this_try->arg_info[i] & CLASS_MASK))
          if ((mode & CLASS_MASK) != (this_try->arg_info[i] & CLASS_MASK))
            {
            {
              /* It could be a pc rel operand, if this is a da mode
              /* It could be a pc rel operand, if this is a da mode
                 and we like disps, then insert it.  */
                 and we like disps, then insert it.  */
 
 
              if (mode == CLASS_DA && this_try->arg_info[i] == CLASS_DISP)
              if (mode == CLASS_DA && this_try->arg_info[i] == CLASS_DISP)
                {
                {
                  /* This is the case.  */
                  /* This is the case.  */
                  operands[i].mode = CLASS_DISP;
                  operands[i].mode = CLASS_DISP;
                }
                }
              else if (mode == CLASS_BA && this_try->arg_info[i])
              else if (mode == CLASS_BA && this_try->arg_info[i])
                {
                {
                  /* Can't think of a way to turn what we've been
                  /* Can't think of a way to turn what we've been
                     given into something that's OK.  */
                     given into something that's OK.  */
                  goto fail;
                  goto fail;
                }
                }
              else if (this_try->arg_info[i] & CLASS_PR)
              else if (this_try->arg_info[i] & CLASS_PR)
                {
                {
                  if (mode == CLASS_REG_LONG && segmented_mode)
                  if (mode == CLASS_REG_LONG && segmented_mode)
                    {
                    {
                      /* OK.  */
                      /* OK.  */
                    }
                    }
                  else if (mode == CLASS_REG_WORD && !segmented_mode)
                  else if (mode == CLASS_REG_WORD && !segmented_mode)
                    {
                    {
                      /* OK.  */
                      /* OK.  */
                    }
                    }
                  else
                  else
                    goto fail;
                    goto fail;
                }
                }
              else
              else
                goto fail;
                goto fail;
            }
            }
          switch (mode & CLASS_MASK)
          switch (mode & CLASS_MASK)
            {
            {
            default:
            default:
              break;
              break;
            case CLASS_IRO:
            case CLASS_IRO:
              if (operands[i].regsize != CLASS_REG_WORD)
              if (operands[i].regsize != CLASS_REG_WORD)
                as_bad (_("invalid indirect register size"));
                as_bad (_("invalid indirect register size"));
              reg[this_try->arg_info[i] & ARG_MASK] = operands[i].reg;
              reg[this_try->arg_info[i] & ARG_MASK] = operands[i].reg;
              break;
              break;
            case CLASS_IR:
            case CLASS_IR:
              if ((segmented_mode && operands[i].regsize != CLASS_REG_LONG)
              if ((segmented_mode && operands[i].regsize != CLASS_REG_LONG)
                  || (!segmented_mode && operands[i].regsize != CLASS_REG_WORD))
                  || (!segmented_mode && operands[i].regsize != CLASS_REG_WORD))
                as_bad (_("invalid indirect register size"));
                as_bad (_("invalid indirect register size"));
              reg[this_try->arg_info[i] & ARG_MASK] = operands[i].reg;
              reg[this_try->arg_info[i] & ARG_MASK] = operands[i].reg;
              break;
              break;
            case CLASS_X:
            case CLASS_X:
            case CLASS_BA:
            case CLASS_BA:
            case CLASS_BX:
            case CLASS_BX:
            case CLASS_DISP:
            case CLASS_DISP:
            case CLASS_REG:
            case CLASS_REG:
            case CLASS_REG_WORD:
            case CLASS_REG_WORD:
            case CLASS_REG_BYTE:
            case CLASS_REG_BYTE:
            case CLASS_REG_QUAD:
            case CLASS_REG_QUAD:
            case CLASS_REG_LONG:
            case CLASS_REG_LONG:
            case CLASS_REGN0:
            case CLASS_REGN0:
              reg[this_try->arg_info[i] & ARG_MASK] = operands[i].reg;
              reg[this_try->arg_info[i] & ARG_MASK] = operands[i].reg;
              break;
              break;
            case CLASS_CTRL:
            case CLASS_CTRL:
              if (this_try->opcode == OPC_ldctlb && the_ctrl != 1)
              if (this_try->opcode == OPC_ldctlb && the_ctrl != 1)
                as_bad (_("invalid control register name"));
                as_bad (_("invalid control register name"));
              break;
              break;
            }
            }
        }
        }
 
 
      found = 1;
      found = 1;
    fail:
    fail:
      ;
      ;
    }
    }
  if (found)
  if (found)
    return this_try;
    return this_try;
  else
  else
    return 0;
    return 0;
}
}
 
 
static char buffer[20];
static char buffer[20];
 
 
static void
static void
newfix (int ptr, int type, int size, expressionS *operand)
newfix (int ptr, int type, int size, expressionS *operand)
{
{
  int is_pcrel = 0;
  int is_pcrel = 0;
  fixS *fixP;
  fixS *fixP;
 
 
  /* Size is in nibbles.  */
  /* Size is in nibbles.  */
  if (operand->X_add_symbol
  if (operand->X_add_symbol
      || operand->X_op_symbol
      || operand->X_op_symbol
      || operand->X_add_number)
      || operand->X_add_number)
    {
    {
      switch(type)
      switch(type)
        {
        {
        case BFD_RELOC_8_PCREL:
        case BFD_RELOC_8_PCREL:
        case BFD_RELOC_Z8K_CALLR:
        case BFD_RELOC_Z8K_CALLR:
        case BFD_RELOC_Z8K_DISP7:
        case BFD_RELOC_Z8K_DISP7:
          is_pcrel = 1;
          is_pcrel = 1;
        }
        }
      fixP = fix_new_exp (frag_now, ptr, size / 2,
      fixP = fix_new_exp (frag_now, ptr, size / 2,
                          operand, is_pcrel, type);
                          operand, is_pcrel, type);
      if (is_pcrel)
      if (is_pcrel)
        fixP->fx_no_overflow = 1;
        fixP->fx_no_overflow = 1;
    }
    }
}
}
 
 
static char *
static char *
apply_fix (char *ptr, int type, expressionS *operand, int size)
apply_fix (char *ptr, int type, expressionS *operand, int size)
{
{
  long n = operand->X_add_number;
  long n = operand->X_add_number;
 
 
  /* size is in nibbles.  */
  /* size is in nibbles.  */
 
 
  newfix ((ptr - buffer) / 2, type, size + 1, operand);
  newfix ((ptr - buffer) / 2, type, size + 1, operand);
  switch (size)
  switch (size)
    {
    {
    case 8:                     /* 8 nibbles == 32 bits.  */
    case 8:                     /* 8 nibbles == 32 bits.  */
      *ptr++ = n >> 28;
      *ptr++ = n >> 28;
      *ptr++ = n >> 24;
      *ptr++ = n >> 24;
      *ptr++ = n >> 20;
      *ptr++ = n >> 20;
      *ptr++ = n >> 16;
      *ptr++ = n >> 16;
    case 4:                     /* 4 nibbles == 16 bits.  */
    case 4:                     /* 4 nibbles == 16 bits.  */
      *ptr++ = n >> 12;
      *ptr++ = n >> 12;
      *ptr++ = n >> 8;
      *ptr++ = n >> 8;
    case 2:
    case 2:
      *ptr++ = n >> 4;
      *ptr++ = n >> 4;
    case 1:
    case 1:
      *ptr++ = n >> 0;
      *ptr++ = n >> 0;
      break;
      break;
    }
    }
  return ptr;
  return ptr;
}
}
 
 
/* Now we know what sort of opcodes it is.  Let's build the bytes.  */
/* Now we know what sort of opcodes it is.  Let's build the bytes.  */
 
 
static void
static void
build_bytes (opcode_entry_type *this_try, struct z8k_op *operand ATTRIBUTE_UNUSED)
build_bytes (opcode_entry_type *this_try, struct z8k_op *operand ATTRIBUTE_UNUSED)
{
{
  char *output_ptr = buffer;
  char *output_ptr = buffer;
  int c;
  int c;
  int nibble;
  int nibble;
  unsigned int *class_ptr;
  unsigned int *class_ptr;
 
 
  frag_wane (frag_now);
  frag_wane (frag_now);
  frag_new (0);
  frag_new (0);
 
 
  if (frag_room () < 8)
  if (frag_room () < 8)
    frag_grow (8);  /* Make room for maximum instruction size.  */
    frag_grow (8);  /* Make room for maximum instruction size.  */
 
 
  memset (buffer, 0, sizeof (buffer));
  memset (buffer, 0, sizeof (buffer));
  class_ptr = this_try->byte_info;
  class_ptr = this_try->byte_info;
 
 
  for (nibble = 0; (c = *class_ptr++); nibble++)
  for (nibble = 0; (c = *class_ptr++); nibble++)
    {
    {
 
 
      switch (c & CLASS_MASK)
      switch (c & CLASS_MASK)
        {
        {
        default:
        default:
          abort ();
          abort ();
 
 
        case CLASS_ADDRESS:
        case CLASS_ADDRESS:
          /* Direct address, we don't cope with the SS mode right now.  */
          /* Direct address, we don't cope with the SS mode right now.  */
          if (segmented_mode)
          if (segmented_mode)
            {
            {
              /* da_operand->X_add_number |= 0x80000000;  --  Now set at relocation time.  */
              /* da_operand->X_add_number |= 0x80000000;  --  Now set at relocation time.  */
              output_ptr = apply_fix (output_ptr, BFD_RELOC_32, da_operand, 8);
              output_ptr = apply_fix (output_ptr, BFD_RELOC_32, da_operand, 8);
            }
            }
          else
          else
            {
            {
              output_ptr = apply_fix (output_ptr, BFD_RELOC_16, da_operand, 4);
              output_ptr = apply_fix (output_ptr, BFD_RELOC_16, da_operand, 4);
            }
            }
          da_operand = 0;
          da_operand = 0;
          break;
          break;
        case CLASS_DISP8:
        case CLASS_DISP8:
          /* pc rel 8 bit  */
          /* pc rel 8 bit  */
          output_ptr = apply_fix (output_ptr, BFD_RELOC_8_PCREL, da_operand, 2);
          output_ptr = apply_fix (output_ptr, BFD_RELOC_8_PCREL, da_operand, 2);
          da_operand = 0;
          da_operand = 0;
          break;
          break;
 
 
        case CLASS_0DISP7:
        case CLASS_0DISP7:
          /* pc rel 7 bit  */
          /* pc rel 7 bit  */
          *output_ptr = 0;
          *output_ptr = 0;
          output_ptr = apply_fix (output_ptr, BFD_RELOC_Z8K_DISP7, da_operand, 2);
          output_ptr = apply_fix (output_ptr, BFD_RELOC_Z8K_DISP7, da_operand, 2);
          da_operand = 0;
          da_operand = 0;
          break;
          break;
 
 
        case CLASS_1DISP7:
        case CLASS_1DISP7:
          /* pc rel 7 bit  */
          /* pc rel 7 bit  */
          *output_ptr = 0x80;
          *output_ptr = 0x80;
          output_ptr = apply_fix (output_ptr, BFD_RELOC_Z8K_DISP7, da_operand, 2);
          output_ptr = apply_fix (output_ptr, BFD_RELOC_Z8K_DISP7, da_operand, 2);
          output_ptr[-2] = 0x8;
          output_ptr[-2] = 0x8;
          da_operand = 0;
          da_operand = 0;
          break;
          break;
 
 
        case CLASS_BIT_1OR2:
        case CLASS_BIT_1OR2:
          *output_ptr = c & 0xf;
          *output_ptr = c & 0xf;
          if (imm_operand)
          if (imm_operand)
            {
            {
              if (imm_operand->X_add_number == 2)
              if (imm_operand->X_add_number == 2)
                *output_ptr |= 2;
                *output_ptr |= 2;
              else if (imm_operand->X_add_number != 1)
              else if (imm_operand->X_add_number != 1)
                as_bad (_("immediate must be 1 or 2"));
                as_bad (_("immediate must be 1 or 2"));
            }
            }
          else
          else
            as_bad (_("immediate 1 or 2 expected"));
            as_bad (_("immediate 1 or 2 expected"));
          output_ptr++;
          output_ptr++;
          break;
          break;
        case CLASS_CC:
        case CLASS_CC:
          *output_ptr++ = the_cc;
          *output_ptr++ = the_cc;
          break;
          break;
        case CLASS_0CCC:
        case CLASS_0CCC:
          if (the_ctrl < 2 || the_ctrl > 7)
          if (the_ctrl < 2 || the_ctrl > 7)
            as_bad (_("invalid control register name"));
            as_bad (_("invalid control register name"));
          *output_ptr++ = the_ctrl;
          *output_ptr++ = the_ctrl;
          break;
          break;
        case CLASS_1CCC:
        case CLASS_1CCC:
          if (the_ctrl < 2 || the_ctrl > 7)
          if (the_ctrl < 2 || the_ctrl > 7)
            as_bad (_("invalid control register name"));
            as_bad (_("invalid control register name"));
          *output_ptr++ = the_ctrl | 0x8;
          *output_ptr++ = the_ctrl | 0x8;
          break;
          break;
        case CLASS_00II:
        case CLASS_00II:
          *output_ptr++ = (~the_interrupt & 0x3);
          *output_ptr++ = (~the_interrupt & 0x3);
          break;
          break;
        case CLASS_01II:
        case CLASS_01II:
          *output_ptr++ = (~the_interrupt & 0x3) | 0x4;
          *output_ptr++ = (~the_interrupt & 0x3) | 0x4;
          break;
          break;
        case CLASS_FLAGS:
        case CLASS_FLAGS:
          *output_ptr++ = the_flags;
          *output_ptr++ = the_flags;
          break;
          break;
        case CLASS_IGNORE:
        case CLASS_IGNORE:
        case CLASS_BIT:
        case CLASS_BIT:
          *output_ptr++ = c & 0xf;
          *output_ptr++ = c & 0xf;
          break;
          break;
        case CLASS_REGN0:
        case CLASS_REGN0:
          if (reg[c & 0xf] == 0)
          if (reg[c & 0xf] == 0)
            as_bad (_("can't use R0 here"));
            as_bad (_("can't use R0 here"));
          /* Fall through.  */
          /* Fall through.  */
        case CLASS_REG:
        case CLASS_REG:
        case CLASS_REG_BYTE:
        case CLASS_REG_BYTE:
        case CLASS_REG_WORD:
        case CLASS_REG_WORD:
        case CLASS_REG_LONG:
        case CLASS_REG_LONG:
        case CLASS_REG_QUAD:
        case CLASS_REG_QUAD:
          /* Insert bit mattern of right reg.  */
          /* Insert bit mattern of right reg.  */
          *output_ptr++ = reg[c & 0xf];
          *output_ptr++ = reg[c & 0xf];
          break;
          break;
        case CLASS_DISP:
        case CLASS_DISP:
          switch (c & ARG_MASK)
          switch (c & ARG_MASK)
            {
            {
            case ARG_DISP12:
            case ARG_DISP12:
              output_ptr = apply_fix (output_ptr, BFD_RELOC_Z8K_CALLR, da_operand, 4);
              output_ptr = apply_fix (output_ptr, BFD_RELOC_Z8K_CALLR, da_operand, 4);
              break;
              break;
            case ARG_DISP16:
            case ARG_DISP16:
              output_ptr = apply_fix (output_ptr, BFD_RELOC_16_PCREL, da_operand, 4);
              output_ptr = apply_fix (output_ptr, BFD_RELOC_16_PCREL, da_operand, 4);
              break;
              break;
            default:
            default:
              output_ptr = apply_fix (output_ptr, BFD_RELOC_16, da_operand, 4);
              output_ptr = apply_fix (output_ptr, BFD_RELOC_16, da_operand, 4);
            }
            }
          da_operand = 0;
          da_operand = 0;
          break;
          break;
 
 
        case CLASS_IMM:
        case CLASS_IMM:
          {
          {
            switch (c & ARG_MASK)
            switch (c & ARG_MASK)
              {
              {
              case ARG_NIM4:
              case ARG_NIM4:
                if (imm_operand->X_add_number > 15)
                if (imm_operand->X_add_number > 15)
                  as_bad (_("immediate value out of range"));
                  as_bad (_("immediate value out of range"));
                imm_operand->X_add_number = -imm_operand->X_add_number;
                imm_operand->X_add_number = -imm_operand->X_add_number;
                output_ptr = apply_fix (output_ptr, BFD_RELOC_Z8K_IMM4L, imm_operand, 1);
                output_ptr = apply_fix (output_ptr, BFD_RELOC_Z8K_IMM4L, imm_operand, 1);
                break;
                break;
              /*case ARG_IMMNMINUS1: not used.  */
              /*case ARG_IMMNMINUS1: not used.  */
              case ARG_IMM4M1:
              case ARG_IMM4M1:
                imm_operand->X_add_number--;
                imm_operand->X_add_number--;
                /* Drop through.  */
                /* Drop through.  */
              case ARG_IMM4:
              case ARG_IMM4:
                if (imm_operand->X_add_number > 15)
                if (imm_operand->X_add_number > 15)
                  as_bad (_("immediate value out of range"));
                  as_bad (_("immediate value out of range"));
                output_ptr = apply_fix (output_ptr, BFD_RELOC_Z8K_IMM4L, imm_operand, 1);
                output_ptr = apply_fix (output_ptr, BFD_RELOC_Z8K_IMM4L, imm_operand, 1);
                break;
                break;
              case ARG_NIM8:
              case ARG_NIM8:
                imm_operand->X_add_number = -imm_operand->X_add_number;
                imm_operand->X_add_number = -imm_operand->X_add_number;
                /* Drop through.  */
                /* Drop through.  */
              case ARG_IMM8:
              case ARG_IMM8:
                output_ptr = apply_fix (output_ptr, BFD_RELOC_8, imm_operand, 2);
                output_ptr = apply_fix (output_ptr, BFD_RELOC_8, imm_operand, 2);
                break;
                break;
              case ARG_IMM16:
              case ARG_IMM16:
                output_ptr = apply_fix (output_ptr, BFD_RELOC_16, imm_operand, 4);
                output_ptr = apply_fix (output_ptr, BFD_RELOC_16, imm_operand, 4);
                break;
                break;
              case ARG_IMM32:
              case ARG_IMM32:
                output_ptr = apply_fix (output_ptr, BFD_RELOC_32, imm_operand, 8);
                output_ptr = apply_fix (output_ptr, BFD_RELOC_32, imm_operand, 8);
                break;
                break;
              default:
              default:
                abort ();
                abort ();
              }
              }
          }
          }
        }
        }
    }
    }
 
 
  /* Copy from the nibble buffer into the frag.  */
  /* Copy from the nibble buffer into the frag.  */
  {
  {
    int length = (output_ptr - buffer) / 2;
    int length = (output_ptr - buffer) / 2;
    char *src = buffer;
    char *src = buffer;
    char *fragp = frag_more (length);
    char *fragp = frag_more (length);
 
 
    while (src < output_ptr)
    while (src < output_ptr)
      {
      {
        *fragp = (src[0] << 4) | src[1];
        *fragp = (src[0] << 4) | src[1];
        src += 2;
        src += 2;
        fragp++;
        fragp++;
      }
      }
  }
  }
}
}
 
 
/* 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 c;
  char c;
  char *op_start;
  char *op_start;
  char *op_end;
  char *op_end;
  struct z8k_op operand[4];
  struct z8k_op operand[4];
  opcode_entry_type *opcode;
  opcode_entry_type *opcode;
 
 
  /* Drop leading whitespace.  */
  /* Drop leading whitespace.  */
  while (*str == ' ')
  while (*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;
       *op_end != 0 && *op_end != ' ' && ! is_end_of_line[(unsigned char) *op_end];
       *op_end != 0 && *op_end != ' ' && ! is_end_of_line[(unsigned char) *op_end];
       op_end++)
       op_end++)
    ;
    ;
 
 
  if (op_end == op_start)
  if (op_end == op_start)
    {
    {
      as_bad (_("can't find opcode "));
      as_bad (_("can't find opcode "));
    }
    }
  c = *op_end;
  c = *op_end;
 
 
  *op_end = 0;  /* Zero-terminate op code string for hash_find() call.  */
  *op_end = 0;  /* Zero-terminate op code string for hash_find() call.  */
 
 
  opcode = (opcode_entry_type *) hash_find (opcode_hash_control, op_start);
  opcode = (opcode_entry_type *) hash_find (opcode_hash_control, op_start);
 
 
  if (opcode == NULL)
  if (opcode == NULL)
    {
    {
      as_bad (_("unknown opcode"));
      as_bad (_("unknown opcode"));
      return;
      return;
    }
    }
 
 
  *op_end = c;  /* Restore original string.  */
  *op_end = c;  /* Restore original string.  */
 
 
  if (opcode->opcode == 250)
  if (opcode->opcode == 250)
    {
    {
      pseudo_typeS *p;
      pseudo_typeS *p;
      char oc;
      char oc;
      char *old = input_line_pointer;
      char *old = input_line_pointer;
 
 
      /* Was really a pseudo op.  */
      /* Was really a pseudo op.  */
 
 
      input_line_pointer = op_end;
      input_line_pointer = op_end;
 
 
      oc = *old;
      oc = *old;
      *old = '\n';
      *old = '\n';
      while (*input_line_pointer == ' ')
      while (*input_line_pointer == ' ')
        input_line_pointer++;
        input_line_pointer++;
      p = (pseudo_typeS *) (opcode->func);
      p = (pseudo_typeS *) (opcode->func);
 
 
      (p->poc_handler) (p->poc_val);
      (p->poc_handler) (p->poc_val);
      input_line_pointer = old;
      input_line_pointer = old;
      *old = oc;
      *old = oc;
    }
    }
  else
  else
    {
    {
      char *new_input_line_pointer;
      char *new_input_line_pointer;
 
 
      new_input_line_pointer = get_operands (opcode, op_end, operand);
      new_input_line_pointer = get_operands (opcode, op_end, operand);
      if (new_input_line_pointer)
      if (new_input_line_pointer)
        {
        {
          input_line_pointer = new_input_line_pointer;
          input_line_pointer = new_input_line_pointer;
          opcode = get_specific (opcode, operand);
          opcode = get_specific (opcode, operand);
        }
        }
 
 
      if (new_input_line_pointer == NULL || opcode == NULL)
      if (new_input_line_pointer == NULL || opcode == NULL)
        {
        {
          /* Couldn't find an opcode which matched the operands.  */
          /* Couldn't find an opcode which matched the operands.  */
          char *where = frag_more (2);
          char *where = frag_more (2);
 
 
          where[0] = 0x0;
          where[0] = 0x0;
          where[1] = 0x0;
          where[1] = 0x0;
 
 
          as_bad (_("Can't find opcode to match operands"));
          as_bad (_("Can't find opcode to match operands"));
          return;
          return;
        }
        }
 
 
      build_bytes (opcode, operand);
      build_bytes (opcode, operand);
    }
    }
}
}
 
 
/* We have no need to default values of symbols.  */
/* We have no need to default values of symbols.  */
 
 
symbolS *
symbolS *
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
{
{
  return 0;
  return 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, TRUE);
  return ieee_md_atof (type, litP, sizeP, TRUE);
}
}


const char *md_shortopts = "z:";
const char *md_shortopts = "z:";
 
 
struct option md_longopts[] =
struct option md_longopts[] =
  {
  {
#define OPTION_RELAX  (OPTION_MD_BASE)
#define OPTION_RELAX  (OPTION_MD_BASE)
    {"linkrelax", no_argument, NULL, OPTION_RELAX},
    {"linkrelax", no_argument, NULL, OPTION_RELAX},
    {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 'z':
    case 'z':
      if (!strcmp (arg, "8001"))
      if (!strcmp (arg, "8001"))
        s_segm (1);
        s_segm (1);
      else if (!strcmp (arg, "8002"))
      else if (!strcmp (arg, "8002"))
        s_segm (0);
        s_segm (0);
      else
      else
        {
        {
          as_bad (_("invalid architecture -z%s"), arg);
          as_bad (_("invalid architecture -z%s"), arg);
          return 0;
          return 0;
        }
        }
      z8k_target_from_cmdline = 1;
      z8k_target_from_cmdline = 1;
      break;
      break;
 
 
    case OPTION_RELAX:
    case OPTION_RELAX:
      linkrelax = 1;
      linkrelax = 1;
      break;
      break;
 
 
    default:
    default:
      return 0;
      return 0;
    }
    }
 
 
  return 1;
  return 1;
}
}
 
 
void
void
md_show_usage (FILE *stream)
md_show_usage (FILE *stream)
{
{
  fprintf (stream, _("\
  fprintf (stream, _("\
 Z8K options:\n\
 Z8K options:\n\
  -z8001                  generate segmented code\n\
  -z8001                  generate segmented code\n\
  -z8002                  generate unsegmented code\n\
  -z8002                  generate unsegmented code\n\
  -linkrelax              create linker relaxable code\n"));
  -linkrelax              create linker relaxable code\n"));
}
}


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 ATTRIBUTE_UNUSED)
                 fragS *fragP ATTRIBUTE_UNUSED)
{
{
  printf (_("call to md_convert_frag\n"));
  printf (_("call to md_convert_frag\n"));
  abort ();
  abort ();
}
}
 
 
/* Generate a machine dependent reloc from a fixup.  */
/* Generate a machine dependent reloc from a fixup.  */
 
 
arelent*
arelent*
tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
              fixS *fixp      ATTRIBUTE_UNUSED)
              fixS *fixp      ATTRIBUTE_UNUSED)
{
{
  arelent *reloc;
  arelent *reloc;
 
 
  reloc = xmalloc (sizeof (*reloc));
  reloc = xmalloc (sizeof (*reloc));
  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
  reloc->addend = fixp->fx_offset;
  reloc->addend = fixp->fx_offset;
  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
 
 
  if (! reloc->howto)
  if (! reloc->howto)
    {
    {
      as_bad_where (fixp->fx_file, fixp->fx_line,
      as_bad_where (fixp->fx_file, fixp->fx_line,
                    _("Cannot represent %s relocation in object file"),
                    _("Cannot represent %s relocation in object file"),
                    bfd_get_reloc_code_name (fixp->fx_r_type));
                    bfd_get_reloc_code_name (fixp->fx_r_type));
      abort ();
      abort ();
    }
    }
  return reloc;
  return reloc;
}
}
 
 
valueT
valueT
md_section_align (segT seg, valueT size)
md_section_align (segT seg, valueT size)
{
{
  int align = bfd_get_section_alignment (stdoutput, seg);
  int align = bfd_get_section_alignment (stdoutput, seg);
  valueT mask = ((valueT) 1 << align) - 1;
  valueT mask = ((valueT) 1 << align) - 1;
 
 
  return (size + mask) & ~mask;
  return (size + mask) & ~mask;
}
}
 
 
/* Attempt to simplify or eliminate a fixup. To indicate that a fixup
/* Attempt to simplify or eliminate a fixup. To indicate that a fixup
   has been eliminated, set fix->fx_done. If fix->fx_addsy is non-NULL,
   has been eliminated, set fix->fx_done. If fix->fx_addsy is non-NULL,
   we will have to generate a reloc entry.  */
   we will have to generate a reloc entry.  */
void
void
md_apply_fix (fixS *fixP, valueT *valP, segT segment ATTRIBUTE_UNUSED)
md_apply_fix (fixS *fixP, valueT *valP, segT segment ATTRIBUTE_UNUSED)
{
{
  long val = * (long *) valP;
  long val = * (long *) valP;
  char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
  char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
 
 
  switch (fixP->fx_r_type)
  switch (fixP->fx_r_type)
    {
    {
    case BFD_RELOC_Z8K_IMM4L:
    case BFD_RELOC_Z8K_IMM4L:
      if (fixP->fx_addsy)
      if (fixP->fx_addsy)
        {
        {
          fixP->fx_no_overflow = 1;
          fixP->fx_no_overflow = 1;
          fixP->fx_done = 0;
          fixP->fx_done = 0;
        }
        }
      else
      else
        buf[0] = (buf[0] & 0xf0) | (val & 0xf);
        buf[0] = (buf[0] & 0xf0) | (val & 0xf);
      break;
      break;
 
 
    case BFD_RELOC_8:
    case BFD_RELOC_8:
      if (fixP->fx_addsy)
      if (fixP->fx_addsy)
        {
        {
          fixP->fx_no_overflow = 1;
          fixP->fx_no_overflow = 1;
          fixP->fx_done = 0;
          fixP->fx_done = 0;
        }
        }
      else
      else
        *buf++ = val;
        *buf++ = val;
      break;
      break;
 
 
    case BFD_RELOC_16:
    case BFD_RELOC_16:
      if (fixP->fx_addsy)
      if (fixP->fx_addsy)
        {
        {
          fixP->fx_no_overflow = 1;
          fixP->fx_no_overflow = 1;
          fixP->fx_done = 0;
          fixP->fx_done = 0;
        }
        }
      else
      else
        {
        {
          *buf++ = (val >> 8);
          *buf++ = (val >> 8);
          *buf++ = val;
          *buf++ = val;
        }
        }
      break;
      break;
 
 
    case BFD_RELOC_32:
    case BFD_RELOC_32:
      if (fixP->fx_addsy)
      if (fixP->fx_addsy)
        {
        {
          fixP->fx_no_overflow = 1;
          fixP->fx_no_overflow = 1;
          fixP->fx_done = 0;
          fixP->fx_done = 0;
        }
        }
      else
      else
        {
        {
          *buf++ = (val >> 24);
          *buf++ = (val >> 24);
          *buf++ = (val >> 16);
          *buf++ = (val >> 16);
          *buf++ = (val >> 8);
          *buf++ = (val >> 8);
          *buf++ = val;
          *buf++ = val;
        }
        }
      break;
      break;
 
 
    case BFD_RELOC_8_PCREL:
    case BFD_RELOC_8_PCREL:
      if (fixP->fx_addsy)
      if (fixP->fx_addsy)
        {
        {
          fixP->fx_no_overflow = 1;
          fixP->fx_no_overflow = 1;
          fixP->fx_done = 0;
          fixP->fx_done = 0;
        }
        }
      else
      else
        {
        {
          if (val & 1)
          if (val & 1)
            as_bad_where (fixP->fx_file, fixP->fx_line,
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("cannot branch to odd address"));
                          _("cannot branch to odd address"));
          val /= 2;
          val /= 2;
          if (val > 127 || val < -128)
          if (val > 127 || val < -128)
            as_bad_where (fixP->fx_file, fixP->fx_line,
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("relative jump out of range"));
                          _("relative jump out of range"));
          *buf++ = val;
          *buf++ = val;
          fixP->fx_no_overflow = 1;
          fixP->fx_no_overflow = 1;
          fixP->fx_done = 1;
          fixP->fx_done = 1;
        }
        }
      break;
      break;
 
 
    case BFD_RELOC_16_PCREL:
    case BFD_RELOC_16_PCREL:
      if (fixP->fx_addsy)
      if (fixP->fx_addsy)
        {
        {
          fixP->fx_no_overflow = 1;
          fixP->fx_no_overflow = 1;
          fixP->fx_done = 0;
          fixP->fx_done = 0;
        }
        }
      else
      else
        {
        {
          val = val - fixP->fx_frag->fr_address + fixP->fx_where - fixP->fx_size;
          val = val - fixP->fx_frag->fr_address + fixP->fx_where - fixP->fx_size;
          if (val > 32767 || val < -32768)
          if (val > 32767 || val < -32768)
            as_bad_where (fixP->fx_file, fixP->fx_line,
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("relative address out of range"));
                          _("relative address out of range"));
          *buf++ = (val >> 8);
          *buf++ = (val >> 8);
          *buf++ = val;
          *buf++ = val;
          fixP->fx_no_overflow = 1;
          fixP->fx_no_overflow = 1;
          fixP->fx_done = 1;
          fixP->fx_done = 1;
        }
        }
      break;
      break;
 
 
    case BFD_RELOC_Z8K_CALLR:
    case BFD_RELOC_Z8K_CALLR:
      if (fixP->fx_addsy)
      if (fixP->fx_addsy)
        {
        {
          fixP->fx_no_overflow = 1;
          fixP->fx_no_overflow = 1;
          fixP->fx_done = 0;
          fixP->fx_done = 0;
        }
        }
      else
      else
        {
        {
          if (val & 1)
          if (val & 1)
            as_bad_where (fixP->fx_file, fixP->fx_line,
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("cannot branch to odd address"));
                          _("cannot branch to odd address"));
          if (val > 4096 || val < -4095)
          if (val > 4096 || val < -4095)
            as_bad_where (fixP->fx_file, fixP->fx_line,
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("relative call out of range"));
                          _("relative call out of range"));
          val = -val / 2;
          val = -val / 2;
          *buf = (*buf & 0xf0) | ((val >> 8) & 0xf);
          *buf = (*buf & 0xf0) | ((val >> 8) & 0xf);
          buf++;
          buf++;
          *buf++ = val & 0xff;
          *buf++ = val & 0xff;
          fixP->fx_no_overflow = 1;
          fixP->fx_no_overflow = 1;
          fixP->fx_done = 1;
          fixP->fx_done = 1;
        }
        }
      break;
      break;
 
 
    case BFD_RELOC_Z8K_DISP7:
    case BFD_RELOC_Z8K_DISP7:
      if (fixP->fx_addsy)
      if (fixP->fx_addsy)
        {
        {
          fixP->fx_no_overflow = 1;
          fixP->fx_no_overflow = 1;
          fixP->fx_done = 0;
          fixP->fx_done = 0;
        }
        }
      else
      else
        {
        {
          if (val & 1)
          if (val & 1)
            as_bad_where (fixP->fx_file, fixP->fx_line,
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("cannot branch to odd address"));
                          _("cannot branch to odd address"));
          val /= 2;
          val /= 2;
          if (val > 0 || val < -127)
          if (val > 0 || val < -127)
            as_bad_where (fixP->fx_file, fixP->fx_line,
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("relative jump out of range"));
                          _("relative jump out of range"));
          *buf = (*buf & 0x80) | (-val & 0x7f);
          *buf = (*buf & 0x80) | (-val & 0x7f);
          fixP->fx_no_overflow = 1;
          fixP->fx_no_overflow = 1;
          fixP->fx_done = 1;
          fixP->fx_done = 1;
        }
        }
      break;
      break;
 
 
    default:
    default:
      printf(_("md_apply_fix: unknown r_type 0x%x\n"), fixP->fx_r_type);
      printf(_("md_apply_fix: unknown r_type 0x%x\n"), fixP->fx_r_type);
      abort ();
      abort ();
    }
    }
 
 
  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
    fixP->fx_done = 1;
    fixP->fx_done = 1;
}
}
 
 
int
int
md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
                               segT segment_type ATTRIBUTE_UNUSED)
                               segT segment_type ATTRIBUTE_UNUSED)
{
{
  printf (_("call to md_estimate_size_before_relax\n"));
  printf (_("call to md_estimate_size_before_relax\n"));
  abort ();
  abort ();
}
}
 
 
/* 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)
{
{
  number_to_chars_bigendian (ptr, use, nbytes);
  number_to_chars_bigendian (ptr, use, nbytes);
}
}
 
 
/* On the Z8000, a PC-relative offset is relative to the address of the
/* On the Z8000, a PC-relative offset is relative to the address of the
   instruction plus its size.  */
   instruction plus its size.  */
long
long
md_pcrel_from (fixS *fixP)
md_pcrel_from (fixS *fixP)
{
{
  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
}
}
 
 
void
void
tc_coff_symbol_emit_hook (symbolS *s ATTRIBUTE_UNUSED)
tc_coff_symbol_emit_hook (symbolS *s ATTRIBUTE_UNUSED)
{
{
}
}
 
 

powered by: WebSVN 2.1.0

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