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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [gas/] [config/] [tc-ns32k.c] - Diff between revs 16 and 163

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

Rev 16 Rev 163
/* ns32k.c  -- Assemble on the National Semiconductor 32k series
/* ns32k.c  -- Assemble on the National Semiconductor 32k series
   Copyright 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
   Copyright 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
   2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009
   2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009
   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.  */
 
 
/*#define SHOW_NUM 1*//* Uncomment for debugging.  */
/*#define SHOW_NUM 1*//* Uncomment for debugging.  */
 
 
#include "as.h"
#include "as.h"
#include "opcode/ns32k.h"
#include "opcode/ns32k.h"
 
 
#include "obstack.h"
#include "obstack.h"
 
 
/* Macros.  */
/* Macros.  */
#define IIF_ENTRIES 13          /* Number of entries in iif.  */
#define IIF_ENTRIES 13          /* Number of entries in iif.  */
#define PRIVATE_SIZE 256        /* Size of my garbage memory.  */
#define PRIVATE_SIZE 256        /* Size of my garbage memory.  */
#define MAX_ARGS 4
#define MAX_ARGS 4
#define DEFAULT -1              /* addr_mode returns this value when
#define DEFAULT -1              /* addr_mode returns this value when
                                   plain constant or label is
                                   plain constant or label is
                                   encountered.  */
                                   encountered.  */
 
 
#define IIF(ptr,a1,c1,e1,g1,i1,k1,m1,o1,q1,s1,u1)       \
#define IIF(ptr,a1,c1,e1,g1,i1,k1,m1,o1,q1,s1,u1)       \
    iif.iifP[ptr].type = a1;                            \
    iif.iifP[ptr].type = a1;                            \
    iif.iifP[ptr].size = c1;                            \
    iif.iifP[ptr].size = c1;                            \
    iif.iifP[ptr].object = e1;                          \
    iif.iifP[ptr].object = e1;                          \
    iif.iifP[ptr].object_adjust = g1;                   \
    iif.iifP[ptr].object_adjust = g1;                   \
    iif.iifP[ptr].pcrel = i1;                           \
    iif.iifP[ptr].pcrel = i1;                           \
    iif.iifP[ptr].pcrel_adjust = k1;                    \
    iif.iifP[ptr].pcrel_adjust = k1;                    \
    iif.iifP[ptr].im_disp = m1;                         \
    iif.iifP[ptr].im_disp = m1;                         \
    iif.iifP[ptr].relax_substate = o1;                  \
    iif.iifP[ptr].relax_substate = o1;                  \
    iif.iifP[ptr].bit_fixP = q1;                        \
    iif.iifP[ptr].bit_fixP = q1;                        \
    iif.iifP[ptr].addr_mode = s1;                       \
    iif.iifP[ptr].addr_mode = s1;                       \
    iif.iifP[ptr].bsr = u1;
    iif.iifP[ptr].bsr = u1;
 
 
#ifdef SEQUENT_COMPATABILITY
#ifdef SEQUENT_COMPATABILITY
#define LINE_COMMENT_CHARS "|"
#define LINE_COMMENT_CHARS "|"
#define ABSOLUTE_PREFIX '@'
#define ABSOLUTE_PREFIX '@'
#define IMMEDIATE_PREFIX '#'
#define IMMEDIATE_PREFIX '#'
#endif
#endif
 
 
#ifndef LINE_COMMENT_CHARS
#ifndef LINE_COMMENT_CHARS
#define LINE_COMMENT_CHARS "#"
#define LINE_COMMENT_CHARS "#"
#endif
#endif
 
 
const char comment_chars[] = "#";
const char comment_chars[] = "#";
const char line_comment_chars[] = LINE_COMMENT_CHARS;
const char line_comment_chars[] = LINE_COMMENT_CHARS;
const char line_separator_chars[] = ";";
const char line_separator_chars[] = ";";
static int default_disp_size = 4; /* Displacement size for external refs.  */
static int default_disp_size = 4; /* Displacement size for external refs.  */
 
 
#if !defined(ABSOLUTE_PREFIX) && !defined(IMMEDIATE_PREFIX)
#if !defined(ABSOLUTE_PREFIX) && !defined(IMMEDIATE_PREFIX)
#define ABSOLUTE_PREFIX '@'     /* One or the other MUST be defined.  */
#define ABSOLUTE_PREFIX '@'     /* One or the other MUST be defined.  */
#endif
#endif
 
 
struct addr_mode
struct addr_mode
{
{
  signed char mode;             /* Addressing mode of operand (0-31).  */
  signed char mode;             /* Addressing mode of operand (0-31).  */
  signed char scaled_mode;      /* Mode combined with scaled mode.  */
  signed char scaled_mode;      /* Mode combined with scaled mode.  */
  char scaled_reg;              /* Register used in scaled+1 (1-8).  */
  char scaled_reg;              /* Register used in scaled+1 (1-8).  */
  char float_flag;              /* Set if R0..R7 was F0..F7 ie a
  char float_flag;              /* Set if R0..R7 was F0..F7 ie a
                                   floating-point-register.  */
                                   floating-point-register.  */
  char am_size;                 /* Estimated max size of general addr-mode
  char am_size;                 /* Estimated max size of general addr-mode
                                   parts.  */
                                   parts.  */
  char im_disp;                 /* If im_disp==1 we have a displacement.  */
  char im_disp;                 /* If im_disp==1 we have a displacement.  */
  char pcrel;                   /* 1 if pcrel, this is really redundant info.  */
  char pcrel;                   /* 1 if pcrel, this is really redundant info.  */
  char disp_suffix[2];          /* Length of displacement(s), 0=undefined.  */
  char disp_suffix[2];          /* Length of displacement(s), 0=undefined.  */
  char *disp[2];                /* Pointer(s) at displacement(s)
  char *disp[2];                /* Pointer(s) at displacement(s)
                                   or immediates(s)     (ascii).  */
                                   or immediates(s)     (ascii).  */
  char index_byte;              /* Index byte.  */
  char index_byte;              /* Index byte.  */
};
};
typedef struct addr_mode addr_modeS;
typedef struct addr_mode addr_modeS;
 
 
char *freeptr, *freeptr_static; /* Points at some number of free bytes.  */
char *freeptr, *freeptr_static; /* Points at some number of free bytes.  */
struct hash_control *inst_hash_handle;
struct hash_control *inst_hash_handle;
 
 
struct ns32k_opcode *desc;      /* Pointer at description of instruction.  */
struct ns32k_opcode *desc;      /* Pointer at description of instruction.  */
addr_modeS addr_modeP;
addr_modeS addr_modeP;
const char EXP_CHARS[] = "eE";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "fd";  /* We don't want to support lowercase,
const char FLT_CHARS[] = "fd";  /* We don't want to support lowercase,
                                   do we?  */
                                   do we?  */
 
 
/* UPPERCASE denotes live names when an instruction is built, IIF is
/* UPPERCASE denotes live names when an instruction is built, IIF is
   used as an intermediate form to store the actual parts of the
   used as an intermediate form to store the actual parts of the
   instruction. A ns32k machine instruction can be divided into a
   instruction. A ns32k machine instruction can be divided into a
   couple of sub PARTs. When an instruction is assembled the
   couple of sub PARTs. When an instruction is assembled the
   appropriate PART get an assignment. When an IIF has been completed
   appropriate PART get an assignment. When an IIF has been completed
   it is converted to a FRAGment as specified in AS.H.  */
   it is converted to a FRAGment as specified in AS.H.  */
 
 
/* Internal structs.  */
/* Internal structs.  */
struct ns32k_option
struct ns32k_option
{
{
  char *pattern;
  char *pattern;
  unsigned long or;
  unsigned long or;
  unsigned long and;
  unsigned long and;
};
};
 
 
typedef struct
typedef struct
{
{
  int type;                     /* How to interpret object.  */
  int type;                     /* How to interpret object.  */
  int size;                     /* Estimated max size of object.  */
  int size;                     /* Estimated max size of object.  */
  unsigned long object;         /* Binary data.  */
  unsigned long object;         /* Binary data.  */
  int object_adjust;            /* Number added to object.  */
  int object_adjust;            /* Number added to object.  */
  int pcrel;                    /* True if object is pcrel.  */
  int pcrel;                    /* True if object is pcrel.  */
  int pcrel_adjust;             /* Length in bytes from the instruction
  int pcrel_adjust;             /* Length in bytes from the instruction
                                   start to the displacement.  */
                                   start to the displacement.  */
  int im_disp;                  /* True if the object is a displacement.  */
  int im_disp;                  /* True if the object is a displacement.  */
  relax_substateT relax_substate;/*Initial relaxsubstate.  */
  relax_substateT relax_substate;/*Initial relaxsubstate.  */
  bit_fixS *bit_fixP;           /* Pointer at bit_fix struct.  */
  bit_fixS *bit_fixP;           /* Pointer at bit_fix struct.  */
  int addr_mode;                /* What addrmode do we associate with this
  int addr_mode;                /* What addrmode do we associate with this
                                   iif-entry.  */
                                   iif-entry.  */
  char bsr;                     /* Sequent hack.  */
  char bsr;                     /* Sequent hack.  */
} iif_entryT;                   /* Internal Instruction Format.  */
} iif_entryT;                   /* Internal Instruction Format.  */
 
 
struct int_ins_form
struct int_ins_form
{
{
  int instr_size;               /* Max size of instruction in bytes.  */
  int instr_size;               /* Max size of instruction in bytes.  */
  iif_entryT iifP[IIF_ENTRIES + 1];
  iif_entryT iifP[IIF_ENTRIES + 1];
};
};
 
 
struct int_ins_form iif;
struct int_ins_form iif;
expressionS exprP;
expressionS exprP;
char *input_line_pointer;
char *input_line_pointer;
 
 
/* Description of the PARTs in IIF
/* Description of the PARTs in IIF
  object[n]:
  object[n]:
   0    total length in bytes of entries in iif
   0    total length in bytes of entries in iif
   1    opcode
   1    opcode
   2    index_byte_a
   2    index_byte_a
   3    index_byte_b
   3    index_byte_b
   4    disp_a_1
   4    disp_a_1
   5    disp_a_2
   5    disp_a_2
   6    disp_b_1
   6    disp_b_1
   7    disp_b_2
   7    disp_b_2
   8    imm_a
   8    imm_a
   9    imm_b
   9    imm_b
   10   implied1
   10   implied1
   11   implied2
   11   implied2
 
 
   For every entry there is a datalength in bytes. This is stored in size[n].
   For every entry there is a datalength in bytes. This is stored in size[n].
         0,     the objectlength is not explicitly given by the instruction
         0,     the objectlength is not explicitly given by the instruction
                and the operand is undefined. This is a case for relaxation.
                and the operand is undefined. This is a case for relaxation.
                Reserve 4 bytes for the final object.
                Reserve 4 bytes for the final object.
 
 
         1,     the entry contains one byte
         1,     the entry contains one byte
         2,     the entry contains two bytes
         2,     the entry contains two bytes
         3,     the entry contains three bytes
         3,     the entry contains three bytes
         4,     the entry contains four bytes
         4,     the entry contains four bytes
        etc
        etc
 
 
   Furthermore, every entry has a data type identifier in type[n].
   Furthermore, every entry has a data type identifier in type[n].
 
 
         0,     the entry is void, ignore it.
         0,     the entry is void, ignore it.
         1,     the entry is a binary number.
         1,     the entry is a binary number.
         2,     the entry is a pointer at an expression.
         2,     the entry is a pointer at an expression.
                Where expression may be as simple as a single '1',
                Where expression may be as simple as a single '1',
                and as complicated as  foo-bar+12,
                and as complicated as  foo-bar+12,
                foo and bar may be undefined but suffixed by :{b|w|d} to
                foo and bar may be undefined but suffixed by :{b|w|d} to
                control the length of the object.
                control the length of the object.
 
 
         3,     the entry is a pointer at a bignum struct
         3,     the entry is a pointer at a bignum struct
 
 
   The low-order-byte corresponds to low physical memory.
   The low-order-byte corresponds to low physical memory.
   Obviously a FRAGment must be created for each valid disp in PART whose
   Obviously a FRAGment must be created for each valid disp in PART whose
   datalength is undefined (to bad) .
   datalength is undefined (to bad) .
   The case where just the expression is undefined is less severe and is
   The case where just the expression is undefined is less severe and is
   handled by fix. Here the number of bytes in the objectfile is known.
   handled by fix. Here the number of bytes in the objectfile is known.
   With this representation we simplify the assembly and separates the
   With this representation we simplify the assembly and separates the
   machine dependent/independent parts in a more clean way (said OE).  */
   machine dependent/independent parts in a more clean way (said OE).  */


