Automatic date update in version.in
[deliverable/binutils-gdb.git] / gas / config / tc-i960.c
index 7c8b662b451ce6388c735e76e9b4781fd9cc146c..b927965bc95b3992f148e64e5b95112faeafb713 100644 (file)
@@ -1,12 +1,11 @@
 /* tc-i960.c - All the i80960-specific stuff
 /* tc-i960.c - All the i80960-specific stuff
-   Copyright (C) 1989, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000
-   Free Software Foundation, Inc.
+   Copyright (C) 1989-2016 Free Software Foundation, Inc.
 
    This file is part of GAS.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This file is part of GAS.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
    any later version.
 
    GAS is distributed in the hope that it will be useful,
@@ -16,8 +15,8 @@
 
    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
 
    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
-   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 /* See comment on md_parse_option for 80960-specific invocation options.  */
 
 
 /* See comment on md_parse_option for 80960-specific invocation options.  */
 
         less than 4096 is specified, in which case we need neither a fixup nor
         a relocation directive.  */
 
         less than 4096 is specified, in which case we need neither a fixup nor
         a relocation directive.  */
 
-#include <stdio.h>
-#include <ctype.h>
-
 #include "as.h"
 
 #include "as.h"
 
-#include "obstack.h"
+#include "safe-ctype.h"
 
 #include "opcode/i960.h"
 
 #if defined (OBJ_AOUT) || defined (OBJ_BOUT)
 
 
 #include "opcode/i960.h"
 
 #if defined (OBJ_AOUT) || defined (OBJ_BOUT)
 
-#define TC_S_IS_SYSPROC(s)     ((1<=S_GET_OTHER(s)) && (S_GET_OTHER(s)<=32))
-#define TC_S_IS_BALNAME(s)     (S_GET_OTHER(s) == N_BALNAME)
-#define TC_S_IS_CALLNAME(s)    (S_GET_OTHER(s) == N_CALLNAME)
-#define TC_S_IS_BADPROC(s)     ((S_GET_OTHER(s) != 0) && !TC_S_IS_CALLNAME(s) && !TC_S_IS_BALNAME(s) && !TC_S_IS_SYSPROC(s))
+#define TC_S_IS_SYSPROC(s)     ((1 <= S_GET_OTHER (s)) && (S_GET_OTHER (s) <= 32))
+#define TC_S_IS_BALNAME(s)     (S_GET_OTHER (s) == N_BALNAME)
+#define TC_S_IS_CALLNAME(s)    (S_GET_OTHER (s) == N_CALLNAME)
+#define TC_S_IS_BADPROC(s)     ((S_GET_OTHER (s) != 0) && !TC_S_IS_CALLNAME (s) && !TC_S_IS_BALNAME (s) && !TC_S_IS_SYSPROC (s))
 
 
-#define TC_S_SET_SYSPROC(s, p) (S_SET_OTHER((s), (p)+1))
-#define TC_S_GET_SYSPROC(s)    (S_GET_OTHER(s)-1)
+#define TC_S_SET_SYSPROC(s, p) (S_SET_OTHER ((s), (p) + 1))
+#define TC_S_GET_SYSPROC(s)    (S_GET_OTHER (s) - 1)
 
 
-#define TC_S_FORCE_TO_BALNAME(s)       (S_SET_OTHER((s), N_BALNAME))
-#define TC_S_FORCE_TO_CALLNAME(s)      (S_SET_OTHER((s), N_CALLNAME))
+#define TC_S_FORCE_TO_BALNAME(s)       (S_SET_OTHER ((s), N_BALNAME))
+#define TC_S_FORCE_TO_CALLNAME(s)      (S_SET_OTHER ((s), N_CALLNAME))
 #define TC_S_FORCE_TO_SYSPROC(s)       {;}
 
 #else /* ! OBJ_A/BOUT */
 #ifdef OBJ_COFF
 
 #define TC_S_FORCE_TO_SYSPROC(s)       {;}
 
 #else /* ! OBJ_A/BOUT */
 #ifdef OBJ_COFF
 
-#define TC_S_IS_SYSPROC(s)     (S_GET_STORAGE_CLASS(s) == C_SCALL)
-#define TC_S_IS_BALNAME(s)     (SF_GET_BALNAME(s))
-#define TC_S_IS_CALLNAME(s)    (SF_GET_CALLNAME(s))
-#define TC_S_IS_BADPROC(s)     (TC_S_IS_SYSPROC(s) && TC_S_GET_SYSPROC(s) < 0 && 31 < TC_S_GET_SYSPROC(s))
+#define TC_S_IS_SYSPROC(s)     (S_GET_STORAGE_CLASS (s) == C_SCALL)
+#define TC_S_IS_BALNAME(s)     (SF_GET_BALNAME (s))
+#define TC_S_IS_CALLNAME(s)    (SF_GET_CALLNAME (s))
+#define TC_S_IS_BADPROC(s)     (TC_S_IS_SYSPROC (s) && TC_S_GET_SYSPROC (s) < 0 && 31 < TC_S_GET_SYSPROC (s))
 
 #define TC_S_SET_SYSPROC(s, p) ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx = (p))
 #define TC_S_GET_SYSPROC(s)    ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx)
 
 
 #define TC_S_SET_SYSPROC(s, p) ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx = (p))
 #define TC_S_GET_SYSPROC(s)    ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx)
 
-#define TC_S_FORCE_TO_BALNAME(s)       (SF_SET_BALNAME(s))
-#define TC_S_FORCE_TO_CALLNAME(s)      (SF_SET_CALLNAME(s))
-#define TC_S_FORCE_TO_SYSPROC(s)       (S_SET_STORAGE_CLASS((s), C_SCALL))
+#define TC_S_FORCE_TO_BALNAME(s)       (SF_SET_BALNAME (s))
+#define TC_S_FORCE_TO_CALLNAME(s)      (SF_SET_CALLNAME (s))
+#define TC_S_FORCE_TO_SYSPROC(s)       (S_SET_STORAGE_CLASS ((s), C_SCALL))
 
 #else /* ! OBJ_COFF */
 #ifdef OBJ_ELF
 
 #else /* ! OBJ_COFF */
 #ifdef OBJ_ELF
 #define TC_S_IS_BADPROC(s)     0
 
 #define TC_S_SET_SYSPROC(s, p)
 #define TC_S_IS_BADPROC(s)     0
 
 #define TC_S_SET_SYSPROC(s, p)
-#define TC_S_GET_SYSPROC(s) 0
+#define TC_S_GET_SYSPROC(s)     0
 
 #define TC_S_FORCE_TO_BALNAME(s)
 #define TC_S_FORCE_TO_CALLNAME(s)
 
 #define TC_S_FORCE_TO_BALNAME(s)
 #define TC_S_FORCE_TO_CALLNAME(s)
 
 extern char *input_line_pointer;
 
 
 extern char *input_line_pointer;
 
-#if !defined (BFD_ASSEMBLER) && !defined (BFD)
-#ifdef OBJ_COFF
-const int md_reloc_size = sizeof (struct reloc);
-#else /* OBJ_COFF */
-const int md_reloc_size = sizeof (struct relocation_info);
-#endif /* OBJ_COFF */
-#endif
-
 /* Local i80960 routines.  */
 /* Local i80960 routines.  */
+struct memS;
+struct regop;
 
 
-static void brcnt_emit ();     /* Emit branch-prediction instrumentation code */
-static char *brlab_next ();    /* Return next branch local label */
-void brtab_emit ();            /* Emit br-predict instrumentation table */
-static void cobr_fmt ();       /* Generate COBR instruction */
-static void ctrl_fmt ();       /* Generate CTRL instruction */
-static char *emit ();          /* Emit (internally) binary */
-static int get_args ();                /* Break arguments out of comma-separated list */
-static void get_cdisp ();      /* Handle COBR or CTRL displacement */
-static char *get_ispec ();     /* Find index specification string */
-static int get_regnum ();      /* Translate text to register number */
-static int i_scan ();          /* Lexical scan of instruction source */
-static void mem_fmt ();                /* Generate MEMA or MEMB instruction */
-static void mema_to_memb ();   /* Convert MEMA instruction to MEMB format */
-static void parse_expr ();     /* Parse an expression */
-static int parse_ldconst ();   /* Parse and replace a 'ldconst' pseudo-op */
-static void parse_memop ();    /* Parse a memory operand */
-static void parse_po ();       /* Parse machine-dependent pseudo-op */
-static void parse_regop ();    /* Parse a register operand */
-static void reg_fmt ();                /* Generate a REG format instruction */
-void reloc_callj ();           /* Relocate a 'callj' instruction */
-static void relax_cobr ();     /* "De-optimize" cobr into compare/branch */
-static void s_leafproc ();     /* Process '.leafproc' pseudo-op */
-static void s_sysproc ();      /* Process '.sysproc' pseudo-op */
-static int shift_ok ();                /* Will a 'shlo' substiture for a 'ldconst'? */
-static void syntax ();         /* Give syntax error */
-static int targ_has_sfr ();    /* Target chip supports spec-func register? */
-static int targ_has_iclass (); /* Target chip supports instruction set? */
-
-/* See md_parse_option() for meanings of these options */
-static char norelax;           /* True if -norelax switch seen */
-static char instrument_branches;       /* True if -b switch seen */
+/* See md_parse_option() for meanings of these options.  */
+static char norelax;                   /* True if -norelax switch seen.  */
+static char instrument_branches;       /* True if -b switch seen.  */
 
 /* Characters that always start a comment.
 
 /* Characters that always start a comment.
-   If the pre-processor is disabled, these aren't very useful.
- */
+   If the pre-processor is disabled, these aren't very useful.  */
 const char comment_chars[] = "#";
 
 /* Characters that only start a comment at the beginning of
 const char comment_chars[] = "#";
 
 /* Characters that only start a comment at the beginning of
@@ -175,21 +136,18 @@ const char comment_chars[] = "#";
 
    Note that input_file.c hand checks for '#' at the beginning of the
    first line of the input file.  This is because the compiler outputs
 
    Note that input_file.c hand checks for '#' at the beginning of the
    first line of the input file.  This is because the compiler outputs
-   #NO_APP at the beginning of its output.
- */
+   #NO_APP at the beginning of its output.  */
 
 /* Also note that comments started like this one will always work.  */
 
 
 /* Also note that comments started like this one will always work.  */
 
-const char line_comment_chars[] = "";
-
+const char line_comment_chars[]   = "#";
 const char line_separator_chars[] = ";";
 
 const char line_separator_chars[] = ";";
 
-/* Chars that can be used to separate mant from exp in floating point nums */
+/* Chars that can be used to separate mant from exp in floating point nums */
 const char EXP_CHARS[] = "eE";
 
 /* Chars that mean this number is a floating point constant,
 const char EXP_CHARS[] = "eE";
 
 /* Chars that mean this number is a floating point constant,
-   as in 0f12.456 or 0d1.2345e12
- */
+   as in 0f12.456 or 0d1.2345e12.  */
 const char FLT_CHARS[] = "fFdDtT";
 
 /* Table used by base assembler to relax addresses based on varying length
 const char FLT_CHARS[] = "fFdDtT";
 
 /* Table used by base assembler to relax addresses based on varying length
@@ -201,52 +159,34 @@ const char FLT_CHARS[] = "fFdDtT";
 
    For i80960, the only application is the (de-)optimization of cobr
    instructions into separate compare and branch instructions when a 13-bit
 
    For i80960, the only application is the (de-)optimization of cobr
    instructions into separate compare and branch instructions when a 13-bit
-   displacement won't hack it.
- */
+   displacement won't hack it.  */
 const relax_typeS md_relax_table[] =
 {
 const relax_typeS md_relax_table[] =
 {
-  {0, 0, 0, 0},                        /* State 0 => no more relaxation possible */
-  {4088, -4096, 0, 2},         /* State 1: conditional branch (cobr) */
-  {0x800000 - 8, -0x800000, 4, 0},     /* State 2: compare (reg) & branch (ctrl) */
+  {0, 0, 0, 0},                                /* State 0 => no more relaxation possible.  */
+  {4088, -4096, 0, 2},                 /* State 1: conditional branch (cobr).  */
+  {0x800000 - 8, -0x800000, 4, 0},     /* State 2: compare (reg) & branch (ctrl) */
 };
 
 };
 
-static void s_endian PARAMS ((int));
-
 /* These are the machine dependent pseudo-ops.
 
    This table describes all the machine specific pseudo-ops the assembler
    has to support.  The fields are:
         pseudo-op name without dot
         function to call to execute this pseudo-op
 /* These are the machine dependent pseudo-ops.
 
    This table describes all the machine specific pseudo-ops the assembler
    has to support.  The fields are:
         pseudo-op name without dot
         function to call to execute this pseudo-op
-        integer arg to pass to the function
- */
+        integer arg to pass to the function.  */
 #define S_LEAFPROC     1
 #define S_SYSPROC      2
 
 #define S_LEAFPROC     1
 #define S_SYSPROC      2
 
-const pseudo_typeS md_pseudo_table[] =
-{
-  {"bss", s_lcomm, 1},
-  {"endian", s_endian, 0},
-  {"extended", float_cons, 't'},
-  {"leafproc", parse_po, S_LEAFPROC},
-  {"sysproc", parse_po, S_SYSPROC},
-
-  {"word", cons, 4},
-  {"quad", cons, 16},
-
-  {0, 0, 0}
-};
-\f
-/* Macros to extract info from an 'expressionS' structure 'e' */
+/* Macros to extract info from an 'expressionS' structure 'e'.  */
 #define adds(e)        e.X_add_symbol
 #define offs(e)        e.X_add_number
 
 #define adds(e)        e.X_add_symbol
 #define offs(e)        e.X_add_number
 
-/* Branch-prediction bits for CTRL/COBR format opcodes */
-#define BP_MASK                0x00000002      /* Mask for branch-prediction bit */
-#define BP_TAKEN       0x00000000      /* Value to OR in to predict branch */
-#define BP_NOT_TAKEN   0x00000002      /* Value to OR in to predict no branch */
+/* Branch-prediction bits for CTRL/COBR format opcodes */
+#define BP_MASK                0x00000002      /* Mask for branch-prediction bit */
+#define BP_TAKEN       0x00000000      /* Value to OR in to predict branch */
+#define BP_NOT_TAKEN   0x00000002      /* Value to OR in to predict no branch */
 
 
-/* Some instruction opcodes that we need explicitly */
+/* Some instruction opcodes that we need explicitly */
 #define BE     0x12000000
 #define BG     0x11000000
 #define BGE    0x13000000
 #define BE     0x12000000
 #define BG     0x11000000
 #define BGE    0x13000000
@@ -275,26 +215,25 @@ const pseudo_typeS md_pseudo_table[] =
    used).  */
 #define MEMA_ABASE     0x2000
 
    used).  */
 #define MEMA_ABASE     0x2000
 
-/* Info from which a MEMA or MEMB format instruction can be generated */
-typedef struct
+/* Info from which a MEMA or MEMB format instruction can be generated */
+typedef struct memS
   {
   {
-    /* (First) 32 bits of instruction */
+    /* (First) 32 bits of instruction */
     long opcode;
     long opcode;
-    /* 0-(none), 12- or, 32-bit displacement needed */
+    /* 0-(none), 12- or, 32-bit displacement needed */
     int disp;
     /* The expression in the source instruction from which the
        displacement should be determined.  */
     char *e;
   }
     int disp;
     /* The expression in the source instruction from which the
        displacement should be determined.  */
     char *e;
   }
-
 memS;
 
 memS;
 