struct ns32k_option opt1[] =            /* restore, exit.  */
struct ns32k_option opt1[] =            /* restore, exit.  */
{
{
  {"r0", 0x80, 0xff},
  {"r0", 0x80, 0xff},
  {"r1", 0x40, 0xff},
  {"r1", 0x40, 0xff},
  {"r2", 0x20, 0xff},
  {"r2", 0x20, 0xff},
  {"r3", 0x10, 0xff},
  {"r3", 0x10, 0xff},
  {"r4", 0x08, 0xff},
  {"r4", 0x08, 0xff},
  {"r5", 0x04, 0xff},
  {"r5", 0x04, 0xff},
  {"r6", 0x02, 0xff},
  {"r6", 0x02, 0xff},
  {"r7", 0x01, 0xff},
  {"r7", 0x01, 0xff},
  {0, 0x00, 0xff}
  {0, 0x00, 0xff}
};
};
struct ns32k_option opt2[] =            /* save, enter.  */
struct ns32k_option opt2[] =            /* save, enter.  */
{
{
  {"r0", 0x01, 0xff},
  {"r0", 0x01, 0xff},
  {"r1", 0x02, 0xff},
  {"r1", 0x02, 0xff},
  {"r2", 0x04, 0xff},
  {"r2", 0x04, 0xff},
  {"r3", 0x08, 0xff},
  {"r3", 0x08, 0xff},
  {"r4", 0x10, 0xff},
  {"r4", 0x10, 0xff},
  {"r5", 0x20, 0xff},
  {"r5", 0x20, 0xff},
  {"r6", 0x40, 0xff},
  {"r6", 0x40, 0xff},
  {"r7", 0x80, 0xff},
  {"r7", 0x80, 0xff},
  {0, 0x00, 0xff}
  {0, 0x00, 0xff}
};
};
struct ns32k_option opt3[] =            /* setcfg.  */
struct ns32k_option opt3[] =            /* setcfg.  */
{
{
  {"c", 0x8, 0xff},
  {"c", 0x8, 0xff},
  {"m", 0x4, 0xff},
  {"m", 0x4, 0xff},
  {"f", 0x2, 0xff},
  {"f", 0x2, 0xff},
  {"i", 0x1, 0xff},
  {"i", 0x1, 0xff},
  {0, 0x0, 0xff}
  {0, 0x0, 0xff}
};
};
struct ns32k_option opt4[] =            /* cinv.  */
struct ns32k_option opt4[] =            /* cinv.  */
{
{
  {"a", 0x4, 0xff},
  {"a", 0x4, 0xff},
  {"i", 0x2, 0xff},
  {"i", 0x2, 0xff},
  {"d", 0x1, 0xff},
  {"d", 0x1, 0xff},
  {0, 0x0, 0xff}
  {0, 0x0, 0xff}
};
};
struct ns32k_option opt5[] =            /* String inst.  */
struct ns32k_option opt5[] =            /* String inst.  */
{
{
  {"b", 0x2, 0xff},
  {"b", 0x2, 0xff},
  {"u", 0xc, 0xff},
  {"u", 0xc, 0xff},
  {"w", 0x4, 0xff},
  {"w", 0x4, 0xff},
  {0, 0x0, 0xff}
  {0, 0x0, 0xff}
};
};
struct ns32k_option opt6[] =            /* Plain reg ext,cvtp etc.  */
struct ns32k_option opt6[] =            /* Plain reg ext,cvtp etc.  */
{
{
  {"r0", 0x00, 0xff},
  {"r0", 0x00, 0xff},
  {"r1", 0x01, 0xff},
  {"r1", 0x01, 0xff},
  {"r2", 0x02, 0xff},
  {"r2", 0x02, 0xff},
  {"r3", 0x03, 0xff},
  {"r3", 0x03, 0xff},
  {"r4", 0x04, 0xff},
  {"r4", 0x04, 0xff},
  {"r5", 0x05, 0xff},
  {"r5", 0x05, 0xff},
  {"r6", 0x06, 0xff},
  {"r6", 0x06, 0xff},
  {"r7", 0x07, 0xff},
  {"r7", 0x07, 0xff},
  {0, 0x00, 0xff}
  {0, 0x00, 0xff}
};
};
 
 
#if !defined(NS32032) && !defined(NS32532)
#if !defined(NS32032) && !defined(NS32532)
#define NS32532
#define NS32532
#endif
#endif
 
 
struct ns32k_option cpureg_532[] =      /* lpr spr.  */
struct ns32k_option cpureg_532[] =      /* lpr spr.  */
{
{
  {"us", 0x0, 0xff},
  {"us", 0x0, 0xff},
  {"dcr", 0x1, 0xff},
  {"dcr", 0x1, 0xff},
  {"bpc", 0x2, 0xff},
  {"bpc", 0x2, 0xff},
  {"dsr", 0x3, 0xff},
  {"dsr", 0x3, 0xff},
  {"car", 0x4, 0xff},
  {"car", 0x4, 0xff},
  {"fp", 0x8, 0xff},
  {"fp", 0x8, 0xff},
  {"sp", 0x9, 0xff},
  {"sp", 0x9, 0xff},
  {"sb", 0xa, 0xff},
  {"sb", 0xa, 0xff},
  {"usp", 0xb, 0xff},
  {"usp", 0xb, 0xff},
  {"cfg", 0xc, 0xff},
  {"cfg", 0xc, 0xff},
  {"psr", 0xd, 0xff},
  {"psr", 0xd, 0xff},
  {"intbase", 0xe, 0xff},
  {"intbase", 0xe, 0xff},
  {"mod", 0xf, 0xff},
  {"mod", 0xf, 0xff},
  {0, 0x00, 0xff}
  {0, 0x00, 0xff}
};
};
struct ns32k_option mmureg_532[] =      /* lmr smr.  */
struct ns32k_option mmureg_532[] =      /* lmr smr.  */
{
{
  {"mcr", 0x9, 0xff},
  {"mcr", 0x9, 0xff},
  {"msr", 0xa, 0xff},
  {"msr", 0xa, 0xff},
  {"tear", 0xb, 0xff},
  {"tear", 0xb, 0xff},
  {"ptb0", 0xc, 0xff},
  {"ptb0", 0xc, 0xff},
  {"ptb1", 0xd, 0xff},
  {"ptb1", 0xd, 0xff},
  {"ivar0", 0xe, 0xff},
  {"ivar0", 0xe, 0xff},
  {"ivar1", 0xf, 0xff},
  {"ivar1", 0xf, 0xff},
  {0, 0x0, 0xff}
  {0, 0x0, 0xff}
};
};
 
 
struct ns32k_option cpureg_032[] =      /* lpr spr.  */
struct ns32k_option cpureg_032[] =      /* lpr spr.  */
{
{
  {"upsr", 0x0, 0xff},
  {"upsr", 0x0, 0xff},
  {"fp", 0x8, 0xff},
  {"fp", 0x8, 0xff},
  {"sp", 0x9, 0xff},
  {"sp", 0x9, 0xff},
  {"sb", 0xa, 0xff},
  {"sb", 0xa, 0xff},
  {"psr", 0xd, 0xff},
  {"psr", 0xd, 0xff},
  {"intbase", 0xe, 0xff},
  {"intbase", 0xe, 0xff},
  {"mod", 0xf, 0xff},
  {"mod", 0xf, 0xff},
  {0, 0x0, 0xff}
  {0, 0x0, 0xff}
};
};
struct ns32k_option mmureg_032[] =      /* lmr smr.  */
struct ns32k_option mmureg_032[] =      /* lmr smr.  */
{
{
  {"bpr0", 0x0, 0xff},
  {"bpr0", 0x0, 0xff},
  {"bpr1", 0x1, 0xff},
  {"bpr1", 0x1, 0xff},
  {"pf0", 0x4, 0xff},
  {"pf0", 0x4, 0xff},
  {"pf1", 0x5, 0xff},
  {"pf1", 0x5, 0xff},
  {"sc", 0x8, 0xff},
  {"sc", 0x8, 0xff},
  {"msr", 0xa, 0xff},
  {"msr", 0xa, 0xff},
  {"bcnt", 0xb, 0xff},
  {"bcnt", 0xb, 0xff},
  {"ptb0", 0xc, 0xff},
  {"ptb0", 0xc, 0xff},
  {"ptb1", 0xd, 0xff},
  {"ptb1", 0xd, 0xff},
  {"eia", 0xf, 0xff},
  {"eia", 0xf, 0xff},
  {0, 0x0, 0xff}
  {0, 0x0, 0xff}
};
};
 
 
#if defined(NS32532)
#if defined(NS32532)
struct ns32k_option *cpureg = cpureg_532;
struct ns32k_option *cpureg = cpureg_532;
struct ns32k_option *mmureg = mmureg_532;
struct ns32k_option *mmureg = mmureg_532;
#else
#else
struct ns32k_option *cpureg = cpureg_032;
struct ns32k_option *cpureg = cpureg_032;
struct ns32k_option *mmureg = mmureg_032;
struct ns32k_option *mmureg = mmureg_032;
#endif
#endif


 
 
const pseudo_typeS md_pseudo_table[] =
const pseudo_typeS md_pseudo_table[] =
{                                       /* So far empty.  */
{                                       /* So far empty.  */
  {0, 0, 0}
  {0, 0, 0}
};
};
 
 
#define IND(x,y)        (((x)<<2)+(y))
#define IND(x,y)        (((x)<<2)+(y))
 
 
/* Those are index's to relax groups in md_relax_table ie it must be
/* Those are index's to relax groups in md_relax_table ie it must be
   multiplied by 4 to point at a group start. Viz IND(x,y) Se function
   multiplied by 4 to point at a group start. Viz IND(x,y) Se function
   relax_segment in write.c for more info.  */
   relax_segment in write.c for more info.  */
 
 
#define BRANCH          1
#define BRANCH          1
#define PCREL           2
#define PCREL           2
 
 
/* Those are index's to entries in a relax group.  */
/* Those are index's to entries in a relax group.  */
 
 
#define BYTE            0
#define BYTE            0
#define WORD            1
#define WORD            1
#define DOUBLE          2
#define DOUBLE          2
#define UNDEF           3
#define UNDEF           3
/* Those limits are calculated from the displacement start in memory.
/* Those limits are calculated from the displacement start in memory.
   The ns32k uses the beginning of the instruction as displacement
   The ns32k uses the beginning of the instruction as displacement
   base.  This type of displacements could be handled here by moving
   base.  This type of displacements could be handled here by moving
   the limit window up or down. I choose to use an internal
   the limit window up or down. I choose to use an internal
   displacement base-adjust as there are other routines that must
   displacement base-adjust as there are other routines that must
   consider this. Also, as we have two various offset-adjusts in the
   consider this. Also, as we have two various offset-adjusts in the
   ns32k (acb versus br/brs/jsr/bcond), two set of limits would have
   ns32k (acb versus br/brs/jsr/bcond), two set of limits would have
   had to be used.  Now we dont have to think about that.  */
   had to be used.  Now we dont have to think about that.  */
 
 
const relax_typeS md_relax_table[] =
const relax_typeS md_relax_table[] =
{
{
  {1, 1, 0, 0},
  {1, 1, 0, 0},
  {1, 1, 0, 0},
  {1, 1, 0, 0},
  {1, 1, 0, 0},
  {1, 1, 0, 0},
  {1, 1, 0, 0},
  {1, 1, 0, 0},
 
 
  {(63), (-64), 1, IND (BRANCH, WORD)},
  {(63), (-64), 1, IND (BRANCH, WORD)},
  {(8192), (-8192), 2, IND (BRANCH, DOUBLE)},
  {(8192), (-8192), 2, IND (BRANCH, DOUBLE)},
  {0, 0, 4, 0},
  {0, 0, 4, 0},
  {1, 1, 0, 0}
  {1, 1, 0, 0}
};
};
 
 
/* Array used to test if mode contains displacements.
/* Array used to test if mode contains displacements.
   Value is true if mode contains displacement.  */
   Value is true if mode contains displacement.  */
 
 
char disp_test[] =
char disp_test[] =
{0, 0, 0, 0, 0, 0, 0, 0,
{0, 0, 0, 0, 0, 0, 0, 0,
 1, 1, 1, 1, 1, 1, 1, 1,
 1, 1, 1, 1, 1, 1, 1, 1,
 1, 1, 1, 0, 0, 1, 1, 0,
 1, 1, 1, 0, 0, 1, 1, 0,
 1, 1, 1, 1, 1, 1, 1, 1};
 1, 1, 1, 1, 1, 1, 1, 1};
 
 
/* Array used to calculate max size of displacements.  */
/* Array used to calculate max size of displacements.  */
 
 
char disp_size[] =
char disp_size[] =
{4, 1, 2, 0, 4};
{4, 1, 2, 0, 4};


/* Parse a general operand into an addressingmode struct
/* Parse a general operand into an addressingmode struct
 
 
   In:  pointer at operand in ascii form
   In:  pointer at operand in ascii form
        pointer at addr_mode struct for result
        pointer at addr_mode struct for result
        the level of recursion. (always 0 or 1)
        the level of recursion. (always 0 or 1)
 
 
   Out: data in addr_mode struct.  */
   Out: data in addr_mode struct.  */
 
 
static int
static int
addr_mode (char *operand,
addr_mode (char *operand,
           addr_modeS *addrmodeP,
           addr_modeS *addrmodeP,
           int recursive_level)
           int recursive_level)
{
{
  char *str;
  char *str;
  int i;
  int i;
  int strl;
  int strl;
  int mode;
  int mode;
  int j;
  int j;
 
 
  mode = DEFAULT;               /* Default.  */
  mode = DEFAULT;               /* Default.  */
  addrmodeP->scaled_mode = 0;    /* Why not.  */
  addrmodeP->scaled_mode = 0;    /* Why not.  */
  addrmodeP->scaled_reg = 0;     /* If 0, not scaled index.  */
  addrmodeP->scaled_reg = 0;     /* If 0, not scaled index.  */
  addrmodeP->float_flag = 0;
  addrmodeP->float_flag = 0;
  addrmodeP->am_size = 0;
  addrmodeP->am_size = 0;
  addrmodeP->im_disp = 0;
  addrmodeP->im_disp = 0;
  addrmodeP->pcrel = 0;  /* Not set in this function.  */
  addrmodeP->pcrel = 0;  /* Not set in this function.  */
  addrmodeP->disp_suffix[0] = 0;
  addrmodeP->disp_suffix[0] = 0;
  addrmodeP->disp_suffix[1] = 0;
  addrmodeP->disp_suffix[1] = 0;
  addrmodeP->disp[0] = NULL;
  addrmodeP->disp[0] = NULL;
  addrmodeP->disp[1] = NULL;
  addrmodeP->disp[1] = NULL;
  str = operand;
  str = operand;
 
 
  if (str[0] == 0)
  if (str[0] == 0)
    return 0;
    return 0;
 
 
  strl = strlen (str);
  strl = strlen (str);
 
 
  switch (str[0])
  switch (str[0])
    {
    {
      /* The following three case statements controls the mode-chars
      /* The following three case statements controls the mode-chars
         this is the place to ed if you want to change them.  */
         this is the place to ed if you want to change them.  */
#ifdef ABSOLUTE_PREFIX
#ifdef ABSOLUTE_PREFIX
    case ABSOLUTE_PREFIX:
    case ABSOLUTE_PREFIX:
      if (str[strl - 1] == ']')
      if (str[strl - 1] == ']')
        break;
        break;
      addrmodeP->mode = 21;     /* absolute */
      addrmodeP->mode = 21;     /* absolute */
      addrmodeP->disp[0] = str + 1;
      addrmodeP->disp[0] = str + 1;
      return -1;
      return -1;
#endif
#endif
#ifdef IMMEDIATE_PREFIX
#ifdef IMMEDIATE_PREFIX
    case IMMEDIATE_PREFIX:
    case IMMEDIATE_PREFIX:
      if (str[strl - 1] == ']')
      if (str[strl - 1] == ']')
        break;
        break;
      addrmodeP->mode = 20;     /* immediate */
      addrmodeP->mode = 20;     /* immediate */
      addrmodeP->disp[0] = str + 1;
      addrmodeP->disp[0] = str + 1;
      return -1;
      return -1;
#endif
#endif
    case '.':
    case '.':
      if (str[strl - 1] != ']')
      if (str[strl - 1] != ']')
        {
        {
          switch (str[1])
          switch (str[1])
            {
            {
            case '-':
            case '-':
            case '+':
            case '+':
              if (str[2] != '\000')
              if (str[2] != '\000')
                {
                {
                  addrmodeP->mode = 27; /* pc-relative */
                  addrmodeP->mode = 27; /* pc-relative */
                  addrmodeP->disp[0] = str + 2;
                  addrmodeP->disp[0] = str + 2;
                  return -1;
                  return -1;
                }
                }
            default:
            default:
              as_bad (_("Invalid syntax in PC-relative addressing mode"));
              as_bad (_("Invalid syntax in PC-relative addressing mode"));
              return 0;
              return 0;
            }
            }
        }
        }
      break;
      break;
    case 'e':
    case 'e':
      if (str[strl - 1] != ']')
      if (str[strl - 1] != ']')
        {
        {
          if ((!strncmp (str, "ext(", 4)) && strl > 7)
          if ((!strncmp (str, "ext(", 4)) && strl > 7)
            {                           /* external */
            {                           /* external */
              addrmodeP->disp[0] = str + 4;
              addrmodeP->disp[0] = str + 4;
              i = 0;
              i = 0;
              j = 2;
              j = 2;
              do
              do
                {                       /* disp[0]'s termination point.  */
                {                       /* disp[0]'s termination point.  */
                  j += 1;
                  j += 1;
                  if (str[j] == '(')
                  if (str[j] == '(')
                    i++;
                    i++;
                  if (str[j] == ')')
                  if (str[j] == ')')
                    i--;
                    i--;
                }
                }
              while (j < strl && i != 0);
              while (j < strl && i != 0);
              if (i != 0 || !(str[j + 1] == '-' || str[j + 1] == '+'))
              if (i != 0 || !(str[j + 1] == '-' || str[j + 1] == '+'))
                {
                {
                  as_bad (_("Invalid syntax in External addressing mode"));
                  as_bad (_("Invalid syntax in External addressing mode"));
                  return (0);
                  return (0);
                }
                }
              str[j] = '\000';          /* null terminate disp[0] */
              str[j] = '\000';          /* null terminate disp[0] */
              addrmodeP->disp[1] = str + j + 2;
              addrmodeP->disp[1] = str + j + 2;
              addrmodeP->mode = 22;
              addrmodeP->mode = 22;
              return -1;
              return -1;
            }
            }
        }
        }
      break;
      break;
 
 
    default:
    default:
      ;
      ;
    }
    }
 
 
  strl = strlen (str);
  strl = strlen (str);
 
 
  switch (strl)
  switch (strl)
    {
    {
    case 2:
    case 2:
      switch (str[0])
      switch (str[0])
        {
        {
        case 'f':
        case 'f':
          addrmodeP->float_flag = 1;
          addrmodeP->float_flag = 1;
          /* Drop through.  */
          /* Drop through.  */
        case 'r':
        case 'r':
          if (str[1] >= '0' && str[1] < '8')
          if (str[1] >= '0' && str[1] < '8')
            {
            {
              addrmodeP->mode = str[1] - '0';
              addrmodeP->mode = str[1] - '0';
              return -1;
              return -1;
            }
            }
          break;
          break;
        default:
        default:
          break;
          break;
        }
        }
      /* Drop through.  */
      /* Drop through.  */
 
 
    case 3:
    case 3:
      if (!strncmp (str, "tos", 3))
      if (!strncmp (str, "tos", 3))
        {
        {
          addrmodeP->mode = 23; /* TopOfStack */
          addrmodeP->mode = 23; /* TopOfStack */
          return -1;
          return -1;
        }
        }
      break;
      break;
 
 
    default:
    default:
      break;
      break;
    }
    }
 
 
  if (strl > 4)
  if (strl > 4)
    {
    {
      if (str[strl - 1] == ')')
      if (str[strl - 1] == ')')
        {
        {
          if (str[strl - 2] == ')')
          if (str[strl - 2] == ')')
            {
            {
              if (!strncmp (&str[strl - 5], "(fp", 3))
              if (!strncmp (&str[strl - 5], "(fp", 3))
                mode = 16;              /* Memory Relative.  */
                mode = 16;              /* Memory Relative.  */
              else if (!strncmp (&str[strl - 5], "(sp", 3))
              else if (!strncmp (&str[strl - 5], "(sp", 3))
                mode = 17;
                mode = 17;
              else if (!strncmp (&str[strl - 5], "(sb", 3))
              else if (!strncmp (&str[strl - 5], "(sb", 3))
                mode = 18;
                mode = 18;
 
 
              if (mode != DEFAULT)
              if (mode != DEFAULT)
                {
                {
                  /* Memory relative.  */
                  /* Memory relative.  */
                  addrmodeP->mode = mode;
                  addrmodeP->mode = mode;
                  j = strl - 5;         /* Temp for end of disp[0].  */
                  j = strl - 5;         /* Temp for end of disp[0].  */
                  i = 0;
                  i = 0;
 
 
                  do
                  do
                    {
                    {
                      strl -= 1;
                      strl -= 1;
                      if (str[strl] == ')')
                      if (str[strl] == ')')
                        i++;
                        i++;
                      if (str[strl] == '(')
                      if (str[strl] == '(')
                        i--;
                        i--;
                    }
                    }
                  while (strl > -1 && i != 0);
                  while (strl > -1 && i != 0);
 
 
                  if (i != 0)
                  if (i != 0)
                    {
                    {
                      as_bad (_("Invalid syntax in Memory Relative addressing mode"));
                      as_bad (_("Invalid syntax in Memory Relative addressing mode"));
                      return (0);
                      return (0);
                    }
                    }
 
 
                  addrmodeP->disp[1] = str;
                  addrmodeP->disp[1] = str;
                  addrmodeP->disp[0] = str + strl + 1;
                  addrmodeP->disp[0] = str + strl + 1;
                  str[j] = '\000';      /* Null terminate disp[0] .  */
                  str[j] = '\000';      /* Null terminate disp[0] .  */
                  str[strl] = '\000';   /* Null terminate disp[1].  */
                  str[strl] = '\000';   /* Null terminate disp[1].  */
 
 
                  return -1;
                  return -1;
                }
                }
            }
            }
 
 
          switch (str[strl - 3])
          switch (str[strl - 3])
            {
            {
            case 'r':
            case 'r':
            case 'R':
            case 'R':
              if (str[strl - 2] >= '0'
              if (str[strl - 2] >= '0'
                  && str[strl - 2] < '8'
                  && str[strl - 2] < '8'
                  && str[strl - 4] == '(')
                  && str[strl - 4] == '(')
                {
                {
                  addrmodeP->mode = str[strl - 2] - '0' + 8;
                  addrmodeP->mode = str[strl - 2] - '0' + 8;
                  addrmodeP->disp[0] = str;
                  addrmodeP->disp[0] = str;
                  str[strl - 4] = 0;
                  str[strl - 4] = 0;
                  return -1;            /* reg rel */
                  return -1;            /* reg rel */
                }
                }
              /* Drop through.  */
              /* Drop through.  */
 
 
            default:
            default:
              if (!strncmp (&str[strl - 4], "(fp", 3))
              if (!strncmp (&str[strl - 4], "(fp", 3))
                mode = 24;
                mode = 24;
              else if (!strncmp (&str[strl - 4], "(sp", 3))
              else if (!strncmp (&str[strl - 4], "(sp", 3))
                mode = 25;
                mode = 25;
              else if (!strncmp (&str[strl - 4], "(sb", 3))
              else if (!strncmp (&str[strl - 4], "(sb", 3))
                mode = 26;
                mode = 26;
              else if (!strncmp (&str[strl - 4], "(pc", 3))
              else if (!strncmp (&str[strl - 4], "(pc", 3))
                mode = 27;
                mode = 27;
 
 
              if (mode != DEFAULT)
              if (mode != DEFAULT)
                {
                {
                  addrmodeP->mode = mode;
                  addrmodeP->mode = mode;
                  addrmodeP->disp[0] = str;
                  addrmodeP->disp[0] = str;
                  str[strl - 4] = '\0';
                  str[strl - 4] = '\0';
 
 
                  return -1;            /* Memory space.  */
                  return -1;            /* Memory space.  */
                }
                }
            }
            }
        }
        }
 
 
      /* No trailing ')' do we have a ']' ?  */
      /* No trailing ')' do we have a ']' ?  */
      if (str[strl - 1] == ']')
      if (str[strl - 1] == ']')
        {
        {
          switch (str[strl - 2])
          switch (str[strl - 2])
            {
            {
            case 'b':
            case 'b':
              mode = 28;
              mode = 28;
              break;
              break;
            case 'w':
            case 'w':
              mode = 29;
              mode = 29;
              break;
              break;
            case 'd':
            case 'd':
              mode = 30;
              mode = 30;
              break;
              break;
            case 'q':
            case 'q':
              mode = 31;
              mode = 31;
              break;
              break;
            default:
            default:
              as_bad (_("Invalid scaled-indexed mode, use (b,w,d,q)"));
              as_bad (_("Invalid scaled-indexed mode, use (b,w,d,q)"));
 
 
              if (str[strl - 3] != ':' || str[strl - 6] != '['
              if (str[strl - 3] != ':' || str[strl - 6] != '['
                  || str[strl - 5] == 'r' || str[strl - 4] < '0'
                  || str[strl - 5] == 'r' || str[strl - 4] < '0'
                  || str[strl - 4] > '7')
                  || str[strl - 4] > '7')
                as_bad (_("Syntax in scaled-indexed mode, use [Rn:m] where n=[0..7] m={b,w,d,q}"));
                as_bad (_("Syntax in scaled-indexed mode, use [Rn:m] where n=[0..7] m={b,w,d,q}"));
            } /* Scaled index.  */
            } /* Scaled index.  */
 
 
          if (recursive_level > 0)
          if (recursive_level > 0)
            {
            {
              as_bad (_("Scaled-indexed addressing mode combined with scaled-index"));
              as_bad (_("Scaled-indexed addressing mode combined with scaled-index"));
              return 0;
              return 0;
            }
            }
 
 
          addrmodeP->am_size += 1;      /* scaled index byte.  */
          addrmodeP->am_size += 1;      /* scaled index byte.  */
          j = str[strl - 4] - '0';      /* store temporary.  */
          j = str[strl - 4] - '0';      /* store temporary.  */
          str[strl - 6] = '\000';       /* nullterminate for recursive call.  */
          str[strl - 6] = '\000';       /* nullterminate for recursive call.  */
          i = addr_mode (str, addrmodeP, 1);
          i = addr_mode (str, addrmodeP, 1);
 
 
          if (!i || addrmodeP->mode == 20)
          if (!i || addrmodeP->mode == 20)
            {
            {
              as_bad (_("Invalid or illegal addressing mode combined with scaled-index"));
              as_bad (_("Invalid or illegal addressing mode combined with scaled-index"));
              return 0;
              return 0;
            }
            }
 
 
          addrmodeP->scaled_mode = addrmodeP->mode;     /* Store the inferior mode.  */
          addrmodeP->scaled_mode = addrmodeP->mode;     /* Store the inferior mode.  */
          addrmodeP->mode = mode;
          addrmodeP->mode = mode;
          addrmodeP->scaled_reg = j + 1;
          addrmodeP->scaled_reg = j + 1;
 
 
          return -1;
          return -1;
        }
        }
    }
    }
 
 
  addrmodeP->mode = DEFAULT;    /* Default to whatever.  */
  addrmodeP->mode = DEFAULT;    /* Default to whatever.  */
  addrmodeP->disp[0] = str;
  addrmodeP->disp[0] = str;
 
 
  return -1;
  return -1;
}
}


static void
static void
evaluate_expr (expressionS *resultP, char *ptr)
evaluate_expr (expressionS *resultP, char *ptr)
{
{
  char *tmp_line;
  char *tmp_line;
 
 
  tmp_line = input_line_pointer;
  tmp_line = input_line_pointer;
  input_line_pointer = ptr;
  input_line_pointer = ptr;
  expression (resultP);
  expression (resultP);
  input_line_pointer = tmp_line;
  input_line_pointer = tmp_line;
}
}
 
 
/* ptr points at string addr_modeP points at struct with result This
/* ptr points at string addr_modeP points at struct with result This
   routine calls addr_mode to determine the general addr.mode of the
   routine calls addr_mode to determine the general addr.mode of the
   operand. When this is ready it parses the displacements for size
   operand. When this is ready it parses the displacements for size
   specifying suffixes and determines size of immediate mode via
   specifying suffixes and determines size of immediate mode via
   ns32k-opcode.  Also builds index bytes if needed.  */
   ns32k-opcode.  Also builds index bytes if needed.  */
 
 
static int
static int
get_addr_mode (char *ptr, addr_modeS *addrmodeP)
get_addr_mode (char *ptr, addr_modeS *addrmodeP)
{
{
  int tmp;
  int tmp;
 
 
  addr_mode (ptr, addrmodeP, 0);
  addr_mode (ptr, addrmodeP, 0);
 
 
  if (addrmodeP->mode == DEFAULT || addrmodeP->scaled_mode == -1)
  if (addrmodeP->mode == DEFAULT || addrmodeP->scaled_mode == -1)
    {
    {
      /* Resolve ambiguous operands, this shouldn't be necessary if
      /* Resolve ambiguous operands, this shouldn't be necessary if
         one uses standard NSC operand syntax. But the sequent
         one uses standard NSC operand syntax. But the sequent
         compiler doesn't!!!  This finds a proper addressing mode
         compiler doesn't!!!  This finds a proper addressing mode
         if it is implicitly stated. See ns32k-opcode.h.  */
         if it is implicitly stated. See ns32k-opcode.h.  */
      (void) evaluate_expr (&exprP, ptr); /* This call takes time Sigh!  */
      (void) evaluate_expr (&exprP, ptr); /* This call takes time Sigh!  */
 
 
      if (addrmodeP->mode == DEFAULT)
      if (addrmodeP->mode == DEFAULT)
        {
        {
          if (exprP.X_add_symbol || exprP.X_op_symbol)
          if (exprP.X_add_symbol || exprP.X_op_symbol)
            addrmodeP->mode = desc->default_model; /* We have a label.  */
            addrmodeP->mode = desc->default_model; /* We have a label.  */
          else
          else
            addrmodeP->mode = desc->default_modec; /* We have a constant.  */
            addrmodeP->mode = desc->default_modec; /* We have a constant.  */
        }
        }
      else
      else
        {
        {
          if (exprP.X_add_symbol || exprP.X_op_symbol)
          if (exprP.X_add_symbol || exprP.X_op_symbol)
            addrmodeP->scaled_mode = desc->default_model;
            addrmodeP->scaled_mode = desc->default_model;
          else
          else
            addrmodeP->scaled_mode = desc->default_modec;
            addrmodeP->scaled_mode = desc->default_modec;
        }
        }
 
 
      /* Must put this mess down in addr_mode to handle the scaled
      /* Must put this mess down in addr_mode to handle the scaled
         case better.  */
         case better.  */
    }
    }
 
 
  /* It appears as the sequent compiler wants an absolute when we have
  /* It appears as the sequent compiler wants an absolute when we have
     a label without @. Constants becomes immediates besides the addr
     a label without @. Constants becomes immediates besides the addr
     case.  Think it does so with local labels too, not optimum, pcrel
     case.  Think it does so with local labels too, not optimum, pcrel
     is better.  When I have time I will make gas check this and
     is better.  When I have time I will make gas check this and
     select pcrel when possible Actually that is trivial.  */
     select pcrel when possible Actually that is trivial.  */
  if ((tmp = addrmodeP->scaled_reg))
  if ((tmp = addrmodeP->scaled_reg))
    {                           /* Build indexbyte.  */
    {                           /* Build indexbyte.  */
      tmp--;                    /* Remember regnumber comes incremented for
      tmp--;                    /* Remember regnumber comes incremented for
                                   flagpurpose.  */
                                   flagpurpose.  */
      tmp |= addrmodeP->scaled_mode << 3;
      tmp |= addrmodeP->scaled_mode << 3;
      addrmodeP->index_byte = (char) tmp;
      addrmodeP->index_byte = (char) tmp;
      addrmodeP->am_size += 1;
      addrmodeP->am_size += 1;
    }
    }
 
 
  gas_assert (addrmodeP->mode >= 0);
  gas_assert (addrmodeP->mode >= 0);
  if (disp_test[(unsigned int) addrmodeP->mode])
  if (disp_test[(unsigned int) addrmodeP->mode])
    {
    {
      char c;
      char c;
      char suffix;
      char suffix;
      char suffix_sub;
      char suffix_sub;
      int i;
      int i;
      char *toP;
      char *toP;
      char *fromP;
      char *fromP;
 
 
      /* There was a displacement, probe for length  specifying suffix.  */
      /* There was a displacement, probe for length  specifying suffix.  */
      addrmodeP->pcrel = 0;
      addrmodeP->pcrel = 0;
 
 
      gas_assert (addrmodeP->mode >= 0);
      gas_assert (addrmodeP->mode >= 0);
      if (disp_test[(unsigned int) addrmodeP->mode])
      if (disp_test[(unsigned int) addrmodeP->mode])
        {
        {
          /* There is a displacement.  */
          /* There is a displacement.  */
          if (addrmodeP->mode == 27 || addrmodeP->scaled_mode == 27)
          if (addrmodeP->mode == 27 || addrmodeP->scaled_mode == 27)
            /* Do we have pcrel. mode.  */
            /* Do we have pcrel. mode.  */
            addrmodeP->pcrel = 1;
            addrmodeP->pcrel = 1;
 
 
          addrmodeP->im_disp = 1;
          addrmodeP->im_disp = 1;
 
 
          for (i = 0; i < 2; i++)
          for (i = 0; i < 2; i++)
            {
            {
              suffix_sub = suffix = 0;
              suffix_sub = suffix = 0;
 
 
              if ((toP = addrmodeP->disp[i]))
              if ((toP = addrmodeP->disp[i]))
                {
                {
                  /* Suffix of expression, the largest size rules.  */
                  /* Suffix of expression, the largest size rules.  */
                  fromP = toP;
                  fromP = toP;
 
 
                  while ((c = *fromP++))
                  while ((c = *fromP++))
                    {
                    {
                      *toP++ = c;
                      *toP++ = c;
                      if (c == ':')
                      if (c == ':')
                        {
                        {
                          switch (*fromP)
                          switch (*fromP)
                            {
                            {
                            case '\0':
                            case '\0':
                              as_warn (_("Premature end of suffix -- Defaulting to d"));
                              as_warn (_("Premature end of suffix -- Defaulting to d"));
                              suffix = 4;
                              suffix = 4;
                              continue;
                              continue;
                            case 'b':
                            case 'b':
                              suffix_sub = 1;
                              suffix_sub = 1;
                              break;
                              break;
                            case 'w':
                            case 'w':
                              suffix_sub = 2;
                              suffix_sub = 2;
                              break;
                              break;
                            case 'd':
                            case 'd':
                              suffix_sub = 4;
                              suffix_sub = 4;
                              break;
                              break;
                            default:
                            default:
                              as_warn (_("Bad suffix after ':' use {b|w|d} Defaulting to d"));
                              as_warn (_("Bad suffix after ':' use {b|w|d} Defaulting to d"));
                              suffix = 4;
                              suffix = 4;
                            }
                            }
 
 
                          fromP ++;
                          fromP ++;
                          toP --;       /* So we write over the ':' */
                          toP --;       /* So we write over the ':' */
 
 
                          if (suffix < suffix_sub)
                          if (suffix < suffix_sub)
                            suffix = suffix_sub;
                            suffix = suffix_sub;
                        }
                        }
                    }
                    }
 
 
                  *toP = '\0'; /* Terminate properly.  */
                  *toP = '\0'; /* Terminate properly.  */
                  addrmodeP->disp_suffix[i] = suffix;
                  addrmodeP->disp_suffix[i] = suffix;
                  addrmodeP->am_size += suffix ? suffix : 4;
                  addrmodeP->am_size += suffix ? suffix : 4;
                }
                }
            }
            }
        }
        }
    }
    }
  else
  else
    {
    {
      if (addrmodeP->mode == 20)
      if (addrmodeP->mode == 20)
        {
        {
          /* Look in ns32k_opcode for size.  */
          /* Look in ns32k_opcode for size.  */
          addrmodeP->disp_suffix[0] = addrmodeP->am_size = desc->im_size;
          addrmodeP->disp_suffix[0] = addrmodeP->am_size = desc->im_size;
          addrmodeP->im_disp = 0;
          addrmodeP->im_disp = 0;
        }
        }
    }
    }
 
 
  return addrmodeP->mode;
  return addrmodeP->mode;
}
}
 
 
/* Read an optionlist.  */
/* Read an optionlist.  */
 
 
static void
static void
optlist (char *str,                     /* The string to extract options from.  */
optlist (char *str,                     /* The string to extract options from.  */
         struct ns32k_option *optionP,  /* How to search the string.  */
         struct ns32k_option *optionP,  /* How to search the string.  */
         unsigned long *default_map)    /* Default pattern and output.  */
         unsigned long *default_map)    /* Default pattern and output.  */
{
{
  int i, j, k, strlen1, strlen2;
  int i, j, k, strlen1, strlen2;
  char *patternP, *strP;
  char *patternP, *strP;
 
 
  strlen1 = strlen (str);
  strlen1 = strlen (str);
 
 
  if (strlen1 < 1)
  if (strlen1 < 1)
    as_fatal (_("Very short instr to option, ie you can't do it on a NULLstr"));
    as_fatal (_("Very short instr to option, ie you can't do it on a NULLstr"));
 
 
  for (i = 0; optionP[i].pattern != 0; i++)
  for (i = 0; optionP[i].pattern != 0; i++)
    {
    {
      strlen2 = strlen (optionP[i].pattern);
      strlen2 = strlen (optionP[i].pattern);
 
 
      for (j = 0; j < strlen1; j++)
      for (j = 0; j < strlen1; j++)
        {
        {
          patternP = optionP[i].pattern;
          patternP = optionP[i].pattern;
          strP = &str[j];
          strP = &str[j];
 
 
          for (k = 0; k < strlen2; k++)
          for (k = 0; k < strlen2; k++)
            {
            {
              if (*(strP++) != *(patternP++))
              if (*(strP++) != *(patternP++))
                break;
                break;
            }
            }
 
 
          if (k == strlen2)
          if (k == strlen2)
            {                   /* match */
            {                   /* match */
              *default_map |= optionP[i].or;
              *default_map |= optionP[i].or;
              *default_map &= optionP[i].and;
              *default_map &= optionP[i].and;
            }
            }
        }
        }
    }
    }
}
}
 
 
/* Search struct for symbols.
/* Search struct for symbols.
   This function is used to get the short integer form of reg names in
   This function is used to get the short integer form of reg names in
   the instructions lmr, smr, lpr, spr return true if str is found in
   the instructions lmr, smr, lpr, spr return true if str is found in
   list.  */
   list.  */
 
 