-/* The two pieces of info we need to generate a register operand */
+/* The two pieces of info we need to generate a register operand */
 struct regop
   {
 struct regop
   {
-    int mode;                  /* 0 =>local/global/spec reg; 1=> literal or fp reg */
-    int special;               /* 0 =>not a sfr;  1=> is a sfr (not valid w/mode=0) */
-    int n;                     /* Register number or literal value */
+    int mode;                  /* 0 =>local/global/spec reg; 1=> literal or fp reg */
+    int special;               /* 0 =>not a sfr;  1=> is a sfr (not valid w/mode=0) */
+    int n;                     /* Register number or literal value */
   };
 
 /* Number and assembler mnemonic for all registers that can appear in
   };
 
 /* Number and assembler mnemonic for all registers that can appear in
@@ -395,10 +334,10 @@ regnames[] =
 /* Number and assembler mnemonic for all registers that can appear as
    'abase' (indirect addressing) registers.  */
 static const struct
 /* Number and assembler mnemonic for all registers that can appear as
    'abase' (indirect addressing) registers.  */
 static const struct
-  {
-    char *areg_name;
-    int areg_num;
-  }
+{
+  char *areg_name;
+  int areg_num;
+}
 aregs[] =
 {
   { "(pfp)", 0 },
 aregs[] =
 {
   { "(pfp)", 0 },
@@ -442,24 +381,23 @@ aregs[] =
   { NULL, 0 },                         /* END OF LIST */
 };
 
   { NULL, 0 },                         /* END OF LIST */
 };
 
-/* Hash tables */
-static struct hash_control *op_hash;   /* Opcode mnemonics */
-static struct hash_control *reg_hash;  /* Register name hash table */
-static struct hash_control *areg_hash; /* Abase register hash table */
+/* Hash tables */
+static struct hash_control *op_hash;   /* Opcode mnemonics */
+static struct hash_control *reg_hash;  /* Register name hash table */
+static struct hash_control *areg_hash; /* Abase register hash table */
 
 
-/* Architecture for which we are assembling */
-#define ARCH_ANY       0       /* Default: no architecture checking done */
+/* Architecture for which we are assembling */
+#define ARCH_ANY       0       /* Default: no architecture checking done */
 #define ARCH_KA                1
 #define ARCH_KB                2
 #define ARCH_MC                3
 #define ARCH_CA                4
 #define ARCH_JX                5
 #define ARCH_HX                6
 #define ARCH_KA                1
 #define ARCH_KB                2
 #define ARCH_MC                3
 #define ARCH_CA                4
 #define ARCH_JX                5
 #define ARCH_HX                6
-int architecture = ARCH_ANY;   /* Architecture requested on invocation line */
+int architecture = ARCH_ANY;   /* Architecture requested on invocation line */
 int iclasses_seen;             /* OR of instruction classes (I_* constants)
 int iclasses_seen;             /* OR of instruction classes (I_* constants)
-                                *    for which we've actually assembled
-                                *      instructions.
-                                */
+                                     for which we've actually assembled
+                                       instructions.  */
 
 /* BRANCH-PREDICTION INSTRUMENTATION
 
 
 /* BRANCH-PREDICTION INSTRUMENTATION
 
@@ -494,8 +432,7 @@ int iclasses_seen;          /* OR of instruction classes (I_* constants)
 
             Note that input source code is expected to already contain calls
             an external routine that will link the branch local table into a
 
             Note that input source code is expected to already contain calls
             an external routine that will link the branch local table into a
-            list of such tables.
- */
+            list of such tables.  */
 
 /* Number of branches instrumented so far.  Also used to generate
    unique local labels for each instrumented branch.  */
 
 /* Number of branches instrumented so far.  Also used to generate
    unique local labels for each instrumented branch.  */
@@ -512,19 +449,16 @@ static int br_cnt;
 #define BR_TAB_NAME    "__BRANCH_TABLE__"
 /* Name of the table of pointers to branches.  A local (i.e.,
    non-external) symbol.  */
 #define BR_TAB_NAME    "__BRANCH_TABLE__"
 /* Name of the table of pointers to branches.  A local (i.e.,
    non-external) symbol.  */
-\f
-/*****************************************************************************
-   md_begin:  One-time initialization.
 
 
-       Set up hash tables.
+static void ctrl_fmt (char *, long, int);
 
 
-  *************************************************************************** */
+\f
 void
 void
-md_begin ()
+md_begin (void)
 {
 {
-  int i;                       /* Loop counter */
-  const struct i960_opcode *oP;        /* Pointer into opcode table */
-  const char *retval;          /* Value returned by hash functions */
+  int i;                       /* Loop counter */
+  const struct i960_opcode *oP;        /* Pointer into opcode table */
+  const char *retval;          /* Value returned by hash functions */
 
   op_hash = hash_new ();
   reg_hash = hash_new ();
 
   op_hash = hash_new ();
   reg_hash = hash_new ();
@@ -535,7 +469,7 @@ md_begin ()
   retval = 0;
 
   for (oP = i960_opcodes; oP->name && !retval; oP++)
   retval = 0;
 
   for (oP = i960_opcodes; oP->name && !retval; oP++)
-    retval = hash_insert (op_hash, oP->name, (PTR) oP);
+    retval = hash_insert (op_hash, oP->name, (void *) oP);
 
   for (i = 0; regnames[i].reg_name && !retval; i++)
     retval = hash_insert (reg_hash, regnames[i].reg_name,
 
   for (i = 0; regnames[i].reg_name && !retval; i++)
     retval = hash_insert (reg_hash, regnames[i].reg_name,
@@ -549,1860 +483,1418 @@ md_begin ()
     as_fatal (_("Hashing returned \"%s\"."), retval);
 }
 
     as_fatal (_("Hashing returned \"%s\"."), retval);
 }
 
-/*****************************************************************************
-   md_assemble:  Assemble an instruction
+/* parse_expr:         parse an expression
 
 
-   Assumptions about the passed-in text:
-       - all comments, labels removed
-       - text is an instruction
-       - all white space compressed to single blanks
-       - all character constants have been replaced with decimal
+   Use base assembler's expression parser to parse an expression.
+   It, unfortunately, runs off a global which we have to save/restore
+   in order to make it work for us.
 
 
-  *************************************************************************** */
-void
-md_assemble (textP)
-     char *textP;              /* Source text of instruction */
-{
-  /* Parsed instruction text, containing NO whitespace: arg[0]->opcode
-     mnemonic arg[1-3]->operands, with char constants replaced by
-     decimal numbers.  */
-  char *args[4];
+   An empty expression string is treated as an absolute 0.
 
 
-  int n_ops;                   /* Number of instruction operands */
-  /* Pointer to instruction description */
-  struct i960_opcode *oP;
-  /* TRUE iff opcode mnemonic included branch-prediction suffix (".f"
-     or ".t").  */
-  int branch_predict;
-  /* Setting of branch-prediction bit(s) to be OR'd into instruction
-     opcode of CTRL/COBR format instructions.  */
-  long bp_bits;
+   Sets O_illegal regardless of expression evaluation if entire input
+   string is not consumed in the evaluation -- tolerate no dangling junk!  */
 
 
-  int n;                       /* Offset of last character in opcode mnemonic */
+static void
+parse_expr (char *textP,               /* Text of expression to be parsed.  */
+           expressionS *expP)          /* Where to put the results of parsing.  */
+{
+  char *save_in;               /* Save global here.  */
+  symbolS *symP;
 
 
-  const char *bp_error_msg = _("branch prediction invalid on this opcode");
+  know (textP);
 
 
-  /* Parse instruction into opcode and operands */
-  memset (args, '\0', sizeof (args));
-  n_ops = i_scan (textP, args);
-  if (n_ops == -1)
+  if (*textP == '\0')
     {
     {
-      return;                  /* Error message already issued */
+      /* Treat empty string as absolute 0.  */
+      expP->X_add_symbol = expP->X_op_symbol = NULL;
+      expP->X_add_number = 0;
+      expP->X_op = O_constant;
     }
     }
-
-  /* Do "macro substitution" (sort of) on 'ldconst' pseudo-instruction */
-  if (!strcmp (args[0], "ldconst"))
+  else
     {
     {
-      n_ops = parse_ldconst (args);
-      if (n_ops == -1)
-       {
-         return;
-       }
-    }
+      save_in = input_line_pointer;    /* Save global.  */
+      input_line_pointer = textP;      /* Make parser work for us.  */
 
 
-  /* Check for branch-prediction suffix on opcode mnemonic, strip it off */
-  n = strlen (args[0]) - 1;
-  branch_predict = 0;
-  bp_bits = 0;
-  if (args[0][n - 1] == '.' && (args[0][n] == 't' || args[0][n] == 'f'))
-    {
-      /* We could check here to see if the target architecture
-        supports branch prediction, but why bother?  The bit will
-        just be ignored by processors that don't use it.  */
-      branch_predict = 1;
-      bp_bits = (args[0][n] == 't') ? BP_TAKEN : BP_NOT_TAKEN;
-      args[0][n - 1] = '\0';   /* Strip suffix from opcode mnemonic */
-    }
+      (void) expression (expP);
+      if ((size_t) (input_line_pointer - textP) != strlen (textP))
+       /* Did not consume all of the input.  */
+       expP->X_op = O_illegal;
 
 
-  /* Look up opcode mnemonic in table and check number of operands.
-     Check that opcode is legal for the target architecture.  If all
-     looks good, assemble instruction.  */
-  oP = (struct i960_opcode *) hash_find (op_hash, args[0]);
-  if (!oP || !targ_has_iclass (oP->iclass))
-    {
-      as_bad (_("invalid opcode, \"%s\"."), args[0]);
+      symP = expP->X_add_symbol;
+      if (symP && (hash_find (reg_hash, S_GET_NAME (symP))))
+       /* Register name in an expression.  */
+       /* FIXME: this isn't much of a check any more.  */
+       expP->X_op = O_illegal;
 
 
+      input_line_pointer = save_in;    /* Restore global.  */
     }
     }
-  else if (n_ops != oP->num_ops)
-    {
-      as_bad (_("improper number of operands.  expecting %d, got %d"),
-             oP->num_ops, n_ops);
-    }
-  else
+}
+
+/* emit:       output instruction binary
+
+   Output instruction binary, in target byte order, 4 bytes at a time.
+   Return pointer to where it was placed.  */
+
+static char *
+emit (long instr)              /* Word to be output, host byte order.  */
+{
+  char *toP;                   /* Where to output it.  */
+
+  toP = frag_more (4);         /* Allocate storage.  */
+  md_number_to_chars (toP, instr, 4);  /* Convert to target byte order.  */
+  return toP;
+}
+
+/* get_cdisp:  handle displacement for a COBR or CTRL instruction.
+
+   Parse displacement for a COBR or CTRL instruction.
+
+   If successful, output the instruction opcode and set up for it,
+   depending on the arg 'var_frag', either:
+           o an address fixup to be done when all symbol values are known, or
+           o a varying length code fragment, with address fixup info.  This
+               will be done for cobr instructions that may have to be relaxed
+               in to compare/branch instructions (8 bytes) if the final
+               address displacement is greater than 13 bits.  */
+
+static void
+get_cdisp (char *dispP, /* Displacement as specified in source instruction.  */
+          char *ifmtP, /* "COBR" or "CTRL" (for use in error message).  */
+          long instr,  /* Instruction needing the displacement.  */
+          int numbits, /* # bits of displacement (13 for COBR, 24 for CTRL).  */
+          int var_frag,/* 1 if varying length code fragment should be emitted;
+                          0 if an address fix should be emitted.  */
+          int callj)   /* 1 if callj relocation should be done; else 0.  */
+{
+  expressionS e;               /* Parsed expression.  */
+  fixS *fixP;                  /* Structure describing needed address fix.  */
+  char *outP;                  /* Where instruction binary is output to.  */
+
+  fixP = NULL;
+
+  parse_expr (dispP, &e);
+  switch (e.X_op)
     {
     {
-      switch (oP->format)
+    case O_illegal:
+      as_bad (_("expression syntax error"));
+
+    case O_symbol:
+      if (S_GET_SEGMENT (e.X_add_symbol) == now_seg
+         || S_GET_SEGMENT (e.X_add_symbol) == undefined_section)
        {
        {
-       case FBRA:
-       case CTRL:
-         ctrl_fmt (args[1], oP->opcode | bp_bits, oP->num_ops);
-         if (oP->format == FBRA)
-           {
-             /* Now generate a 'bno' to same arg */
-             ctrl_fmt (args[1], BNO | bp_bits, 1);
-           }
-         break;
-       case COBR:
-       case COJ:
-         cobr_fmt (args, oP->opcode | bp_bits, oP);
-         break;
-       case REG:
-         if (branch_predict)
-           {
-             as_warn (bp_error_msg);
-           }
-         reg_fmt (args, oP);
-         break;
-       case MEM1:
-         if (args[0][0] == 'c' && args[0][1] == 'a')
-           {
-             if (branch_predict)
-               {
-                 as_warn (bp_error_msg);
-               }
-             mem_fmt (args, oP, 1);
-             break;
-           }
-       case MEM2:
-       case MEM4:
-       case MEM8:
-       case MEM12:
-       case MEM16:
-         if (branch_predict)
+         if (var_frag)
            {
            {
-             as_warn (bp_error_msg);
+             outP = frag_more (8);     /* Allocate worst-case storage.  */
+             md_number_to_chars (outP, instr, 4);
+             frag_variant (rs_machine_dependent, 4, 4, 1,
+                           adds (e), offs (e), outP);
            }
            }
-         mem_fmt (args, oP, 0);
-         break;
-       case CALLJ:
-         if (branch_predict)
+         else
            {
            {
-             as_warn (bp_error_msg);
+             /* Set up a new fix structure, so address can be updated
+                when all symbol values are known.  */
+             outP = emit (instr);
+             fixP = fix_new (frag_now,
+                             outP - frag_now->fr_literal,
+                             4,
+                             adds (e),
+                             offs (e),
+                             1,
+                             NO_RELOC);
+
+             fixP->fx_tcbit = callj;
+
+             /* We want to modify a bit field when the address is
+                known.  But we don't need all the garbage in the
+                bit_fix structure.  So we're going to lie and store
+                the number of bits affected instead of a pointer.  */
+             fixP->fx_bit_fixP = (bit_fixS *) (size_t) numbits;
            }
            }
-         /* Output opcode & set up "fixup" (relocation); flag
-            relocation as 'callj' type.  */
-         know (oP->num_ops == 1);
-         get_cdisp (args[1], "CTRL", oP->opcode, 24, 0, 1);
-         break;
-       default:
-         BAD_CASE (oP->format);
-         break;
        }
        }
-    }
-}                              /* md_assemble() */
-
-/*****************************************************************************
-   md_number_to_chars:  convert a number to target byte order
+      else
+       as_bad (_("attempt to branch into different segment"));
+      break;
 
 
-  *************************************************************************** */
-void
-md_number_to_chars (buf, value, n)
-     char *buf;
-     valueT value;
-     int n;
-{
-  number_to_chars_littleendian (buf, value, n);
+    default:
+      as_bad (_("target of %s instruction must be a label"), ifmtP);
+      break;
+    }
 }
 
 }
 
-/*****************************************************************************
-   md_chars_to_number:  convert from target byte order to host byte order.
-
-  *************************************************************************** */
-int
-md_chars_to_number (val, n)
-     unsigned char *val;       /* Value in target byte order */
-     int n;                    /* Number of bytes in the input */
+static int
+md_chars_to_number (char * val,                /* Value in target byte order.  */
+                   int n)              /* Number of bytes in the input.  */
 {
   int retval;
 
   for (retval = 0; n--;)
     {
       retval <<= 8;
 {
   int retval;
 
   for (retval = 0; n--;)
     {
       retval <<= 8;
-      retval |= val[n];
+      retval |= (unsigned char) val[n];
     }
   return retval;
 }
 
     }
   return retval;
 }
 
-#define MAX_LITTLENUMS 6
-#define LNUM_SIZE      sizeof (LITTLENUM_TYPE)
+/* mema_to_memb:       convert a MEMA-format opcode to a MEMB-format opcode.
 
 
-/*****************************************************************************
-   md_atof:    convert ascii to floating point
-
-   Turn a string at input_line_pointer into a floating point constant of type
-   'type', and store the appropriate bytes at *litP.  The number of LITTLENUMS
-   emitted is returned at 'sizeP'.  An error message is returned, or a pointer
-   to an empty message if OK.
+   There are 2 possible MEMA formats:
+       - displacement only
+       - displacement + abase
 
 
-   Note we call the i386 floating point routine, rather than complicating
-   things with more files or symbolic links.
+   They are distinguished by the setting of the MEMA_ABASE bit.  */
 
 
-  *************************************************************************** */
-char *
-md_atof (type, litP, sizeP)
-     int type;
-     char *litP;
-     int *sizeP;
+static void
+mema_to_memb (char * opcodeP)  /* Where to find the opcode, in target byte order.  */
 {
 {
-  LITTLENUM_TYPE words[MAX_LITTLENUMS];
-  LITTLENUM_TYPE *wordP;
-  int prec;
-  char *t;
-  char *atof_ieee ();
-
-  switch (type)
-    {
-    case 'f':
-    case 'F':
-      prec = 2;
-      break;
+  long opcode;                 /* Opcode in host byte order.  */
+  long mode;                   /* Mode bits for MEMB instruction.  */
 
 
-    case 'd':
-    case 'D':
-      prec = 4;
-      break;
+  opcode = md_chars_to_number (opcodeP, 4);
+  know (!(opcode & MEMB_BIT));
 
 
-    case 't':
-    case 'T':
-      prec = 5;
-      type = 'x';              /* That's what atof_ieee() understands */
-      break;
+  mode = MEMB_BIT | D_BIT;
+  if (opcode & MEMA_ABASE)
+    mode |= A_BIT;
 
 
-    default:
-      *sizeP = 0;
-      return _("Bad call to md_atof()");
-    }
+  opcode &= 0xffffc000;                /* Clear MEMA offset and mode bits.  */
+  opcode |= mode;              /* Set MEMB mode bits.  */
 
 
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    {
-      input_line_pointer = t;
-    }
+  md_number_to_chars (opcodeP, opcode, 4);
+}
 
 
-  *sizeP = prec * LNUM_SIZE;
+/* targ_has_sfr:
 
 
-  /* Output the LITTLENUMs in REVERSE order in accord with i80960
-     word-order.  (Dunno why atof_ieee doesn't do it in the right
-     order in the first place -- probably because it's a hack of
-     atof_m68k.)  */
+   Return TRUE iff the target architecture supports the specified
+   special-function register (sfr).  */
 
 
-  for (wordP = words + prec - 1; prec--;)
+static int
+targ_has_sfr (int n)           /* Number (0-31) of sfr.  */
+{
+  switch (architecture)
     {
     {
-      md_number_to_chars (litP, (long) (*wordP--), LNUM_SIZE);
-      litP += sizeof (LITTLENUM_TYPE);
+    case ARCH_KA:
+    case ARCH_KB:
+    case ARCH_MC:
+    case ARCH_JX:
+      return 0;
+    case ARCH_HX:
+      return ((0 <= n) && (n <= 4));
+    case ARCH_CA:
+    default:
+      return ((0 <= n) && (n <= 2));
     }
     }
-
-  return 0;
 }
 
 }
 
-/*****************************************************************************
-   md_number_to_imm
+/* Look up a (suspected) register name in the register table and return the
+   associated register number (or -1 if not found).  */
 
 
-  *************************************************************************** */
-void
-md_number_to_imm (buf, val, n)
-     char *buf;
-     long val;
-     int n;
+static int
+get_regnum (char *regname)     /* Suspected register name.  */
 {
 {
-  md_number_to_chars (buf, val, n);
+  int *rP;
+
+  rP = (int *) hash_find (reg_hash, regname);
+  return (rP == NULL) ? -1 : *rP;
 }
 
 }
 
-/*****************************************************************************
-   md_number_to_disp
+/* syntax: Issue a syntax error.  */
 
 
-  *************************************************************************** */
-void
-md_number_to_disp (buf, val, n)
-     char *buf;
-     long val;
-     int n;
+static void
+syntax (void)
 {
 {
-  md_number_to_chars (buf, val, n);
+  as_bad (_("syntax error"));
 }
 
 }
 
-/*****************************************************************************
-   md_number_to_field:
+/* parse_regop: parse a register operand.
 
 
-       Stick a value (an address fixup) into a bit field of
-       previously-generated instruction.
+   In case of illegal operand, issue a message and return some valid
+   information so instruction processing can continue.  */
 
 
-  *************************************************************************** */
-void
-md_number_to_field (instrP, val, bfixP)
-     char *instrP;             /* Pointer to instruction to be fixed */
-     long val;                 /* Address fixup value */
-     bit_fixS *bfixP;          /* Description of bit field to be fixed up */
+static void
+parse_regop (struct regop *regopP,     /* Where to put description of register operand.  */
+            char *optext,              /* Text of operand.  */
+            char opdesc)               /* Descriptor byte:  what's legal for this operand.  */
 {
 {
-  int numbits;                 /* Length of bit field to be fixed */
-  long instr;                  /* 32-bit instruction to be fixed-up */
-  long sign;                   /* 0 or -1, according to sign bit of 'val' */
+  int n;                       /* Register number.  */
+  expressionS e;               /* Parsed expression.  */
 
 
-  /* Convert instruction back to host byte order.  */
-  instr = md_chars_to_number (instrP, 4);
-
-  /* Surprise! -- we stored the number of bits to be modified rather
-     than a pointer to a structure.  */
-  numbits = (int) bfixP;
-  if (numbits == 1)
+  /* See if operand is a register.  */
+  n = get_regnum (optext);
+  if (n >= 0)
     {
     {
-      /* This is a no-op, stuck here by reloc_callj() */
-      return;
-    }
+      if (IS_RG_REG (n))
+       {
+         /* Global or local register.  */
+         if (!REG_ALIGN (opdesc, n))
+           as_bad (_("unaligned register"));
 
 
-  know ((numbits == 13) || (numbits == 24));
+         regopP->n = n;
+         regopP->mode = 0;
+         regopP->special = 0;
+         return;
+       }
+      else if (IS_FP_REG (n) && FP_OK (opdesc))
+       {
+         /* Floating point register, and it's allowed.  */
+         regopP->n = n - FP0;
+         regopP->mode = 1;
+         regopP->special = 0;
+         return;
+       }
+      else if (IS_SF_REG (n) && SFR_OK (opdesc))
+       {
+         /* Special-function register, and it's allowed.  */
+         regopP->n = n - SF0;
+         regopP->mode = 0;
+         regopP->special = 1;
+         if (!targ_has_sfr (regopP->n))
+           as_bad (_("no such sfr in this architecture"));
 
 
-  /* Propagate sign bit of 'val' for the given number of bits.  Result
-     should be all 0 or all 1.  */
-  sign = val >> ((int) numbits - 1);
-  if (((val < 0) && (sign != -1))
-      || ((val > 0) && (sign != 0)))
-    {
-      as_bad (_("Fixup of %ld too large for field width of %d"),
-             val, numbits);
-    }
-  else
-    {
-      /* Put bit field into instruction and write back in target
-         * byte order.
-       */
-      val &= ~(-1 << (int) numbits);   /* Clear unused sign bits */
-      instr |= val;
-      md_number_to_chars (instrP, instr, 4);
+         return;
+       }
     }
     }
-}                              /* md_number_to_field() */
-\f
-
-/*****************************************************************************
-   md_parse_option
-       Invocation line includes a switch not recognized by the base assembler.
-       See if it's a processor-specific option.  For the 960, these are:
-
-       -norelax:
-               Conditional branch instructions that require displacements
-               greater than 13 bits (or that have external targets) should
-               generate errors.  The default is to replace each such
-               instruction with the corresponding compare (or chkbit) and
-               branch instructions.  Note that the Intel "j" cobr directives
-               are ALWAYS "de-optimized" in this way when necessary,
-               regardless of the setting of this option.
-
-       -b:
-               Add code to collect information about branches taken, for
-               later optimization of branch prediction bits by a separate
-               tool.  COBR and CNTL format instructions have branch
-               prediction bits (in the CX architecture);  if "BR" represents
-               an instruction in one of these classes, the following rep-
-               resents the code generated by the assembler:
-
-                       call    <increment routine>
-                       .word   0       # pre-counter
-               Label:  BR
-                       call    <increment routine>
-                       .word   0       # post-counter
-
-               A table of all such "Labels" is also generated.
-
-       -AKA, -AKB, -AKC, -ASA, -ASB, -AMC, -ACA:
-               Select the 80960 architecture.  Instructions or features not
-               supported by the selected architecture cause fatal errors.
-               The default is to generate code for any instruction or feature
-               that is supported by SOME version of the 960 (even if this
-               means mixing architectures!).
-
-  ****************************************************************************/
-
-CONST char *md_shortopts = "A:b";
-struct option md_longopts[] =
-{
-#define OPTION_LINKRELAX (OPTION_MD_BASE)
-  {"linkrelax", no_argument, NULL, OPTION_LINKRELAX},
-  {"link-relax", no_argument, NULL, OPTION_LINKRELAX},
-#define OPTION_NORELAX (OPTION_MD_BASE + 1)
-  {"norelax", no_argument, NULL, OPTION_NORELAX},
-  {"no-relax", no_argument, NULL, OPTION_NORELAX},
-  {NULL, no_argument, NULL, 0}
-};
-size_t md_longopts_size = sizeof (md_longopts);
-
-struct tabentry
-  {
-    char *flag;
-    int arch;
-  };
-static const struct tabentry arch_tab[] =
-{
-  {"KA", ARCH_KA},
-  {"KB", ARCH_KB},
-  {"SA", ARCH_KA},             /* Synonym for KA */
-  {"SB", ARCH_KB},             /* Synonym for KB */
-  {"KC", ARCH_MC},             /* Synonym for MC */
-  {"MC", ARCH_MC},
-  {"CA", ARCH_CA},
-  {"JX", ARCH_JX},
-  {"HX", ARCH_HX},
-  {NULL, 0}
-};
-
-int
-md_parse_option (c, arg)
-     int c;
-     char *arg;
-{
-  switch (c)
+  else if (LIT_OK (opdesc))
     {
     {
-    case OPTION_LINKRELAX:
-      linkrelax = 1;
-      flag_keep_locals = 1;
-      break;
-
-    case OPTION_NORELAX:
-      norelax = 1;
-      break;
-
-    case 'b':
-      instrument_branches = 1;
-      break;
-
-    case 'A':
-      {
-       const struct tabentry *tp;
-       char *p = arg;
-
-       for (tp = arch_tab; tp->flag != NULL; tp++)
-         if (!strcmp (p, tp->flag))
-           break;
+      /* How about a literal?  */
+      regopP->mode = 1;
+      regopP->special = 0;
+      if (FP_OK (opdesc))
+       {
+         /* Floating point literal acceptable.  */
+         /* Skip over 0f, 0d, or 0e prefix.  */
+         if ((optext[0] == '0')
+             && (optext[1] >= 'd')
+             && (optext[1] <= 'f'))
+           optext += 2;
 
 
-       if (tp->flag == NULL)
-         {
-           as_bad (_("invalid architecture %s"), p);
-           return 0;
-         }
-       else
-         architecture = tp->arch;
-      }
-      break;
+         if (!strcmp (optext, "0.0") || !strcmp (optext, "0"))
+           {
+             regopP->n = 0x10;
+             return;
+           }
 
 
-    default:
-      return 0;
+         if (!strcmp (optext, "1.0") || !strcmp (optext, "1"))
+           {
+             regopP->n = 0x16;
+             return;
+           }
+       }
+      else
+       {
+         /* Fixed point literal acceptable.  */
+         parse_expr (optext, &e);
+         if (e.X_op != O_constant
+             || (offs (e) < 0) || (offs (e) > 31))
+           {
+             as_bad (_("illegal literal"));
+             offs (e) = 0;
+           }
+         regopP->n = offs (e);
+         return;
+       }
     }
 
     }
 
-  return 1;
+  /* Nothing worked.  */
+  syntax ();
+  regopP->mode = 0;            /* Register r0 is always a good one.  */
+  regopP->n = 0;
+  regopP->special = 0;
 }
 
 }
 
-void
-md_show_usage (stream)
-     FILE *stream;
-{
-  int i;
-  fprintf (stream, _("I960 options:\n"));
-  for (i = 0; arch_tab[i].flag; i++)
-    fprintf (stream, "%s-A%s", i ? " | " : "", arch_tab[i].flag);
-  fprintf (stream, _("\n\
-                       specify variant of 960 architecture\n\
--b                     add code to collect statistics about branches taken\n\
--link-relax            preserve individual alignment directives so linker\n\
-                       can do relaxing (b.out format only)\n\
--no-relax              don't alter compare-and-branch instructions for\n\
-                       long displacements\n"));
-}
-\f
+/* get_ispec:  parse a memory operand for an index specification
 
 
-/*****************************************************************************
-   md_convert_frag:
-       Called by base assembler after address relaxation is finished:  modify
-       variable fragments according to how much relaxation was done.
+   Here, an "index specification" is taken to be anything surrounded
+   by square brackets and NOT followed by anything else.
 
 
-       If the fragment substate is still 1, a 13-bit displacement was enough
-       to reach the symbol in question.  Set up an address fixup, but otherwise
-       leave the cobr instruction alone.
+   If it's found, detach it from the input string, remove the surrounding
+   square brackets, and return a pointer to it.  Otherwise, return NULL.  */
 
 
-       If the fragment substate is 2, a 13-bit displacement was not enough.
-       Replace the cobr with a two instructions (a compare and a branch).
+static char *
+get_ispec (char *textP)  /* Pointer to memory operand from source instruction, no white space.  */
 
 
-  *************************************************************************** */
-#ifndef BFD_ASSEMBLER
-void
-md_convert_frag (headers, seg, fragP)
-     object_headers *headers;
-     segT seg;
-     fragS *fragP;
-#else
-void
-md_convert_frag (abfd, sec, fragP)
-     bfd *abfd;
-     segT sec;
-     fragS *fragP;
-#endif
 {
 {
-  fixS *fixP;                  /* Structure describing needed address fix */
+  /* Points to start of index specification.  */
+  char *start;
+  /* Points to end of index specification.  */
+  char *end;
 
 
-  switch (fragP->fr_subtype)
+  /* Find opening square bracket, if any.  */
+  start = strchr (textP, '[');
+
+  if (start != NULL)
     {
     {
-    case 1:
-      /* LEAVE SINGLE COBR INSTRUCTION */
-      fixP = fix_new (fragP,
-                     fragP->fr_opcode - fragP->fr_literal,
-                     4,
-                     fragP->fr_symbol,
-                     fragP->fr_offset,
-                     1,
-                     NO_RELOC);
+      /* Eliminate '[', detach from rest of operand.  */
+      *start++ = '\0';
 
 
-      fixP->fx_bit_fixP = (bit_fixS *) 13;     /* size of bit field */
-      break;
-    case 2:
-      /* REPLACE COBR WITH COMPARE/BRANCH INSTRUCTIONS */
-      relax_cobr (fragP);
-      break;
-    default:
-      BAD_CASE (fragP->fr_subtype);
-      break;
+      end = strchr (start, ']');
+
+      if (end == NULL)
+       as_bad (_("unmatched '['"));
+      else
+       {
+         /* Eliminate ']' and make sure it was the last thing
+            in the string.  */
+         *end = '\0';
+         if (*(end + 1) != '\0')
+           as_bad (_("garbage after index spec ignored"));
+       }
     }
     }
+  return start;
 }
 
 }
 
-/*****************************************************************************
-   md_estimate_size_before_relax:  How much does it look like *fragP will grow?
+/* parse_memop:        parse a memory operand
 
 
-       Called by base assembler just before address relaxation.
-       Return the amount by which the fragment will grow.
+       This routine is based on the observation that the 4 mode bits of the
+       MEMB format, taken individually, have fairly consistent meaning:
 
 
-       Any symbol that is now undefined will not become defined; cobr's
-       based on undefined symbols will have to be replaced with a compare
-       instruction and a branch instruction, and the code fragment will grow
-       by 4 bytes.
+                M3 (bit 13): 1 if displacement is present (D_BIT)
+                M2 (bit 12): 1 for MEMB instructions (MEMB_BIT)
+                M1 (bit 11): 1 if index is present (I_BIT)
+                M0 (bit 10): 1 if abase is present (A_BIT)
 
 
-  *************************************************************************** */
-int
-md_estimate_size_before_relax (fragP, segment_type)
-     register fragS *fragP;
-     register segT segment_type;
-{
-  /* If symbol is undefined in this segment, go to "relaxed" state
-     (compare and branch instructions instead of cobr) right now.  */
-  if (S_GET_SEGMENT (fragP->fr_symbol) != segment_type)
-    {
-      relax_cobr (fragP);
-      return 4;
-    }
-  return 0;
-}                              /* md_estimate_size_before_relax() */
+       So we parse the memory operand and set bits in the mode as we find
+       things.  Then at the end, if we go to MEMB format, we need only set
+       the MEMB bit (M2) and our mode is built for us.
 
 
-#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+       Unfortunately, I said "fairly consistent".  The exceptions:
 
 
-/*****************************************************************************
-   md_ri_to_chars:
-       This routine exists in order to overcome machine byte-order problems
-       when dealing with bit-field entries in the relocation_info struct.
+                DBIA
+                0100   Would seem illegal, but means "abase-only".
 
 
-       But relocation info will be used on the host machine only (only
-       executable code is actually downloaded to the i80960).  Therefore,
-       we leave it in host byte order.
+                0101   Would seem to mean "abase-only" -- it means IP-relative.
+                       Must be converted to 0100.
 
 
-       The above comment is no longer true.  This routine now really
-       does do the reordering (Ian Taylor 28 Aug 92).
+                0110   Would seem to mean "index-only", but is reserved.
+                       We turn on the D bit and provide a 0 displacement.
 
 
-  *************************************************************************** */
+       The other thing to observe is that we parse from the right, peeling
+       things * off as we go:  first any index spec, then any abase, then
+       the displacement.  */
 
 static void
 
 static void
-md_ri_to_chars (where, ri)
-     char *where;
-     struct relocation_info *ri;
-{
-  md_number_to_chars (where, ri->r_address,
-                     sizeof (ri->r_address));
-  where[4] = ri->r_index & 0x0ff;
-  where[5] = (ri->r_index >> 8) & 0x0ff;
-  where[6] = (ri->r_index >> 16) & 0x0ff;
-  where[7] = ((ri->r_pcrel << 0)
-             | (ri->r_length << 1)
-             | (ri->r_extern << 3)
-             | (ri->r_bsr << 4)
-             | (ri->r_disp << 5)
-             | (ri->r_callj << 6));
-}
-
-#endif /* defined(OBJ_AOUT) | defined(OBJ_BOUT) */
-
-\f
-/* FOLLOWING ARE THE LOCAL ROUTINES, IN ALPHABETICAL ORDER  */
-
-/*****************************************************************************
-   brcnt_emit: Emit code to increment inline branch counter.
+parse_memop (memS *memP,       /* Where to put the results.  */
+            char *argP,        /* Text of the operand to be parsed.  */
+            int optype)        /* MEM1, MEM2, MEM4, MEM8, MEM12, or MEM16.  */
+{
+  char *indexP;                        /* Pointer to index specification with "[]" removed.  */
+  char *p;                     /* Temp char pointer.  */
+  char iprel_flag;             /* True if this is an IP-relative operand.  */
+  int regnum;                  /* Register number.  */
+  /* Scale factor: 1,2,4,8, or 16.  Later converted to internal format
+     (0,1,2,3,4 respectively).  */
+  int scale;
+  int mode;                    /* MEMB mode bits.  */
+  int *intP;                   /* Pointer to register number.  */
 
 
-       See the comments above the declaration of 'br_cnt' for details on
-       branch-prediction instrumentation.
-  *************************************************************************** */
-static void
-brcnt_emit ()
-{
-  ctrl_fmt (BR_CNT_FUNC, CALL, 1);     /* Emit call to "increment" routine */
-  emit (0);                    /* Emit inline counter to be incremented */
-}
+  /* The following table contains the default scale factors for each
+     type of memory instruction.  It is accessed using (optype-MEM1)
+     as an index -- thus it assumes the 'optype' constants are
+     assigned consecutive values, in the order they appear in this
+     table.  */
+  static const int def_scale[] =
+  {
+    1,                         /* MEM1 */
+    2,                         /* MEM2 */
+    4,                         /* MEM4 */
+    8,                         /* MEM8 */
+    -1,                                /* MEM12 -- no valid default */
+    16                         /* MEM16 */
+  };
 
 
-/*****************************************************************************
-   brlab_next: generate the next branch local label
+  iprel_flag = mode = 0;
 
 
-       See the comments above the declaration of 'br_cnt' for details on
-       branch-prediction instrumentation.
-  *************************************************************************** */
-static char *
-brlab_next ()
-{
-  static char buf[20];
+  /* Any index present? */
+  indexP = get_ispec (argP);
+  if (indexP)
+    {
+      p = strchr (indexP, '*');
+      if (p == NULL)
+       {
+         /* No explicit scale -- use default for this instruction
+            type and assembler mode.  */
+         if (flag_mri)
+           scale = 1;
+         else
+           /* GNU960 compatibility */
+           scale = def_scale[optype - MEM1];
+       }
+      else
+       {
+         *p++ = '\0';          /* Eliminate '*' */
 
 
-  sprintf (buf, "%s%d", BR_LABEL_BASE, br_cnt++);
-  return buf;
-}
+         /* Now indexP->a '\0'-terminated register name,
+            and p->a scale factor.  */
 
 
-/*****************************************************************************
-   brtab_emit: generate the fetch-prediction branch table.
+         if (!strcmp (p, "16"))
+           scale = 16;
+         else if (strchr ("1248", *p) && (p[1] == '\0'))
+           scale = *p - '0';
+         else
+           scale = -1;
+       }
 
 
-       See the comments above the declaration of 'br_cnt' for details on
-       branch-prediction instrumentation.
+      regnum = get_regnum (indexP);    /* Get index reg. # */
+      if (!IS_RG_REG (regnum))
+       {
+         as_bad (_("invalid index register"));
+         return;
+       }
 
 
-       The code emitted here would be functionally equivalent to the following
-       example assembler source.
+      /* Convert scale to its binary encoding.  */
+      switch (scale)
+       {
+       case 1:
+         scale = 0 << 7;
+         break;
+       case 2:
+         scale = 1 << 7;
+         break;
+       case 4:
+         scale = 2 << 7;
+         break;
+       case 8:
+         scale = 3 << 7;
+         break;
+       case 16:
+         scale = 4 << 7;
+         break;
+       default:
+         as_bad (_("invalid scale factor"));
+         return;
+       };
 
 
-                       .data
-                       .align  2
-          BR_TAB_NAME:
-                       .word   0               # link to next table
-                       .word   3               # length of table
-                       .word   LBRANCH0        # 1st entry in table proper
-                       .word   LBRANCH1
-                       .word   LBRANCH2
-  **************************************************************************** */
-void
-brtab_emit ()
-{
-  int i;
-  char buf[20];
-  char *p;                     /* Where the binary was output to */
-  /* Pointer to description of deferred address fixup.  */
-  fixS *fixP;
+      memP->opcode |= scale | regnum;  /* Set index bits in opcode.  */
+      mode |= I_BIT;                   /* Found a valid index spec.  */
+    }
 
 
-  if (!instrument_branches)
+  /* Any abase (Register Indirect) specification present?  */
+  if ((p = strrchr (argP, '(')) != NULL)
     {
     {
-      return;
+      /* "(" is there -- does it start a legal abase spec?  If not, it
+         could be part of a displacement expression.  */
+      intP = (int *) hash_find (areg_hash, p);
+      if (intP != NULL)
+       {
+         /* Got an abase here.  */
+         regnum = *intP;
+         *p = '\0';            /* Discard register spec.  */
+         if (regnum == IPREL)
+           /* We have to specialcase ip-rel mode.  */
+           iprel_flag = 1;
+         else
+           {
+             memP->opcode |= regnum << 14;
+             mode |= A_BIT;
+           }
+       }
     }
 
     }
 
-  subseg_set (data_section, 0);        /*      .data */
-  frag_align (2, 0, 0);                /*      .align 2 */
-  record_alignment (now_seg, 2);
-  colon (BR_TAB_NAME);         /* BR_TAB_NAME: */
-  emit (0);                    /*      .word 0 #link to next table */
-  emit (br_cnt);               /*      .word n #length of table */
+  /* Any expression present?  */
+  memP->e = argP;
+  if (*argP != '\0')
+    mode |= D_BIT;
 
 
-  for (i = 0; i < br_cnt; i++)
+  /* Special-case ip-relative addressing.  */
+  if (iprel_flag)
     {
     {
-      sprintf (buf, "%s%d", BR_LABEL_BASE, i);
-      p = emit (0);
-      fixP = fix_new (frag_now,
-                     p - frag_now->fr_literal,
-                     4,
-                     symbol_find (buf),
-                     0,
-                     0,
-                     NO_RELOC);
+      if (mode & I_BIT)
+       syntax ();
+      else
+       {
+         memP->opcode |= 5 << 10;      /* IP-relative mode.  */
+         memP->disp = 32;
+       }
+      return;
     }
     }
-}
 
 
-/*****************************************************************************
-   cobr_fmt:   generate a COBR-format instruction
+  /* Handle all other modes.  */
+  switch (mode)
+    {
+    case D_BIT | A_BIT:
+      /* Go with MEMA instruction format for now (grow to MEMB later
+         if 12 bits is not enough for the displacement).  MEMA format
+         has a single mode bit: set it to indicate that abase is
+         present.  */
+      memP->opcode |= MEMA_ABASE;
+      memP->disp = 12;
+      break;
 
 
-  *************************************************************************** */
-static
-void
-cobr_fmt (arg, opcode, oP)
-     /* arg[0]->opcode mnemonic, arg[1-3]->operands (ascii) */
-     char *arg[];
-     /* Opcode, with branch-prediction bits already set if necessary.  */
-     long opcode;
-     /* Pointer to description of instruction.  */
-     struct i960_opcode *oP;
-{
-  long instr;                  /* 32-bit instruction */
-  struct regop regop;          /* Description of register operand */
-  int n;                       /* Number of operands */
-  int var_frag;                        /* 1 if varying length code fragment should
-                                *    be emitted;  0 if an address fix
-                                *      should be emitted.
-                                */
+    case D_BIT:
+      /* Go with MEMA instruction format for now (grow to MEMB later
+         if 12 bits is not enough for the displacement).  */
+      memP->disp = 12;
+      break;
 
 
-  instr = opcode;
-  n = oP->num_ops;
+    case A_BIT:
+      /* For some reason, the bit string for this mode is not
+         consistent: it should be 0 (exclusive of the MEMB bit), so we
+         set it "by hand" here.  */
+      memP->opcode |= MEMB_BIT;
+      break;
 
 
-  if (n >= 1)
-    {
-      /* First operand (if any) of a COBR is always a register
-        operand.  Parse it.  */
-      parse_regop (&regop, arg[1], oP->operand[0]);
-      instr |= (regop.n << 19) | (regop.mode << 13);
-    }
-  if (n >= 2)
-    {
-      /* Second operand (if any) of a COBR is always a register
-        operand.  Parse it.  */
-    parse_regop (&regop, arg[2], oP->operand[1]);
-      instr |= (regop.n << 14) | regop.special;
-    }
+    case A_BIT | I_BIT:
+      /* set MEMB bit in mode, and OR in mode bits.  */
+      memP->opcode |= mode | MEMB_BIT;
+      break;
 
 
-  if (n < 3)
-    {
-      emit (instr);
+    case I_BIT:
+      /* Treat missing displacement as displacement of 0.  */
+      mode |= D_BIT;
+      /* Fall into next case.  */
+    case D_BIT | A_BIT | I_BIT:
+    case D_BIT | I_BIT:
+      /* Set MEMB bit in mode, and OR in mode bits.  */
+      memP->opcode |= mode | MEMB_BIT;
+      memP->disp = 32;
+      break;
 
 
+    default:
+      syntax ();
+      break;
     }
     }
-  else
-    {
-      if (instrument_branches)
-       {
-         brcnt_emit ();
-         colon (brlab_next ());
-       }
+}
 
 
-      /* A third operand to a COBR is always a displacement.  Parse
-         it; if it's relaxable (a cobr "j" directive, or any cobr
-         other than bbs/bbc when the "-norelax" option is not in use)
-         set up a variable code fragment; otherwise set up an address
-         fix.  */
-      var_frag = !norelax || (oP->format == COJ);      /* TRUE or FALSE */
-      get_cdisp (arg[3], "COBR", instr, 13, var_frag, 0);
+/* Generate a MEMA- or MEMB-format instruction.  */
 
 
-      if (instrument_branches)
-       {
-         brcnt_emit ();
-       }
-    }
-}                              /* cobr_fmt() */
+static void
+mem_fmt (char *args[],         /* args[0]->opcode mnemonic, args[1-3]->operands.  */
+        struct i960_opcode *oP,/* Pointer to description of instruction.  */
+        int callx)             /* Is this a callx opcode.  */
+{
+  int i;                       /* Loop counter.  */
+  struct regop regop;          /* Description of register operand.  */
+  char opdesc;                 /* Operand descriptor byte.  */
+  memS instr;                  /* Description of binary to be output.  */
+  char *outP;                  /* Where the binary was output to.  */
+  expressionS exp;             /* Parsed expression.  */
+  /* ->description of deferred address fixup.  */
+  fixS *fixP;
 
 
-/*****************************************************************************
-   ctrl_fmt:   generate a CTRL-format instruction
+#ifdef OBJ_COFF
+  /* COFF support isn't in place yet for callx relaxing.  */
+  callx = 0;
+#endif
 
 
-  *************************************************************************** */
-static
-void
-ctrl_fmt (targP, opcode, num_ops)
-     char *targP;              /* Pointer to text of lone operand (if any) */
-     long opcode;              /* Template of instruction */
-     int num_ops;              /* Number of operands */
-{
-  int instrument;              /* TRUE iff we should add instrumentation to track
-                                  * how often the branch is taken
-                                */
+  memset (&instr, '\0', sizeof (memS));
+  instr.opcode = oP->opcode;
 
 
-  if (num_ops == 0)
-    {
-      emit (opcode);           /* Output opcode */
-    }
-  else
+  /* Process operands.  */
+  for (i = 1; i <= oP->num_ops; i++)
     {
     {
+      opdesc = oP->operand[i - 1];
 
 
-      instrument = instrument_branches && (opcode != CALL)
-       && (opcode != B) && (opcode != RET) && (opcode != BAL);
-
-      if (instrument)
-       {
-         brcnt_emit ();
-         colon (brlab_next ());
-       }
-
-      /* The operand MUST be an ip-relative displacment. Parse it
-         * and set up address fix for the instruction we just output.
-       */
-      get_cdisp (targP, "CTRL", opcode, 24, 0, 0);
-
-      if (instrument)
+      if (MEMOP (opdesc))
+       parse_memop (&instr, args[i], oP->format);
+      else
        {
        {
-         brcnt_emit ();
+         parse_regop (&regop, args[i], opdesc);
+         instr.opcode |= regop.n << 19;
        }
     }
 
        }
     }
 
-}
-
-/*****************************************************************************
-   emit:       output instruction binary
+  /* Parse the displacement; this must be done before emitting the
+     opcode, in case it is an expression using `.'.  */
+  parse_expr (instr.e, &exp);
 
 
-       Output instruction binary, in target byte order, 4 bytes at a time.
-       Return pointer to where it was placed.
+  /* Output opcode.  */
+  outP = emit (instr.opcode);
 
 
-  *************************************************************************** */
-static
-char *
-emit (instr)
-     long instr;               /* Word to be output, host byte order */
-{
-  char *toP;                   /* Where to output it */
+  if (instr.disp == 0)
+    return;
 
 
-  toP = frag_more (4);         /* Allocate storage */
-  md_number_to_chars (toP, instr, 4);  /* Convert to target byte order */
-  return toP;
-}
+  /* Process the displacement.  */
+  switch (exp.X_op)
+    {
+    case O_illegal:
+      as_bad (_("expression syntax error"));
+      break;
 
 
-/*****************************************************************************
-   get_args:   break individual arguments out of comma-separated list
+    case O_constant:
+      if (instr.disp == 32)
+       (void) emit (offs (exp));       /* Output displacement.  */
+      else
+       {
+         /* 12-bit displacement.  */
+         if (offs (exp) & ~0xfff)
+           {
+             /* Won't fit in 12 bits: convert already-output
+                instruction to MEMB format, output
+                displacement.  */
+             mema_to_memb (outP);
+             (void) emit (offs (exp));
+           }
+         else
+           {
+             /* WILL fit in 12 bits:  OR into opcode and
+                overwrite the binary we already put out.  */
+             instr.opcode |= offs (exp);
+             md_number_to_chars (outP, instr.opcode, 4);
+           }
+       }
+      break;
 
 
-   Input assumptions:
-       - all comments and labels have been removed
-       - all strings of whitespace have been collapsed to a single blank.
-       - all character constants ('x') have been replaced with decimal
+    default:
+      if (instr.disp == 12)
+       /* Displacement is dependent on a symbol, whose value
+          may change at link time.  We HAVE to reserve 32 bits.
+          Convert already-output opcode to MEMB format.  */
+       mema_to_memb (outP);
 
 
-   Output:
-       args[0] is untouched. args[1] points to first operand, etc. All args:
-       - are NULL-terminated
-       - contain no whitespace
+      /* Output 0 displacement and set up address fixup for when
+         this symbol's value becomes known.  */
+      outP = emit ((long) 0);
+      fixP = fix_new_exp (frag_now,
+                         outP - frag_now->fr_literal,
+                         4, &exp, 0, NO_RELOC);
+      /* Steve's linker relaxing hack.  Mark this 32-bit relocation as
+         being in the instruction stream, specifically as part of a callx
+         instruction.  */
+      fixP->fx_bsr = callx;
+      break;
+    }
+}
 
 
-   Return value:
-       Number of operands (0,1,2, or 3) or -1 on error.
+/* targ_has_iclass:
+
+   Return TRUE iff the target architecture supports the indicated
+   class of instructions.  */
 
 
-  *************************************************************************** */
 static int
 static int
-get_args (p, args)
-     /* Pointer to comma-separated operands; MUCKED BY US */
-     register char *p;
-     /* Output arg: pointers to operands placed in args[1-3].  MUST
-        ACCOMMODATE 4 ENTRIES (args[0-3]).  */
-     char *args[];
+targ_has_iclass (int ic) /* Instruction class;  one of:
+                           I_BASE, I_CX, I_DEC, I_KX, I_FP, I_MIL, I_CASIM, I_CX2, I_HX, I_HX2.  */
 {
 {
-  register int n;              /* Number of operands */
-  register char *to;
+  iclasses_seen |= ic;
 
 
-  /* Skip lead white space */
-  while (*p == ' ')
+  switch (architecture)
     {
     {
-      p++;
+    case ARCH_KA:
+      return ic & (I_BASE | I_KX);
+    case ARCH_KB:
+      return ic & (I_BASE | I_KX | I_FP | I_DEC);
+    case ARCH_MC:
+      return ic & (I_BASE | I_KX | I_FP | I_DEC | I_MIL);
+    case ARCH_CA:
+      return ic & (I_BASE | I_CX | I_CX2 | I_CASIM);
+    case ARCH_JX:
+      return ic & (I_BASE | I_CX2 | I_JX);
+    case ARCH_HX:
+      return ic & (I_BASE | I_CX2 | I_JX | I_HX);
+    default:
+      if ((iclasses_seen & (I_KX | I_FP | I_DEC | I_MIL))
+         && (iclasses_seen & (I_CX | I_CX2)))
+       {
+         as_warn (_("architecture of opcode conflicts with that of earlier instruction(s)"));
+         iclasses_seen &= ~ic;
+       }
+      return 1;
     }
     }
+}
 
 
-  if (*p == '\0')
-    {
-      return 0;
-    }
+/* shift_ok:
+   Determine if a "shlo" instruction can be used to implement a "ldconst".
+   This means that some number X < 32 can be shifted left to produce the
+   constant of interest.
 
 
-  n = 1;
-  args[1] = p;
+   Return the shift count, or 0 if we can't do it.
+   Caller calculates X by shifting original constant right 'shift' places.  */
 
 
-  /* Squeze blanks out by moving non-blanks toward start of string.
-     * Isolate operands, whenever comma is found.
-   */
-  to = p;
-  while (*p != '\0')
-    {
+static int
+shift_ok (int n)               /* The constant of interest.  */
+{
+  int shift;                   /* The shift count.  */
 
 
-      if (*p == ' '
-         && (! isalnum ((unsigned char) p[1])
-             || ! isalnum ((unsigned char) p[-1])))
-       {
-         p++;
+  if (n <= 0)
+    /* Can't do it for negative numbers.  */
+    return 0;
 
 
-       }
-      else if (*p == ',')
-       {
+  /* Shift 'n' right until a 1 is about to be lost.  */
+  for (shift = 0; (n & 1) == 0; shift++)
+    n >>= 1;
 
 
-         /* Start of operand */
-         if (n == 3)
-           {
-             as_bad (_("too many operands"));
-             return -1;
-           }
-         *to++ = '\0';         /* Terminate argument */
-         args[++n] = to;       /* Start next argument */
-         p++;
+  if (n >= 32)
+    return 0;
 
 
-       }
-      else
-       {
-         *to++ = *p++;
-       }
-    }
-  *to = '\0';
-  return n;
+  return shift;
 }
 
 }
 
-/*****************************************************************************
-   get_cdisp:  handle displacement for a COBR or CTRL instruction.
+/* parse_ldcont:
+   Parse and replace a 'ldconst' pseudo-instruction with an appropriate
+   i80960 instruction.
 
 
-       Parse displacement for a COBR or CTRL instruction.
+   Assumes the input consists of:
+               arg[0]  opcode mnemonic ('ldconst')
+               arg[1]  first operand (constant)
+               arg[2]  name of register to be loaded
 
 
-       If successful, output the instruction opcode and set up for it,
-       depending on the arg 'var_frag', either:
-           o an address fixup to be done when all symbol values are known, or
-           o a varying length code fragment, with address fixup info.  This
-               will be done for cobr instructions that may have to be relaxed
-               in to compare/branch instructions (8 bytes) if the final
-               address displacement is greater than 13 bits.
+   Replaces opcode and/or operands as appropriate.
 
 
-  ****************************************************************************/
-static
-void
-get_cdisp (dispP, ifmtP, instr, numbits, var_frag, callj)
-     /* displacement as specified in source instruction */
-     char *dispP;
-     /* "COBR" or "CTRL" (for use in error message) */
-     char *ifmtP;
-     /* Instruction needing the displacement */
-     long instr;
-     /* # bits of displacement (13 for COBR, 24 for CTRL) */
-     int numbits;
-     /* 1 if varying length code fragment should be emitted;
-      *       0 if an address fix should be emitted.
-      */
-     int var_frag;
-     /* 1 if callj relocation should be done; else 0 */
-     int callj;
+   Returns the new number of arguments, or -1 on failure.  */
+
+static int
+parse_ldconst (char *arg[])    /* See above.  */
 {
 {
-  expressionS e;               /* Parsed expression */
-  fixS *fixP;                  /* Structure describing needed address fix */
-  char *outP;                  /* Where instruction binary is output to */
+  int n;                       /* Constant to be loaded.  */
+  int shift;                   /* Shift count for "shlo" instruction.  */
+  static char buf[5];          /* Literal for first operand.  */
+  static char buf2[5];         /* Literal for second operand.  */
+  expressionS e;               /* Parsed expression.  */
 
 
-  fixP = NULL;
+  arg[3] = NULL;               /* So we can tell at the end if it got used or not.  */
 
 
-  parse_expr (dispP, &e);
+  parse_expr (arg[1], &e);
   switch (e.X_op)
     {
   switch (e.X_op)
     {
-    case O_illegal:
-      as_bad (_("expression syntax error"));
+    default:
+      /* We're dependent on one or more symbols -- use "lda".  */
+      arg[0] = "lda";
+      break;
 
 
-    case O_symbol:
-      if (S_GET_SEGMENT (e.X_add_symbol) == now_seg
-         || S_GET_SEGMENT (e.X_add_symbol) == undefined_section)
+    case O_constant:
+      /* Try the following mappings:
+              ldconst   0,<reg>  -> mov  0,<reg>
+              ldconst  31,<reg>  -> mov  31,<reg>
+              ldconst  32,<reg>  -> addo 1,31,<reg>
+              ldconst  62,<reg>  -> addo 31,31,<reg>
+              ldconst  64,<reg>  -> shlo 8,3,<reg>
+              ldconst  -1,<reg>  -> subo 1,0,<reg>
+              ldconst -31,<reg>  -> subo 31,0,<reg>
+
+         Anything else becomes:
+                lda xxx,<reg>.  */
+      n = offs (e);
+      if ((0 <= n) && (n <= 31))
+       arg[0] = "mov";
+      else if ((-31 <= n) && (n <= -1))
        {
        {
-         if (var_frag)
-           {
-             outP = frag_more (8);     /* Allocate worst-case storage */
-             md_number_to_chars (outP, instr, 4);
-             frag_variant (rs_machine_dependent, 4, 4, 1,
-                           adds (e), offs (e), outP);
-           }
-         else
-           {
-             /* Set up a new fix structure, so address can be updated
-              * when all symbol values are known.
-              */
-             outP = emit (instr);
-             fixP = fix_new (frag_now,
-                             outP - frag_now->fr_literal,
-                             4,
-                             adds (e),
-                             offs (e),
-                             1,
-                             NO_RELOC);
-
-             fixP->fx_tcbit = callj;
-
-             /* We want to modify a bit field when the address is
-              * known.  But we don't need all the garbage in the
-              * bit_fix structure.  So we're going to lie and store
-              * the number of bits affected instead of a pointer.
-              */
-             fixP->fx_bit_fixP = (bit_fixS *) numbits;
-           }
+         arg[0] = "subo";
+         arg[3] = arg[2];
+         sprintf (buf, "%d", -n);
+         arg[1] = buf;
+         arg[2] = "0";
+       }
+      else if ((32 <= n) && (n <= 62))
+       {
+         arg[0] = "addo";
+         arg[3] = arg[2];
+         arg[1] = "31";
+         sprintf (buf, "%d", n - 31);
+         arg[2] = buf;
+       }
+      else if ((shift = shift_ok (n)) != 0)
+       {
+         arg[0] = "shlo";
+         arg[3] = arg[2];
+         sprintf (buf, "%d", shift);
+         arg[1] = buf;
+         sprintf (buf2, "%d", n >> shift);
+         arg[2] = buf2;
        }
       else
        }
       else
-       as_bad (_("attempt to branch into different segment"));
+       arg[0] = "lda";
       break;
 
       break;
 
-    default:
-      as_bad (_("target of %s instruction must be a label"), ifmtP);
+    case O_illegal:
+      as_bad (_("invalid constant"));
+      return -1;
       break;
     }
       break;
     }
+  return (arg[3] == 0) ? 2 : 3;
 }
 
 }
 
-/*****************************************************************************
-   get_ispec:  parse a memory operand for an index specification
-
-       Here, an "index specification" is taken to be anything surrounded
-       by square brackets and NOT followed by anything else.
+/* reg_fmt:    generate a REG-format instruction.  */
 
 
-       If it's found, detach it from the input string, remove the surrounding
-       square brackets, and return a pointer to it.  Otherwise, return NULL.
-
-  *************************************************************************** */
-static
-char *
-get_ispec (textP)
-     /* Pointer to memory operand from source instruction, no white space.  */
-     char *textP;
+static void
+reg_fmt (char *args[],         /* args[0]->opcode mnemonic, args[1-3]->operands.  */
+        struct i960_opcode *oP)/* Pointer to description of instruction.  */
 {
 {
-  /* Points to start of index specification.  */
-  char *start;
-  /* Points to end of index specification.  */
-  char *end;
+  long instr;                  /* Binary to be output.  */
+  struct regop regop;          /* Description of register operand.  */
+  int n_ops;                   /* Number of operands.  */
 
 
-  /* Find opening square bracket, if any.  */
-  start = strchr (textP, '[');
+  instr = oP->opcode;
+  n_ops = oP->num_ops;
 
 
-  if (start != NULL)
+  if (n_ops >= 1)
     {
     {
+      parse_regop (&regop, args[1], oP->operand[0]);
 
 
-      /* Eliminate '[', detach from rest of operand */
-      *start++ = '\0';
-
-      end = strchr (start, ']');
-
-      if (end == NULL)
+      if ((n_ops == 1) && !(instr & M3))
        {
        {
-         as_bad (_("unmatched '['"));
-
+         /* 1-operand instruction in which the dst field should
+            be used (instead of src1).  */
+         regop.n <<= 19;
+         if (regop.special)
+           regop.mode = regop.special;
+         regop.mode <<= 13;
+         regop.special = 0;
        }
       else
        {
        }
       else
        {
-         /* Eliminate ']' and make sure it was the last thing
-            * in the string.
-          */
-         *end = '\0';
-         if (*(end + 1) != '\0')
-           {
-             as_bad (_("garbage after index spec ignored"));
-           }
+         /* regop.n goes in bit 0, needs no shifting.  */
+         regop.mode <<= 11;
+         regop.special <<= 5;
        }
        }
+      instr |= regop.n | regop.mode | regop.special;
     }
     }
-  return start;
-}
 
 
-/*****************************************************************************
-   get_regnum:
-
-       Look up a (suspected) register name in the register table and return the
-       associated register number (or -1 if not found).
-
-  *************************************************************************** */
-static
-int
-get_regnum (regname)
-     char *regname;            /* Suspected register name */
-{
-  int *rP;
+  if (n_ops >= 2)
+    {
+      parse_regop (&regop, args[2], oP->operand[1]);
 
 
-  rP = (int *) hash_find (reg_hash, regname);
-  return (rP == NULL) ? -1 : *rP;
+      if ((n_ops == 2) && !(instr & M3))
+       {
+         /* 2-operand instruction in which the dst field should
+            be used instead of src2).  */
+         regop.n <<= 19;
+         if (regop.special)
+           regop.mode = regop.special;
+         regop.mode <<= 13;
+         regop.special = 0;
+       }
+      else
+       {
+         regop.n <<= 14;
+         regop.mode <<= 12;
+         regop.special <<= 6;
+       }
+      instr |= regop.n | regop.mode | regop.special;
+    }
+  if (n_ops == 3)
+    {
+      parse_regop (&regop, args[3], oP->operand[2]);
+      if (regop.special)
+       regop.mode = regop.special;
+      instr |= (regop.n <<= 19) | (regop.mode <<= 13);
+    }
+  emit (instr);
 }
 
 }
 
-/*****************************************************************************
-   i_scan:     perform lexical scan of ascii assembler instruction.
+/* get_args:   break individual arguments out of comma-separated list
 
    Input assumptions:
 
    Input assumptions:
-       - input string is an i80960 instruction (not a pseudo-op)
        - all comments and labels have been removed
        - all strings of whitespace have been collapsed to a single blank.
        - all comments and labels have been removed
        - all strings of whitespace have been collapsed to a single blank.
+       - all character constants ('x') have been replaced with decimal
 
    Output:
 
    Output:
-       args[0] points to opcode, other entries point to operands. All strings:
+       args[0] is untouched. args[1] points to first operand, etc. All args:
        - are NULL-terminated
        - contain no whitespace
        - are NULL-terminated
        - contain no whitespace
-       - have character constants ('x') replaced with a decimal number
 
    Return value:
 
    Return value:
-       Number of operands (0,1,2, or 3) or -1 on error.
+   Number of operands (0,1,2, or 3) or -1 on error.  */
 
 
-  *************************************************************************** */
 static int
 static int
-i_scan (iP, args)
-     /* Pointer to ascii instruction;  MUCKED BY US.  */
-     register char *iP;
-     /* Output arg: pointers to opcode and operands placed here.  MUST
-       ACCOMMODATE 4 ENTRIES.  */
-     char *args[];
+get_args (char *p,     /* Pointer to comma-separated operands; Mucked by us.  */
+         char *args[]) /* Output arg: pointers to operands placed in args[1-3].
+                          Must accommodate 4 entries (args[0-3]).  */
+
 {
 {
+  int n;               /* Number of operands.  */
+  char *to;
 
 
-  /* Isolate opcode */
-  if (*(iP) == ' ')
+  /* Skip lead white space.  */
+  while (*p == ' ')
+    p++;
+
+  if (*p == '\0')
+    return 0;
+
+  n = 1;
+  args[1] = p;
+
+  /* Squeze blanks out by moving non-blanks toward start of string.
+     Isolate operands, whenever comma is found.  */
+  to = p;
+  while (*p != '\0')
     {
     {
-      iP++;
-    }                          /* Skip lead space, if any */
+      if (*p == ' '
+         && (! ISALNUM (p[1])
+             || ! ISALNUM (p[-1])))
+       p++;
+      else if (*p == ',')
+       {
+         /* Start of operand.  */
+         if (n == 3)
+           {
+             as_bad (_("too many operands"));
+             return -1;
+           }
+         *to++ = '\0';         /* Terminate argument.  */
+         args[++n] = to;       /* Start next argument.  */
+         p++;
+       }
+      else
+       *to++ = *p++;
+    }
+  *to = '\0';
+  return n;
+}
+
+/* i_scan:     perform lexical scan of ascii assembler instruction.
+
+   Input assumptions:
+       - input string is an i80960 instruction (not a pseudo-op)
+       - all comments and labels have been removed
+       - all strings of whitespace have been collapsed to a single blank.
+
+   Output:
+       args[0] points to opcode, other entries point to operands. All strings:
+       - are NULL-terminated
+       - contain no whitespace
+       - have character constants ('x') replaced with a decimal number
+
+   Return value:
+     Number of operands (0,1,2, or 3) or -1 on error.  */
+
+static int
+i_scan (char *iP,     /* Pointer to ascii instruction;  Mucked by us.  */
+       char *args[]) /* Output arg: pointers to opcode and operands placed here.
+                        Must accommodate 4 entries.  */
+{
+  /* Isolate opcode.  */
+  if (*(iP) == ' ')
+    iP++;
+
   args[0] = iP;
   for (; *iP != ' '; iP++)
     {
       if (*iP == '\0')
        {
   args[0] = iP;
   for (; *iP != ' '; iP++)
     {
       if (*iP == '\0')
        {
-         /* There are no operands */
+         /* There are no operands */
          if (args[0] == iP)
            {
          if (args[0] == iP)
            {
-             /* We never moved: there was no opcode either! */
+             /* We never moved: there was no opcode either!  */
              as_bad (_("missing opcode"));
              return -1;
            }
          return 0;
        }
     }
              as_bad (_("missing opcode"));
              return -1;
            }
          return 0;
        }
     }
-  *iP++ = '\0';                        /* Terminate opcode */
+  *iP++ = '\0';
   return (get_args (iP, args));
   return (get_args (iP, args));
-}                              /* i_scan() */
-
-/*****************************************************************************
-   mem_fmt:    generate a MEMA- or MEMB-format instruction
+}
 
 
-  *************************************************************************** */
 static void
 static void
-mem_fmt (args, oP, callx)
-     char *args[];             /* args[0]->opcode mnemonic, args[1-3]->operands */
-     struct i960_opcode *oP;   /* Pointer to description of instruction */
-     int callx;                        /* Is this a callx opcode */
+brcnt_emit (void)
 {
 {
-  int i;                       /* Loop counter */
-  struct regop regop;          /* Description of register operand */
-  char opdesc;                 /* Operand descriptor byte */
-  memS instr;                  /* Description of binary to be output */
-  char *outP;                  /* Where the binary was output to */
-  expressionS expr;            /* Parsed expression */
-  /* ->description of deferred address fixup */
-  fixS *fixP;
-
-#ifdef OBJ_COFF
-  /* COFF support isn't in place yet for callx relaxing.  */
-  callx = 0;
-#endif
-
-  memset (&instr, '\0', sizeof (memS));
-  instr.opcode = oP->opcode;
-
-  /* Process operands.  */
-  for (i = 1; i <= oP->num_ops; i++)
-    {
-      opdesc = oP->operand[i - 1];
-
-      if (MEMOP (opdesc))
-       {
-         parse_memop (&instr, args[i], oP->format);
-       }
-      else
-       {
-         parse_regop (&regop, args[i], opdesc);
-         instr.opcode |= regop.n << 19;
-       }
-    }
+  /* Emit call to "increment" routine.  */
+  ctrl_fmt (BR_CNT_FUNC, CALL, 1);
+  /* Emit inline counter to be incremented.  */
+  emit (0);
+}
 
 
-  /* Parse the displacement; this must be done before emitting the
-     opcode, in case it is an expression using `.'.  */
-  parse_expr (instr.e, &expr);
+static char *
+brlab_next (void)
+{
+  static char buf[20];
 
 
-  /* Output opcode */
-  outP = emit (instr.opcode);
+  sprintf (buf, "%s%d", BR_LABEL_BASE, br_cnt++);
+  return buf;
+}
 
 
-  if (instr.disp == 0)
-    {
-      return;
-    }
+static void
+ctrl_fmt (char *targP,         /* Pointer to text of lone operand (if any).  */
+         long opcode,          /* Template of instruction.  */
+         int num_ops)          /* Number of operands.  */
+{
+  int instrument;              /* TRUE iff we should add instrumentation to track
+                                  how often the branch is taken.  */
 
 
-  /* Process the displacement */
-  switch (expr.X_op)
+  if (num_ops == 0)
+    emit (opcode);             /* Output opcode.  */
+  else
     {
     {
-    case O_illegal:
-      as_bad (_("expression syntax error"));
-      break;
+      instrument = instrument_branches && (opcode != CALL)
+       && (opcode != B) && (opcode != RET) && (opcode != BAL);
 
 
-    case O_constant:
-      if (instr.disp == 32)
-       {
-         (void) emit (offs (expr));    /* Output displacement */
-       }
-      else
+      if (instrument)
        {
        {
-         /* 12-bit displacement */
-         if (offs (expr) & ~0xfff)
-           {
-             /* Won't fit in 12 bits: convert already-output
-              * instruction to MEMB format, output
-              * displacement.
-              */
-             mema_to_memb (outP);
-             (void) emit (offs (expr));
-           }
-         else
-           {
-             /* WILL fit in 12 bits:  OR into opcode and
-              * overwrite the binary we already put out
-              */
-             instr.opcode |= offs (expr);
-             md_number_to_chars (outP, instr.opcode, 4);
-           }
+         brcnt_emit ();
+         colon (brlab_next ());
        }
        }
-      break;
 
 
-    default:
-      if (instr.disp == 12)
-       {
-         /* Displacement is dependent on a symbol, whose value
-          * may change at link time.  We HAVE to reserve 32 bits.
-          * Convert already-output opcode to MEMB format.
-          */
-         mema_to_memb (outP);
-       }
+      /* The operand MUST be an ip-relative displacement. Parse it
+         and set up address fix for the instruction we just output.  */
+      get_cdisp (targP, "CTRL", opcode, 24, 0, 0);
 
 
-      /* Output 0 displacement and set up address fixup for when
-       * this symbol's value becomes known.
-       */
-      outP = emit ((long) 0);
-      fixP = fix_new_exp (frag_now,
-                         outP - frag_now->fr_literal,
-                         4,
-                         &expr,
-                         0,
-                         NO_RELOC);
-      /* Steve's linker relaxing hack.  Mark this 32-bit relocation as
-         being in the instruction stream, specifically as part of a callx
-         instruction.  */
-      fixP->fx_bsr = callx;
-      break;
+      if (instrument)
+       brcnt_emit ();
     }
     }
-}                              /* memfmt() */
-
-/*****************************************************************************
-   mema_to_memb:       convert a MEMA-format opcode to a MEMB-format opcode.
-
-   There are 2 possible MEMA formats:
-       - displacement only
-       - displacement + abase
-
-   They are distinguished by the setting of the MEMA_ABASE bit.
+}
 
 
-  *************************************************************************** */
 static void
 static void
-mema_to_memb (opcodeP)
-     char *opcodeP;            /* Where to find the opcode, in target byte order */
-{
-  long opcode;                 /* Opcode in host byte order */
-  long mode;                   /* Mode bits for MEMB instruction */
+cobr_fmt (/* arg[0]->opcode mnemonic, arg[1-3]->operands (ascii) */
+         char *arg[],
+         /* Opcode, with branch-prediction bits already set if necessary.  */
+         long opcode,
+         /* Pointer to description of instruction.  */
+         struct i960_opcode *oP)
+{
+  long instr;                  /* 32-bit instruction.  */
+  struct regop regop;          /* Description of register operand.  */
+  int n;                       /* Number of operands.  */
+  int var_frag;                        /* 1 if varying length code fragment should
+                                    be emitted;  0 if an address fix
+                                       should be emitted.  */
 
 
-  opcode = md_chars_to_number (opcodeP, 4);
-  know (!(opcode & MEMB_BIT));
+  instr = opcode;
+  n = oP->num_ops;
 
 
-  mode = MEMB_BIT | D_BIT;
-  if (opcode & MEMA_ABASE)
+  if (n >= 1)
     {
     {
-      mode |= A_BIT;
+      /* First operand (if any) of a COBR is always a register
+        operand.  Parse it.  */
+      parse_regop (&regop, arg[1], oP->operand[0]);
+      instr |= (regop.n << 19) | (regop.mode << 13);
     }
 
     }
 
-  opcode &= 0xffffc000;                /* Clear MEMA offset and mode bits */
-  opcode |= mode;              /* Set MEMB mode bits */
-
-  md_number_to_chars (opcodeP, opcode, 4);
-}                              /* mema_to_memb() */
-
-/*****************************************************************************
-   parse_expr:         parse an expression
-
-       Use base assembler's expression parser to parse an expression.
-       It, unfortunately, runs off a global which we have to save/restore
-       in order to make it work for us.
-
-       An empty expression string is treated as an absolute 0.
-
-       Sets O_illegal regardless of expression evaluation if entire input
-       string is not consumed in the evaluation -- tolerate no dangling junk!
-
-  *************************************************************************** */
-static void
-parse_expr (textP, expP)
-     char *textP;              /* Text of expression to be parsed */
-     expressionS *expP;                /* Where to put the results of parsing */
-{
-  char *save_in;               /* Save global here */
-  symbolS *symP;
-
-  know (textP);
-
-  if (*textP == '\0')
+  if (n >= 2)
     {
     {
-      /* Treat empty string as absolute 0 */
-      expP->X_add_symbol = expP->X_op_symbol = NULL;
-      expP->X_add_number = 0;
-      expP->X_op = O_constant;
+      /* Second operand (if any) of a COBR is always a register
+        operand.  Parse it.  */
+      parse_regop (&regop, arg[2], oP->operand[1]);
+      instr |= (regop.n << 14) | regop.special;
     }
     }
+
+  if (n < 3)
+    emit (instr);
   else
     {
   else
     {
-      save_in = input_line_pointer;    /* Save global */
-      input_line_pointer = textP;      /* Make parser work for us */
-
-      (void) expression (expP);
-      if ((size_t) (input_line_pointer - textP) != strlen (textP))
-       {
-         /* Did not consume all of the input */
-         expP->X_op = O_illegal;
-       }
-      symP = expP->X_add_symbol;
-      if (symP && (hash_find (reg_hash, S_GET_NAME (symP))))
+      if (instrument_branches)
        {
        {
-         /* Register name in an expression */
-         /* FIXME: this isn't much of a check any more.  */
-         expP->X_op = O_illegal;
+         brcnt_emit ();
+         colon (brlab_next ());
        }
 
        }
 
-      input_line_pointer = save_in;    /* Restore global */
+      /* A third operand to a COBR is always a displacement.  Parse
+         it; if it's relaxable (a cobr "j" directive, or any cobr
+         other than bbs/bbc when the "-norelax" option is not in use)
+         set up a variable code fragment; otherwise set up an address
+         fix.  */
+      var_frag = !norelax || (oP->format == COJ);      /* TRUE or FALSE */
+      get_cdisp (arg[3], "COBR", instr, 13, var_frag, 0);
+
+      if (instrument_branches)
+       brcnt_emit ();
     }
 }
 
     }
 }
 
-/*****************************************************************************
-   parse_ldcont:
-       Parse and replace a 'ldconst' pseudo-instruction with an appropriate
-       i80960 instruction.
-
-       Assumes the input consists of:
-               arg[0]  opcode mnemonic ('ldconst')
-               arg[1]  first operand (constant)
-               arg[2]  name of register to be loaded
+/* Assumptions about the passed-in text:
+       - all comments, labels removed
+       - text is an instruction
+       - all white space compressed to single blanks
+       - all character constants have been replaced with decimal.  */
 
 
-       Replaces opcode and/or operands as appropriate.
+void
+md_assemble (char *textP)
+{
+  /* Parsed instruction text, containing NO whitespace: arg[0]->opcode
+     mnemonic arg[1-3]->operands, with char constants replaced by
+     decimal numbers.  */
+  char *args[4];
+  /* Number of instruction operands.  */
+  int n_ops;
+  /* Pointer to instruction description.  */
+  struct i960_opcode *oP;
+  /* TRUE iff opcode mnemonic included branch-prediction suffix (".f"
+     or ".t").  */
+  int branch_predict;
+  /* Setting of branch-prediction bit(s) to be OR'd into instruction
+     opcode of CTRL/COBR format instructions.  */
+  long bp_bits;
+  /* Offset of last character in opcode mnemonic.  */
+  int n;
+  const char *bp_error_msg = _("branch prediction invalid on this opcode");
 
 
-       Returns the new number of arguments, or -1 on failure.
+  /* Parse instruction into opcode and operands.  */
+  memset (args, '\0', sizeof (args));
 
 
-  *************************************************************************** */
-static
-int
-parse_ldconst (arg)
-     char *arg[];              /* See above */
-{
-  int n;                       /* Constant to be loaded */
-  int shift;                   /* Shift count for "shlo" instruction */
-  static char buf[5];          /* Literal for first operand */
-  static char buf2[5];         /* Literal for second operand */
-  expressionS e;               /* Parsed expression */
+  n_ops = i_scan (textP, args);
 
 
-  arg[3] = NULL;               /* So we can tell at the end if it got used or not */
+  if (n_ops == -1)
+    return;                    /* Error message already issued.  */
 
 
-  parse_expr (arg[1], &e);
-  switch (e.X_op)
+  /* Do "macro substitution" (sort of) on 'ldconst' pseudo-instruction.  */
+  if (!strcmp (args[0], "ldconst"))
     {
     {
-    default:
-      /* We're dependent on one or more symbols -- use "lda" */
-      arg[0] = "lda";
-      break;
+      n_ops = parse_ldconst (args);
+      if (n_ops == -1)
+       return;
+    }
 
 
-    case O_constant:
-      /* Try the following mappings:
-       *      ldconst 0,<reg>  ->mov  0,<reg>
-       *        ldconst 31,<reg> ->mov  31,<reg>
-       *        ldconst 32,<reg> ->addo 1,31,<reg>
-       *        ldconst 62,<reg> ->addo 31,31,<reg>
-       *        ldconst 64,<reg> ->shlo 8,3,<reg>
-       *        ldconst -1,<reg> ->subo 1,0,<reg>
-       *        ldconst -31,<reg>->subo 31,0,<reg>
-       *
-       * anthing else becomes:
-       *        lda xxx,<reg>
-       */
-      n = offs (e);
-      if ((0 <= n) && (n <= 31))
-       {
-         arg[0] = "mov";
+  /* Check for branch-prediction suffix on opcode mnemonic, strip it off.  */
+  n = strlen (args[0]) - 1;
+  branch_predict = 0;
+  bp_bits = 0;
 
 
-       }
-      else if ((-31 <= n) && (n <= -1))
-       {
-         arg[0] = "subo";
-         arg[3] = arg[2];
-         sprintf (buf, "%d", -n);
-         arg[1] = buf;
-         arg[2] = "0";
+  if (args[0][n - 1] == '.' && (args[0][n] == 't' || args[0][n] == 'f'))
+    {
+      /* We could check here to see if the target architecture
+        supports branch prediction, but why bother?  The bit will
+        just be ignored by processors that don't use it.  */
+      branch_predict = 1;
+      bp_bits = (args[0][n] == 't') ? BP_TAKEN : BP_NOT_TAKEN;
+      args[0][n - 1] = '\0';   /* Strip suffix from opcode mnemonic */
+    }
 
 
-       }
-      else if ((32 <= n) && (n <= 62))
-       {
-         arg[0] = "addo";
-         arg[3] = arg[2];
-         arg[1] = "31";
-         sprintf (buf, "%d", n - 31);
-         arg[2] = buf;
-
-       }
-      else if ((shift = shift_ok (n)) != 0)
-       {
-         arg[0] = "shlo";
-         arg[3] = arg[2];
-         sprintf (buf, "%d", shift);
-         arg[1] = buf;
-         sprintf (buf2, "%d", n >> shift);
-         arg[2] = buf2;
-
-       }
-      else
-       {
-         arg[0] = "lda";
-       }
-      break;
-
-    case O_illegal:
-      as_bad (_("invalid constant"));
-      return -1;
-      break;
-    }
-  return (arg[3] == 0) ? 2 : 3;
-}
-
-/*****************************************************************************
-   parse_memop:        parse a memory operand
-
-       This routine is based on the observation that the 4 mode bits of the
-       MEMB format, taken individually, have fairly consistent meaning:
-
-                M3 (bit 13): 1 if displacement is present (D_BIT)
-                M2 (bit 12): 1 for MEMB instructions (MEMB_BIT)
-                M1 (bit 11): 1 if index is present (I_BIT)
-                M0 (bit 10): 1 if abase is present (A_BIT)
-
-       So we parse the memory operand and set bits in the mode as we find
-       things.  Then at the end, if we go to MEMB format, we need only set
-       the MEMB bit (M2) and our mode is built for us.
-
-       Unfortunately, I said "fairly consistent".  The exceptions:
-
-                DBIA
-                0100   Would seem illegal, but means "abase-only".
-
-                0101   Would seem to mean "abase-only" -- it means IP-relative.
-                       Must be converted to 0100.
-
-                0110   Would seem to mean "index-only", but is reserved.
-                       We turn on the D bit and provide a 0 displacement.
-
-       The other thing to observe is that we parse from the right, peeling
-       things * off as we go:  first any index spec, then any abase, then
-       the displacement.
-
-  *************************************************************************** */
-static
-void
-parse_memop (memP, argP, optype)
-     memS *memP;               /* Where to put the results */
-     char *argP;               /* Text of the operand to be parsed */
-     int optype;               /* MEM1, MEM2, MEM4, MEM8, MEM12, or MEM16 */
-{
-  char *indexP;                        /* Pointer to index specification with "[]" removed */
-  char *p;                     /* Temp char pointer */
-  char iprel_flag;             /* True if this is an IP-relative operand */
-  int regnum;                  /* Register number */
-  /* Scale factor: 1,2,4,8, or 16.  Later converted to internal format
-     (0,1,2,3,4 respectively).  */
-  int scale;
-  int mode;                    /* MEMB mode bits */
-  int *intP;                   /* Pointer to register number */
-
-  /* The following table contains the default scale factors for each
-     type of memory instruction.  It is accessed using (optype-MEM1)
-     as an index -- thus it assumes the 'optype' constants are
-     assigned consecutive values, in the order they appear in this
-     table.  */
-  static const int def_scale[] =
-  {
-    1,                         /* MEM1 */
-    2,                         /* MEM2 */
-    4,                         /* MEM4 */
-    8,                         /* MEM8 */
-    -1,                                /* MEM12 -- no valid default */
-    16                         /* MEM16 */
-  };
-
-  iprel_flag = mode = 0;
-
-  /* Any index present? */
-  indexP = get_ispec (argP);
-  if (indexP)
+  /* Look up opcode mnemonic in table and check number of operands.
+     Check that opcode is legal for the target architecture.  If all
+     looks good, assemble instruction.  */
+  oP = (struct i960_opcode *) hash_find (op_hash, args[0]);
+  if (!oP || !targ_has_iclass (oP->iclass))
+    as_bad (_("invalid opcode, \"%s\"."), args[0]);
+  else if (n_ops != oP->num_ops)
+    as_bad (_("improper number of operands.  expecting %d, got %d"),
+           oP->num_ops, n_ops);
+  else
     {
     {
-      p = strchr (indexP, '*');
-      if (p == NULL)
-       {
-         /* No explicit scale -- use default for this instruction
-            type and assembler mode.  */
-         if (flag_mri)
-           scale = 1;
-         else
-           /* GNU960 compatibility */
-           scale = def_scale[optype - MEM1];
-       }
-      else
-       {
-         *p++ = '\0';          /* Eliminate '*' */
-
-         /* Now indexP->a '\0'-terminated register name,
-            * and p->a scale factor.
-          */
-
-         if (!strcmp (p, "16"))
-           {
-             scale = 16;
-           }
-         else if (strchr ("1248", *p) && (p[1] == '\0'))
-           {
-             scale = *p - '0';
-           }
-         else
-           {
-             scale = -1;
-           }
-       }
-
-      regnum = get_regnum (indexP);    /* Get index reg. # */
-      if (!IS_RG_REG (regnum))
-       {
-         as_bad (_("invalid index register"));
-         return;
-       }
-
-      /* Convert scale to its binary encoding */
-      switch (scale)
+      switch (oP->format)
        {
        {
-       case 1:
-         scale = 0 << 7;
+       case FBRA:
+       case CTRL:
+         ctrl_fmt (args[1], oP->opcode | bp_bits, oP->num_ops);
+         if (oP->format == FBRA)
+           /* Now generate a 'bno' to same arg */
+           ctrl_fmt (args[1], BNO | bp_bits, 1);
          break;
          break;
-       case 2:
-         scale = 1 << 7;
+       case COBR:
+       case COJ:
+         cobr_fmt (args, oP->opcode | bp_bits, oP);
          break;
          break;
-       case 4:
-         scale = 2 << 7;
+       case REG:
+         if (branch_predict)
+           as_warn ("%s", bp_error_msg);
+         reg_fmt (args, oP);
          break;
          break;
-       case 8:
-         scale = 3 << 7;
+       case MEM1:
+         if (args[0][0] == 'c' && args[0][1] == 'a')
+           {
+             if (branch_predict)
+               as_warn ("%s", bp_error_msg);
+             mem_fmt (args, oP, 1);
+             break;
+           }
+       case MEM2:
+       case MEM4:
+       case MEM8:
+       case MEM12:
+       case MEM16:
+         if (branch_predict)
+           as_warn ("%s", bp_error_msg);
+         mem_fmt (args, oP, 0);
          break;
          break;
-       case 16:
-         scale = 4 << 7;
+       case CALLJ:
+         if (branch_predict)
+           as_warn ("%s", bp_error_msg);
+         /* Output opcode & set up "fixup" (relocation); flag
+            relocation as 'callj' type.  */
+         know (oP->num_ops == 1);
+         get_cdisp (args[1], "CTRL", oP->opcode, 24, 0, 1);
          break;
        default:
          break;
        default:
-         as_bad (_("invalid scale factor"));
-         return;
-       };
-
-      memP->opcode |= scale | regnum;  /* Set index bits in opcode */
-      mode |= I_BIT;           /* Found a valid index spec */
-    }
-
-  /* Any abase (Register Indirect) specification present? */
-  if ((p = strrchr (argP, '(')) != NULL)
-    {
-      /* "(" is there -- does it start a legal abase spec?  If not, it
-         could be part of a displacement expression.  */
-      intP = (int *) hash_find (areg_hash, p);
-      if (intP != NULL)
-       {
-         /* Got an abase here */
-         regnum = *intP;
-         *p = '\0';            /* discard register spec */
-         if (regnum == IPREL)
-           {
-             /* We have to specialcase ip-rel mode */
-             iprel_flag = 1;
-           }
-         else
-           {
-             memP->opcode |= regnum << 14;
-             mode |= A_BIT;
-           }
-       }
-    }
-
-  /* Any expression present? */
-  memP->e = argP;
-  if (*argP != '\0')
-    {
-      mode |= D_BIT;
-    }
-
-  /* Special-case ip-relative addressing */
-  if (iprel_flag)
-    {
-      if (mode & I_BIT)
-       {
-         syntax ();
-       }
-      else
-       {
-         memP->opcode |= 5 << 10;      /* IP-relative mode */
-         memP->disp = 32;
+         BAD_CASE (oP->format);
+         break;
        }
        }
-      return;
     }
     }
+}
 
 
-  /* Handle all other modes */
-  switch (mode)
-    {
-    case D_BIT | A_BIT:
-      /* Go with MEMA instruction format for now (grow to MEMB later
-         if 12 bits is not enough for the displacement).  MEMA format
-         has a single mode bit: set it to indicate that abase is
-         present.  */
-      memP->opcode |= MEMA_ABASE;
-      memP->disp = 12;
-      break;
-
-    case D_BIT:
-      /* Go with MEMA instruction format for now (grow to MEMB later
-         if 12 bits is not enough for the displacement).  */
-      memP->disp = 12;
-      break;
-
-    case A_BIT:
-      /* For some reason, the bit string for this mode is not
-         consistent: it should be 0 (exclusive of the MEMB bit), so we
-         set it "by hand" here.  */
-      memP->opcode |= MEMB_BIT;
-      break;
-
-    case A_BIT | I_BIT:
-      /* set MEMB bit in mode, and OR in mode bits */
-      memP->opcode |= mode | MEMB_BIT;
-      break;
-
-    case I_BIT:
-      /* Treat missing displacement as displacement of 0.  */
-      mode |= D_BIT;
-      /* Fall into next case.  */
-    case D_BIT | A_BIT | I_BIT:
-    case D_BIT | I_BIT:
-      /* set MEMB bit in mode, and OR in mode bits */
-      memP->opcode |= mode | MEMB_BIT;
-      memP->disp = 32;
-      break;
+void
+md_number_to_chars (char *buf,
+                   valueT value,
+                   int n)
+{
+  number_to_chars_littleendian (buf, value, n);
+}
 
 
-    default:
-      syntax ();
-      break;
-    }
+char *
+md_atof (int type, char *litP, int *sizeP)
+{
+  return ieee_md_atof (type, litP, sizeP, FALSE);
 }
 
 }
 
-/*****************************************************************************
-   parse_po:   parse machine-dependent pseudo-op
+static void
+md_number_to_imm (char *buf, long val, int n)
+{
+  md_number_to_chars (buf, val, n);
+}
 
 
-       This is a top-level routine for machine-dependent pseudo-ops.  It slurps
-       up the rest of the input line, breaks out the individual arguments,
-       and dispatches them to the correct handler.
-  *************************************************************************** */
-static
-void
-parse_po (po_num)
-     int po_num;               /* Pseudo-op number:  currently S_LEAFPROC or S_SYSPROC */
+static void
+md_number_to_field (char *instrP,              /* Pointer to instruction to be fixed.  */
+                   long val,                   /* Address fixup value.  */
+                   bit_fixS *bfixP)            /* Description of bit field to be fixed up.  */
 {
 {
-  /* Pointers operands, with no embedded whitespace.
-     arg[0] unused, arg[1-3]->operands */
-  char *args[4];
-  int n_ops;                   /* Number of operands */
-  char *p;                     /* Pointer to beginning of unparsed argument string */
-  char eol;                    /* Character that indicated end of line */
+  int numbits;                 /* Length of bit field to be fixed.  */
+  long instr;                  /* 32-bit instruction to be fixed-up.  */
+  long sign;                   /* 0 or -1, according to sign bit of 'val'.  */
 
 
-  extern char is_end_of_line[];
+  /* Convert instruction back to host byte order.  */
+  instr = md_chars_to_number (instrP, 4);
 
 
-  /* Advance input pointer to end of line.  */
-  p = input_line_pointer;
-  while (!is_end_of_line[(unsigned char) *input_line_pointer])
-    {
-      input_line_pointer++;
-    }
-  eol = *input_line_pointer;   /* Save end-of-line char */
-  *input_line_pointer = '\0';  /* Terminate argument list */
+  /* Surprise! -- we stored the number of bits to be modified rather
+     than a pointer to a structure.  */
+  numbits = (int) (size_t) bfixP;
+  if (numbits == 1)
+    /* This is a no-op, stuck here by reloc_callj().  */
+    return;
 
 
-  /* Parse out operands */
-  n_ops = get_args (p, args);
-  if (n_ops == -1)
-    {
-      return;
-    }
+  know ((numbits == 13) || (numbits == 24));
 
 
-  /* Dispatch to correct handler */
-  switch (po_num)
+  /* Propagate sign bit of 'val' for the given number of bits.  Result
+     should be all 0 or all 1.  */
+  sign = val >> ((int) numbits - 1);
+  if (((val < 0) && (sign != -1))
+      || ((val > 0) && (sign != 0)))
+    as_bad (_("Fixup of %ld too large for field width of %d"),
+           val, numbits);
+  else
     {
     {
-    case S_SYSPROC:
-      s_sysproc (n_ops, args);
-      break;
-    case S_LEAFPROC:
-      s_leafproc (n_ops, args);
-      break;
-    default:
-      BAD_CASE (po_num);
-      break;
+      /* Put bit field into instruction and write back in target
+         * byte order.  */
+      val &= ~(-(1 << (int) numbits)); /* Clear unused sign bits.  */
+      instr |= val;
+      md_number_to_chars (instrP, instr, 4);
     }
     }
-
-  /* Restore eol, so line numbers get updated correctly.  Base
-     assembler assumes we leave input pointer pointing at char
-     following the eol.  */
-  *input_line_pointer++ = eol;
 }
 }
+\f
 
 
-/*****************************************************************************
-   parse_regop: parse a register operand.
-
-       In case of illegal operand, issue a message and return some valid
-       information so instruction processing can continue.
-  *************************************************************************** */
-static
-void
-parse_regop (regopP, optext, opdesc)
-     struct regop *regopP;     /* Where to put description of register operand */
-     char *optext;             /* Text of operand */
-     char opdesc;              /* Descriptor byte:  what's legal for this operand */
-{
-  int n;                       /* Register number */
-  expressionS e;               /* Parsed expression */
-
-  /* See if operand is a register */
-  n = get_regnum (optext);
-  if (n >= 0)
-    {
-      if (IS_RG_REG (n))
-       {
-         /* global or local register */
-         if (!REG_ALIGN (opdesc, n))
-           {
-             as_bad (_("unaligned register"));
-           }
-         regopP->n = n;
-         regopP->mode = 0;
-         regopP->special = 0;
-         return;
-       }
-      else if (IS_FP_REG (n) && FP_OK (opdesc))
-       {
-         /* Floating point register, and it's allowed */
-         regopP->n = n - FP0;
-         regopP->mode = 1;
-         regopP->special = 0;
-         return;
-       }
-      else if (IS_SF_REG (n) && SFR_OK (opdesc))
-       {
-         /* Special-function register, and it's allowed */
-         regopP->n = n - SF0;
-         regopP->mode = 0;
-         regopP->special = 1;
-         if (!targ_has_sfr (regopP->n))
-           {
-             as_bad (_("no such sfr in this architecture"));
-           }
-         return;
-       }
-    }
-  else if (LIT_OK (opdesc))
-    {
-      /* How about a literal?  */
-      regopP->mode = 1;
-      regopP->special = 0;
-      if (FP_OK (opdesc))
-       {                       /* floating point literal acceptable */
-         /* Skip over 0f, 0d, or 0e prefix */
-         if ((optext[0] == '0')
-             && (optext[1] >= 'd')
-             && (optext[1] <= 'f'))
-           {
-             optext += 2;
-           }
+/* md_parse_option
+       Invocation line includes a switch not recognized by the base assembler.
+       See if it's a processor-specific option.  For the 960, these are:
 
 
-         if (!strcmp (optext, "0.0") || !strcmp (optext, "0"))
-           {
-             regopP->n = 0x10;
-             return;
-           }
-         if (!strcmp (optext, "1.0") || !strcmp (optext, "1"))
-           {
-             regopP->n = 0x16;
-             return;
-           }
+       -norelax:
+               Conditional branch instructions that require displacements
+               greater than 13 bits (or that have external targets) should
+               generate errors.  The default is to replace each such
+               instruction with the corresponding compare (or chkbit) and
+               branch instructions.  Note that the Intel "j" cobr directives
+               are ALWAYS "de-optimized" in this way when necessary,
+               regardless of the setting of this option.
 
 
-       }
-      else
-       {                       /* fixed point literal acceptable */
-         parse_expr (optext, &e);
-         if (e.X_op != O_constant
-             || (offs (e) < 0) || (offs (e) > 31))
-           {
-             as_bad (_("illegal literal"));
-             offs (e) = 0;
-           }
-         regopP->n = offs (e);
-         return;
-       }
-    }
+       -b:
+               Add code to collect information about branches taken, for
+               later optimization of branch prediction bits by a separate
+               tool.  COBR and CNTL format instructions have branch
+               prediction bits (in the CX architecture);  if "BR" represents
+               an instruction in one of these classes, the following rep-
+               resents the code generated by the assembler:
 
 
-  /* Nothing worked */
-  syntax ();
-  regopP->mode = 0;            /* Register r0 is always a good one */
-  regopP->n = 0;
-  regopP->special = 0;
-}                              /* parse_regop() */
+                       call    <increment routine>
+                       .word   0       # pre-counter
+               Label:  BR
+                       call    <increment routine>
+                       .word   0       # post-counter
 
 
-/*****************************************************************************
-   reg_fmt:    generate a REG-format instruction
+               A table of all such "Labels" is also generated.
 
 
-  *************************************************************************** */
-static void
-reg_fmt (args, oP)
-     char *args[];             /* args[0]->opcode mnemonic, args[1-3]->operands */
-     struct i960_opcode *oP;   /* Pointer to description of instruction */
+       -AKA, -AKB, -AKC, -ASA, -ASB, -AMC, -ACA:
+               Select the 80960 architecture.  Instructions or features not
+               supported by the selected architecture cause fatal errors.
+               The default is to generate code for any instruction or feature
+               that is supported by SOME version of the 960 (even if this
+               means mixing architectures!).  */
+
+const char *md_shortopts = "A:b";
+struct option md_longopts[] =
 {
 {
-  long instr;                  /* Binary to be output */
-  struct regop regop;          /* Description of register operand */
-  int n_ops;                   /* Number of operands */
+#define OPTION_LINKRELAX (OPTION_MD_BASE)
+  {"linkrelax", no_argument, NULL, OPTION_LINKRELAX},
+  {"link-relax", no_argument, NULL, OPTION_LINKRELAX},
+#define OPTION_NORELAX (OPTION_MD_BASE + 1)
+  {"norelax", no_argument, NULL, OPTION_NORELAX},
+  {"no-relax", no_argument, NULL, OPTION_NORELAX},
+  {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof (md_longopts);
 
 
-  instr = oP->opcode;
-  n_ops = oP->num_ops;
+struct tabentry
+{
+  char *flag;
+  int arch;
+};
+static const struct tabentry arch_tab[] =
+{
+  {"KA", ARCH_KA},
+  {"KB", ARCH_KB},
+  {"SA", ARCH_KA},             /* Synonym for KA.  */
+  {"SB", ARCH_KB},             /* Synonym for KB.  */
+  {"KC", ARCH_MC},             /* Synonym for MC.  */
+  {"MC", ARCH_MC},
+  {"CA", ARCH_CA},
+  {"JX", ARCH_JX},
+  {"HX", ARCH_HX},
+  {NULL, 0}
+};
 
 
-  if (n_ops >= 1)
+int
+md_parse_option (int c, char *arg)
+{
+  switch (c)
     {
     {
-      parse_regop (&regop, args[1], oP->operand[0]);
+    case OPTION_LINKRELAX:
+      linkrelax = 1;
+      flag_keep_locals = 1;
+      break;
 
 
-      if ((n_ops == 1) && !(instr & M3))
-       {
-         /* 1-operand instruction in which the dst field should
-            * be used (instead of src1).
-          */
-         regop.n <<= 19;
-         if (regop.special)
-           {
-             regop.mode = regop.special;
-           }
-         regop.mode <<= 13;
-         regop.special = 0;
-       }
-      else
-       {
-         /* regop.n goes in bit 0, needs no shifting */
-         regop.mode <<= 11;
-         regop.special <<= 5;
-       }
-      instr |= regop.n | regop.mode | regop.special;
-    }
+    case OPTION_NORELAX:
+      norelax = 1;
+      break;
 
 
-  if (n_ops >= 2)
-    {
-      parse_regop (&regop, args[2], oP->operand[1]);
+    case 'b':
+      instrument_branches = 1;
+      break;
 
 
-      if ((n_ops == 2) && !(instr & M3))
-       {
-         /* 2-operand instruction in which the dst field should
-            * be used instead of src2).
-          */
-         regop.n <<= 19;
-         if (regop.special)
-           {
-             regop.mode = regop.special;
-           }
-         regop.mode <<= 13;
-         regop.special = 0;
-       }
-      else
-       {
-         regop.n <<= 14;
-         regop.mode <<= 12;
-         regop.special <<= 6;
-       }
-      instr |= regop.n | regop.mode | regop.special;
-    }
-  if (n_ops == 3)
-    {
-      parse_regop (&regop, args[3], oP->operand[2]);
-      if (regop.special)
-       {
-         regop.mode = regop.special;
-       }
-      instr |= (regop.n <<= 19) | (regop.mode <<= 13);
+    case 'A':
+      {
+       const struct tabentry *tp;
+       char *p = arg;
+
+       for (tp = arch_tab; tp->flag != NULL; tp++)
+         if (!strcmp (p, tp->flag))
+           break;
+
+       if (tp->flag == NULL)
+         {
+           as_bad (_("invalid architecture %s"), p);
+           return 0;
+         }
+       else
+         architecture = tp->arch;
+      }
+      break;
+
+    default:
+      return 0;
     }
     }
-  emit (instr);
+
+  return 1;
 }
 
 }
 
-/*****************************************************************************
-   relax_cobr:
-       Replace cobr instruction in a code fragment with equivalent branch and
-       compare instructions, so it can reach beyond a 13-bit displacement.
-       Set up an address fix/relocation for the new branch instruction.
+void
+md_show_usage (FILE *stream)
+{
+  int i;
 
 
-  *************************************************************************** */
+  fprintf (stream, _("I960 options:\n"));
+  for (i = 0; arch_tab[i].flag; i++)
+    fprintf (stream, "%s-A%s", i ? " | " : "", arch_tab[i].flag);
+  fprintf (stream, _("\n\
+                       specify variant of 960 architecture\n\
+-b                     add code to collect statistics about branches taken\n\
+-link-relax            preserve individual alignment directives so linker\n\
+                       can do relaxing (b.out format only)\n\
+-no-relax              don't alter compare-and-branch instructions for\n\
+                       long displacements\n"));
+}
+\f
+/* relax_cobr:
+   Replace cobr instruction in a code fragment with equivalent branch and
+   compare instructions, so it can reach beyond a 13-bit displacement.
+   Set up an address fix/relocation for the new branch instruction.  */
 
 /* This "conditional jump" table maps cobr instructions into
    equivalent compare and branch opcodes.  */
 
 /* This "conditional jump" table maps cobr instructions into
    equivalent compare and branch opcodes.  */
+
 static const
 struct
 {
 static const
 struct
 {
@@ -2430,41 +1922,38 @@ coj[] =
   { CMPI, BO },                        /*      0x3f - cmpibo */
 };
 
   { CMPI, BO },                        /*      0x3f - cmpibo */
 };
 
-static
-void
-relax_cobr (fragP)
-     register fragS *fragP;    /* fragP->fr_opcode is assumed to point to
-                                * the cobr instruction, which comes at the
-                                * end of the code fragment.
-                                */
+static void
+relax_cobr (fragS *fragP)      /* fragP->fr_opcode is assumed to point to
+                                  the cobr instruction, which comes at the
+                                  end of the code fragment.  */
 {
   int opcode, src1, src2, m1, s2;
 {
   int opcode, src1, src2, m1, s2;
-  /* Bit fields from cobr instruction */
-  long bp_bits;                        /* Branch prediction bits from cobr instruction */
-  long instr;                  /* A single i960 instruction */
-  /* ->instruction to be replaced */
+  /* Bit fields from cobr instruction */
+  long bp_bits;                        /* Branch prediction bits from cobr instruction */
+  long instr;                  /* A single i960 instruction */
+  /* ->instruction to be replaced */
   char *iP;
   char *iP;
-  fixS *fixP;                  /* Relocation that can be done at assembly time */
+  fixS *fixP;                  /* Relocation that can be done at assembly time */
 
 
-  /* PICK UP & PARSE COBR INSTRUCTION */
+  /* Pick up & parse cobr instruction.  */
   iP = fragP->fr_opcode;
   instr = md_chars_to_number (iP, 4);
   iP = fragP->fr_opcode;
   instr = md_chars_to_number (iP, 4);
-  opcode = ((instr >> 24) & 0xff) - 0x30;      /* "-0x30" for table index */
+  opcode = ((instr >> 24) & 0xff) - 0x30;      /* "-0x30" for table index */
   src1 = (instr >> 19) & 0x1f;
   m1 = (instr >> 13) & 1;
   s2 = instr & 1;
   src2 = (instr >> 14) & 0x1f;
   bp_bits = instr & BP_MASK;
 
   src1 = (instr >> 19) & 0x1f;
   m1 = (instr >> 13) & 1;
   s2 = instr & 1;
   src2 = (instr >> 14) & 0x1f;
   bp_bits = instr & BP_MASK;
 
-  /* GENERATE AND OUTPUT COMPARE INSTRUCTION */
+  /* Generate and output compare instruction.  */
   instr = coj[opcode].compare
     | src1 | (m1 << 11) | (s2 << 6) | (src2 << 14);
   md_number_to_chars (iP, instr, 4);
 
   instr = coj[opcode].compare
     | src1 | (m1 << 11) | (s2 << 6) | (src2 << 14);
   md_number_to_chars (iP, instr, 4);
 
-  /* OUTPUT BRANCH INSTRUCTION */
+  /* Output branch instruction.  */
   md_number_to_chars (iP + 4, coj[opcode].branch | bp_bits, 4);
 
   md_number_to_chars (iP + 4, coj[opcode].branch | bp_bits, 4);
 
-  /* SET UP ADDRESS FIXUP/RELOCATION */
+  /* Set up address fixup/relocation.  */
   fixP = fix_new (fragP,
                  iP + 4 - fragP->fr_literal,
                  4,
   fixP = fix_new (fragP,
                  iP + 4 - fragP->fr_literal,
                  4,
@@ -2473,81 +1962,163 @@ relax_cobr (fragP)
                  1,
                  NO_RELOC);
 
                  1,
                  NO_RELOC);
 
-  fixP->fx_bit_fixP = (bit_fixS *) 24; /* Store size of bit field */
+  fixP->fx_bit_fixP = (bit_fixS *) 24; /* Store size of bit field */
 
   fragP->fr_fix += 4;
   frag_wane (fragP);
 }
 
 
   fragP->fr_fix += 4;
   frag_wane (fragP);
 }
 
-/*****************************************************************************
-   reloc_callj:        Relocate a 'callj' instruction
-
-       This is a "non-(GNU)-standard" machine-dependent hook.  The base
-       assembler calls it when it decides it can relocate an address at
-       assembly time instead of emitting a relocation directive.
+/* md_convert_frag:
 
 
-       Check to see if the relocation involves a 'callj' instruction to a:
-           sysproc:    Replace the default 'call' instruction with a 'calls'
-           leafproc:   Replace the default 'call' instruction with a 'bal'.
-           other proc: Do nothing.
+   Called by base assembler after address relaxation is finished:  modify
+   variable fragments according to how much relaxation was done.
 
 
-       See b.out.h for details on the 'n_other' field in a symbol structure.
+   If the fragment substate is still 1, a 13-bit displacement was enough
+   to reach the symbol in question.  Set up an address fixup, but otherwise
+   leave the cobr instruction alone.
 
 
-   IMPORTANT!:
-       Assumes the caller has already figured out, in the case of a leafproc,
-       to use the 'bal' entry point, and has substituted that symbol into the
-       passed fixup structure.
+   If the fragment substate is 2, a 13-bit displacement was not enough.
+   Replace the cobr with a two instructions (a compare and a branch).  */
 
 
-  *************************************************************************** */
 void
 void
-reloc_callj (fixP)
-     /* Relocation that can be done at assembly time */
-     fixS *fixP;
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
+                segT sec ATTRIBUTE_UNUSED,
+                fragS *fragP)
 {
 {
-  /* Points to the binary for the instruction being relocated.  */
-  char *where;
+  /* Structure describing needed address fix.  */
+  fixS *fixP;
 
 
-  if (!fixP->fx_tcbit)
+  switch (fragP->fr_subtype)
     {
     {
-      /* This wasn't a callj instruction in the first place */
-      return;
+    case 1:
+      /* Leave single cobr instruction.  */
+      fixP = fix_new (fragP,
+                     fragP->fr_opcode - fragP->fr_literal,
+                     4,
+                     fragP->fr_symbol,
+                     fragP->fr_offset,
+                     1,
+                     NO_RELOC);
+
+      fixP->fx_bit_fixP = (bit_fixS *) 13;     /* Size of bit field.  */
+      break;
+    case 2:
+      /* Replace cobr with compare/branch instructions.  */
+      relax_cobr (fragP);
+      break;
+    default:
+      BAD_CASE (fragP->fr_subtype);
+      break;
     }
     }
+}
 
 
-  where = fixP->fx_frag->fr_literal + fixP->fx_where;
+/* md_estimate_size_before_relax:  How much does it look like *fragP will grow?
 
 
-  if (TC_S_IS_SYSPROC (fixP->fx_addsy))
-    {
-      /* Symbol is a .sysproc: replace 'call' with 'calls'.  System
-         procedure number is (other-1).  */
-      md_number_to_chars (where, CALLS | TC_S_GET_SYSPROC (fixP->fx_addsy), 4);
+   Called by base assembler just before address relaxation.
+   Return the amount by which the fragment will grow.
 
 
-      /* Nothing else needs to be done for this instruction.  Make
-         sure 'md_number_to_field()' will perform a no-op.  */
-      fixP->fx_bit_fixP = (bit_fixS *) 1;
+   Any symbol that is now undefined will not become defined; cobr's
+   based on undefined symbols will have to be replaced with a compare
+   instruction and a branch instruction, and the code fragment will grow
+   by 4 bytes.  */
 
 
-    }
-  else if (TC_S_IS_CALLNAME (fixP->fx_addsy))
+int
+md_estimate_size_before_relax (fragS *fragP, segT segment_type)
+{
+  /* If symbol is undefined in this segment, go to "relaxed" state
+     (compare and branch instructions instead of cobr) right now.  */
+  if (S_GET_SEGMENT (fragP->fr_symbol) != segment_type)
     {
     {
-      /* Should not happen: see block comment above */
-      as_fatal (_("Trying to 'bal' to %s"), S_GET_NAME (fixP->fx_addsy));
+      relax_cobr (fragP);
+      return 4;
     }
     }
-  else if (TC_S_IS_BALNAME (fixP->fx_addsy))
+
+  return md_relax_table[fragP->fr_subtype].rlx_length;
+}
+
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+
+/* md_ri_to_chars:
+   This routine exists in order to overcome machine byte-order problems
+   when dealing with bit-field entries in the relocation_info struct.
+
+   But relocation info will be used on the host machine only (only
+   executable code is actually downloaded to the i80960).  Therefore,
+   we leave it in host byte order.  */
+
+static void
+md_ri_to_chars (char *where, struct relocation_info *ri)
+{
+  host_number_to_chars (where, ri->r_address, 4);
+  host_number_to_chars (where + 4, ri->r_index, 3);
+#if WORDS_BIGENDIAN
+  where[7] = (ri->r_pcrel << 7
+             | ri->r_length << 5
+             | ri->r_extern << 4
+             | ri->r_bsr << 3
+             | ri->r_disp << 2
+             | ri->r_callj << 1
+             | ri->nuthin << 0);
+#else
+  where[7] = (ri->r_pcrel << 0
+             | ri->r_length << 1
+             | ri->r_extern << 3
+             | ri->r_bsr << 4
+             | ri->r_disp << 5
+             | ri->r_callj << 6
+             | ri->nuthin << 7);
+#endif
+}
+
+#endif /* defined(OBJ_AOUT) | defined(OBJ_BOUT) */
+
+\f
+/* brtab_emit: generate the fetch-prediction branch table.
+
+   See the comments above the declaration of 'br_cnt' for details on
+   branch-prediction instrumentation.
+
+   The code emitted here would be functionally equivalent to the following
+   example assembler source.
+
+                       .data
+                       .align  2
+          BR_TAB_NAME:
+                       .word   0               # link to next table
+                       .word   3               # length of table
+                       .word   LBRANCH0        # 1st entry in table proper
+                       .word   LBRANCH1
+                       .word   LBRANCH2  */
+
+void
+brtab_emit (void)
+{
+  int i;
+  char buf[20];
+  /* Where the binary was output to.  */
+  char *p;
+
+  if (!instrument_branches)
+    return;
+
+  subseg_set (data_section, 0);        /*      .data */
+  frag_align (2, 0, 0);                /*      .align 2 */
+  record_alignment (now_seg, 2);
+  colon (BR_TAB_NAME);         /* BR_TAB_NAME: */
+  emit (0);                    /*      .word 0 #link to next table */
+  emit (br_cnt);               /*      .word n #length of table */
+
+  for (i = 0; i < br_cnt; i++)
     {
     {
-      /* Replace 'call' with 'bal'; both instructions have the same
-         format, so calling code should complete relocation as if
-         nothing happened here.  */
-      md_number_to_chars (where, BAL, 4);
+      sprintf (buf, "%s%d", BR_LABEL_BASE, i);
+      p = emit (0);
+      fix_new (frag_now,
+              p - frag_now->fr_literal,
+              4, symbol_find (buf), 0, 0, NO_RELOC);
     }
     }
-  else if (TC_S_IS_BADPROC (fixP->fx_addsy))
-    {
-      as_bad (_("Looks like a proc, but can't tell what kind.\n"));
-    }                          /* switch on proc type */
-
-  /* else Symbol is neither a sysproc nor a leafproc */
 }
 
 }
 
-/*****************************************************************************
-   s_leafproc: process .leafproc pseudo-op
+/* s_leafproc: process .leafproc pseudo-op
 
        .leafproc takes two arguments, the second one is optional:
                arg[1]: name of 'call' entry point to leaf procedure
 
        .leafproc takes two arguments, the second one is optional:
                arg[1]: name of 'call' entry point to leaf procedure
@@ -2558,39 +2129,33 @@ reloc_callj (fixP)
 
        If there are 2 distinct arguments, we must make sure that the 'bal'
        entry point immediately follows the 'call' entry point in the linked
 
        If there are 2 distinct arguments, we must make sure that the 'bal'
        entry point immediately follows the 'call' entry point in the linked
-       list of symbols.
+       list of symbols.  */
 
 
-  *************************************************************************** */
 static void
 static void
-s_leafproc (n_ops, args)
-     int n_ops;                        /* Number of operands */
-     char *args[];             /* args[1]->1st operand, args[2]->2nd operand */
+s_leafproc (int n_ops,         /* Number of operands.  */
+           char *args[])       /* args[1]->1st operand, args[2]->2nd operand.  */
 {
 {
-  symbolS *callP;              /* Pointer to leafproc 'call' entry point symbol */
-  symbolS *balP;               /* Pointer to leafproc 'bal' entry point symbol */
+  symbolS *callP;              /* Pointer to leafproc 'call' entry point symbol */
+  symbolS *balP;               /* Pointer to leafproc 'bal' entry point symbol */
 
   if ((n_ops != 1) && (n_ops != 2))
     {
       as_bad (_("should have 1 or 2 operands"));
       return;
 
   if ((n_ops != 1) && (n_ops != 2))
     {
       as_bad (_("should have 1 or 2 operands"));
       return;
-    }                          /* Check number of arguments */
+    }
 
   /* Find or create symbol for 'call' entry point.  */
   callP = symbol_find_or_make (args[1]);
 
   if (TC_S_IS_CALLNAME (callP))
 
   /* Find or create symbol for 'call' entry point.  */
   callP = symbol_find_or_make (args[1]);
 
   if (TC_S_IS_CALLNAME (callP))
-    {
-      as_warn (_("Redefining leafproc %s"), S_GET_NAME (callP));
-    }                          /* is leafproc */
+    as_warn (_("Redefining leafproc %s"), S_GET_NAME (callP));
 
   /* If that was the only argument, use it as the 'bal' entry point.
 
   /* If that was the only argument, use it as the 'bal' entry point.
-     * Otherwise, mark it as the 'call' entry point and find or create
-     * another symbol for the 'bal' entry point.
-   */
+     Otherwise, mark it as the 'call' entry point and find or create
+     another symbol for the 'bal' entry point.  */
   if ((n_ops == 1) || !strcmp (args[1], args[2]))
     {
       TC_S_FORCE_TO_BALNAME (callP);
   if ((n_ops == 1) || !strcmp (args[1], args[2]))
     {
       TC_S_FORCE_TO_BALNAME (callP);
-
     }
   else
     {
     }
   else
     {
@@ -2598,32 +2163,30 @@ s_leafproc (n_ops, args)
 
       balP = symbol_find_or_make (args[2]);
       if (TC_S_IS_CALLNAME (balP))
 
       balP = symbol_find_or_make (args[2]);
       if (TC_S_IS_CALLNAME (balP))
-       {
-         as_warn (_("Redefining leafproc %s"), S_GET_NAME (balP));
-       }
+       as_warn (_("Redefining leafproc %s"), S_GET_NAME (balP));
+
       TC_S_FORCE_TO_BALNAME (balP);
 
 #ifndef OBJ_ELF
       tc_set_bal_of_call (callP, balP);
 #endif
       TC_S_FORCE_TO_BALNAME (balP);
 
 #ifndef OBJ_ELF
       tc_set_bal_of_call (callP, balP);
 #endif
-    }                          /* if only one arg, or the args are the same */
+    }
 }
 
 }
 
-/*
-   s_sysproc: process .sysproc pseudo-op
+/* s_sysproc: process .sysproc pseudo-op
 
 
-        .sysproc takes two arguments:
-                arg[1]: name of entry point to system procedure
-                arg[2]: 'entry_num' (index) of system procedure in the range
-                        [0,31] inclusive.
+   .sysproc takes two arguments:
+     arg[1]: name of entry point to system procedure
+     arg[2]: 'entry_num' (index) of system procedure in the range
+     [0,31] inclusive.
+
+   For [ab].out, we store the 'entrynum' in the 'n_other' field of
+   the symbol.  Since that entry is normally 0, we bias 'entrynum'
+   by adding 1 to it.  It must be unbiased before it is used.  */
 
 
-        For [ab].out, we store the 'entrynum' in the 'n_other' field of
-        the symbol.  Since that entry is normally 0, we bias 'entrynum'
-        by adding 1 to it.  It must be unbiased before it is used.  */
 static void
 static void
-s_sysproc (n_ops, args)
-     int n_ops;                        /* Number of operands */
-     char *args[];             /* args[1]->1st operand, args[2]->2nd operand */
+s_sysproc (int n_ops,          /* Number of operands.  */
+          char *args[])        /* args[1]->1st operand, args[2]->2nd operand.  */
 {
   expressionS exp;
   symbolS *symP;
 {
   expressionS exp;
   symbolS *symP;
@@ -2632,7 +2195,7 @@ s_sysproc (n_ops, args)
     {
       as_bad (_("should have two operands"));
       return;
     {
       as_bad (_("should have two operands"));
       return;
-    }                          /* bad arg count */
+    }
 
   /* Parse "entry_num" argument and check it for validity.  */
   parse_expr (args[2], &exp);
 
   /* Parse "entry_num" argument and check it for validity.  */
   parse_expr (args[2], &exp);
@@ -2644,136 +2207,135 @@ s_sysproc (n_ops, args)
       return;
     }
 
       return;
     }
 
-  /* Find/make symbol and stick entry number (biased by +1) into it */
+  /* Find/make symbol and stick entry number (biased by +1) into it */
   symP = symbol_find_or_make (args[1]);
 
   if (TC_S_IS_SYSPROC (symP))
   symP = symbol_find_or_make (args[1]);
 
   if (TC_S_IS_SYSPROC (symP))
-    {
-      as_warn (_("Redefining entrynum for sysproc %s"), S_GET_NAME (symP));
-    }                          /* redefining */
+    as_warn (_("Redefining entrynum for sysproc %s"), S_GET_NAME (symP));
 
 
-  TC_S_SET_SYSPROC (symP, offs (exp)); /* encode entry number */
+  TC_S_SET_SYSPROC (symP, offs (exp)); /* Encode entry number.  */
   TC_S_FORCE_TO_SYSPROC (symP);
 }
 
   TC_S_FORCE_TO_SYSPROC (symP);
 }
 
-/*****************************************************************************
-   shift_ok:
-       Determine if a "shlo" instruction can be used to implement a "ldconst".
-       This means that some number X < 32 can be shifted left to produce the
-       constant of interest.
+/* parse_po:   parse machine-dependent pseudo-op
 
 
-       Return the shift count, or 0 if we can't do it.
-       Caller calculates X by shifting original constant right 'shift' places.
+   This is a top-level routine for machine-dependent pseudo-ops.  It slurps
+   up the rest of the input line, breaks out the individual arguments,
+   and dispatches them to the correct handler.  */
 
 
-  *************************************************************************** */
-static
-int
-shift_ok (n)
-     int n;                    /* The constant of interest */
+static void
+parse_po (int po_num)  /* Pseudo-op number:  currently S_LEAFPROC or S_SYSPROC.  */
 {
 {
-  int shift;                   /* The shift count */
+  /* Pointers operands, with no embedded whitespace.
+     arg[0] unused, arg[1-3]->operands.  */
+  char *args[4];
+  int n_ops;                   /* Number of operands.  */
+  char *p;                     /* Pointer to beginning of unparsed argument string.  */
+  char eol;                    /* Character that indicated end of line.  */
 
 
-  if (n <= 0)
-    {
-      /* Can't do it for negative numbers */
-      return 0;
-    }
+  extern char is_end_of_line[];
 
 
-  /* Shift 'n' right until a 1 is about to be lost */
-  for (shift = 0; (n & 1) == 0; shift++)
-    {
-      n >>= 1;
-    }
+  /* Advance input pointer to end of line.  */
+  p = input_line_pointer;
+  while (!is_end_of_line[(unsigned char) *input_line_pointer])
+    input_line_pointer++;
 
 
-  if (n >= 32)
+  eol = *input_line_pointer;   /* Save end-of-line char.  */
+  *input_line_pointer = '\0';  /* Terminate argument list.  */
+
+  /* Parse out operands.  */
+  n_ops = get_args (p, args);
+  if (n_ops == -1)
+    return;
+
+  /* Dispatch to correct handler.  */
+  switch (po_num)
     {
     {
-      return 0;
+    case S_SYSPROC:
+      s_sysproc (n_ops, args);
+      break;
+    case S_LEAFPROC:
+      s_leafproc (n_ops, args);
+      break;
+    default:
+      BAD_CASE (po_num);
+      break;
     }
     }
-  return shift;
+
+  /* Restore eol, so line numbers get updated correctly.  Base
+     assembler assumes we leave input pointer pointing at char
+     following the eol.  */
+  *input_line_pointer++ = eol;
 }
 
 }
 
-/* syntax: issue syntax error */
+/* reloc_callj:        Relocate a 'callj' instruction
 
 
-static void
-syntax ()
-{
-  as_bad (_("syntax error"));
-}                              /* syntax() */
+       This is a "non-(GNU)-standard" machine-dependent hook.  The base
+       assembler calls it when it decides it can relocate an address at
+       assembly time instead of emitting a relocation directive.
 
 
-/* targ_has_sfr:
+       Check to see if the relocation involves a 'callj' instruction to a:
+           sysproc:    Replace the default 'call' instruction with a 'calls'
+           leafproc:   Replace the default 'call' instruction with a 'bal'.
+           other proc: Do nothing.
 
 
-   Return TRUE iff the target architecture supports the specified
-   special-function register (sfr).  */
+       See b.out.h for details on the 'n_other' field in a symbol structure.
+
+   IMPORTANT!:
+       Assumes the caller has already figured out, in the case of a leafproc,
+       to use the 'bal' entry point, and has substituted that symbol into the
+       passed fixup structure.  */
 
 
-static
 int
 int
-targ_has_sfr (n)
-     int n;                    /* Number (0-31) of sfr */
+reloc_callj (fixS *fixP)  /* Relocation that can be done at assembly time.  */
 {
 {
-  switch (architecture)
-    {
-    case ARCH_KA:
-    case ARCH_KB:
-    case ARCH_MC:
-    case ARCH_JX:
-      return 0;
-    case ARCH_HX:
-      return ((0 <= n) && (n <= 4));
-    case ARCH_CA:
-    default:
-      return ((0 <= n) && (n <= 2));
-    }
-}
+  /* Points to the binary for the instruction being relocated.  */
+  char *where;
 
 
-/* targ_has_iclass:
+  if (!fixP->fx_tcbit)
+    /* This wasn't a callj instruction in the first place.  */
+    return 0;
 
 
-   Return TRUE iff the target architecture supports the indicated
-   class of instructions.  */
-static
-int
-targ_has_iclass (ic)
-     /* Instruction class;  one of:
-        I_BASE, I_CX, I_DEC, I_KX, I_FP, I_MIL, I_CASIM, I_CX2, I_HX, I_HX2
-      */
-     int ic;
-{
-  iclasses_seen |= ic;
-  switch (architecture)
+  where = fixP->fx_frag->fr_literal + fixP->fx_where;
+
+  if (TC_S_IS_SYSPROC (fixP->fx_addsy))
     {
     {
-    case ARCH_KA:
-      return ic & (I_BASE | I_KX);
-    case ARCH_KB:
-      return ic & (I_BASE | I_KX | I_FP | I_DEC);
-    case ARCH_MC:
-      return ic & (I_BASE | I_KX | I_FP | I_DEC | I_MIL);
-    case ARCH_CA:
-      return ic & (I_BASE | I_CX | I_CX2 | I_CASIM);
-    case ARCH_JX:
-      return ic & (I_BASE | I_CX2 | I_JX);
-    case ARCH_HX:
-      return ic & (I_BASE | I_CX2 | I_JX | I_HX);
-    default:
-      if ((iclasses_seen & (I_KX | I_FP | I_DEC | I_MIL))
-         && (iclasses_seen & (I_CX | I_CX2)))
-       {
-         as_warn (_("architecture of opcode conflicts with that of earlier instruction(s)"));
-         iclasses_seen &= ~ic;
-       }
-      return 1;
+      /* Symbol is a .sysproc: replace 'call' with 'calls'.  System
+         procedure number is (other-1).  */
+      md_number_to_chars (where, CALLS | TC_S_GET_SYSPROC (fixP->fx_addsy), 4);
+
+      /* Nothing else needs to be done for this instruction.  Make
+         sure 'md_number_to_field()' will perform a no-op.  */
+      fixP->fx_bit_fixP = (bit_fixS *) 1;
+    }
+  else if (TC_S_IS_CALLNAME (fixP->fx_addsy))
+    {
+      /* Should not happen: see block comment above.  */
+      as_fatal (_("Trying to 'bal' to %s"), S_GET_NAME (fixP->fx_addsy));
+    }
+  else if (TC_S_IS_BALNAME (fixP->fx_addsy))
+    {
+      /* Replace 'call' with 'bal'; both instructions have the same
+         format, so calling code should complete relocation as if
+         nothing happened here.  */
+      md_number_to_chars (where, BAL, 4);
     }
     }
+  else if (TC_S_IS_BADPROC (fixP->fx_addsy))
+    as_bad (_("Looks like a proc, but can't tell what kind.\n"));
+
+  /* Otherwise Symbol is neither a sysproc nor a leafproc.  */
+  return 0;
 }
 
 /* Handle the MRI .endian pseudo-op.  */
 
 static void
 }
 
 /* Handle the MRI .endian pseudo-op.  */
 
 static void
-s_endian (ignore)
-     int ignore;
+s_endian (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
   char c;
 
 {
   char *name;
   char c;
 
-  name = input_line_pointer;
-  c = get_symbol_end ();
+  c = get_symbol_name (&name);
   if (strcasecmp (name, "little") == 0)
     ;
   else if (strcasecmp (name, "big") == 0)
   if (strcasecmp (name, "little") == 0)
     ;
   else if (strcasecmp (name, "big") == 0)
@@ -2781,17 +2343,15 @@ s_endian (ignore)
   else
     as_warn (_("ignoring unrecognized .endian type `%s'"), name);
 
   else
     as_warn (_("ignoring unrecognized .endian type `%s'"), name);
 
-  *input_line_pointer = c;
+  (void) restore_line_pointer (c);
 
   demand_empty_rest_of_line ();
 }
 
 /* We have no need to default values of symbols.  */
 
 
   demand_empty_rest_of_line ();
 }
 
 /* We have no need to default values of symbols.  */
 
-/* ARGSUSED */
 symbolS *
 symbolS *
-md_undefined_symbol (name)
-     char *name;
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 {
   return 0;
 }
 {
   return 0;
 }
@@ -2800,56 +2360,47 @@ md_undefined_symbol (name)
    On the i960, they're relative to the address of the instruction,
    which we have set up as the address of the fixup too.  */
 long
    On the i960, they're relative to the address of the instruction,
    which we have set up as the address of the fixup too.  */
 long
-md_pcrel_from (fixP)
-     fixS *fixP;
+md_pcrel_from (fixS *fixP)
 {
   return fixP->fx_where + fixP->fx_frag->fr_address;
 }
 
 {
   return fixP->fx_where + fixP->fx_frag->fr_address;
 }
 
-#ifdef BFD_ASSEMBLER
-int
-md_apply_fix (fixP, valp)
-     fixS *fixP;
-     valueT *valp;
-#else
 void
 void
-md_apply_fix (fixP, val)
-     fixS *fixP;
-     long val;
-#endif
+md_apply_fix (fixS *fixP,
+              valueT *valP,
+              segT seg ATTRIBUTE_UNUSED)
 {
 {
-#ifdef BFD_ASSEMBLER
-  long val = *valp;
-#endif
+  long val = *valP;
   char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
 
   if (!fixP->fx_bit_fixP)
     {
   char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
 
   if (!fixP->fx_bit_fixP)
     {
-#ifndef BFD_ASSEMBLER
-      /* For callx, we always want to write out zero, and emit a
-        symbolic relocation.  */
-      if (fixP->fx_bsr)
-       val = 0;
-
-      fixP->fx_addnumber = val;
-#endif
-
-      md_number_to_imm (place, val, fixP->fx_size, fixP);
+      md_number_to_imm (place, val, fixP->fx_size);
+    }
+  else if ((int) (size_t) fixP->fx_bit_fixP == 13
+          && fixP->fx_addsy != NULL
+          && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section)
+    {
+      /* This is a COBR instruction.  They have only a
+        13-bit displacement and are only to be used
+        for local branches: flag as error, don't generate
+        relocation.  */
+      as_bad_where (fixP->fx_file, fixP->fx_line,
+                   _("can't use COBR format with external label"));
+      fixP->fx_addsy = NULL;
     }
   else
     md_number_to_field (place, val, fixP->fx_bit_fixP);
 
     }
   else
     md_number_to_field (place, val, fixP->fx_bit_fixP);
 
-#ifdef BFD_ASSEMBLER
-  return 0;
-#endif
+  if (fixP->fx_addsy == NULL)
+    fixP->fx_done = 1;
 }
 
 #if defined(OBJ_AOUT) | defined(OBJ_BOUT)
 void
 }
 
 #if defined(OBJ_AOUT) | defined(OBJ_BOUT)
 void
-tc_bout_fix_to_chars (where, fixP, segment_address_in_file)
-     char *where;
-     fixS *fixP;
-     relax_addressT segment_address_in_file;
+tc_bout_fix_to_chars (char *where,
+                     fixS *fixP,
+                     relax_addressT segment_address_in_file)
 {
   static const unsigned char nbytes_r_length[] = {42, 0, 1, 42, 2};
   struct relocation_info ri;
 {
   static const unsigned char nbytes_r_length[] = {42, 0, 1, 42, 2};
   struct relocation_info ri;
@@ -2906,180 +2457,20 @@ tc_bout_fix_to_chars (where, fixP, segment_address_in_file)
 
 #endif /* OBJ_AOUT or OBJ_BOUT */
 
 
 #endif /* OBJ_AOUT or OBJ_BOUT */
 
-#if defined (OBJ_COFF) && defined (BFD)
-short
-tc_coff_fix2rtype (fixP)
-     fixS *fixP;
-{
-  if (fixP->fx_bsr)
-    abort ();
-
-  if (fixP->fx_pcrel == 0 && fixP->fx_size == 4)
-    return R_RELLONG;
-
-  if (fixP->fx_pcrel != 0 && fixP->fx_size == 4)
-    return R_IPRMED;
-
-  abort ();
-  return 0;
-}
-
-int
-tc_coff_sizemachdep (frag)
-     fragS *frag;
-{
-  if (frag->fr_next)
-    return frag->fr_next->fr_address - frag->fr_address;
-  else
-    return 0;
-}
-#endif
-
 /* Align an address by rounding it up to the specified boundary.  */
 /* Align an address by rounding it up to the specified boundary.  */
+
 valueT
 valueT
-md_section_align (seg, addr)
-     segT seg;
-     valueT addr;              /* Address to be rounded up */
+md_section_align (segT seg,
+                 valueT addr)          /* Address to be rounded up.  */
 {
   int align;
 {
   int align;
-#ifdef BFD_ASSEMBLER
+
   align = bfd_get_section_alignment (stdoutput, seg);
   align = bfd_get_section_alignment (stdoutput, seg);
-#else
-  align = section_alignment[(int) seg];
-#endif
-  return (addr + (1 << align) - 1) & (-1 << align);
+  return (addr + (1 << align) - 1) & -(1 << align);
 }
 
 extern int coff_flags;
 
 }
 
 extern int coff_flags;
 
-#ifdef OBJ_COFF
-void
-tc_headers_hook (headers)
-     object_headers *headers;
-{
-  switch (architecture)
-    {
-    case ARCH_KA:
-      coff_flags |= F_I960KA;
-      break;
-
-    case ARCH_KB:
-      coff_flags |= F_I960KB;
-      break;
-
-    case ARCH_MC:
-      coff_flags |= F_I960MC;
-      break;
-
-    case ARCH_CA:
-      coff_flags |= F_I960CA;
-      break;
-
-    case ARCH_JX:
-      coff_flags |= F_I960JX;
-      break;
-
-    case ARCH_HX:
-      coff_flags |= F_I960HX;
-      break;
-
-    default:
-      if (iclasses_seen == I_BASE)
-       coff_flags |= F_I960CORE;
-      else if (iclasses_seen & I_CX)
-       coff_flags |= F_I960CA;
-      else if (iclasses_seen & I_HX)
-       coff_flags |= F_I960HX;
-      else if (iclasses_seen & I_JX)
-       coff_flags |= F_I960JX;
-      else if (iclasses_seen & I_CX2)
-       coff_flags |= F_I960CA;
-      else if (iclasses_seen & I_MIL)
-       coff_flags |= F_I960MC;
-      else if (iclasses_seen & (I_DEC | I_FP))
-       coff_flags |= F_I960KB;
-      else
-       coff_flags |= F_I960KA;
-      break;
-    }
-
-  if (flag_readonly_data_in_text)
-    {
-      headers->filehdr.f_magic = I960RWMAGIC;
-      headers->aouthdr.magic = OMAGIC;
-    }
-  else
-    {
-      headers->filehdr.f_magic = I960ROMAGIC;
-      headers->aouthdr.magic = NMAGIC;
-    }                          /* set magic numbers */
-}
-
-#endif /* OBJ_COFF */
-
-#ifndef BFD_ASSEMBLER
-
-/* Things going on here:
-
-   For bout, We need to assure a couple of simplifying
-   assumptions about leafprocs for the linker: the leafproc
-   entry symbols will be defined in the same assembly in
-   which they're declared with the '.leafproc' directive;
-   and if a leafproc has both 'call' and 'bal' entry points
-   they are both global or both local.
-
-   For coff, the call symbol has a second aux entry that
-   contains the bal entry point.  The bal symbol becomes a
-   label.
-
-   For coff representation, the call symbol has a second aux entry that
-   contains the bal entry point.  The bal symbol becomes a label.  */
-
-void
-tc_crawl_symbol_chain (headers)
-     object_headers *headers;
-{
-  symbolS *symbolP;
-
-  for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
-    {
-#ifdef OBJ_COFF
-      if (TC_S_IS_SYSPROC (symbolP))
-       {
-         /* second aux entry already contains the sysproc number */
-         S_SET_NUMBER_AUXILIARY (symbolP, 2);
-         S_SET_STORAGE_CLASS (symbolP, C_SCALL);
-         S_SET_DATA_TYPE (symbolP, S_GET_DATA_TYPE (symbolP) | (DT_FCN << N_BTSHFT));
-         continue;
-       }                       /* rewrite sysproc */
-#endif /* OBJ_COFF */
-
-      if (!TC_S_IS_BALNAME (symbolP) && !TC_S_IS_CALLNAME (symbolP))
-       {
-         continue;
-       }                       /* Not a leafproc symbol */
-
-      if (!S_IS_DEFINED (symbolP))
-       {
-         as_bad (_("leafproc symbol '%s' undefined"), S_GET_NAME (symbolP));
-       }                       /* undefined leaf */
-
-      if (TC_S_IS_CALLNAME (symbolP))
-       {
-         symbolS *balP = tc_get_bal_of_call (symbolP);
-         if (S_IS_EXTERNAL (symbolP) != S_IS_EXTERNAL (balP))
-           {
-             S_SET_EXTERNAL (symbolP);
-             S_SET_EXTERNAL (balP);
-             as_warn (_("Warning: making leafproc entries %s and %s both global\n"),
-                      S_GET_NAME (symbolP), S_GET_NAME (balP));
-           }                   /* externality mismatch */
-       }                       /* if callname */
-    }                          /* walk the symbol chain */
-}
-
-#endif /* ! BFD_ASSEMBLER */
-
 /* For aout or bout, the bal immediately follows the call.
 
    For coff, we cheat and store a pointer to the bal symbol in the
 /* For aout or bout, the bal immediately follows the call.
 
    For coff, we cheat and store a pointer to the bal symbol in the
@@ -3094,9 +2485,8 @@ tc_crawl_symbol_chain (headers)
 #endif
 
 void
 #endif
 
 void
-tc_set_bal_of_call (callP, balP)
-     symbolS *callP;
-     symbolS *balP;
+tc_set_bal_of_call (symbolS *callP ATTRIBUTE_UNUSED,
+                   symbolS *balP ATTRIBUTE_UNUSED)
 {
   know (TC_S_IS_CALLNAME (callP));
   know (TC_S_IS_BALNAME (balP));
 {
   know (TC_S_IS_CALLNAME (callP));
   know (TC_S_IS_BALNAME (balP));
@@ -3110,8 +2500,7 @@ tc_set_bal_of_call (callP, balP)
 #ifdef OBJ_ABOUT
 
   /* If the 'bal' entry doesn't immediately follow the 'call'
 #ifdef OBJ_ABOUT
 
   /* If the 'bal' entry doesn't immediately follow the 'call'
-     * symbol, unlink it from the symbol list and re-insert it.
-   */
+     symbol, unlink it from the symbol list and re-insert it.  */
   if (symbol_next (callP) != balP)
     {
       symbol_remove (balP, &symbol_rootP, &symbol_lastP);
   if (symbol_next (callP) != balP)
     {
       symbol_remove (balP, &symbol_rootP, &symbol_lastP);
@@ -3125,8 +2514,7 @@ tc_set_bal_of_call (callP, balP)
 }
 
 symbolS *
 }
 
 symbolS *
-tc_get_bal_of_call (callP)
-     symbolS *callP;
+tc_get_bal_of_call (symbolS *callP ATTRIBUTE_UNUSED)
 {
   symbolS *retval;
 
 {
   symbolS *retval;
 
@@ -3144,46 +2532,38 @@ tc_get_bal_of_call (callP)
 
   know (TC_S_IS_BALNAME (retval));
   return retval;
 
   know (TC_S_IS_BALNAME (retval));
   return retval;
-}                              /* _tc_get_bal_of_call() */
+}
 
 
+#ifdef OBJ_COFF
 void
 void
-tc_coff_symbol_emit_hook (symbolP)
-     symbolS *symbolP;
+tc_coff_symbol_emit_hook (symbolS *symbolP ATTRIBUTE_UNUSED)
 {
   if (TC_S_IS_CALLNAME (symbolP))
     {
 {
   if (TC_S_IS_CALLNAME (symbolP))
     {
-#ifdef OBJ_COFF
       symbolS *balP = tc_get_bal_of_call (symbolP);
 
       symbolS *balP = tc_get_bal_of_call (symbolP);
 
-#if 0
-      /* second aux entry contains the bal entry point */
-      S_SET_NUMBER_AUXILIARY (symbolP, 2);
-#endif
       symbolP->sy_symbol.ost_auxent[1].x_bal.x_balntry = S_GET_VALUE (balP);
       if (S_GET_STORAGE_CLASS (symbolP) == C_EXT)
        S_SET_STORAGE_CLASS (symbolP, C_LEAFEXT);
       else
        S_SET_STORAGE_CLASS (symbolP, C_LEAFSTAT);
       S_SET_DATA_TYPE (symbolP, S_GET_DATA_TYPE (symbolP) | (DT_FCN << N_BTSHFT));
       symbolP->sy_symbol.ost_auxent[1].x_bal.x_balntry = S_GET_VALUE (balP);
       if (S_GET_STORAGE_CLASS (symbolP) == C_EXT)
        S_SET_STORAGE_CLASS (symbolP, C_LEAFEXT);
       else
        S_SET_STORAGE_CLASS (symbolP, C_LEAFSTAT);
       S_SET_DATA_TYPE (symbolP, S_GET_DATA_TYPE (symbolP) | (DT_FCN << N_BTSHFT));
-      /* fix up the bal symbol */
+      /* Fix up the bal symbol.  */
       S_SET_STORAGE_CLASS (balP, C_LABEL);
       S_SET_STORAGE_CLASS (balP, C_LABEL);
-#endif /* OBJ_COFF */
-    }                          /* only on calls */
+    }
 }
 }
+#endif /* OBJ_COFF */
 
 void
 
 void
-i960_handle_align (fragp)
-     fragS *fragp;
+i960_handle_align (fragS *fragp ATTRIBUTE_UNUSED)
 {
   if (!linkrelax)
     return;
 
 #ifndef OBJ_BOUT
 {
   if (!linkrelax)
     return;
 
 #ifndef OBJ_BOUT
-
   as_bad (_("option --link-relax is only supported in b.out format"));
   linkrelax = 0;
   return;
   as_bad (_("option --link-relax is only supported in b.out format"));
   linkrelax = 0;
   return;
-
 #else
 
   /* The text section "ends" with another alignment reloc, to which we
 #else
 
   /* The text section "ends" with another alignment reloc, to which we
@@ -3199,62 +2579,30 @@ i960_handle_align (fragp)
 }
 
 int
 }
 
 int
-i960_validate_fix (fixP, this_segment_type, add_symbolPP)
-     fixS *fixP;
-     segT this_segment_type;
-     symbolS **add_symbolPP;
+i960_validate_fix (fixS *fixP, segT this_segment_type ATTRIBUTE_UNUSED)
 {
 {
-#define add_symbolP (*add_symbolPP)
-  if (fixP->fx_tcbit && TC_S_IS_CALLNAME (add_symbolP))
+  if (fixP->fx_tcbit && TC_S_IS_CALLNAME (fixP->fx_addsy))
     {
       /* Relocation should be done via the associated 'bal'
          entry point symbol.  */
     {
       /* Relocation should be done via the associated 'bal'
          entry point symbol.  */
-
-      if (!TC_S_IS_BALNAME (tc_get_bal_of_call (add_symbolP)))
+      if (!TC_S_IS_BALNAME (tc_get_bal_of_call (fixP->fx_addsy)))
        {
        {
-         as_bad (_("No 'bal' entry point for leafproc %s"),
-                 S_GET_NAME (add_symbolP));
-         return 1;
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("No 'bal' entry point for leafproc %s"),
+                       S_GET_NAME (fixP->fx_addsy));
+         return 0;
        }
        }
-      fixP->fx_addsy = add_symbolP = tc_get_bal_of_call (add_symbolP);
+      fixP->fx_addsy = tc_get_bal_of_call (fixP->fx_addsy);
     }
     }
-#if 0
-  /* Still have to work out other conditions for these tests.  */
-  {
-    if (fixP->fx_tcbit)
-      {
-       as_bad (_("callj to difference of two symbols"));
-       return 1;
-      }
-    reloc_callj (fixP);
-    if ((int) fixP->fx_bit_fixP == 13)
-      {
-       /* This is a COBR instruction.  They have only a 13-bit
-          displacement and are only to be used for local branches:
-          flag as error, don't generate relocation.  */
-       as_bad (_("can't use COBR format with external label"));
-       fixP->fx_addsy = NULL;  /* No relocations please.  */
-       return 1;
-      }
-  }
-#endif
-#undef add_symbolP
-  return 0;
-}
 
 
-#ifdef BFD_ASSEMBLER
+  return 1;
+}
 
 /* From cgen.c:  */
 
 static short
 
 /* From cgen.c:  */
 
 static short
-tc_bfd_fix2rtype (fixP)
-     fixS *fixP;
+tc_bfd_fix2rtype (fixS *fixP)
 {
 {
-#if 0
-  if (fixP->fx_bsr)
-    abort ();
-#endif
-
   if (fixP->fx_pcrel == 0 && fixP->fx_size == 4)
     return BFD_RELOC_32;
 
   if (fixP->fx_pcrel == 0 && fixP->fx_size == 4)
     return BFD_RELOC_32;
 
@@ -3271,30 +2619,28 @@ tc_bfd_fix2rtype (fixP)
    FIXME: To what extent can we get all relevant targets to use this?  */
 
 arelent *
    FIXME: To what extent can we get all relevant targets to use this?  */
 
 arelent *
-tc_gen_reloc (section, fixP)
-     asection *section;
-     fixS *fixP;
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
 {
   arelent * reloc;
 
 {
   arelent * reloc;
 
-  reloc = (arelent *) xmalloc (sizeof (arelent));
+  reloc = xmalloc (sizeof (arelent));
 
 
-  /* HACK: Is this right? */
+  /* HACK: Is this right?  */
   fixP->fx_r_type = tc_bfd_fix2rtype (fixP);
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
   fixP->fx_r_type = tc_bfd_fix2rtype (fixP);
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
-  if (reloc->howto == (reloc_howto_type *) NULL)
+  if (reloc->howto == NULL)
     {
       as_bad_where (fixP->fx_file, fixP->fx_line,
     {
       as_bad_where (fixP->fx_file, fixP->fx_line,
-                   "internal error: can't export reloc type %d (`%s')",
+                   _("internal error: can't export reloc type %d (`%s')"),
                    fixP->fx_r_type,
                    bfd_get_reloc_code_name (fixP->fx_r_type));
       return NULL;
     }
 
                    fixP->fx_r_type,
                    bfd_get_reloc_code_name (fixP->fx_r_type));
       return NULL;
     }
 
-  assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
+  gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
 
 
-  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
   reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
   reloc->addend = fixP->fx_addnumber;
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
   reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
   reloc->addend = fixP->fx_addnumber;
@@ -3304,6 +2650,16 @@ tc_gen_reloc (section, fixP)
 
 /* end from cgen.c */
 
 
 /* end from cgen.c */
 
-#endif /* BFD_ASSEMBLER */
+const pseudo_typeS md_pseudo_table[] =
+{
+  {"bss", s_lcomm, 1},
+  {"endian", s_endian, 0},
+  {"extended", float_cons, 't'},
+  {"leafproc", parse_po, S_LEAFPROC},
+  {"sysproc", parse_po, S_SYSPROC},
+
+  {"word", cons, 4},
+  {"quad", cons, 16},
 
 
-/* end of tc-i960.c */
+  {0, 0, 0}
+};
This page took 0.079893 seconds and 4 git commands to generate.