static int
static int
list_search (char *str,                         /* The string to match.  */
list_search (char *str,                         /* The string to match.  */
             struct ns32k_option *optionP,      /* List to search.  */
             struct ns32k_option *optionP,      /* List to search.  */
             unsigned long *default_map)        /* Default pattern and output.  */
             unsigned long *default_map)        /* Default pattern and output.  */
{
{
  int i;
  int i;
 
 
  for (i = 0; optionP[i].pattern != 0; i++)
  for (i = 0; optionP[i].pattern != 0; i++)
    {
    {
      if (!strncmp (optionP[i].pattern, str, 20))
      if (!strncmp (optionP[i].pattern, str, 20))
        {
        {
          /* Use strncmp to be safe.  */
          /* Use strncmp to be safe.  */
          *default_map |= optionP[i].or;
          *default_map |= optionP[i].or;
          *default_map &= optionP[i].and;
          *default_map &= optionP[i].and;
 
 
          return -1;
          return -1;
        }
        }
    }
    }
 
 
  as_bad (_("No such entry in list. (cpu/mmu register)"));
  as_bad (_("No such entry in list. (cpu/mmu register)"));
  return 0;
  return 0;
}
}


/* Create a bit_fixS in obstack 'notes'.
/* Create a bit_fixS in obstack 'notes'.
   This struct is used to profile the normal fix. If the bit_fixP is a
   This struct is used to profile the normal fix. If the bit_fixP is a
   valid pointer (not NULL) the bit_fix data will be used to format
   valid pointer (not NULL) the bit_fix data will be used to format
   the fix.  */
   the fix.  */
 
 
static bit_fixS *
static bit_fixS *
bit_fix_new (int size,          /* Length of bitfield.  */
bit_fix_new (int size,          /* Length of bitfield.  */
             int offset,        /* Bit offset to bitfield.  */
             int offset,        /* Bit offset to bitfield.  */
             long min,          /* Signextended min for bitfield.  */
             long min,          /* Signextended min for bitfield.  */
             long max,          /* Signextended max for bitfield.  */
             long max,          /* Signextended max for bitfield.  */
             long add,          /* Add mask, used for huffman prefix.  */
             long add,          /* Add mask, used for huffman prefix.  */
             long base_type,    /* 0 or 1, if 1 it's exploded to opcode ptr.  */
             long base_type,    /* 0 or 1, if 1 it's exploded to opcode ptr.  */
             long base_adj)
             long base_adj)
{
{
  bit_fixS *bit_fixP;
  bit_fixS *bit_fixP;
 
 
  bit_fixP = obstack_alloc (&notes, sizeof (bit_fixS));
  bit_fixP = obstack_alloc (&notes, sizeof (bit_fixS));
 
 
  bit_fixP->fx_bit_size = size;
  bit_fixP->fx_bit_size = size;
  bit_fixP->fx_bit_offset = offset;
  bit_fixP->fx_bit_offset = offset;
  bit_fixP->fx_bit_base = base_type;
  bit_fixP->fx_bit_base = base_type;
  bit_fixP->fx_bit_base_adj = base_adj;
  bit_fixP->fx_bit_base_adj = base_adj;
  bit_fixP->fx_bit_max = max;
  bit_fixP->fx_bit_max = max;
  bit_fixP->fx_bit_min = min;
  bit_fixP->fx_bit_min = min;
  bit_fixP->fx_bit_add = add;
  bit_fixP->fx_bit_add = add;
 
 
  return bit_fixP;
  return bit_fixP;
}
}
 
 
/* Convert operands to iif-format and adds bitfields to the opcode.
/* Convert operands to iif-format and adds bitfields to the opcode.
   Operands are parsed in such an order that the opcode is updated from
   Operands are parsed in such an order that the opcode is updated from
   its most significant bit, that is when the operand need to alter the
   its most significant bit, that is when the operand need to alter the
   opcode.
   opcode.
   Be careful not to put to objects in the same iif-slot.  */
   Be careful not to put to objects in the same iif-slot.  */
 
 
static void
static void
encode_operand (int argc,
encode_operand (int argc,
                char **argv,
                char **argv,
                const char *operandsP,
                const char *operandsP,
                const char *suffixP,
                const char *suffixP,
                char im_size ATTRIBUTE_UNUSED,
                char im_size ATTRIBUTE_UNUSED,
                char opcode_bit_ptr)
                char opcode_bit_ptr)
{
{
  int i, j;
  int i, j;
  char d;
  char d;
  int pcrel, b, loop, pcrel_adjust;
  int pcrel, b, loop, pcrel_adjust;
  unsigned long tmp;
  unsigned long tmp;
 
 
  for (loop = 0; loop < argc; loop++)
  for (loop = 0; loop < argc; loop++)
    {
    {
      /* What operand are we supposed to work on.  */
      /* What operand are we supposed to work on.  */
      i = operandsP[loop << 1] - '1';
      i = operandsP[loop << 1] - '1';
      if (i > 3)
      if (i > 3)
        as_fatal (_("Internal consistency error.  check ns32k-opcode.h"));
        as_fatal (_("Internal consistency error.  check ns32k-opcode.h"));
 
 
      pcrel = 0;
      pcrel = 0;
      pcrel_adjust = 0;
      pcrel_adjust = 0;
      tmp = 0;
      tmp = 0;
 
 
      switch ((d = operandsP[(loop << 1) + 1]))
      switch ((d = operandsP[(loop << 1) + 1]))
        {
        {
        case 'f':               /* Operand of sfsr turns out to be a nasty
        case 'f':               /* Operand of sfsr turns out to be a nasty
                                   specialcase.  */
                                   specialcase.  */
          opcode_bit_ptr -= 5;
          opcode_bit_ptr -= 5;
        case 'Z':               /* Float not immediate.  */
        case 'Z':               /* Float not immediate.  */
        case 'F':               /* 32 bit float general form.  */
        case 'F':               /* 32 bit float general form.  */
        case 'L':               /* 64 bit float.  */
        case 'L':               /* 64 bit float.  */
        case 'I':               /* Integer not immediate.  */
        case 'I':               /* Integer not immediate.  */
        case 'B':               /* Byte  */
        case 'B':               /* Byte  */
        case 'W':               /* Word  */
        case 'W':               /* Word  */
        case 'D':               /* Double-word.  */
        case 'D':               /* Double-word.  */
        case 'A':               /* Double-word  gen-address-form ie no regs
        case 'A':               /* Double-word  gen-address-form ie no regs
                                   allowed.  */
                                   allowed.  */
          get_addr_mode (argv[i], &addr_modeP);
          get_addr_mode (argv[i], &addr_modeP);
 
 
          if ((addr_modeP.mode == 20) &&
          if ((addr_modeP.mode == 20) &&
             (d == 'I' || d == 'Z' || d == 'A'))
             (d == 'I' || d == 'Z' || d == 'A'))
            as_fatal (d == 'A'? _("Address of immediate operand"):
            as_fatal (d == 'A'? _("Address of immediate operand"):
                        _("Invalid immediate write operand."));
                        _("Invalid immediate write operand."));
 
 
          if (opcode_bit_ptr == desc->opcode_size)
          if (opcode_bit_ptr == desc->opcode_size)
            b = 4;
            b = 4;
          else
          else
            b = 6;
            b = 6;
 
 
          for (j = b; j < (b + 2); j++)
          for (j = b; j < (b + 2); j++)
            {
            {
              if (addr_modeP.disp[j - b])
              if (addr_modeP.disp[j - b])
                {
                {
                  IIF (j,
                  IIF (j,
                       2,
                       2,
                       addr_modeP.disp_suffix[j - b],
                       addr_modeP.disp_suffix[j - b],
                       (unsigned long) addr_modeP.disp[j - b],
                       (unsigned long) addr_modeP.disp[j - b],
                       0,
                       0,
                       addr_modeP.pcrel,
                       addr_modeP.pcrel,
                       iif.instr_size,
                       iif.instr_size,
                       addr_modeP.im_disp,
                       addr_modeP.im_disp,
                       IND (BRANCH, BYTE),
                       IND (BRANCH, BYTE),
                       NULL,
                       NULL,
                       (addr_modeP.scaled_reg ? addr_modeP.scaled_mode
                       (addr_modeP.scaled_reg ? addr_modeP.scaled_mode
                        : addr_modeP.mode),
                        : addr_modeP.mode),
                       0);
                       0);
                }
                }
            }
            }
 
 
          opcode_bit_ptr -= 5;
          opcode_bit_ptr -= 5;
          iif.iifP[1].object |= ((long) addr_modeP.mode) << opcode_bit_ptr;
          iif.iifP[1].object |= ((long) addr_modeP.mode) << opcode_bit_ptr;
 
 
          if (addr_modeP.scaled_reg)
          if (addr_modeP.scaled_reg)
            {
            {
              j = b / 2;
              j = b / 2;
              IIF (j, 1, 1, (unsigned long) addr_modeP.index_byte,
              IIF (j, 1, 1, (unsigned long) addr_modeP.index_byte,
                   0, 0, 0, 0, 0, NULL, -1, 0);
                   0, 0, 0, 0, 0, NULL, -1, 0);
            }
            }
          break;
          break;
 
 
        case 'b':               /* Multiple instruction disp.  */
        case 'b':               /* Multiple instruction disp.  */
          freeptr++;            /* OVE:this is an useful hack.  */
          freeptr++;            /* OVE:this is an useful hack.  */
          sprintf (freeptr, "((%s-1)*%d)", argv[i], desc->im_size);
          sprintf (freeptr, "((%s-1)*%d)", argv[i], desc->im_size);
          argv[i] = freeptr;
          argv[i] = freeptr;
          pcrel -= 1;           /* Make pcrel 0 in spite of what case 'p':
          pcrel -= 1;           /* Make pcrel 0 in spite of what case 'p':
                                   wants.  */
                                   wants.  */
          /* fall thru */
          /* fall thru */
        case 'p':               /* Displacement - pc relative addressing.  */
        case 'p':               /* Displacement - pc relative addressing.  */
          pcrel += 1;
          pcrel += 1;
          /* fall thru */
          /* fall thru */
        case 'd':               /* Displacement.  */
        case 'd':               /* Displacement.  */
          iif.instr_size += suffixP[i] ? suffixP[i] : 4;
          iif.instr_size += suffixP[i] ? suffixP[i] : 4;
          IIF (12, 2, suffixP[i], (unsigned long) argv[i], 0,
          IIF (12, 2, suffixP[i], (unsigned long) argv[i], 0,
               pcrel, pcrel_adjust, 1, IND (BRANCH, BYTE), NULL, -1, 0);
               pcrel, pcrel_adjust, 1, IND (BRANCH, BYTE), NULL, -1, 0);
          break;
          break;
        case 'H':               /* Sequent-hack: the linker wants a bit set
        case 'H':               /* Sequent-hack: the linker wants a bit set
                                   when bsr.  */
                                   when bsr.  */
          pcrel = 1;
          pcrel = 1;
          iif.instr_size += suffixP[i] ? suffixP[i] : 4;
          iif.instr_size += suffixP[i] ? suffixP[i] : 4;
          IIF (12, 2, suffixP[i], (unsigned long) argv[i], 0,
          IIF (12, 2, suffixP[i], (unsigned long) argv[i], 0,
               pcrel, pcrel_adjust, 1, IND (BRANCH, BYTE), NULL, -1, 1);
               pcrel, pcrel_adjust, 1, IND (BRANCH, BYTE), NULL, -1, 1);
          break;
          break;
        case 'q':               /* quick */
        case 'q':               /* quick */
          opcode_bit_ptr -= 4;
          opcode_bit_ptr -= 4;
          IIF (11, 2, 42, (unsigned long) argv[i], 0, 0, 0, 0, 0,
          IIF (11, 2, 42, (unsigned long) argv[i], 0, 0, 0, 0, 0,
               bit_fix_new (4, opcode_bit_ptr, -8, 7, 0, 1, 0), -1, 0);
               bit_fix_new (4, opcode_bit_ptr, -8, 7, 0, 1, 0), -1, 0);
          break;
          break;
        case 'r':               /* Register number (3 bits).  */
        case 'r':               /* Register number (3 bits).  */
          list_search (argv[i], opt6, &tmp);
          list_search (argv[i], opt6, &tmp);
          opcode_bit_ptr -= 3;
          opcode_bit_ptr -= 3;
          iif.iifP[1].object |= tmp << opcode_bit_ptr;
          iif.iifP[1].object |= tmp << opcode_bit_ptr;
          break;
          break;
        case 'O':               /* Setcfg instruction optionslist.  */
        case 'O':               /* Setcfg instruction optionslist.  */
          optlist (argv[i], opt3, &tmp);
          optlist (argv[i], opt3, &tmp);
          opcode_bit_ptr -= 4;
          opcode_bit_ptr -= 4;
          iif.iifP[1].object |= tmp << 15;
          iif.iifP[1].object |= tmp << 15;
          break;
          break;
        case 'C':               /* Cinv instruction optionslist.  */
        case 'C':               /* Cinv instruction optionslist.  */
          optlist (argv[i], opt4, &tmp);
          optlist (argv[i], opt4, &tmp);
          opcode_bit_ptr -= 4;
          opcode_bit_ptr -= 4;
          iif.iifP[1].object |= tmp << 15; /* Insert the regtype in opcode.  */
          iif.iifP[1].object |= tmp << 15; /* Insert the regtype in opcode.  */
          break;
          break;
        case 'S':               /* String instruction options list.  */
        case 'S':               /* String instruction options list.  */
          optlist (argv[i], opt5, &tmp);
          optlist (argv[i], opt5, &tmp);
          opcode_bit_ptr -= 4;
          opcode_bit_ptr -= 4;
          iif.iifP[1].object |= tmp << 15;
          iif.iifP[1].object |= tmp << 15;
          break;
          break;
        case 'u':
        case 'u':
        case 'U':               /* Register list.  */
        case 'U':               /* Register list.  */
          IIF (10, 1, 1, 0, 0, 0, 0, 0, 0, NULL, -1, 0);
          IIF (10, 1, 1, 0, 0, 0, 0, 0, 0, NULL, -1, 0);
          switch (operandsP[(i << 1) + 1])
          switch (operandsP[(i << 1) + 1])
            {
            {
            case 'u':           /* Restore, exit.  */
            case 'u':           /* Restore, exit.  */
              optlist (argv[i], opt1, &iif.iifP[10].object);
              optlist (argv[i], opt1, &iif.iifP[10].object);
              break;
              break;
            case 'U':           /* Save, enter.  */
            case 'U':           /* Save, enter.  */
              optlist (argv[i], opt2, &iif.iifP[10].object);
              optlist (argv[i], opt2, &iif.iifP[10].object);
              break;
              break;
            }
            }
          iif.instr_size += 1;
          iif.instr_size += 1;
          break;
          break;
        case 'M':               /* MMU register.  */
        case 'M':               /* MMU register.  */
          list_search (argv[i], mmureg, &tmp);
          list_search (argv[i], mmureg, &tmp);
          opcode_bit_ptr -= 4;
          opcode_bit_ptr -= 4;
          iif.iifP[1].object |= tmp << opcode_bit_ptr;
          iif.iifP[1].object |= tmp << opcode_bit_ptr;
          break;
          break;
        case 'P':               /* CPU register.  */
        case 'P':               /* CPU register.  */
          list_search (argv[i], cpureg, &tmp);
          list_search (argv[i], cpureg, &tmp);
          opcode_bit_ptr -= 4;
          opcode_bit_ptr -= 4;
          iif.iifP[1].object |= tmp << opcode_bit_ptr;
          iif.iifP[1].object |= tmp << opcode_bit_ptr;
          break;
          break;
        case 'g':               /* Inss exts.  */
        case 'g':               /* Inss exts.  */
          iif.instr_size += 1;  /* 1 byte is allocated after the opcode.  */
          iif.instr_size += 1;  /* 1 byte is allocated after the opcode.  */
          IIF (10, 2, 1,
          IIF (10, 2, 1,
               (unsigned long) argv[i], /* i always 2 here.  */
               (unsigned long) argv[i], /* i always 2 here.  */
               0, 0, 0, 0, 0,
               0, 0, 0, 0, 0,
               bit_fix_new (3, 5, 0, 7, 0, 0, 0), /* A bit_fix is targeted to
               bit_fix_new (3, 5, 0, 7, 0, 0, 0), /* A bit_fix is targeted to
                                                     the byte.  */
                                                     the byte.  */
               -1, 0);
               -1, 0);
          break;
          break;
        case 'G':
        case 'G':
          IIF (11, 2, 42,
          IIF (11, 2, 42,
               (unsigned long) argv[i], /* i always 3 here.  */
               (unsigned long) argv[i], /* i always 3 here.  */
               0, 0, 0, 0, 0,
               0, 0, 0, 0, 0,
               bit_fix_new (5, 0, 1, 32, -1, 0, -1), -1, 0);
               bit_fix_new (5, 0, 1, 32, -1, 0, -1), -1, 0);
          break;
          break;
        case 'i':
        case 'i':
          iif.instr_size += 1;
          iif.instr_size += 1;
          b = 2 + i;            /* Put the extension byte after opcode.  */
          b = 2 + i;            /* Put the extension byte after opcode.  */
          IIF (b, 2, 1, 0, 0, 0, 0, 0, 0, 0, -1, 0);
          IIF (b, 2, 1, 0, 0, 0, 0, 0, 0, 0, -1, 0);
          break;
          break;
        default:
        default:
          as_fatal (_("Bad opcode-table-option, check in file ns32k-opcode.h"));
          as_fatal (_("Bad opcode-table-option, check in file ns32k-opcode.h"));
        }
        }
    }
    }
}
}


/* in:  instruction line
/* in:  instruction line
   out: internal structure of instruction
   out: internal structure of instruction
   that has been prepared for direct conversion to fragment(s) and
   that has been prepared for direct conversion to fragment(s) and
   fixes in a systematical fashion
   fixes in a systematical fashion
   Return-value = recursive_level.  */
   Return-value = recursive_level.  */
/* Build iif of one assembly text line.  */
/* Build iif of one assembly text line.  */
 
 
static int
static int
parse (const char *line, int recursive_level)
parse (const char *line, int recursive_level)
{
{
  const char *lineptr;
  const char *lineptr;
  char c, suffix_separator;
  char c, suffix_separator;
  int i;
  int i;
  unsigned int argc;
  unsigned int argc;
  int arg_type;
  int arg_type;
  char sqr, sep;
  char sqr, sep;
  char suffix[MAX_ARGS], *argv[MAX_ARGS];       /* No more than 4 operands.  */
  char suffix[MAX_ARGS], *argv[MAX_ARGS];       /* No more than 4 operands.  */
 
 
  if (recursive_level <= 0)
  if (recursive_level <= 0)
    {
    {
      /* Called from md_assemble.  */
      /* Called from md_assemble.  */
      for (lineptr = line; (*lineptr) != '\0' && (*lineptr) != ' '; lineptr++)
      for (lineptr = line; (*lineptr) != '\0' && (*lineptr) != ' '; lineptr++)
        continue;
        continue;
 
 
      c = *lineptr;
      c = *lineptr;
      *(char *) lineptr = '\0';
      *(char *) lineptr = '\0';
 
 
      if (!(desc = (struct ns32k_opcode *) hash_find (inst_hash_handle, line)))
      if (!(desc = (struct ns32k_opcode *) hash_find (inst_hash_handle, line)))
        as_fatal (_("No such opcode"));
        as_fatal (_("No such opcode"));
 
 
      *(char *) lineptr = c;
      *(char *) lineptr = c;
    }
    }
  else
  else
    lineptr = line;
    lineptr = line;
 
 
  argc = 0;
  argc = 0;
 
 
  if (*desc->operands)
  if (*desc->operands)
    {
    {
      if (*lineptr++ != '\0')
      if (*lineptr++ != '\0')
        {
        {
          sqr = '[';
          sqr = '[';
          sep = ',';
          sep = ',';
 
 
          while (*lineptr != '\0')
          while (*lineptr != '\0')
            {
            {
              if (desc->operands[argc << 1])
              if (desc->operands[argc << 1])
                {
                {
                  suffix[argc] = 0;
                  suffix[argc] = 0;
                  arg_type = desc->operands[(argc << 1) + 1];
                  arg_type = desc->operands[(argc << 1) + 1];
 
 
                  switch (arg_type)
                  switch (arg_type)
                    {
                    {
                    case 'd':
                    case 'd':
                    case 'b':
                    case 'b':
                    case 'p':
                    case 'p':
                    case 'H':
                    case 'H':
                      /* The operand is supposed to be a displacement.  */
                      /* The operand is supposed to be a displacement.  */
                      /* Hackwarning: do not forget to update the 4
                      /* Hackwarning: do not forget to update the 4
                         cases above when editing ns32k-opcode.h.  */
                         cases above when editing ns32k-opcode.h.  */
                      suffix_separator = ':';
                      suffix_separator = ':';
                      break;
                      break;
                    default:
                    default:
                      /* If this char occurs we loose.  */
                      /* If this char occurs we loose.  */
                      suffix_separator = '\255';
                      suffix_separator = '\255';
                      break;
                      break;
                    }
                    }
 
 
                  suffix[argc] = 0; /* 0 when no ':' is encountered.  */
                  suffix[argc] = 0; /* 0 when no ':' is encountered.  */
                  argv[argc] = freeptr;
                  argv[argc] = freeptr;
                  *freeptr = '\0';
                  *freeptr = '\0';
 
 
                  while ((c = *lineptr) != '\0' && c != sep)
                  while ((c = *lineptr) != '\0' && c != sep)
                    {
                    {
                      if (c == sqr)
                      if (c == sqr)
                        {
                        {
                          if (sqr == '[')
                          if (sqr == '[')
                            {
                            {
                              sqr = ']';
                              sqr = ']';
                              sep = '\0';
                              sep = '\0';
                            }
                            }
                          else
                          else
                            {
                            {
                              sqr = '[';
                              sqr = '[';
                              sep = ',';
                              sep = ',';
                            }
                            }
                        }
                        }
 
 
                      if (c == suffix_separator)
                      if (c == suffix_separator)
                        {
                        {
                          /* ':' - label/suffix separator.  */
                          /* ':' - label/suffix separator.  */
                          switch (lineptr[1])
                          switch (lineptr[1])
                            {
                            {
                            case 'b':
                            case 'b':
                              suffix[argc] = 1;
                              suffix[argc] = 1;
                              break;
                              break;
                            case 'w':
                            case 'w':
                              suffix[argc] = 2;
                              suffix[argc] = 2;
                              break;
                              break;
                            case 'd':
                            case 'd':
                              suffix[argc] = 4;
                              suffix[argc] = 4;
                              break;
                              break;
                            default:
                            default:
                              as_warn (_("Bad suffix, defaulting to d"));
                              as_warn (_("Bad suffix, defaulting to d"));
                              suffix[argc] = 4;
                              suffix[argc] = 4;
                              if (lineptr[1] == '\0' || lineptr[1] == sep)
                              if (lineptr[1] == '\0' || lineptr[1] == sep)
                                {
                                {
                                  lineptr += 1;
                                  lineptr += 1;
                                  continue;
                                  continue;
                                }
                                }
                              break;
                              break;
                            }
                            }
 
 
                          lineptr += 2;
                          lineptr += 2;
                          continue;
                          continue;
                        }
                        }
 
 
                      *freeptr++ = c;
                      *freeptr++ = c;
                      lineptr++;
                      lineptr++;
                    }
                    }
 
 
                  *freeptr++ = '\0';
                  *freeptr++ = '\0';
                  argc += 1;
                  argc += 1;
 
 
                  if (*lineptr == '\0')
                  if (*lineptr == '\0')
                    continue;
                    continue;
 
 
                  lineptr += 1;
                  lineptr += 1;
                }
                }
              else
              else
                as_fatal (_("Too many operands passed to instruction"));
                as_fatal (_("Too many operands passed to instruction"));
            }
            }
        }
        }
    }
    }
 
 
  if (argc != strlen (desc->operands) / 2)
  if (argc != strlen (desc->operands) / 2)
    {
    {
      if (strlen (desc->default_args))
      if (strlen (desc->default_args))
        {
        {
          /* We can apply default, don't goof.  */
          /* We can apply default, don't goof.  */
          if (parse (desc->default_args, 1) != 1)
          if (parse (desc->default_args, 1) != 1)
            /* Check error in default.  */
            /* Check error in default.  */
            as_fatal (_("Wrong numbers of operands in default, check ns32k-opcodes.h"));
            as_fatal (_("Wrong numbers of operands in default, check ns32k-opcodes.h"));
        }
        }
      else
      else
        as_fatal (_("Wrong number of operands"));
        as_fatal (_("Wrong number of operands"));
    }
    }
 
 
  for (i = 0; i < IIF_ENTRIES; i++)
  for (i = 0; i < IIF_ENTRIES; i++)
    /* Mark all entries as void.  */
    /* Mark all entries as void.  */
    iif.iifP[i].type = 0;
    iif.iifP[i].type = 0;
 
 
  /* Build opcode iif-entry.  */
  /* Build opcode iif-entry.  */
  iif.instr_size = desc->opcode_size / 8;
  iif.instr_size = desc->opcode_size / 8;
  IIF (1, 1, iif.instr_size, desc->opcode_seed, 0, 0, 0, 0, 0, 0, -1, 0);
  IIF (1, 1, iif.instr_size, desc->opcode_seed, 0, 0, 0, 0, 0, 0, -1, 0);
 
 
  /* This call encodes operands to iif format.  */
  /* This call encodes operands to iif format.  */
  if (argc)
  if (argc)
    encode_operand (argc, argv, &desc->operands[0],
    encode_operand (argc, argv, &desc->operands[0],
                    &suffix[0], desc->im_size, desc->opcode_size);
                    &suffix[0], desc->im_size, desc->opcode_size);
 
 
  return recursive_level;
  return recursive_level;
}
}


/* This functionality should really be in the bfd library.  */
/* This functionality should really be in the bfd library.  */
 
 
static bfd_reloc_code_real_type
static bfd_reloc_code_real_type
reloc (int size, int pcrel, int type)
reloc (int size, int pcrel, int type)
{
{
  int length, rel_index;
  int length, rel_index;
  bfd_reloc_code_real_type relocs[] =
  bfd_reloc_code_real_type relocs[] =
  {
  {
    BFD_RELOC_NS32K_IMM_8,
    BFD_RELOC_NS32K_IMM_8,
    BFD_RELOC_NS32K_IMM_16,
    BFD_RELOC_NS32K_IMM_16,
    BFD_RELOC_NS32K_IMM_32,
    BFD_RELOC_NS32K_IMM_32,
    BFD_RELOC_NS32K_IMM_8_PCREL,
    BFD_RELOC_NS32K_IMM_8_PCREL,
    BFD_RELOC_NS32K_IMM_16_PCREL,
    BFD_RELOC_NS32K_IMM_16_PCREL,
    BFD_RELOC_NS32K_IMM_32_PCREL,
    BFD_RELOC_NS32K_IMM_32_PCREL,
 
 
    /* ns32k displacements.  */
    /* ns32k displacements.  */
    BFD_RELOC_NS32K_DISP_8,
    BFD_RELOC_NS32K_DISP_8,
    BFD_RELOC_NS32K_DISP_16,
    BFD_RELOC_NS32K_DISP_16,
    BFD_RELOC_NS32K_DISP_32,
    BFD_RELOC_NS32K_DISP_32,
    BFD_RELOC_NS32K_DISP_8_PCREL,
    BFD_RELOC_NS32K_DISP_8_PCREL,
    BFD_RELOC_NS32K_DISP_16_PCREL,
    BFD_RELOC_NS32K_DISP_16_PCREL,
    BFD_RELOC_NS32K_DISP_32_PCREL,
    BFD_RELOC_NS32K_DISP_32_PCREL,
 
 
    /* Normal 2's complement.  */
    /* Normal 2's complement.  */
    BFD_RELOC_8,
    BFD_RELOC_8,
    BFD_RELOC_16,
    BFD_RELOC_16,
    BFD_RELOC_32,
    BFD_RELOC_32,
    BFD_RELOC_8_PCREL,
    BFD_RELOC_8_PCREL,
    BFD_RELOC_16_PCREL,
    BFD_RELOC_16_PCREL,
    BFD_RELOC_32_PCREL
    BFD_RELOC_32_PCREL
  };
  };
 
 
  switch (size)
  switch (size)
    {
    {
    case 1:
    case 1:
      length = 0;
      length = 0;
      break;
      break;
    case 2:
    case 2:
      length = 1;
      length = 1;
      break;
      break;
    case 4:
    case 4:
      length = 2;
      length = 2;
      break;
      break;
    default:
    default:
      length = -1;
      length = -1;
      break;
      break;
    }
    }
 
 
  rel_index = length + 3 * pcrel + 6 * type;
  rel_index = length + 3 * pcrel + 6 * type;
 
 
  if (rel_index >= 0 && (unsigned int) rel_index < sizeof (relocs) / sizeof (relocs[0]))
  if (rel_index >= 0 && (unsigned int) rel_index < sizeof (relocs) / sizeof (relocs[0]))
    return relocs[rel_index];
    return relocs[rel_index];
 
 
  if (pcrel)
  if (pcrel)
    as_bad (_("Can not do %d byte pc-relative relocation for storage type %d"),
    as_bad (_("Can not do %d byte pc-relative relocation for storage type %d"),
            size, type);
            size, type);
  else
  else
    as_bad (_("Can not do %d byte relocation for storage type %d"),
    as_bad (_("Can not do %d byte relocation for storage type %d"),
            size, type);
            size, type);
 
 
  return BFD_RELOC_NONE;
  return BFD_RELOC_NONE;
 
 
}
}
 
 
static void
static void
fix_new_ns32k (fragS *frag,             /* Which frag? */
fix_new_ns32k (fragS *frag,             /* Which frag? */
               int where,               /* Where in that frag? */
               int where,               /* Where in that frag? */
               int size,                /* 1, 2  or 4 usually.  */
               int size,                /* 1, 2  or 4 usually.  */
               symbolS *add_symbol,     /* X_add_symbol.  */
               symbolS *add_symbol,     /* X_add_symbol.  */
               long offset,             /* X_add_number.  */
               long offset,             /* X_add_number.  */
               int pcrel,               /* True if PC-relative relocation.  */
               int pcrel,               /* True if PC-relative relocation.  */
               char im_disp,            /* True if the value to write is a
               char im_disp,            /* True if the value to write is a
                                           displacement.  */
                                           displacement.  */
               bit_fixS *bit_fixP,      /* Pointer at struct of bit_fix's, ignored if
               bit_fixS *bit_fixP,      /* Pointer at struct of bit_fix's, ignored if
                                           NULL.  */
                                           NULL.  */
               char bsr,                /* Sequent-linker-hack: 1 when relocobject is
               char bsr,                /* Sequent-linker-hack: 1 when relocobject is
                                           a bsr.  */
                                           a bsr.  */
               fragS *opcode_frag,
               fragS *opcode_frag,
               unsigned int opcode_offset)
               unsigned int opcode_offset)
{
{
  fixS *fixP = fix_new (frag, where, size, add_symbol,
  fixS *fixP = fix_new (frag, where, size, add_symbol,
                        offset, pcrel,
                        offset, pcrel,
                        bit_fixP ? NO_RELOC : reloc (size, pcrel, im_disp)
                        bit_fixP ? NO_RELOC : reloc (size, pcrel, im_disp)
                        );
                        );
 
 
  fix_opcode_frag (fixP) = opcode_frag;
  fix_opcode_frag (fixP) = opcode_frag;
  fix_opcode_offset (fixP) = opcode_offset;
  fix_opcode_offset (fixP) = opcode_offset;
  fix_im_disp (fixP) = im_disp;
  fix_im_disp (fixP) = im_disp;
  fix_bsr (fixP) = bsr;
  fix_bsr (fixP) = bsr;
  fix_bit_fixP (fixP) = bit_fixP;
  fix_bit_fixP (fixP) = bit_fixP;
  /* We have a MD overflow check for displacements.  */
  /* We have a MD overflow check for displacements.  */
  fixP->fx_no_overflow = (im_disp != 0);
  fixP->fx_no_overflow = (im_disp != 0);
}
}
 
 
static void
static void
fix_new_ns32k_exp (fragS *frag,         /* Which frag? */
fix_new_ns32k_exp (fragS *frag,         /* Which frag? */
                   int where,           /* Where in that frag? */
                   int where,           /* Where in that frag? */
                   int size,            /* 1, 2  or 4 usually.  */
                   int size,            /* 1, 2  or 4 usually.  */
                   expressionS *exp,    /* Expression.  */
                   expressionS *exp,    /* Expression.  */
                   int pcrel,           /* True if PC-relative relocation.  */
                   int pcrel,           /* True if PC-relative relocation.  */
                   char im_disp,        /* True if the value to write is a
                   char im_disp,        /* True if the value to write is a
                                           displacement.  */
                                           displacement.  */
                   bit_fixS *bit_fixP,  /* Pointer at struct of bit_fix's, ignored if
                   bit_fixS *bit_fixP,  /* Pointer at struct of bit_fix's, ignored if
                                           NULL.  */
                                           NULL.  */
                   char bsr,            /* Sequent-linker-hack: 1 when relocobject is
                   char bsr,            /* Sequent-linker-hack: 1 when relocobject is
                                           a bsr.  */
                                           a bsr.  */
                   fragS *opcode_frag,
                   fragS *opcode_frag,
                   unsigned int opcode_offset)
                   unsigned int opcode_offset)
{
{
  fixS *fixP = fix_new_exp (frag, where, size, exp, pcrel,
  fixS *fixP = fix_new_exp (frag, where, size, exp, pcrel,
                            bit_fixP ? NO_RELOC : reloc (size, pcrel, im_disp)
                            bit_fixP ? NO_RELOC : reloc (size, pcrel, im_disp)
                            );
                            );
 
 
  fix_opcode_frag (fixP) = opcode_frag;
  fix_opcode_frag (fixP) = opcode_frag;
  fix_opcode_offset (fixP) = opcode_offset;
  fix_opcode_offset (fixP) = opcode_offset;
  fix_im_disp (fixP) = im_disp;
  fix_im_disp (fixP) = im_disp;
  fix_bsr (fixP) = bsr;
  fix_bsr (fixP) = bsr;
  fix_bit_fixP (fixP) = bit_fixP;
  fix_bit_fixP (fixP) = bit_fixP;
  /* We have a MD overflow check for displacements.  */
  /* We have a MD overflow check for displacements.  */
  fixP->fx_no_overflow = (im_disp != 0);
  fixP->fx_no_overflow = (im_disp != 0);
}
}
 
 
/* Convert number to chars in correct order.  */
/* Convert number to chars in correct order.  */
 
 
void
void
md_number_to_chars (char *buf, valueT value, int nbytes)
md_number_to_chars (char *buf, valueT value, int nbytes)
{
{
  number_to_chars_littleendian (buf, value, nbytes);
  number_to_chars_littleendian (buf, value, nbytes);
}
}
 
 
/* This is a variant of md_numbers_to_chars. The reason for its'
/* This is a variant of md_numbers_to_chars. The reason for its'
   existence is the fact that ns32k uses Huffman coded
   existence is the fact that ns32k uses Huffman coded
   displacements. This implies that the bit order is reversed in
   displacements. This implies that the bit order is reversed in
   displacements and that they are prefixed with a size-tag.
   displacements and that they are prefixed with a size-tag.
 
 
   binary: msb -> lsb
   binary: msb -> lsb
   0xxxxxxx                             byte
   0xxxxxxx                             byte
   10xxxxxx xxxxxxxx                    word
   10xxxxxx xxxxxxxx                    word
   11xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx  double word
   11xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx  double word
 
 
   This must be taken care of and we do it here!  */
   This must be taken care of and we do it here!  */
 
 
static void
static void
md_number_to_disp (char *buf, long val, int n)
md_number_to_disp (char *buf, long val, int n)
{
{
  switch (n)
  switch (n)
    {
    {
    case 1:
    case 1:
      if (val < -64 || val > 63)
      if (val < -64 || val > 63)
        as_bad (_("value of %ld out of byte displacement range."), val);
        as_bad (_("value of %ld out of byte displacement range."), val);
      val &= 0x7f;
      val &= 0x7f;
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val & 0xff);
      printf ("%x ", val & 0xff);
#endif
#endif
      *buf++ = val;
      *buf++ = val;
      break;
      break;
 
 
    case 2:
    case 2:
      if (val < -8192 || val > 8191)
      if (val < -8192 || val > 8191)
        as_bad (_("value of %ld out of word displacement range."), val);
        as_bad (_("value of %ld out of word displacement range."), val);
      val &= 0x3fff;
      val &= 0x3fff;
      val |= 0x8000;
      val |= 0x8000;
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val >> 8 & 0xff);
      printf ("%x ", val >> 8 & 0xff);
#endif
#endif
      *buf++ = (val >> 8);
      *buf++ = (val >> 8);
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val & 0xff);
      printf ("%x ", val & 0xff);
#endif
#endif
      *buf++ = val;
      *buf++ = val;
      break;
      break;
 
 
    case 4:
    case 4:
      if (val < -0x20000000 || val >= 0x20000000)
      if (val < -0x20000000 || val >= 0x20000000)
        as_bad (_("value of %ld out of double word displacement range."), val);
        as_bad (_("value of %ld out of double word displacement range."), val);
      val |= 0xc0000000;
      val |= 0xc0000000;
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val >> 24 & 0xff);
      printf ("%x ", val >> 24 & 0xff);
#endif
#endif
      *buf++ = (val >> 24);
      *buf++ = (val >> 24);
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val >> 16 & 0xff);
      printf ("%x ", val >> 16 & 0xff);
#endif
#endif
      *buf++ = (val >> 16);
      *buf++ = (val >> 16);
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val >> 8 & 0xff);
      printf ("%x ", val >> 8 & 0xff);
#endif
#endif
      *buf++ = (val >> 8);
      *buf++ = (val >> 8);
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val & 0xff);
      printf ("%x ", val & 0xff);
#endif
#endif
      *buf++ = val;
      *buf++ = val;
      break;
      break;
 
 
    default:
    default:
      as_fatal (_("Internal logic error.  line %d, file \"%s\""),
      as_fatal (_("Internal logic error.  line %d, file \"%s\""),
                __LINE__, __FILE__);
                __LINE__, __FILE__);
    }
    }
}
}
 
 
static void
static void
md_number_to_imm (char *buf, long val, int n)
md_number_to_imm (char *buf, long val, int n)
{
{
  switch (n)
  switch (n)
    {
    {
    case 1:
    case 1:
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val & 0xff);
      printf ("%x ", val & 0xff);
#endif
#endif
      *buf++ = val;
      *buf++ = val;
      break;
      break;
 
 
    case 2:
    case 2:
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val >> 8 & 0xff);
      printf ("%x ", val >> 8 & 0xff);
#endif
#endif
      *buf++ = (val >> 8);
      *buf++ = (val >> 8);
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val & 0xff);
      printf ("%x ", val & 0xff);
#endif
#endif
      *buf++ = val;
      *buf++ = val;
      break;
      break;
 
 
    case 4:
    case 4:
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val >> 24 & 0xff);
      printf ("%x ", val >> 24 & 0xff);
#endif
#endif
      *buf++ = (val >> 24);
      *buf++ = (val >> 24);
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val >> 16 & 0xff);
      printf ("%x ", val >> 16 & 0xff);
#endif
#endif
      *buf++ = (val >> 16);
      *buf++ = (val >> 16);
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val >> 8 & 0xff);
      printf ("%x ", val >> 8 & 0xff);
#endif
#endif
      *buf++ = (val >> 8);
      *buf++ = (val >> 8);
#ifdef SHOW_NUM
#ifdef SHOW_NUM
      printf ("%x ", val & 0xff);
      printf ("%x ", val & 0xff);
#endif
#endif
      *buf++ = val;
      *buf++ = val;
      break;
      break;
 
 
    default:
    default:
      as_fatal (_("Internal logic error. line %d, file \"%s\""),
      as_fatal (_("Internal logic error. line %d, file \"%s\""),
                __LINE__, __FILE__);
                __LINE__, __FILE__);
    }
    }
}
}
 
 
/* Fast bitfiddling support.  */
/* Fast bitfiddling support.  */
/* Mask used to zero bitfield before oring in the true field.  */
/* Mask used to zero bitfield before oring in the true field.  */
 
 
static unsigned long l_mask[] =
static unsigned long l_mask[] =
{
{
  0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8,
  0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8,
  0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80,
  0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80,
  0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800,
  0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800,
  0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000,
  0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000,
  0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000,
  0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000,
  0xfff00000, 0xffe00000, 0xffc00000, 0xff800000,
  0xfff00000, 0xffe00000, 0xffc00000, 0xff800000,
  0xff000000, 0xfe000000, 0xfc000000, 0xf8000000,
  0xff000000, 0xfe000000, 0xfc000000, 0xf8000000,
  0xf0000000, 0xe0000000, 0xc0000000, 0x80000000,
  0xf0000000, 0xe0000000, 0xc0000000, 0x80000000,
};
};
static unsigned long r_mask[] =
static unsigned long r_mask[] =
{
{
  0x00000000, 0x00000001, 0x00000003, 0x00000007,
  0x00000000, 0x00000001, 0x00000003, 0x00000007,
  0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
  0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
  0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
  0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
  0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
  0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
  0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
  0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
  0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
  0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
  0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
  0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
  0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
  0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
};
};
#define MASK_BITS 31
#define MASK_BITS 31
/* Insert bitfield described by field_ptr and val at buf
/* Insert bitfield described by field_ptr and val at buf
   This routine is written for modification of the first 4 bytes pointed
   This routine is written for modification of the first 4 bytes pointed
   to by buf, to yield speed.
   to by buf, to yield speed.
   The ifdef stuff is for selection between a ns32k-dependent routine
   The ifdef stuff is for selection between a ns32k-dependent routine
   and a general version. (My advice: use the general version!).  */
   and a general version. (My advice: use the general version!).  */
 
 
static void
static void
md_number_to_field (char *buf, long val, bit_fixS *field_ptr)
md_number_to_field (char *buf, long val, bit_fixS *field_ptr)
{
{
  unsigned long object;
  unsigned long object;
  unsigned long mask;
  unsigned long mask;
  /* Define ENDIAN on a ns32k machine.  */
  /* Define ENDIAN on a ns32k machine.  */
#ifdef ENDIAN
#ifdef ENDIAN
  unsigned long *mem_ptr;
  unsigned long *mem_ptr;
#else
#else
  char *mem_ptr;
  char *mem_ptr;
#endif
#endif
 
 
  if (field_ptr->fx_bit_min <= val && val <= field_ptr->fx_bit_max)
  if (field_ptr->fx_bit_min <= val && val <= field_ptr->fx_bit_max)
    {
    {
#ifdef ENDIAN
#ifdef ENDIAN
      if (field_ptr->fx_bit_base)
      if (field_ptr->fx_bit_base)
        /* Override buf.  */
        /* Override buf.  */
        mem_ptr = (unsigned long *) field_ptr->fx_bit_base;
        mem_ptr = (unsigned long *) field_ptr->fx_bit_base;
      else
      else
        mem_ptr = (unsigned long *) buf;
        mem_ptr = (unsigned long *) buf;
 
 
      mem_ptr = ((unsigned long *)
      mem_ptr = ((unsigned long *)
                 ((char *) mem_ptr + field_ptr->fx_bit_base_adj));
                 ((char *) mem_ptr + field_ptr->fx_bit_base_adj));
#else
#else
      if (field_ptr->fx_bit_base)
      if (field_ptr->fx_bit_base)
        mem_ptr = (char *) field_ptr->fx_bit_base;
        mem_ptr = (char *) field_ptr->fx_bit_base;
      else
      else
        mem_ptr = buf;
        mem_ptr = buf;
 
 
      mem_ptr += field_ptr->fx_bit_base_adj;
      mem_ptr += field_ptr->fx_bit_base_adj;
#endif
#endif
#ifdef ENDIAN
#ifdef ENDIAN
      /* We have a nice ns32k machine with lowbyte at low-physical mem.  */
      /* We have a nice ns32k machine with lowbyte at low-physical mem.  */
      object = *mem_ptr;        /* get some bytes */
      object = *mem_ptr;        /* get some bytes */
#else /* OVE Goof! the machine is a m68k or dito.  */
#else /* OVE Goof! the machine is a m68k or dito.  */
      /* That takes more byte fiddling.  */
      /* That takes more byte fiddling.  */
      object = 0;
      object = 0;
      object |= mem_ptr[3] & 0xff;
      object |= mem_ptr[3] & 0xff;
      object <<= 8;
      object <<= 8;
      object |= mem_ptr[2] & 0xff;
      object |= mem_ptr[2] & 0xff;
      object <<= 8;
      object <<= 8;
      object |= mem_ptr[1] & 0xff;
      object |= mem_ptr[1] & 0xff;
      object <<= 8;
      object <<= 8;
      object |= mem_ptr[0] & 0xff;
      object |= mem_ptr[0] & 0xff;
#endif
#endif
      mask = 0;
      mask = 0;
      mask |= (r_mask[field_ptr->fx_bit_offset]);
      mask |= (r_mask[field_ptr->fx_bit_offset]);
      mask |= (l_mask[field_ptr->fx_bit_offset + field_ptr->fx_bit_size]);
      mask |= (l_mask[field_ptr->fx_bit_offset + field_ptr->fx_bit_size]);
      object &= mask;
      object &= mask;
      val += field_ptr->fx_bit_add;
      val += field_ptr->fx_bit_add;
      object |= ((val << field_ptr->fx_bit_offset) & (mask ^ 0xffffffff));
      object |= ((val << field_ptr->fx_bit_offset) & (mask ^ 0xffffffff));
#ifdef ENDIAN
#ifdef ENDIAN
      *mem_ptr = object;
      *mem_ptr = object;
#else
#else
      mem_ptr[0] = (char) object;
      mem_ptr[0] = (char) object;
      object >>= 8;
      object >>= 8;
      mem_ptr[1] = (char) object;
      mem_ptr[1] = (char) object;
      object >>= 8;
      object >>= 8;
      mem_ptr[2] = (char) object;
      mem_ptr[2] = (char) object;
      object >>= 8;
      object >>= 8;
      mem_ptr[3] = (char) object;
      mem_ptr[3] = (char) object;
#endif
#endif
    }
    }
  else
  else
    as_bad (_("Bit field out of range"));
    as_bad (_("Bit field out of range"));
}
}
 
 
/* Convert iif to fragments.  From this point we start to dribble with
/* Convert iif to fragments.  From this point we start to dribble with
   functions in other files than this one.(Except hash.c) So, if it's
   functions in other files than this one.(Except hash.c) So, if it's
   possible to make an iif for an other CPU, you don't need to know
   possible to make an iif for an other CPU, you don't need to know
   what frags, relax, obstacks, etc is in order to port this
   what frags, relax, obstacks, etc is in order to port this
   assembler. You only need to know if it's possible to reduce your
   assembler. You only need to know if it's possible to reduce your
   cpu-instruction to iif-format (takes some work) and adopt the other
   cpu-instruction to iif-format (takes some work) and adopt the other
   md_? parts according to given instructions Note that iif was
   md_? parts according to given instructions Note that iif was
   invented for the clean ns32k`s architecture.  */
   invented for the clean ns32k`s architecture.  */
 
 
/* GAS for the ns32k has a problem. PC relative displacements are
/* GAS for the ns32k has a problem. PC relative displacements are
   relative to the address of the opcode, not the address of the
   relative to the address of the opcode, not the address of the
   operand. We used to keep track of the offset between the operand
   operand. We used to keep track of the offset between the operand
   and the opcode in pcrel_adjust for each frag and each fix. However,
   and the opcode in pcrel_adjust for each frag and each fix. However,
   we get into trouble where there are two or more pc-relative
   we get into trouble where there are two or more pc-relative
   operands and the size of the first one can't be determined. Then in
   operands and the size of the first one can't be determined. Then in
   the relax phase, the size of the first operand will change and
   the relax phase, the size of the first operand will change and
   pcrel_adjust will no longer be correct.  The current solution is
   pcrel_adjust will no longer be correct.  The current solution is
   keep a pointer to the frag with the opcode in it and the offset in
   keep a pointer to the frag with the opcode in it and the offset in
   that frag for each frag and each fix. Then, when needed, we can
   that frag for each frag and each fix. Then, when needed, we can
   always figure out how far it is between the opcode and the pcrel
   always figure out how far it is between the opcode and the pcrel
   object.  See also md_pcrel_adjust and md_fix_pcrel_adjust.  For
   object.  See also md_pcrel_adjust and md_fix_pcrel_adjust.  For
   objects not part of an instruction, the pointer to the opcode frag
   objects not part of an instruction, the pointer to the opcode frag
   is always zero.  */
   is always zero.  */
 
 
static void
static void
convert_iif (void)
convert_iif (void)
{
{
  int i;
  int i;
  bit_fixS *j;
  bit_fixS *j;
  fragS *inst_frag;
  fragS *inst_frag;
  unsigned int inst_offset;
  unsigned int inst_offset;
  char *inst_opcode;
  char *inst_opcode;
  char *memP;
  char *memP;
  int l;
  int l;
  int k;
  int k;
  char type;
  char type;
  char size = 0;
  char size = 0;
 
 
  frag_grow (iif.instr_size);   /* This is important.  */
  frag_grow (iif.instr_size);   /* This is important.  */
  memP = frag_more (0);
  memP = frag_more (0);
  inst_opcode = memP;
  inst_opcode = memP;
  inst_offset = (memP - frag_now->fr_literal);
  inst_offset = (memP - frag_now->fr_literal);
  inst_frag = frag_now;
  inst_frag = frag_now;
 
 
  for (i = 0; i < IIF_ENTRIES; i++)
  for (i = 0; i < IIF_ENTRIES; i++)
    {
    {
      if ((type = iif.iifP[i].type))
      if ((type = iif.iifP[i].type))
        {
        {
          /* The object exist, so handle it.  */
          /* The object exist, so handle it.  */
          switch (size = iif.iifP[i].size)
          switch (size = iif.iifP[i].size)
            {
            {
            case 42:
            case 42:
              size = 0;
              size = 0;
              /* It's a bitfix that operates on an existing object.  */
              /* It's a bitfix that operates on an existing object.  */
              if (iif.iifP[i].bit_fixP->fx_bit_base)
              if (iif.iifP[i].bit_fixP->fx_bit_base)
                /* Expand fx_bit_base to point at opcode.  */
                /* Expand fx_bit_base to point at opcode.  */
                iif.iifP[i].bit_fixP->fx_bit_base = (long) inst_opcode;
                iif.iifP[i].bit_fixP->fx_bit_base = (long) inst_opcode;
              /* Fall through.  */
              /* Fall through.  */
 
 
            case 8:             /* bignum or doublefloat.  */
            case 8:             /* bignum or doublefloat.  */
            case 1:
            case 1:
            case 2:
            case 2:
            case 3:
            case 3:
            case 4:
            case 4:
              /* The final size in objectmemory is known.  */
              /* The final size in objectmemory is known.  */
              memP = frag_more (size);
              memP = frag_more (size);
              j = iif.iifP[i].bit_fixP;
              j = iif.iifP[i].bit_fixP;
 
 
              switch (type)
              switch (type)
                {
                {
                case 1: /* The object is pure binary.  */
                case 1: /* The object is pure binary.  */
                  if (j)
                  if (j)
                    md_number_to_field (memP, exprP.X_add_number, j);
                    md_number_to_field (memP, exprP.X_add_number, j);
 
 
                  else if (iif.iifP[i].pcrel)
                  else if (iif.iifP[i].pcrel)
                    fix_new_ns32k (frag_now,
                    fix_new_ns32k (frag_now,
                                   (long) (memP - frag_now->fr_literal),
                                   (long) (memP - frag_now->fr_literal),
                                   size,
                                   size,
                                   0,
                                   0,
                                   iif.iifP[i].object,
                                   iif.iifP[i].object,
                                   iif.iifP[i].pcrel,
                                   iif.iifP[i].pcrel,
                                   iif.iifP[i].im_disp,
                                   iif.iifP[i].im_disp,
                                   0,
                                   0,
                                   iif.iifP[i].bsr,     /* Sequent hack.  */
                                   iif.iifP[i].bsr,     /* Sequent hack.  */
                                   inst_frag, inst_offset);
                                   inst_frag, inst_offset);
                  else
                  else
                    {
                    {
                      /* Good, just put them bytes out.  */
                      /* Good, just put them bytes out.  */
                      switch (iif.iifP[i].im_disp)
                      switch (iif.iifP[i].im_disp)
                        {
                        {
                        case 0:
                        case 0:
                          md_number_to_chars (memP, iif.iifP[i].object, size);
                          md_number_to_chars (memP, iif.iifP[i].object, size);
                          break;
                          break;
                        case 1:
                        case 1:
                          md_number_to_disp (memP, iif.iifP[i].object, size);
                          md_number_to_disp (memP, iif.iifP[i].object, size);
                          break;
                          break;
                        default:
                        default:
                          as_fatal (_("iif convert internal pcrel/binary"));
                          as_fatal (_("iif convert internal pcrel/binary"));
                        }
                        }
                    }
                    }
                  break;
                  break;
 
 
                case 2:
                case 2:
                  /* The object is a pointer at an expression, so
                  /* The object is a pointer at an expression, so
                     unpack it, note that bignums may result from the
                     unpack it, note that bignums may result from the
                     expression.  */
                     expression.  */
                  evaluate_expr (&exprP, (char *) iif.iifP[i].object);
                  evaluate_expr (&exprP, (char *) iif.iifP[i].object);
                  if (exprP.X_op == O_big || size == 8)
                  if (exprP.X_op == O_big || size == 8)
                    {
                    {
                      if ((k = exprP.X_add_number) > 0)
                      if ((k = exprP.X_add_number) > 0)
                        {
                        {
                          /* We have a bignum ie a quad. This can only
                          /* We have a bignum ie a quad. This can only
                             happens in a long suffixed instruction.  */
                             happens in a long suffixed instruction.  */
                          if (k * 2 > size)
                          if (k * 2 > size)
                            as_bad (_("Bignum too big for long"));
                            as_bad (_("Bignum too big for long"));
 
 
                          if (k == 3)
                          if (k == 3)
                            memP += 2;
                            memP += 2;
 
 
                          for (l = 0; k > 0; k--, l += 2)
                          for (l = 0; k > 0; k--, l += 2)
                            md_number_to_chars (memP + l,
                            md_number_to_chars (memP + l,
                                                generic_bignum[l >> 1],
                                                generic_bignum[l >> 1],
                                                sizeof (LITTLENUM_TYPE));
                                                sizeof (LITTLENUM_TYPE));
                        }
                        }
                      else
                      else
                        {
                        {
                          /* flonum.  */
                          /* flonum.  */
                          LITTLENUM_TYPE words[4];
                          LITTLENUM_TYPE words[4];
 
 
                          switch (size)
                          switch (size)
                            {
                            {
                            case 4:
                            case 4:
                              gen_to_words (words, 2, 8);
                              gen_to_words (words, 2, 8);
                              md_number_to_imm (memP, (long) words[0],
                              md_number_to_imm (memP, (long) words[0],
                                                sizeof (LITTLENUM_TYPE));
                                                sizeof (LITTLENUM_TYPE));
                              md_number_to_imm (memP + sizeof (LITTLENUM_TYPE),
                              md_number_to_imm (memP + sizeof (LITTLENUM_TYPE),
                                                (long) words[1],
                                                (long) words[1],
                                                sizeof (LITTLENUM_TYPE));
                                                sizeof (LITTLENUM_TYPE));
                              break;
                              break;
                            case 8:
                            case 8:
                              gen_to_words (words, 4, 11);
                              gen_to_words (words, 4, 11);
                              md_number_to_imm (memP, (long) words[0],
                              md_number_to_imm (memP, (long) words[0],
                                                sizeof (LITTLENUM_TYPE));
                                                sizeof (LITTLENUM_TYPE));
                              md_number_to_imm (memP + sizeof (LITTLENUM_TYPE),
                              md_number_to_imm (memP + sizeof (LITTLENUM_TYPE),
                                                (long) words[1],
                                                (long) words[1],
                                                sizeof (LITTLENUM_TYPE));
                                                sizeof (LITTLENUM_TYPE));
                              md_number_to_imm ((memP + 2
                              md_number_to_imm ((memP + 2
                                                 * sizeof (LITTLENUM_TYPE)),
                                                 * sizeof (LITTLENUM_TYPE)),
                                                (long) words[2],
                                                (long) words[2],
                                                sizeof (LITTLENUM_TYPE));
                                                sizeof (LITTLENUM_TYPE));
                              md_number_to_imm ((memP + 3
                              md_number_to_imm ((memP + 3
                                                 * sizeof (LITTLENUM_TYPE)),
                                                 * sizeof (LITTLENUM_TYPE)),
                                                (long) words[3],
                                                (long) words[3],
                                                sizeof (LITTLENUM_TYPE));
                                                sizeof (LITTLENUM_TYPE));
                              break;
                              break;
                            }
                            }
                        }
                        }
                      break;
                      break;
                    }
                    }
                  if (exprP.X_add_symbol ||
                  if (exprP.X_add_symbol ||
                      exprP.X_op_symbol ||
                      exprP.X_op_symbol ||
                      iif.iifP[i].pcrel)
                      iif.iifP[i].pcrel)
                    {
                    {
                      /* The expression was undefined due to an
                      /* The expression was undefined due to an
                         undefined label. Create a fix so we can fix
                         undefined label. Create a fix so we can fix
                         the object later.  */
                         the object later.  */
                      exprP.X_add_number += iif.iifP[i].object_adjust;
                      exprP.X_add_number += iif.iifP[i].object_adjust;
                      fix_new_ns32k_exp (frag_now,
                      fix_new_ns32k_exp (frag_now,
                                         (long) (memP - frag_now->fr_literal),
                                         (long) (memP - frag_now->fr_literal),
                                         size,
                                         size,
                                         &exprP,
                                         &exprP,
                                         iif.iifP[i].pcrel,
                                         iif.iifP[i].pcrel,
                                         iif.iifP[i].im_disp,
                                         iif.iifP[i].im_disp,
                                         j,
                                         j,
                                         iif.iifP[i].bsr,
                                         iif.iifP[i].bsr,
                                         inst_frag, inst_offset);
                                         inst_frag, inst_offset);
                    }
                    }
                  else if (j)
                  else if (j)
                    md_number_to_field (memP, exprP.X_add_number, j);
                    md_number_to_field (memP, exprP.X_add_number, j);
                  else
                  else
                    {
                    {
                      /* Good, just put them bytes out.  */
                      /* Good, just put them bytes out.  */
                      switch (iif.iifP[i].im_disp)
                      switch (iif.iifP[i].im_disp)
                        {
                        {
                        case 0:
                        case 0:
                          md_number_to_imm (memP, exprP.X_add_number, size);
                          md_number_to_imm (memP, exprP.X_add_number, size);
                          break;
                          break;
                        case 1:
                        case 1:
                          md_number_to_disp (memP, exprP.X_add_number, size);
                          md_number_to_disp (memP, exprP.X_add_number, size);
                          break;
                          break;
                        default:
                        default:
                          as_fatal (_("iif convert internal pcrel/pointer"));
                          as_fatal (_("iif convert internal pcrel/pointer"));
                        }
                        }
                    }
                    }
                  break;
                  break;
                default:
                default:
                  as_fatal (_("Internal logic error in iif.iifP[n].type"));
                  as_fatal (_("Internal logic error in iif.iifP[n].type"));
                }
                }
              break;
              break;
 
 
            case 0:
            case 0:
              /* Too bad, the object may be undefined as far as its
              /* Too bad, the object may be undefined as far as its
                 final nsize in object memory is concerned.  The size
                 final nsize in object memory is concerned.  The size
                 of the object in objectmemory is not explicitly
                 of the object in objectmemory is not explicitly
                 given.  If the object is defined its length can be
                 given.  If the object is defined its length can be
                 determined and a fix can replace the frag.  */
                 determined and a fix can replace the frag.  */
              {
              {
                evaluate_expr (&exprP, (char *) iif.iifP[i].object);
                evaluate_expr (&exprP, (char *) iif.iifP[i].object);
 
 
                if ((exprP.X_add_symbol || exprP.X_op_symbol) &&
                if ((exprP.X_add_symbol || exprP.X_op_symbol) &&
                    !iif.iifP[i].pcrel)
                    !iif.iifP[i].pcrel)
                  {
                  {
                    /* Size is unknown until link time so have to default.  */
                    /* Size is unknown until link time so have to default.  */
                    size = default_disp_size; /* Normally 4 bytes.  */
                    size = default_disp_size; /* Normally 4 bytes.  */
                    memP = frag_more (size);
                    memP = frag_more (size);
                    fix_new_ns32k_exp (frag_now,
                    fix_new_ns32k_exp (frag_now,
                                       (long) (memP - frag_now->fr_literal),
                                       (long) (memP - frag_now->fr_literal),
                                       size,
                                       size,
                                       &exprP,
                                       &exprP,
                                       0, /* never iif.iifP[i].pcrel, */
                                       0, /* never iif.iifP[i].pcrel, */
                                       1, /* always iif.iifP[i].im_disp */
                                       1, /* always iif.iifP[i].im_disp */
                                       (bit_fixS *) 0, 0,
                                       (bit_fixS *) 0, 0,
                                       inst_frag,
                                       inst_frag,
                                       inst_offset);
                                       inst_offset);
                    break;              /* Exit this absolute hack.  */
                    break;              /* Exit this absolute hack.  */
                  }
                  }
 
 
                if (exprP.X_add_symbol || exprP.X_op_symbol)
                if (exprP.X_add_symbol || exprP.X_op_symbol)
                  {
                  {
                    /* Frag it.  */
                    /* Frag it.  */
                    if (exprP.X_op_symbol)
                    if (exprP.X_op_symbol)
                      /* We cant relax this case.  */
                      /* We cant relax this case.  */
                      as_fatal (_("Can't relax difference"));
                      as_fatal (_("Can't relax difference"));
                    else
                    else
                      {
                      {
                        /* Size is not important.  This gets fixed by
                        /* Size is not important.  This gets fixed by
                           relax, but we assume 0 in what follows.  */
                           relax, but we assume 0 in what follows.  */
                        memP = frag_more (4); /* Max size.  */
                        memP = frag_more (4); /* Max size.  */
                        size = 0;
                        size = 0;
 
 
                        {
                        {
                          fragS *old_frag = frag_now;
                          fragS *old_frag = frag_now;
                          frag_variant (rs_machine_dependent,
                          frag_variant (rs_machine_dependent,
                                        4, /* Max size.  */
                                        4, /* Max size.  */
                                        0, /* Size.  */
                                        0, /* Size.  */
                                        IND (BRANCH, UNDEF), /* Expecting
                                        IND (BRANCH, UNDEF), /* Expecting
                                                                the worst.  */
                                                                the worst.  */
                                        exprP.X_add_symbol,
                                        exprP.X_add_symbol,
                                        exprP.X_add_number,
                                        exprP.X_add_number,
                                        inst_opcode);
                                        inst_opcode);
                          frag_opcode_frag (old_frag) = inst_frag;
                          frag_opcode_frag (old_frag) = inst_frag;
                          frag_opcode_offset (old_frag) = inst_offset;
                          frag_opcode_offset (old_frag) = inst_offset;
                          frag_bsr (old_frag) = iif.iifP[i].bsr;
                          frag_bsr (old_frag) = iif.iifP[i].bsr;
                        }
                        }
                      }
                      }
                  }
                  }
                else
                else
                  {
                  {
                    /* This duplicates code in md_number_to_disp.  */
                    /* This duplicates code in md_number_to_disp.  */
                    if (-64 <= exprP.X_add_number && exprP.X_add_number <= 63)
                    if (-64 <= exprP.X_add_number && exprP.X_add_number <= 63)
                      size = 1;
                      size = 1;
                    else
                    else
                      {
                      {
                        if (-8192 <= exprP.X_add_number
                        if (-8192 <= exprP.X_add_number
                            && exprP.X_add_number <= 8191)
                            && exprP.X_add_number <= 8191)
                          size = 2;
                          size = 2;
                        else
                        else
                          {
                          {
                            if (-0x20000000 <= exprP.X_add_number
                            if (-0x20000000 <= exprP.X_add_number
                                && exprP.X_add_number<=0x1fffffff)
                                && exprP.X_add_number<=0x1fffffff)
                              size = 4;
                              size = 4;
                            else
                            else
                              {
                              {
                                as_bad (_("Displacement too large for :d"));
                                as_bad (_("Displacement too large for :d"));
                                size = 4;
                                size = 4;
                              }
                              }
                          }
                          }
                      }
                      }
 
 
                    memP = frag_more (size);
                    memP = frag_more (size);
                    md_number_to_disp (memP, exprP.X_add_number, size);
                    md_number_to_disp (memP, exprP.X_add_number, size);
                  }
                  }
              }
              }
              break;
              break;
 
 
            default:
            default:
              as_fatal (_("Internal logic error in iif.iifP[].type"));
              as_fatal (_("Internal logic error in iif.iifP[].type"));
            }
            }
        }
        }
    }
    }
}
}


void
void
md_assemble (char *line)
md_assemble (char *line)
{
{
  freeptr = freeptr_static;
  freeptr = freeptr_static;
  parse (line, 0);               /* Explode line to more fix form in iif.  */
  parse (line, 0);               /* Explode line to more fix form in iif.  */
  convert_iif ();               /* Convert iif to frags, fix's etc.  */
  convert_iif ();               /* Convert iif to frags, fix's etc.  */
#ifdef SHOW_NUM
#ifdef SHOW_NUM
  printf (" \t\t\t%s\n", line);
  printf (" \t\t\t%s\n", line);
#endif
#endif
}
}
 
 
void
void
md_begin (void)
md_begin (void)
{
{
  /* Build a hashtable of the instructions.  */
  /* Build a hashtable of the instructions.  */
  const struct ns32k_opcode *ptr;
  const struct ns32k_opcode *ptr;
  const char *stat;
  const char *status;
  const struct ns32k_opcode *endop;
  const struct ns32k_opcode *endop;
 
 
  inst_hash_handle = hash_new ();
  inst_hash_handle = hash_new ();
 
 
  endop = ns32k_opcodes + sizeof (ns32k_opcodes) / sizeof (ns32k_opcodes[0]);
  endop = ns32k_opcodes + sizeof (ns32k_opcodes) / sizeof (ns32k_opcodes[0]);
  for (ptr = ns32k_opcodes; ptr < endop; ptr++)
  for (ptr = ns32k_opcodes; ptr < endop; ptr++)
    {
    {
      if ((stat = hash_insert (inst_hash_handle, ptr->name, (char *) ptr)))
      if ((status = hash_insert (inst_hash_handle, ptr->name, (char *) ptr)))
        /* Fatal.  */
        /* Fatal.  */
        as_fatal (_("Can't hash %s: %s"), ptr->name, stat);
        as_fatal (_("Can't hash %s: %s"), ptr->name, status);
    }
    }
 
 
  /* Some private space please!  */
  /* Some private space please!  */
  freeptr_static = (char *) malloc (PRIVATE_SIZE);
  freeptr_static = (char *) malloc (PRIVATE_SIZE);
}
}
 
 
/* Turn the string pointed to by litP into a floating point constant
/* Turn the string pointed to by litP into a floating point constant
   of type TYPE, and emit the appropriate bytes.  The number of
   of type TYPE, and emit the appropriate bytes.  The number of
   LITTLENUMS emitted is stored in *SIZEP.  An error message is
   LITTLENUMS emitted is stored in *SIZEP.  An error message is
   returned, or NULL on OK.  */
   returned, or NULL on OK.  */
 
 
char *
char *
md_atof (int type, char *litP, int *sizeP)
md_atof (int type, char *litP, int *sizeP)
{
{
  return ieee_md_atof (type, litP, sizeP, FALSE);
  return ieee_md_atof (type, litP, sizeP, FALSE);
}
}


int
int
md_pcrel_adjust (fragS *fragP)
md_pcrel_adjust (fragS *fragP)
{
{
  fragS *opcode_frag;
  fragS *opcode_frag;
  addressT opcode_address;
  addressT opcode_address;
  unsigned int offset;
  unsigned int offset;
 
 
  opcode_frag = frag_opcode_frag (fragP);
  opcode_frag = frag_opcode_frag (fragP);
  if (opcode_frag == 0)
  if (opcode_frag == 0)
    return 0;
    return 0;
 
 
  offset = frag_opcode_offset (fragP);
  offset = frag_opcode_offset (fragP);
  opcode_address = offset + opcode_frag->fr_address;
  opcode_address = offset + opcode_frag->fr_address;
 
 
  return fragP->fr_address + fragP->fr_fix - opcode_address;
  return fragP->fr_address + fragP->fr_fix - opcode_address;
}
}
 
 
static int
static int
md_fix_pcrel_adjust (fixS *fixP)
md_fix_pcrel_adjust (fixS *fixP)
{
{
  fragS *opcode_frag;
  fragS *opcode_frag;
  addressT opcode_address;
  addressT opcode_address;
  unsigned int offset;
  unsigned int offset;
 
 
  opcode_frag = fix_opcode_frag (fixP);
  opcode_frag = fix_opcode_frag (fixP);
  if (opcode_frag == 0)
  if (opcode_frag == 0)
    return 0;
    return 0;
 
 
  offset = fix_opcode_offset (fixP);
  offset = fix_opcode_offset (fixP);
  opcode_address = offset + opcode_frag->fr_address;
  opcode_address = offset + opcode_frag->fr_address;
 
 
  return fixP->fx_where + fixP->fx_frag->fr_address - opcode_address;
  return fixP->fx_where + fixP->fx_frag->fr_address - opcode_address;
}
}
 
 
/* Apply a fixS (fixup of an instruction or data that we didn't have
/* Apply a fixS (fixup of an instruction or data that we didn't have
   enough info to complete immediately) to the data in a frag.
   enough info to complete immediately) to the data in a frag.
 
 
   On the ns32k, everything is in a different format, so we have broken
   On the ns32k, everything is in a different format, so we have broken
   out separate functions for each kind of thing we could be fixing.
   out separate functions for each kind of thing we could be fixing.
   They all get called from here.  */
   They all get called from here.  */
 
 
void
void
md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
md_apply_fix (fixS *fixP, valueT * valP, segT seg 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;
 
 
  if (fix_bit_fixP (fixP))
  if (fix_bit_fixP (fixP))
    /* Bitfields to fix, sigh.  */
    /* Bitfields to fix, sigh.  */
    md_number_to_field (buf, val, fix_bit_fixP (fixP));
    md_number_to_field (buf, val, fix_bit_fixP (fixP));
  else switch (fix_im_disp (fixP))
  else switch (fix_im_disp (fixP))
    {
    {
    case 0:
    case 0:
      /* Immediate field.  */
      /* Immediate field.  */
      md_number_to_imm (buf, val, fixP->fx_size);
      md_number_to_imm (buf, val, fixP->fx_size);
      break;
      break;
 
 
    case 1:
    case 1:
      /* Displacement field.  */
      /* Displacement field.  */
      /* Calculate offset.  */
      /* Calculate offset.  */
      md_number_to_disp (buf,
      md_number_to_disp (buf,
                         (fixP->fx_pcrel ? val + md_fix_pcrel_adjust (fixP)
                         (fixP->fx_pcrel ? val + md_fix_pcrel_adjust (fixP)
                          : val), fixP->fx_size);
                          : val), fixP->fx_size);
      break;
      break;
 
 
    case 2:
    case 2:
      /* Pointer in a data object.  */
      /* Pointer in a data object.  */
      md_number_to_chars (buf, val, fixP->fx_size);
      md_number_to_chars (buf, val, fixP->fx_size);
      break;
      break;
    }
    }
 
 
  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;
}
}


/* Convert a relaxed displacement to ditto in final output.  */
/* Convert a relaxed displacement to ditto in final output.  */
 
 
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)
{
{
  long disp;
  long disp;
  long ext = 0;
  long ext = 0;
  /* Address in gas core of the place to store the displacement.  */
  /* Address in gas core of the place to store the displacement.  */
  char *buffer_address = fragP->fr_fix + fragP->fr_literal;
  char *buffer_address = fragP->fr_fix + fragP->fr_literal;
  /* Address in object code of the displacement.  */
  /* Address in object code of the displacement.  */
  int object_address;
  int object_address;
 
 
  switch (fragP->fr_subtype)
  switch (fragP->fr_subtype)
    {
    {
    case IND (BRANCH, BYTE):
    case IND (BRANCH, BYTE):
      ext = 1;
      ext = 1;
      break;
      break;
    case IND (BRANCH, WORD):
    case IND (BRANCH, WORD):
      ext = 2;
      ext = 2;
      break;
      break;
    case IND (BRANCH, DOUBLE):
    case IND (BRANCH, DOUBLE):
      ext = 4;
      ext = 4;
      break;
      break;
    }
    }
 
 
  if (ext == 0)
  if (ext == 0)
    return;
    return;
 
 
  know (fragP->fr_symbol);
  know (fragP->fr_symbol);
 
 
  object_address = fragP->fr_fix + fragP->fr_address;
  object_address = fragP->fr_fix + fragP->fr_address;
 
 
  /* The displacement of the address, from current location.  */
  /* The displacement of the address, from current location.  */
  disp = (S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset) - object_address;
  disp = (S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset) - object_address;
  disp += md_pcrel_adjust (fragP);
  disp += md_pcrel_adjust (fragP);
 
 
  md_number_to_disp (buffer_address, (long) disp, (int) ext);
  md_number_to_disp (buffer_address, (long) disp, (int) ext);
  fragP->fr_fix += ext;
  fragP->fr_fix += ext;
}
}
 
 
/* This function returns the estimated size a variable object will occupy,
/* This function returns the estimated size a variable object will occupy,
   one can say that we tries to guess the size of the objects before we
   one can say that we tries to guess the size of the objects before we
   actually know it.  */
   actually know it.  */
 
 
int
int
md_estimate_size_before_relax (fragS *fragP, segT segment)
md_estimate_size_before_relax (fragS *fragP, segT segment)
{
{
  if (fragP->fr_subtype == IND (BRANCH, UNDEF))
  if (fragP->fr_subtype == IND (BRANCH, UNDEF))
    {
    {
      if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
      if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
        {
        {
          /* We don't relax symbols defined in another segment.  The
          /* We don't relax symbols defined in another segment.  The
             thing to do is to assume the object will occupy 4 bytes.  */
             thing to do is to assume the object will occupy 4 bytes.  */
          fix_new_ns32k (fragP,
          fix_new_ns32k (fragP,
                         (int) (fragP->fr_fix),
                         (int) (fragP->fr_fix),
                         4,
                         4,
                         fragP->fr_symbol,
                         fragP->fr_symbol,
                         fragP->fr_offset,
                         fragP->fr_offset,
                         1,
                         1,
                         1,
                         1,
                         0,
                         0,
                         frag_bsr(fragP), /* Sequent hack.  */
                         frag_bsr(fragP), /* Sequent hack.  */
                         frag_opcode_frag (fragP),
                         frag_opcode_frag (fragP),
                         frag_opcode_offset (fragP));
                         frag_opcode_offset (fragP));
          fragP->fr_fix += 4;
          fragP->fr_fix += 4;
          frag_wane (fragP);
          frag_wane (fragP);
          return 4;
          return 4;
        }
        }
 
 
      /* Relaxable case.  Set up the initial guess for the variable
      /* Relaxable case.  Set up the initial guess for the variable
         part of the frag.  */
         part of the frag.  */
      fragP->fr_subtype = IND (BRANCH, BYTE);
      fragP->fr_subtype = IND (BRANCH, BYTE);
    }
    }
 
 
  if (fragP->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
  if (fragP->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
    abort ();
    abort ();
 
 
  /* Return the size of the variable part of the frag.  */
  /* Return the size of the variable part of the frag.  */
  return md_relax_table[fragP->fr_subtype].rlx_length;
  return md_relax_table[fragP->fr_subtype].rlx_length;
}
}
 
 
int md_short_jump_size = 3;
int md_short_jump_size = 3;
int md_long_jump_size = 5;
int md_long_jump_size = 5;
 
 
void
void
md_create_short_jump (char *ptr,
md_create_short_jump (char *ptr,
                      addressT from_addr,
                      addressT from_addr,
                      addressT to_addr,
                      addressT to_addr,
                      fragS *frag ATTRIBUTE_UNUSED,
                      fragS *frag ATTRIBUTE_UNUSED,
                      symbolS *to_symbol ATTRIBUTE_UNUSED)
                      symbolS *to_symbol ATTRIBUTE_UNUSED)
{
{
  valueT offset;
  valueT offset;
 
 
  offset = to_addr - from_addr;
  offset = to_addr - from_addr;
  md_number_to_chars (ptr, (valueT) 0xEA, 1);
  md_number_to_chars (ptr, (valueT) 0xEA, 1);
  md_number_to_disp (ptr + 1, (valueT) offset, 2);
  md_number_to_disp (ptr + 1, (valueT) offset, 2);
}
}
 
 
void
void
md_create_long_jump (char *ptr,
md_create_long_jump (char *ptr,
                     addressT from_addr,
                     addressT from_addr,
                     addressT to_addr,
                     addressT to_addr,
                     fragS *frag ATTRIBUTE_UNUSED,
                     fragS *frag ATTRIBUTE_UNUSED,
                     symbolS *to_symbol ATTRIBUTE_UNUSED)
                     symbolS *to_symbol ATTRIBUTE_UNUSED)
{
{
  valueT offset;
  valueT offset;
 
 
  offset = to_addr - from_addr;
  offset = to_addr - from_addr;
  md_number_to_chars (ptr, (valueT) 0xEA, 1);
  md_number_to_chars (ptr, (valueT) 0xEA, 1);
  md_number_to_disp (ptr + 1, (valueT) offset, 4);
  md_number_to_disp (ptr + 1, (valueT) offset, 4);
}
}


const char *md_shortopts = "m:";
const char *md_shortopts = "m:";
 
 
struct option md_longopts[] =
struct option md_longopts[] =
{
{
#define OPTION_DISP_SIZE (OPTION_MD_BASE)
#define OPTION_DISP_SIZE (OPTION_MD_BASE)
  {"disp-size-default", required_argument , NULL, OPTION_DISP_SIZE},
  {"disp-size-default", required_argument , NULL, OPTION_DISP_SIZE},
  {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 'm':
    case 'm':
      if (!strcmp (arg, "32032"))
      if (!strcmp (arg, "32032"))
        {
        {
          cpureg = cpureg_032;
          cpureg = cpureg_032;
          mmureg = mmureg_032;
          mmureg = mmureg_032;
        }
        }
      else if (!strcmp (arg, "32532"))
      else if (!strcmp (arg, "32532"))
        {
        {
          cpureg = cpureg_532;
          cpureg = cpureg_532;
          mmureg = mmureg_532;
          mmureg = mmureg_532;
        }
        }
      else
      else
        {
        {
          as_warn (_("invalid architecture option -m%s, ignored"), arg);
          as_warn (_("invalid architecture option -m%s, ignored"), arg);
          return 0;
          return 0;
        }
        }
      break;
      break;
    case OPTION_DISP_SIZE:
    case OPTION_DISP_SIZE:
      {
      {
        int size = atoi(arg);
        int size = atoi(arg);
        switch (size)
        switch (size)
          {
          {
          case 1: case 2: case 4:
          case 1: case 2: case 4:
            default_disp_size = size;
            default_disp_size = size;
            break;
            break;
          default:
          default:
            as_warn (_("invalid default displacement size \"%s\". Defaulting to %d."),
            as_warn (_("invalid default displacement size \"%s\". Defaulting to %d."),
                     arg, default_disp_size);
                     arg, default_disp_size);
          }
          }
        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, _("\
NS32K options:\n\
NS32K options:\n\
-m32032 | -m32532       select variant of NS32K architecture\n\
-m32032 | -m32532       select variant of NS32K architecture\n\
--disp-size-default=<1|2|4>\n"));
--disp-size-default=<1|2|4>\n"));
}
}


/* This is TC_CONS_FIX_NEW, called by emit_expr in read.c.  */
/* This is TC_CONS_FIX_NEW, called by emit_expr in read.c.  */
 
 
void
void
cons_fix_new_ns32k (fragS *frag,        /* Which frag? */
cons_fix_new_ns32k (fragS *frag,        /* Which frag? */
                    int where,          /* Where in that frag? */
                    int where,          /* Where in that frag? */
                    int size,           /* 1, 2  or 4 usually.  */
                    int size,           /* 1, 2  or 4 usually.  */
                    expressionS *exp)   /* Expression.  */
                    expressionS *exp)   /* Expression.  */
{
{
  fix_new_ns32k_exp (frag, where, size, exp,
  fix_new_ns32k_exp (frag, where, size, exp,
                     0, 2, 0, 0, 0, 0);
                     0, 2, 0, 0, 0, 0);
}
}
 
 
/* 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;
}
}
 
 
/* 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, valueT size)
md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
{
{
  return size;                  /* Byte alignment is fine.  */
  return size;                  /* Byte alignment is fine.  */
}
}
 
 
/* Exactly what point is a PC-relative offset relative TO?  On the
/* Exactly what point is a PC-relative offset relative TO?  On the
   ns32k, they're relative to the start of the instruction.  */
   ns32k, they're relative to the start of the instruction.  */
 
 
long
long
md_pcrel_from (fixS *fixP)
md_pcrel_from (fixS *fixP)
{
{
  long res;
  long res;
 
 
  res = fixP->fx_where + fixP->fx_frag->fr_address;
  res = fixP->fx_where + fixP->fx_frag->fr_address;
#ifdef SEQUENT_COMPATABILITY
#ifdef SEQUENT_COMPATABILITY
  if (frag_bsr (fixP->fx_frag))
  if (frag_bsr (fixP->fx_frag))
    res += 0x12                 /* FOO Kludge alert!  */
    res += 0x12                 /* FOO Kludge alert!  */
#endif
#endif
      return res;
      return res;
}
}
 
 
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;
 
 
  code = reloc (fixp->fx_size, fixp->fx_pcrel, fix_im_disp (fixp));
  code = reloc (fixp->fx_size, fixp->fx_pcrel, fix_im_disp (fixp));
 
 
  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;
  if (fixp->fx_pcrel)
  if (fixp->fx_pcrel)
    rel->addend = fixp->fx_addnumber;
    rel->addend = fixp->fx_addnumber;
  else
  else
    rel->addend = 0;
    rel->addend = 0;
 
 
  rel->howto = bfd_reloc_type_lookup (stdoutput, code);
  rel->howto = bfd_reloc_type_lookup (stdoutput, code);
  if (!rel->howto)
  if (!rel->howto)
    {
    {
      const char *name;
      const char *name;
 
 
      name = S_GET_NAME (fixp->fx_addsy);
      name = S_GET_NAME (fixp->fx_addsy);
      if (name == NULL)
      if (name == NULL)
        name = _("<unknown>");
        name = _("<unknown>");
      as_fatal (_("Cannot find relocation type for symbol %s, code %d"),
      as_fatal (_("Cannot find relocation type for symbol %s, code %d"),
                name, (int) code);
                name, (int) code);
    }
    }
 
 
  return rel;
  return rel;
}
}
 
 

powered by: WebSVN 2.1.0

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