update copyright dates
[deliverable/binutils-gdb.git] / gas / config / tc-i860.c
index d9dd84cd906abcee9795e28ee7b633acb33d5ae2..ec9bda8a33e840a939fb3f72f443f08192f920a1 100644 (file)
-/* i860.c -- Assemble for the I860
-   Copyright (C) 1989 Free Software Foundation, Inc.
+/* tc-i860.c -- Assembler for the Intel i860 architecture.
+   Copyright 1989, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2002,
+   2003, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
-This file is part of GAS, the GNU Assembler.
+   Brought back from the dead and completely reworked
+   by Jason Eckhardt <jle@cygnus.com>.
 
-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 1, or (at your option)
-any later version.
+   This file is part of GAS, the GNU Assembler.
 
-GAS is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   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 3, or (at your option)
+   any later version.
 
-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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   GAS is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-/* $Id$ */
+   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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 #include "as.h"
+#include "safe-ctype.h"
+#include "subsegs.h"
+#include "opcode/i860.h"
+#include "elf/i860.h"
 
-#include "i860-opcode.h"
-
-/* incorporated from i860.h */
-enum reloc_type /* NOTE: three bits max, see struct reloc_info_i860.r_type */
-{
-    NO_RELOC = 0, BRADDR, LOW0, LOW1, LOW2, LOW3, LOW4, SPLIT0, SPLIT1, SPLIT2, RELOC_32,
-};
-      
-enum highlow_type       /* NOTE: two bits max, see reloc_info_i860.r_type */
-{
-    NO_SPEC = 0, PAIR, HIGH, HIGHADJ,
-};
-          
-struct reloc_info_i860
-{
-    unsigned long r_address;
-/*
- * Using bit fields here is a bad idea because the order is not portable. :-(
- */
-    unsigned int r_symbolnum: 24;
-    unsigned int r_pcrel    : 1;
-    unsigned int r_extern   : 1;
-    /* combining the two field simplifies the argument passing in "new_fix()" */
-    /* and is compatible with the existing Sparc #ifdef's */
-    /* r_type:  highlow_type - bits 5,4; reloc_type - bits 3-0 */
-    unsigned int r_type     : 6;
-    long r_addend;
-};
-
-#define relocation_info reloc_info_i860
 
+/* The opcode hash table.  */
+static struct hash_control *op_hash = NULL;
 
-void md_begin();
-void md_end();
-void md_number_to_chars();
-void md_assemble();
-char *md_atof();
-void md_convert_frag();
-void md_create_short_jump();
-void md_create_long_jump();
-int  md_estimate_size_before_relax();
-void md_number_to_imm();
-void md_number_to_disp();
-void md_number_to_field();
-void md_ri_to_chars();
-static void i860_ip();
-void emit_machine_reloc();
+/* These characters always start a comment.  */
+const char comment_chars[] = "#!/";
 
-int md_reloc_size = sizeof(struct relocation_info);
+/* These characters start a comment at the beginning of a line.  */
+const char line_comment_chars[] = "#/";
 
-void (*md_emit_relocations)() = emit_machine_reloc;
+const char line_separator_chars[] = ";";
 
-const relax_typeS md_relax_table[] = { 0 };
+/* Characters that can be used to separate the mantissa from the exponent
+   in floating point numbers.  */
+const char EXP_CHARS[] = "eE";
 
-/* handle of the OPCODE hash table */
-static struct hash_control *op_hash = NULL;
+/* Characters that indicate this number is a floating point constant.
+   As in 0f12.456 or 0d1.2345e12.  */
+const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
-static void s_dual(), s_enddual();
-static void s_atmp();
+/* Register prefix (depends on syntax).  */
+static char reg_prefix;
 
-const pseudo_typeS
-md_pseudo_table[] = {
-    { "dual",       s_dual,     4 },
-    { "enddual",    s_enddual,  4 },
-    { "atmp",      s_atmp,     4 },
-    { NULL,         0,          0 },
-};
+#define MAX_FIXUPS 2
 
-int md_short_jump_size = 4;
-int md_long_jump_size = 4;
-
-/* This array holds the chars that always start a comment.  If the
-    pre-processor is disabled, these aren't very useful */
-char comment_chars[] = "!/";   /* JF removed '|' from comment_chars */
-
-/* This array holds the chars that only start a comment at the beginning of
-   a line.  If the line seems to have the form '# 123 filename'
-   .line and .file directives will appear in the pre-processed output */
-/* 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. */
-/* Also note that comments like this one will always work. */
-char line_comment_chars[] = "#/";
-
-/* Chars that can be used to separate mant from exp in floating point nums */
-char EXP_CHARS[] = "eE";
-
-/* Chars that mean this number is a floating point constant */
-/* As in 0f12.456 */
-/* or    0d1.2345e12 */
-char FLT_CHARS[] = "rRsSfFdDxXpP";
-
-/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
-   changed in read.c .  Ideally it shouldn't have to know about it at all,
-   but nothing is ideal around here.
- */
-int size_reloc_info = sizeof(struct relocation_info);
-
-static unsigned char octal[256];
-#define isoctal(c)  octal[c]
-static unsigned char toHex[256];
-
-struct i860_it {
-    char    *error;
-    unsigned long opcode;
-    struct nlist *nlistp;
+struct i860_it
+{
+  char *error;
+  unsigned long opcode;
+  enum expand_type expand;
+  struct i860_fi
+  {
     expressionS exp;
+    bfd_reloc_code_real_type reloc;
     int pcrel;
-    enum expand_type expand;
-    enum highlow_type highlow;
-    enum reloc_type reloc;
+    valueT fup;
+  } fi[MAX_FIXUPS];
 } the_insn;
 
-#ifdef __STDC__
-static void print_insn(struct i860_it *insn);
-static int getExpression(char *str);
-#else
-static void print_insn();
-static int getExpression();
-#endif
+/* The current fixup count.  */
+static int fc;
+
 static char *expr_end;
-static char last_expand;       /* error if expansion after branch */
 
+/* Indicates error if a pseudo operation was expanded after a branch.  */
+static char last_expand;
+
+/* If true, then warn if any pseudo operations were expanded.  */
+static int target_warn_expand = 0;
+
+/* If true, then XP support is enabled.  */
+static int target_xp = 0;
+
+/* If true, then Intel syntax is enabled (default to AT&T/SVR4 syntax).  */
+static int target_intel_syntax = 0;
+
+
+/* Prototypes.  */
+static void i860_process_insn (char *);
+static void s_dual (int);
+static void s_enddual (int);
+static void s_atmp (int);
+static void s_align_wrapper (int);
+static int i860_get_expression (char *);
+static bfd_reloc_code_real_type obtain_reloc_for_imm16 (fixS *, long *); 
+#ifdef DEBUG_I860
+static void print_insn (struct i860_it *);
+#endif
+
+const pseudo_typeS md_pseudo_table[] =
+{
+  {"align",   s_align_wrapper, 0},
+  {"dual",    s_dual,          0},
+  {"enddual", s_enddual,       0},
+  {"atmp",    s_atmp,          0},
+  {NULL,      0,               0},
+};
+
+/* Dual-instruction mode handling.  */
 enum dual
 {
-    DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT,
+  DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT,
 };
-static enum dual dual_mode = DUAL_OFF; /* dual-instruction mode */
+static enum dual dual_mode = DUAL_OFF;
 
+/* Handle ".dual" directive.  */
 static void
-s_dual()       /* floating point instructions have dual set */
+s_dual (int ignore ATTRIBUTE_UNUSED)
 {
+  if (target_intel_syntax)
     dual_mode = DUAL_ON;
+  else
+    as_bad (_("Directive .dual available only with -mintel-syntax option"));
 }
 
+/* Handle ".enddual" directive.  */
 static void
-s_enddual()    /* floating point instructions have dual set */
+s_enddual (int ignore ATTRIBUTE_UNUSED)
 {
+  if (target_intel_syntax)
     dual_mode = DUAL_OFF;
+  else
+    as_bad (_("Directive .enddual available only with -mintel-syntax option"));
 }
 
-static int atmp = 31; /* temporary register for pseudo's */
+/* Temporary register used when expanding assembler pseudo operations.  */
+static int atmp = 31;
 
 static void
-s_atmp()
+s_atmp (int ignore ATTRIBUTE_UNUSED)
 {
-    register int temp;
-    if (strncmp(input_line_pointer, "sp", 2) == 0) {
+  int temp;
+
+  if (! target_intel_syntax)
+    {
+      as_bad (_("Directive .atmp available only with -mintel-syntax option"));
+      demand_empty_rest_of_line ();
+      return;
+    }
+
+  if (strncmp (input_line_pointer, "sp", 2) == 0)
+    {
       input_line_pointer += 2;
       atmp = 2;
     }
-    else if (strncmp(input_line_pointer, "fp", 2) == 0) {
+  else if (strncmp (input_line_pointer, "fp", 2) == 0)
+    {
       input_line_pointer += 2;
       atmp = 3;
     }
-    else if (strncmp(input_line_pointer, "r", 1) == 0) {
+  else if (strncmp (input_line_pointer, "r", 1) == 0)
+    {
       input_line_pointer += 1;
-      temp = get_absolute_expression();
+      temp = get_absolute_expression ();
       if (temp >= 0 && temp <= 31)
-          atmp = temp;
-        else
-            as_bad("Unknown temporary pseudo register");
+       atmp = temp;
+      else
+       as_bad (_("Unknown temporary pseudo register"));
     }
-    else {
-        as_bad("Unknown temporary pseudo register");
+  else
+    {
+      as_bad (_("Unknown temporary pseudo register"));
     }
-    demand_empty_rest_of_line();
-    return;
+  demand_empty_rest_of_line ();
+}
+
+/* Handle ".align" directive depending on syntax mode.
+   AT&T/SVR4 syntax uses the standard align directive.  However, 
+   the Intel syntax additionally allows keywords for the alignment
+   parameter: ".align type", where type is one of {.short, .long,
+   .quad, .single, .double} representing alignments of 2, 4,
+   16, 4, and 8, respectively.  */
+static void
+s_align_wrapper (int arg)
+{
+  char *parm = input_line_pointer;
+
+  if (target_intel_syntax)
+    {
+      /* Replace a keyword with the equivalent integer so the
+         standard align routine can parse the directive.  */
+      if (strncmp (parm, ".short", 6) == 0)
+        strncpy (parm, "     2", 6);
+      else if (strncmp (parm, ".long", 5) == 0)
+        strncpy (parm, "    4", 5);
+      else if (strncmp (parm, ".quad", 5) == 0)
+        strncpy (parm, "   16", 5);
+      else if (strncmp (parm, ".single", 7) == 0)
+        strncpy (parm, "      4", 7);
+      else if (strncmp (parm, ".double", 7) == 0)
+        strncpy (parm, "      8", 7);
+     
+      while (*input_line_pointer == ' ')
+        ++input_line_pointer;
+    }
+
+  s_align_bytes (arg);
 }
 
 /* This function is called once, at assembler startup time.  It should
-   set up all the tables, etc. that the MD part of the assembler will need.  */
+   set up all the tables and data structures that the MD part of the
+   assembler will need.  */
 void
-md_begin()
+md_begin (void)
 {
-  register char *retval = NULL;
+  const char *retval = NULL;
   int lose = 0;
-  register unsigned int i = 0;
+  unsigned int i = 0;
 
-  op_hash = hash_new();
-  if (op_hash == NULL)
-    as_fatal("Virtual memory exhausted");
+  op_hash = hash_new ();
 
-  while (i < NUMOPCODES)
+  while (i860_opcodes[i].name != NULL)
     {
       const char *name = i860_opcodes[i].name;
-      retval = hash_insert(op_hash, name, &i860_opcodes[i]);
-      if(retval != NULL && *retval != '\0')
+      retval = hash_insert (op_hash, name, (void *) &i860_opcodes[i]);
+      if (retval != NULL)
        {
-         fprintf (stderr, "internal error: can't hash `%s': %s\n",
+         fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
                   i860_opcodes[i].name, retval);
          lose = 1;
        }
@@ -218,1038 +232,1260 @@ md_begin()
        {
          if (i860_opcodes[i].match & i860_opcodes[i].lose)
            {
-             fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",
+             fprintf (stderr,
+                      _("internal error: losing opcode: `%s' \"%s\"\n"),
                       i860_opcodes[i].name, i860_opcodes[i].args);
              lose = 1;
            }
          ++i;
-       } while (i < NUMOPCODES
-                && !strcmp(i860_opcodes[i].name, name));
+       }
+      while (i860_opcodes[i].name != NULL
+            && strcmp (i860_opcodes[i].name, name) == 0);
     }
 
   if (lose)
-    as_fatal("Broken assembler.  No assembly attempted.");
-
-  for (i = '0'; i < '8'; ++i)
-    octal[i] = 1;
-  for (i = '0'; i <= '9'; ++i)
-    toHex[i] = i - '0';
-  for (i = 'a'; i <= 'f'; ++i)
-    toHex[i] = i + 10 - 'a';
-  for (i = 'A'; i <= 'F'; ++i)
-    toHex[i] = i + 10 - 'A';
-}
+    as_fatal (_("Defective assembler.  No assembly attempted."));
 
-void
-md_end()
-{
-    return;
+  /* Set the register prefix for either Intel or AT&T/SVR4 syntax.  */
+  reg_prefix = target_intel_syntax ? 0 : '%';
 }
 
+/* This is the core of the machine-dependent assembler.  STR points to a
+   machine dependent instruction.  This function emits the frags/bytes
+   it assembles to.  */
 void
-md_assemble(str)
-    char *str;
+md_assemble (char *str)
 {
-    char *toP;
-    int rsd;
-    int no_opcodes = 1;
-    int i;
-    struct i860_it pseudo[3];
-
-    assert(str);
-    i860_ip(str);
-
-    /* check for expandable flag to produce pseudo-instructions */
-    if (the_insn.expand != 0 && the_insn.highlow == NO_SPEC) {
-       for (i = 0; i < 3; i++)
-           pseudo[i] = the_insn;
+  char *destp;
+  int num_opcodes = 1;
+  int i;
+  struct i860_it pseudo[3];
+
+  gas_assert (str);
+  fc = 0;
+
+  /* Assemble the instruction.  */
+  i860_process_insn (str);
+
+  /* Check for expandable flag to produce pseudo-instructions.  This
+     is an undesirable feature that should be avoided.  */
+  if (the_insn.expand != 0 && the_insn.expand != XP_ONLY
+      && ! (the_insn.fi[0].fup & (OP_SEL_HA | OP_SEL_H | OP_SEL_L | OP_SEL_GOT
+                           | OP_SEL_GOTOFF | OP_SEL_PLT)))
+    {
+      for (i = 0; i < 3; i++)
+       pseudo[i] = the_insn;
 
-       switch (the_insn.expand) {
+      fc = 1;
+      switch (the_insn.expand)
+       {
 
        case E_DELAY:
-               no_opcodes = 1;
-               break;
+         num_opcodes = 1;
+         break;
 
        case E_MOV:
-           if (the_insn.exp.X_add_symbol == NULL &&
-               the_insn.exp.X_subtract_symbol == NULL &&
-               (the_insn.exp.X_add_number < (1 << 15) &&
-                the_insn.exp.X_add_number >= -(1 << 15)))
-               break;
-           /* or l%const,r0,ireg_dest */
-           pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000;
-           pseudo[0].highlow = PAIR;
-           /* orh h%const,ireg_dest,ireg_dest */
-           pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 |
-               ((the_insn.opcode & 0x001f0000) << 5);
-           pseudo[1].highlow = HIGH;
-           no_opcodes = 2;
+         if (the_insn.fi[0].exp.X_add_symbol == NULL
+             && the_insn.fi[0].exp.X_op_symbol == NULL
+             && (the_insn.fi[0].exp.X_add_number < (1 << 15)
+                 && the_insn.fi[0].exp.X_add_number >= -(1 << 15)))
            break;
 
+         /* Emit "or l%const,r0,ireg_dest".  */
+         pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000;
+         pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_L);
+
+         /* Emit "orh h%const,ireg_dest,ireg_dest".  */
+         pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000
+                             | ((the_insn.opcode & 0x001f0000) << 5);
+         pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_H);
+
+         num_opcodes = 2;
+         break;
+
        case E_ADDR:
-           if (the_insn.exp.X_add_symbol == NULL &&
-               the_insn.exp.X_subtract_symbol == NULL)
-               break;
-           /* orh ha%addr_expr,r0,r31 */
-           pseudo[0].opcode = 0xec000000 | (atmp<<16);
-           pseudo[0].highlow = HIGHADJ;
-           pseudo[0].reloc = LOW0;     /* must overwrite */
-           /* l%addr_expr(r31),ireg_dest */
-           pseudo[1].opcode = (the_insn.opcode & ~0x003e0000) | (atmp << 21);
-           pseudo[1].highlow = PAIR;
-           no_opcodes = 2;
+         if (the_insn.fi[0].exp.X_add_symbol == NULL
+             && the_insn.fi[0].exp.X_op_symbol == NULL
+             && (the_insn.fi[0].exp.X_add_number < (1 << 15)
+                 && the_insn.fi[0].exp.X_add_number >= -(1 << 15)))
            break;
 
-       case E_U32:     /* 2nd version emulates Intel as, not doc. */
-           if (the_insn.exp.X_add_symbol == NULL &&
-               the_insn.exp.X_subtract_symbol == NULL &&
-               (the_insn.exp.X_add_number < (1 << 16) &&
-                the_insn.exp.X_add_number >= 0))
-               break;
-           /* $(opcode)h h%const,ireg_src2,ireg_dest
-           pseudo[0].opcode = (the_insn.opcode & 0xf3ffffff) | 0x0c000000; */
-           /* $(opcode)h h%const,ireg_src2,r31 */
-           pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 |
-               (atmp << 16);
-           pseudo[0].highlow = HIGH;
-           /* $(opcode) l%const,ireg_dest,ireg_dest
-           pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |
-               ((the_insn.opcode & 0x001f0000) << 5); */
-           /* $(opcode) l%const,r31,ireg_dest */
-           pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |
-               (atmp << 21);
-           pseudo[1].highlow = PAIR;
-           no_opcodes = 2;
+         /* Emit "orh ha%addr_expr,ireg_src2,r31".  */
+         pseudo[0].opcode = 0xec000000 | (the_insn.opcode & 0x03e00000)
+                            | (atmp << 16);
+         pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_HA);
+
+         /* Emit "l%addr_expr(r31),ireg_dest".  We pick up the fixup
+            information from the original instruction.   */
+         pseudo[1].opcode = (the_insn.opcode & ~0x03e00000) | (atmp << 21);
+         pseudo[1].fi[0].fup = the_insn.fi[0].fup | OP_SEL_L;
+
+         num_opcodes = 2;
+         break;
+
+       case E_U32:
+         if (the_insn.fi[0].exp.X_add_symbol == NULL
+             && the_insn.fi[0].exp.X_op_symbol == NULL
+             && (the_insn.fi[0].exp.X_add_number < (1 << 16)
+                 && the_insn.fi[0].exp.X_add_number >= 0))
            break;
 
-       case E_AND:     /* 2nd version emulates Intel as, not doc. */
-           if (the_insn.exp.X_add_symbol == NULL &&
-               the_insn.exp.X_subtract_symbol == NULL &&
-               (the_insn.exp.X_add_number < (1 << 16) &&
-                the_insn.exp.X_add_number >= 0))
-               break;
-           /* andnot h%const,ireg_src2,ireg_dest
-           pseudo[0].opcode = (the_insn.opcode & 0x03ffffff) | 0xd4000000; */
-           /* andnot h%const,ireg_src2,r31 */
-           pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 |
-               (atmp << 16);
-           pseudo[0].highlow = HIGH;
-           pseudo[0].exp.X_add_number = -1 - the_insn.exp.X_add_number;
-           /* andnot l%const,ireg_dest,ireg_dest
-           pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 |
-               ((the_insn.opcode & 0x001f0000) << 5); */
-           /* andnot l%const,r31,ireg_dest */
-           pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 |
-               (atmp << 21);
-           pseudo[1].highlow = PAIR;
-           pseudo[1].exp.X_add_number = -1 - the_insn.exp.X_add_number;
-           no_opcodes = 2;
+         /* Emit "$(opcode)h h%const,ireg_src2,r31".  */
+         pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000
+                             | (atmp << 16);
+         pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_H);
+
+         /* Emit "$(opcode) l%const,r31,ireg_dest".  */
+         pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000
+                             | (atmp << 21);
+         pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_L);
+
+         num_opcodes = 2;
+         break;
+
+       case E_AND:
+         if (the_insn.fi[0].exp.X_add_symbol == NULL
+             && the_insn.fi[0].exp.X_op_symbol == NULL
+             && (the_insn.fi[0].exp.X_add_number < (1 << 16)
+                 && the_insn.fi[0].exp.X_add_number >= 0))
            break;
 
+         /* Emit "andnot h%const,ireg_src2,r31".  */
+         pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000
+                             | (atmp << 16);
+         pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_H);
+         pseudo[0].fi[0].exp.X_add_number =
+            -1 - the_insn.fi[0].exp.X_add_number;
+
+         /* Emit "andnot l%const,r31,ireg_dest".  */
+         pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000
+                             | (atmp << 21);
+         pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_L);
+         pseudo[1].fi[0].exp.X_add_number =
+            -1 - the_insn.fi[0].exp.X_add_number;
+
+         num_opcodes = 2;
+         break;
+
        case E_S32:
-           if (the_insn.exp.X_add_symbol == NULL &&
-               the_insn.exp.X_subtract_symbol == NULL &&
-               (the_insn.exp.X_add_number < (1 << 15) &&
-                the_insn.exp.X_add_number >= -(1 << 15)))
-               break;
-           /* orh h%const,r0,r31 */
-           pseudo[0].opcode = 0xec000000 | (atmp << 16);
-           pseudo[0].highlow = HIGH;
-           /* or l%const,r31,r31 */
-           pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16);
-           pseudo[1].highlow = PAIR;
-           /* r31,ireg_src2,ireg_dest */
-           pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11);
-           pseudo[2].reloc = NO_RELOC;
-           no_opcodes = 3;
+         if (the_insn.fi[0].exp.X_add_symbol == NULL
+             && the_insn.fi[0].exp.X_op_symbol == NULL
+             && (the_insn.fi[0].exp.X_add_number < (1 << 15)
+                 && the_insn.fi[0].exp.X_add_number >= -(1 << 15)))
            break;
 
-       default:
-           abort();
+         /* Emit "orh h%const,r0,r31".  */
+         pseudo[0].opcode = 0xec000000 | (atmp << 16);
+         pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_H);
+
+         /* Emit "or l%const,r31,r31".  */
+         pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16);
+         pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_L);
+
+         /* Emit "r31,ireg_src2,ireg_dest".  */
+         pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11);
+         pseudo[2].fi[0].fup = OP_IMM_S16;
+
+         num_opcodes = 3;
+         break;
+
+       default:
+         as_fatal (_("failed sanity check."));
        }
 
-        the_insn = pseudo[0];
-       /* check for expanded opcode after branch or in dual */
-       if (no_opcodes > 1 && last_expand == 1)
-           as_warn("Expanded opcode after delayed branch: `%s'", str);
-       if (no_opcodes > 1 && dual_mode != DUAL_OFF)
-           as_warn("Expanded opcode in dual mode: `%s'", str);
+      the_insn = pseudo[0];
+
+      /* Warn if an opcode is expanded after a delayed branch.  */
+      if (num_opcodes > 1 && last_expand == 1)
+       as_warn (_("Expanded opcode after delayed branch: `%s'"), str);
+
+      /* Warn if an opcode is expanded in dual mode.  */
+      if (num_opcodes > 1 && dual_mode != DUAL_OFF)
+       as_warn (_("Expanded opcode in dual mode: `%s'"), str);
+
+      /* Notify if any expansions happen.  */
+      if (target_warn_expand && num_opcodes > 1)
+       as_warn (_("An instruction was expanded (%s)"), str);
     }
 
-    i = 0;
-    do {       /* always produce at least one opcode */
-        toP = frag_more(4);
-        /* put out the opcode */
-        md_number_to_chars(toP, the_insn.opcode, 4);
-
-       /* check for expanded opcode after branch or in dual */
-       last_expand = the_insn.pcrel;
-
-        /* put out the symbol-dependent stuff */
-        if (the_insn.reloc != NO_RELOC) {
-           fix_new(
-               frag_now,                           /* which frag */
-               (toP - frag_now->fr_literal), /* where */
-               4,                                  /* size */
-               the_insn.exp.X_add_symbol,
-               the_insn.exp.X_subtract_symbol,
-               the_insn.exp.X_add_number,
-               the_insn.pcrel,
-               /* merge bit fields into one argument */
-               (int)(((the_insn.highlow & 0x3) << 4) | (the_insn.reloc & 0xf))
-           );
+  i = 0;
+  do
+    {
+      int tmp;
+
+      /* Output the opcode.  Note that the i860 always reads instructions
+        as little-endian data.  */
+      destp = frag_more (4);
+      number_to_chars_littleendian (destp, the_insn.opcode, 4);
+
+      /* Check for expanded opcode after branch or in dual mode.  */
+      last_expand = the_insn.fi[0].pcrel;
+
+      /* Output the symbol-dependent stuff.  Only btne and bte will ever
+         loop more than once here, since only they (possibly) have more
+         than one fixup.  */
+      for (tmp = 0; tmp < fc; tmp++)
+        {
+          if (the_insn.fi[tmp].fup != OP_NONE)
+           {
+             fixS *fix;
+             fix = fix_new_exp (frag_now,
+                                destp - frag_now->fr_literal,
+                                4,
+                                &the_insn.fi[tmp].exp,
+                                the_insn.fi[tmp].pcrel,
+                                the_insn.fi[tmp].reloc);
+
+            /* Despite the odd name, this is a scratch field.  We use
+               it to encode operand type information.  */
+            fix->fx_addnumber = the_insn.fi[tmp].fup;
+          }
         }
-        the_insn = pseudo[++i];
-    } while (--no_opcodes > 0);
+      the_insn = pseudo[++i];
+    }
+  while (--num_opcodes > 0);
 
 }
 
+/* Assemble the instruction pointed to by STR.  */
 static void
-i860_ip(str)
-    char *str;
+i860_process_insn (char *str)
 {
-    char *s;
-    const char *args;
-    char c;
-    unsigned long i;
-    struct i860_opcode *insn;
-    char *argsStart;
-    unsigned long   opcode;
-    unsigned int mask;
-    int match = 0;
-    int comma = 0;
-
-
-    for (s = str; islower(*s) || *s == '.' || *s == '3'; ++s)
-       ;
-    switch (*s) {
+  char *s;
+  const char *args;
+  char c;
+  struct i860_opcode *insn;
+  char *args_start;
+  unsigned long opcode;
+  unsigned int mask;
+  int match = 0;
+  int comma = 0;
+
+#if 1 /* For compiler warnings.  */
+  args = 0;
+  insn = 0;
+  args_start = 0;
+  opcode = 0;
+#endif
+
+  for (s = str; ISLOWER (*s) || *s == '.' || *s == '3'
+       || *s == '2' || *s == '1'; ++s)
+    ;
 
+  switch (*s)
+    {
     case '\0':
-       break;
+      break;
 
     case ',':
-       comma = 1;
+      comma = 1;
 
-       /*FALLTHROUGH*/
+      /*FALLTHROUGH*/
 
     case ' ':
-       *s++ = '\0';
-       break;
+      *s++ = '\0';
+      break;
 
     default:
-           as_bad("Unknown opcode: `%s'", str);
-           exit(1);
+      as_fatal (_("Unknown opcode: `%s'"), str);
     }
 
-    if (strncmp(str, "d.", 2) == 0) {  /* check for d. opcode prefix */
-       if (dual_mode == DUAL_ON)
-           dual_mode = DUAL_ONDDOT;
-       else
-           dual_mode = DUAL_DDOT;
-       str += 2;
+  /* Check for dual mode ("d.") opcode prefix.  */
+  if (strncmp (str, "d.", 2) == 0)
+    {
+      if (dual_mode == DUAL_ON)
+       dual_mode = DUAL_ONDDOT;
+      else
+       dual_mode = DUAL_DDOT;
+      str += 2;
     }
 
-    if ((insn = (struct i860_opcode *) hash_find(op_hash, str)) == NULL) {
-       if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT)
-           str -= 2;
-       as_bad("Unknown opcode: `%s'", str);
-       return;
-    }
-    if (comma) {
-       *--s = ',';
+  if ((insn = (struct i860_opcode *) hash_find (op_hash, str)) == NULL)
+    {
+      if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT)
+       str -= 2;
+      as_bad (_("Unknown opcode: `%s'"), str);
+      return;
     }
-    argsStart = s;
-    for (;;) {
-       opcode = insn->match;
-       bzero(&the_insn, sizeof(the_insn));
-       the_insn.reloc = NO_RELOC;
-
-       /*
-        * Build the opcode, checking as we go to make
-        * sure that the operands match
-        */
-       for (args = insn->args; ; ++args) {
-           switch (*args) {
-
-           case '\0':  /* end of args */
-               if (*s == '\0') {
-                   match = 1;
-               }
-               break;
 
+  if (comma)
+    *--s = ',';
+
+  args_start = s;
+  for (;;)
+    {
+      int t;
+      opcode = insn->match;
+      memset (&the_insn, '\0', sizeof (the_insn));
+      fc = 0;
+      for (t = 0; t < MAX_FIXUPS; t++)
+        {
+          the_insn.fi[t].reloc = BFD_RELOC_NONE;
+          the_insn.fi[t].pcrel = 0;
+          the_insn.fi[t].fup = OP_NONE;
+        }
+
+      /* Build the opcode, checking as we go that the operands match.  */
+      for (args = insn->args; ; ++args)
+       {
+          if (fc > MAX_FIXUPS)
+            abort ();
+
+         switch (*args)
+           {
+
+           /* End of args.  */
+           case '\0':
+             if (*s == '\0')
+               match = 1;
+             break;
+
+           /* These must match exactly.  */
            case '+':
-           case '(':   /* these must match exactly */
+           case '(':
            case ')':
            case ',':
            case ' ':
-               if (*s++ == *args)
-                   continue;
-               break;
-
-           case '#':   /* must be at least one digit */
-               if (isdigit(*s++)) {
-                   while (isdigit(*s)) {
-                       ++s;
-                   }
-                   continue;
+             if (*s++ == *args)
+               continue;
+             break;
+
+           /* Must be at least one digit.  */
+           case '#':
+             if (ISDIGIT (*s++))
+               {
+                 while (ISDIGIT (*s))
+                   ++s;
+                 continue;
                }
-               break;
+             break;
 
-           case '1':   /* next operand must be a register */
+           /* Next operand must be a register.  */
+           case '1':
            case '2':
            case 'd':
-               switch (*s) {
-
-               case 'f':   /* frame pointer */
-                   s++;
-                   if (*s++ == 'p') {
-                       mask = 0x3;
-                       break;
+             /* Check for register prefix if necessary.  */
+             if (reg_prefix && *s != reg_prefix)
+               goto error;
+             else if (reg_prefix)
+               s++;
+
+             switch (*s)
+               {
+               /* Frame pointer.  */
+               case 'f':
+                 s++;
+                 if (*s++ == 'p')
+                   {
+                     mask = 0x3;
+                     break;
                    }
-                   goto error;
+                 goto error;
 
-               case 's':   /* stack pointer */
-                   s++;
-                   if (*s++ == 'p') {
-                       mask= 0x2;
-                       break;
+               /* Stack pointer.  */
+               case 's':
+                 s++;
+                 if (*s++ == 'p')
+                   {
+                     mask = 0x2;
+                     break;
                    }
-                   goto error;
+                 goto error;
 
-               case 'r': /* any register */
-                   s++;
-                   if (!isdigit(c = *s++)) {
-                       goto error;
+               /* Any register r0..r31.  */
+               case 'r':
+                 s++;
+                 if (!ISDIGIT (c = *s++))
+                   {
+                     goto error;
                    }
-                   if (isdigit(*s)) {
-                       if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) {
-                           goto error;
-                       }
-                   } else {
-                       c -= '0';
+                 if (ISDIGIT (*s))
+                   {
+                     if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32)
+                       goto error;
                    }
-                   mask= c;
-                   break;
+                 else
+                   c -= '0';
+                 mask = c;
+                 break;
 
-               default:        /* not this opcode */
-                   goto error;
+               /* Not this opcode.  */
+               default:
+                 goto error;
                }
-               /*
-                * Got the register, now figure out where
-                * it goes in the opcode.
-                */
-               switch (*args) {
 
+             /* Obtained the register, now place it in the opcode.  */
+             switch (*args)
+               {
                case '1':
-                   opcode |= mask << 11;
-                   continue;
+                 opcode |= mask << 11;
+                 continue;
 
                case '2':
-                   opcode |= mask << 21;
-                   continue;
+                 opcode |= mask << 21;
+                 continue;
 
                case 'd':
-                   opcode |= mask << 16;
-                   continue;
+                 opcode |= mask << 16;
+                 continue;
 
                }
-               break;
+             break;
 
-           case 'e':    /* next operand is a floating point register */
+           /* Next operand is a floating point register.  */
+           case 'e':
            case 'f':
            case 'g':
-               if (*s++ == 'f' && isdigit(*s)) {
-                   mask = *s++;
-                   if (isdigit(*s)) {
-                       mask = 10 * (mask - '0') + (*s++ - '0');
-                       if (mask >= 32) {
-                           break;
+             /* Check for register prefix if necessary.  */
+             if (reg_prefix && *s != reg_prefix)
+               goto error;
+             else if (reg_prefix)
+               s++;
+
+             if (*s++ == 'f' && ISDIGIT (*s))
+               {
+                 mask = *s++;
+                 if (ISDIGIT (*s))
+                   {
+                     mask = 10 * (mask - '0') + (*s++ - '0');
+                     if (mask >= 32)
+                       {
+                         break;
                        }
-                   } else {
-                       mask -= '0';
                    }
-                   switch (*args) {
+                 else
+                   mask -= '0';
+
+                 switch (*args)
+                   {
 
                    case 'e':
-                       opcode |= mask << 11;
-                       continue;
+                     opcode |= mask << 11;
+                     continue;
 
                    case 'f':
-                       opcode |= mask << 21;
-                       continue;
+                     opcode |= mask << 21;
+                     continue;
 
                    case 'g':
-                       opcode |= mask << 16;
-                       if (dual_mode != DUAL_OFF)
-                           opcode |= (1 << 9); /* dual mode instruction */
-                       if (dual_mode == DUAL_DDOT)
-                           dual_mode = DUAL_OFF;
-                       if (dual_mode == DUAL_ONDDOT)
-                           dual_mode = DUAL_ON;
-                       if ((opcode & (1 << 10)) && (mask == ((opcode >> 11) & 0x1f)))
-                           as_warn("Fsr1 equals fdest with Pipelining");
-                       continue;
+                     opcode |= mask << 16;
+                     if ((opcode & (1 << 10)) && mask != 0
+                         && (mask == ((opcode >> 11) & 0x1f)))
+                       as_warn (_("Pipelined instruction: fsrc1 = fdest"));
+                     continue;
                    }
                }
-               break;
-
-           case 'c': /* next operand must be a control register */
-               if (strncmp(s, "fir", 3) == 0) {
-                   opcode |= 0x0 << 21;
-                   s += 3;
-                   continue;
+             break;
+
+           /* Next operand must be a control register.  */
+           case 'c':
+             /* Check for register prefix if necessary.  */
+             if (reg_prefix && *s != reg_prefix)
+               goto error;
+             else if (reg_prefix)
+               s++;
+
+             if (strncmp (s, "fir", 3) == 0)
+               {
+                 opcode |= 0x0 << 21;
+                 s += 3;
+                 continue;
+               }
+             if (strncmp (s, "psr", 3) == 0)
+               {
+                 opcode |= 0x1 << 21;
+                 s += 3;
+                 continue;
+               }
+             if (strncmp (s, "dirbase", 7) == 0)
+               {
+                 opcode |= 0x2 << 21;
+                 s += 7;
+                 continue;
+               }
+             if (strncmp (s, "db", 2) == 0)
+               {
+                 opcode |= 0x3 << 21;
+                 s += 2;
+                 continue;
+               }
+             if (strncmp (s, "fsr", 3) == 0)
+               {
+                 opcode |= 0x4 << 21;
+                 s += 3;
+                 continue;
                }
-               if (strncmp(s, "psr", 3) == 0) {
-                   opcode |= 0x1 << 21;
-                   s += 3;
-                   continue;
+             if (strncmp (s, "epsr", 4) == 0)
+               {
+                 opcode |= 0x5 << 21;
+                 s += 4;
+                 continue;
                }
-               if (strncmp(s, "dirbase", 7) == 0) {
-                   opcode |= 0x2 << 21;
-                   s += 7;
-                   continue;
+             /* The remaining control registers are XP only.  */
+             if (target_xp && strncmp (s, "bear", 4) == 0)
+               {
+                 opcode |= 0x6 << 21;
+                 s += 4;
+                 continue;
                }
-               if (strncmp(s, "db", 2) == 0) {
-                   opcode |= 0x3 << 21;
-                   s += 2;
-                   continue;
+             if (target_xp && strncmp (s, "ccr", 3) == 0)
+               {
+                 opcode |= 0x7 << 21;
+                 s += 3;
+                 continue;
                }
-               if (strncmp(s, "fsr", 3) == 0) {
-                   opcode |= 0x4 << 21;
-                   s += 3;
-                   continue;
+             if (target_xp && strncmp (s, "p0", 2) == 0)
+               {
+                 opcode |= 0x8 << 21;
+                 s += 2;
+                 continue;
                }
-               if (strncmp(s, "epsr", 4) == 0) {
-                   opcode |= 0x5 << 21;
-                   s += 4;
-                   continue;
+             if (target_xp && strncmp (s, "p1", 2) == 0)
+               {
+                 opcode |= 0x9 << 21;
+                 s += 2;
+                 continue;
                }
-               break;
+             if (target_xp && strncmp (s, "p2", 2) == 0)
+               {
+                 opcode |= 0xa << 21;
+                 s += 2;
+                 continue;
+               }
+             if (target_xp && strncmp (s, "p3", 2) == 0)
+               {
+                 opcode |= 0xb << 21;
+                 s += 2;
+                 continue;
+               }
+             break;
+
+           /* 5-bit immediate in src1.  */
+           case '5':
+             if (! i860_get_expression (s))
+               {
+                 s = expr_end;
+                 the_insn.fi[fc].fup |= OP_IMM_U5;
+                 fc++;
+                 continue;
+               }
+             break;
+
+           /* 26-bit immediate, relative branch (lbroff).  */
+           case 'l':
+             the_insn.fi[fc].pcrel = 1;
+             the_insn.fi[fc].fup |= OP_IMM_BR26;
+             goto immediate;
+
+           /* 16-bit split immediate, relative branch (sbroff).  */
+           case 'r':
+             the_insn.fi[fc].pcrel = 1;
+             the_insn.fi[fc].fup |= OP_IMM_BR16;
+             goto immediate;
+
+           /* 16-bit split immediate.  */
+           case 's':
+             the_insn.fi[fc].fup |= OP_IMM_SPLIT16;
+             goto immediate;
+
+           /* 16-bit split immediate, byte aligned (st.b).  */
+           case 'S':
+             the_insn.fi[fc].fup |= OP_IMM_SPLIT16;
+             goto immediate;
+
+           /* 16-bit split immediate, half-word aligned (st.s).  */
+           case 'T':
+             the_insn.fi[fc].fup |= (OP_IMM_SPLIT16 | OP_ENCODE1 | OP_ALIGN2);
+             goto immediate;
+
+           /* 16-bit split immediate, word aligned (st.l).  */
+           case 'U':
+             the_insn.fi[fc].fup |= (OP_IMM_SPLIT16 | OP_ENCODE1 | OP_ALIGN4);
+             goto immediate;
+
+           /* 16-bit immediate.  */
+           case 'i':
+             the_insn.fi[fc].fup |= OP_IMM_S16;
+             goto immediate;
+
+           /* 16-bit immediate, byte aligned (ld.b).  */
+           case 'I':
+             the_insn.fi[fc].fup |= OP_IMM_S16;
+             goto immediate;
+
+           /* 16-bit immediate, half-word aligned (ld.s).  */
+           case 'J':
+             the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE1 | OP_ALIGN2);
+             goto immediate;
+
+           /* 16-bit immediate, word aligned (ld.l, {p}fld.l, fst.l).  */
+           case 'K':
+             if (insn->name[0] == 'l')
+               the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE1 | OP_ALIGN4);
+             else
+               the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE2 | OP_ALIGN4);
+             goto immediate;
+
+           /* 16-bit immediate, double-word aligned ({p}fld.d, fst.d).  */
+           case 'L':
+             the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE3 | OP_ALIGN8);
+             goto immediate;
+
+           /* 16-bit immediate, quad-word aligned (fld.q, fst.q).  */
+           case 'M':
+             the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE3 | OP_ALIGN16);
+
+             /*FALLTHROUGH*/
+
+             /* Handle the immediate for either the Intel syntax or
+                SVR4 syntax. The Intel syntax is "ha%immediate"
+                whereas SVR4 syntax is "[immediate]@ha".  */
+           immediate:
+             if (target_intel_syntax == 0)
+               {
+                 /* AT&T/SVR4 syntax.  */
+                 if (*s == ' ')
+                   s++;
 
-           case '5':   /* 5 bit immediate in src1 */
-               bzero(&the_insn, sizeof(the_insn));
-               if ( !getExpression(s)) {
+                 /* Note that if i860_get_expression() fails, we will still
+                    have created U entries in the symbol table for the
+                    'symbols' in the input string.  Try not to create U
+                    symbols for registers, etc.  */
+                 if (! i860_get_expression (s))
                    s = expr_end;
-                   if (the_insn.exp.X_add_number & ~0x1f)
-                       as_bad("5-bit immediate too large");
-                   opcode |= (the_insn.exp.X_add_number & 0x1f) << 11;
-                   bzero(&the_insn, sizeof(the_insn));
-                   the_insn.reloc = NO_RELOC;
-                   continue;
-               }
-               break;
-
-           case 'l':   /* 26 bit immediate, relative branch */
-               the_insn.reloc = BRADDR;
-               the_insn.pcrel = 1;
-               goto immediate;
-
-           case 's':   /* 16 bit immediate, split relative branch */
-                       /* upper 5 bits of offset in dest field */
-               the_insn.pcrel = 1;
-               the_insn.reloc = SPLIT0;
-               goto immediate;
-
-           case 'S':   /* 16 bit immediate, split (st), aligned */
-               if (opcode & (1 << 28))
-                   if (opcode & 0x1)
-                       the_insn.reloc = SPLIT2;
-                   else
-                       the_insn.reloc = SPLIT1;
-               else
-                   the_insn.reloc = SPLIT0;
-               goto immediate;
-
-           case 'I':   /* 16 bit immediate, aligned */
-               if (opcode & (1 << 28))
-                   if (opcode & 0x1)
-                       the_insn.reloc = LOW2;
-                   else
-                       the_insn.reloc = LOW1;
-               else
-                   the_insn.reloc = LOW0;
-               goto immediate;
-
-           case 'i':   /* 16 bit immediate */
-               the_insn.reloc = LOW0;
-
-               /*FALLTHROUGH*/
+                 else
+                   goto error;
 
-           immediate:
-               if(*s==' ')
-                 s++;
-               if (strncmp(s, "ha%", 3) == 0) {
-                   the_insn.highlow = HIGHADJ;
-                   s += 3;
-               } else if (strncmp(s, "h%", 2) == 0) {
-                   the_insn.highlow = HIGH;
-                   s += 2;
-               } else if (strncmp(s, "l%", 2) == 0) {
-                   the_insn.highlow = PAIR;
-                   s += 2;
-               }
-               the_insn.expand = insn->expand; 
+                 if (strncmp (s, "@ha", 3) == 0)
+                   {
+                     the_insn.fi[fc].fup |= OP_SEL_HA;
+                     s += 3;
+                   }
+                 else if (strncmp (s, "@h", 2) == 0)
+                   {
+                     the_insn.fi[fc].fup |= OP_SEL_H;
+                     s += 2;
+                   }
+                 else if (strncmp (s, "@l", 2) == 0)
+                   {
+                     the_insn.fi[fc].fup |= OP_SEL_L;
+                     s += 2;
+                   }
+                 else if (strncmp (s, "@gotoff", 7) == 0
+                          || strncmp (s, "@GOTOFF", 7) == 0)
+                   {
+                     as_bad (_("Assembler does not yet support PIC"));
+                     the_insn.fi[fc].fup |= OP_SEL_GOTOFF;
+                     s += 7;
+                   }
+                 else if (strncmp (s, "@got", 4) == 0
+                          || strncmp (s, "@GOT", 4) == 0)
+                   {
+                     as_bad (_("Assembler does not yet support PIC"));
+                     the_insn.fi[fc].fup |= OP_SEL_GOT;
+                     s += 4;
+                   }
+                 else if (strncmp (s, "@plt", 4) == 0
+                          || strncmp (s, "@PLT", 4) == 0)
+                   {
+                     as_bad (_("Assembler does not yet support PIC"));
+                     the_insn.fi[fc].fup |= OP_SEL_PLT;
+                     s += 4;
+                   }
 
-               /* Note that if the getExpression() fails, we will still have
-                  created U entries in the symbol table for the 'symbols'
-                  in the input string.  Try not to create U symbols for
-                  registers, etc. */
+                 the_insn.expand = insn->expand;
+                  fc++;
+              
+                 continue;
+               }
+             else
+               {
+                 /* Intel syntax.  */
+                 if (*s == ' ')
+                   s++;
+                 if (strncmp (s, "ha%", 3) == 0)
+                   {
+                     the_insn.fi[fc].fup |= OP_SEL_HA;
+                     s += 3;
+                   }
+                 else if (strncmp (s, "h%", 2) == 0)
+                   {
+                     the_insn.fi[fc].fup |= OP_SEL_H;
+                     s += 2;
+                   }
+                 else if (strncmp (s, "l%", 2) == 0)
+                   {
+                     the_insn.fi[fc].fup |= OP_SEL_L;
+                     s += 2;
+                   }
+                 the_insn.expand = insn->expand;
 
-               if ( !getExpression(s)) {
+                 /* Note that if i860_get_expression() fails, we will still
+                    have created U entries in the symbol table for the
+                    'symbols' in the input string.  Try not to create U
+                    symbols for registers, etc.  */
+                 if (! i860_get_expression (s))
                    s = expr_end;
-                   continue;
+                 else
+                   goto error;
+
+                  fc++;
+                 continue;
                }
-               break;
+             break;
 
            default:
-               abort();
+             as_fatal (_("failed sanity check."));
            }
-           break;
+         break;
        }
-       error:
-       if (match == 0)
-         {
-           /* Args don't match.  */
-           if (&insn[1] - i860_opcodes < NUMOPCODES
-               && !strcmp(insn->name, insn[1].name))
-             {
-               ++insn;
-               s = argsStart;
-               continue;
-             }
-           else
-             {
-               as_bad("Illegal operands");
-               return;
-             }
-         }
-       break;
+    error:
+      if (match == 0)
+       {
+         /* Args don't match.  */
+         if (insn[1].name != NULL
+             && ! strcmp (insn->name, insn[1].name))
+           {
+             ++insn;
+             s = args_start;
+             continue;
+           }
+         else
+           {
+             as_bad (_("Illegal operands for %s"), insn->name);
+             return;
+           }
+       }
+      break;
     }
 
-    the_insn.opcode = opcode;
-    return;
+  /* Set the dual bit on this instruction if necessary.  */
+  if (dual_mode != DUAL_OFF)
+    {
+      if ((opcode & 0xfc000000) == 0x48000000 || opcode == 0xb0000000)
+        {
+         /* The instruction is a flop or a fnop, so set its dual bit
+            (but check that it is 8-byte aligned).  */
+         if (((frag_now->fr_address + frag_now_fix_octets ()) & 7) == 0)
+           opcode |= (1 << 9);
+         else
+            as_bad (_("'d.%s' must be 8-byte aligned"), insn->name);
+
+          if (dual_mode == DUAL_DDOT)
+           dual_mode = DUAL_OFF;
+          else if (dual_mode == DUAL_ONDDOT)
+           dual_mode = DUAL_ON;
+        }
+      else if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT)
+        as_bad (_("Prefix 'd.' invalid for instruction `%s'"), insn->name);
+    }
+
+  the_insn.opcode = opcode;
+
+  /* Only recognize XP instructions when the user has requested it.  */
+  if (insn->expand == XP_ONLY && ! target_xp)
+    as_bad (_("Unknown opcode: `%s'"), insn->name);
 }
 
 static int
-getExpression(str)
-    char *str;
+i860_get_expression (char *str)
 {
-    char *save_in;
-    segT seg;
-
-    save_in = input_line_pointer;
-    input_line_pointer = str;
-    switch (seg = expression(&the_insn.exp)) {
-
-    case SEG_ABSOLUTE:
-    case SEG_TEXT:
-    case SEG_DATA:
-    case SEG_BSS:
-    case SEG_UNKNOWN:
-    case SEG_DIFFERENCE:
-    case SEG_BIG:
-    case SEG_ABSENT:
-       break;
-
-    default:
-       the_insn.error = "bad segment";
-       expr_end = input_line_pointer;
-       input_line_pointer=save_in;
-       return 1;
+  char *save_in;
+  segT seg;
+
+  save_in = input_line_pointer;
+  input_line_pointer = str;
+  seg = expression (&the_insn.fi[fc].exp);
+  if (seg != absolute_section
+      && seg != undefined_section
+      && ! SEG_NORMAL (seg))
+    {
+      the_insn.error = _("bad segment");
+      expr_end = input_line_pointer;
+      input_line_pointer = save_in;
+      return 1;
     }
-    expr_end = input_line_pointer;
-    input_line_pointer = save_in;
-    return 0;
+  expr_end = input_line_pointer;
+  input_line_pointer = save_in;
+  return 0;
 }
 
-
-/*
-    This is identical to the md_atof in m68k.c.  I think this is right,
-    but I'm not sure.
-
-   Turn a string in input_line_pointer into a floating point constant of type
-   type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
-   emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
- */
-
-/* Equal to MAX_PRECISION in atof-ieee.c */
-#define MAX_LITTLENUMS 6
-
 char *
-md_atof(type,litP,sizeP)
-    char type;
-    char *litP;
-    int *sizeP;
+md_atof (int type, char *litP, int *sizeP)
 {
-    int        prec;
-    LITTLENUM_TYPE words[MAX_LITTLENUMS];
-    LITTLENUM_TYPE *wordP;
-    char       *t;
-    char       *atof_ieee();
-
-    switch(type) {
-
-    case 'f':
-    case 'F':
-    case 's':
-    case 'S':
-       prec = 2;
-       break;
-
-    case 'd':
-    case 'D':
-    case 'r':
-    case 'R':
-       prec = 4;
-       break;
-
-    case 'x':
-    case 'X':
-       prec = 6;
-       break;
-
-    case 'p':
-    case 'P':
-       prec = 6;
-       break;
-
-    default:
-       *sizeP=0;
-       return "Bad call to MD_ATOF()";
-    }
-    t=atof_ieee(input_line_pointer,type,words);
-    if(t)
-       input_line_pointer=t;
-    *sizeP=prec * sizeof(LITTLENUM_TYPE);
-    for(wordP=words;prec--;) {
-       md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
-       litP+=sizeof(LITTLENUM_TYPE);
-    }
-    return ""; /* Someone should teach Dean about null pointers */
+  return ieee_md_atof (type, litP, sizeP, TRUE);
 }
 
-/*
- * Write out big-endian.
- */
+/* Write out in current endian mode.  */
 void
-md_number_to_chars(buf,val,n)
-    char *buf;
-    long val;
-    int n;
+md_number_to_chars (char *buf, valueT val, int n)
 {
-    switch(n) {
-
-    case 4:
-       *buf++ = val >> 24;
-       *buf++ = val >> 16;
-    case 2:
-       *buf++ = val >> 8;
-    case 1:
-       *buf = val;
-       break;
-
-    default:
-       abort();
-    }
-    return;
+  if (target_big_endian)
+    number_to_chars_bigendian (buf, val, n);
+  else
+    number_to_chars_littleendian (buf, val, n);
 }
 
-void md_number_to_imm(buf,val,n, fixP)
-    char *buf;
-    long val;
-    int n;
-    fixS *fixP;
+/* This should never be called for i860.  */
+int
+md_estimate_size_before_relax (register fragS *fragP ATTRIBUTE_UNUSED,
+                              segT segtype ATTRIBUTE_UNUSED)
 {
-    enum reloc_type reloc = fixP->fx_r_type & 0xf;
-    enum highlow_type highlow = (fixP->fx_r_type >> 4) & 0x3;
-
-    assert(buf);
-    assert(n == 4);    /* always on i860 */
-
-    switch(highlow)
-    {
-
-    case HIGHADJ:      /* adjusts the high-order 16-bits */
-       if (val & (1 << 15))
-           val += (1 << 16);
-
-           /*FALLTHROUGH*/
+  as_fatal (_("relaxation not supported\n"));
+}
 
-    case HIGH: /* selects the high-order 16-bits */
-       val >>= 16;
-       break;
+#ifdef DEBUG_I860
+static void
+print_insn (struct i860_it *insn)
+{
+  if (insn->error)
+    fprintf (stderr, "ERROR: %s\n", insn->error);
+
+  fprintf (stderr, "opcode = 0x%08lx\t", insn->opcode);
+  fprintf (stderr, "expand = 0x%x\t", insn->expand);
+  fprintf (stderr, "reloc = %s\t\n",
+          bfd_get_reloc_code_name (insn->reloc));
+  fprintf (stderr, "exp =  {\n");
+  fprintf (stderr, "\t\tX_add_symbol = %s\n",
+          insn->exp.X_add_symbol ?
+          (S_GET_NAME (insn->exp.X_add_symbol) ?
+           S_GET_NAME (insn->exp.X_add_symbol) : "???") : "0");
+  fprintf (stderr, "\t\tX_op_symbol = %s\n",
+          insn->exp.X_op_symbol ?
+          (S_GET_NAME (insn->exp.X_op_symbol) ?
+           S_GET_NAME (insn->exp.X_op_symbol) : "???") : "0");
+  fprintf (stderr, "\t\tX_add_number = %lx\n",
+          insn->exp.X_add_number);
+  fprintf (stderr, "}\n");
+}
+#endif /* DEBUG_I860 */
 
-    case PAIR: /* selects the low-order 16-bits */
-       val = val & 0xffff;
-       break;
+\f
+#ifdef OBJ_ELF
+const char *md_shortopts = "VQ:";
+#else
+const char *md_shortopts = "";
+#endif
 
-    default:
-       break;
-    }
+#define OPTION_EB              (OPTION_MD_BASE + 0)
+#define OPTION_EL              (OPTION_MD_BASE + 1)
+#define OPTION_WARN_EXPAND     (OPTION_MD_BASE + 2)
+#define OPTION_XP              (OPTION_MD_BASE + 3)
+#define OPTION_INTEL_SYNTAX    (OPTION_MD_BASE + 4)
+
+struct option md_longopts[] = {
+  { "EB",          no_argument, NULL, OPTION_EB },
+  { "EL",          no_argument, NULL, OPTION_EL },
+  { "mwarn-expand", no_argument, NULL, OPTION_WARN_EXPAND },
+  { "mxp",         no_argument, NULL, OPTION_XP },
+  { "mintel-syntax",no_argument, NULL, OPTION_INTEL_SYNTAX },
+  { NULL,          no_argument, NULL, 0 }
+};
+size_t md_longopts_size = sizeof (md_longopts);
 
-    switch(reloc)
+int
+md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
+{
+  switch (c)
     {
+    case OPTION_EB:
+      target_big_endian = 1;
+      break;
+
+    case OPTION_EL:
+      target_big_endian = 0;
+      break;
+
+    case OPTION_WARN_EXPAND:
+      target_warn_expand = 1;
+      break;
+
+    case OPTION_XP:
+      target_xp = 1;
+      break;
+
+    case OPTION_INTEL_SYNTAX:
+      target_intel_syntax = 1;
+      break;
+
+#ifdef OBJ_ELF
+    /* SVR4 argument compatibility (-V): print version ID.  */
+    case 'V':
+      print_version_id ();
+      break;
+
+    /* SVR4 argument compatibility (-Qy, -Qn): controls whether
+       a .comment section should be emitted or not (ignored).  */
+    case 'Q':
+      break;
+#endif
 
-    case BRADDR:       /* br,call,bc,bc.t,bnc,bnc.t w/26-bit immediate */
-       if (fixP->fx_pcrel != 1)
-           as_bad("26-bit branch w/o pc relative set: 0x%08x", val);
-       val >>= 2;      /* align pcrel offset, see manual */
-
-       if (val >= (1 << 25) || val < -(1 << 25))       /* check for overflow */
-           as_bad("26-bit branch offset overflow: 0x%08x", val);
-       buf[0] = (buf[0] & 0xfc) | ((val >> 24) & 0x3);
-       buf[1] = val >> 16;
-       buf[2] = val >> 8;
-       buf[3] = val;
-       break;
-
-    case SPLIT2:       /* 16 bit immediate, 4-byte aligned */
-       if (val & 0x3)
-           as_bad("16-bit immediate 4-byte alignment error: 0x%08x", val);
-       val &= ~0x3;    /* 4-byte align value */
-       /*FALLTHROUGH*/
-    case SPLIT1:       /* 16 bit immediate, 2-byte aligned */
-       if (val & 0x1)
-           as_bad("16-bit immediate 2-byte alignment error: 0x%08x", val);
-       val &= ~0x1;    /* 2-byte align value */
-       /*FALLTHROUGH*/
-    case SPLIT0:       /* st,bla,bte,btne w/16-bit immediate */
-       if (fixP->fx_pcrel == 1)
-           val >>= 2;  /* align pcrel offset, see manual */
-       /* check for bounds */
-       if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15)))
-           as_bad("16-bit branch offset overflow: 0x%08x", val);
-       buf[1] = (buf[1] & ~0x1f) | ((val >> 11) & 0x1f);
-       buf[2] = (buf[2] & ~0x7) | ((val >> 8) & 0x7);
-       buf[3] |= val;  /* perserve bottom opcode bits */       
-       break;
-
-    case LOW4: /* fld,pfld,pst,flush 16-byte aligned */
-       if (val & 0xf)
-           as_bad("16-bit immediate 16-byte alignment error: 0x%08x", val);
-       val &= ~0xf;    /* 16-byte align value */
-       /*FALLTHROUGH*/
-    case LOW3: /* fld,pfld,pst,flush 8-byte aligned */
-       if (val & 0x7)
-           as_bad("16-bit immediate 8-byte alignment error: 0x%08x", val);
-       val &= ~0x7;    /* 8-byte align value */
-       /*FALLTHROUGH*/
-    case LOW2: /* 16 bit immediate, 4-byte aligned */
-       if (val & 0x3)
-           as_bad("16-bit immediate 4-byte alignment error: 0x%08x", val);
-       val &= ~0x3;    /* 4-byte align value */
-       /*FALLTHROUGH*/
-    case LOW1: /* 16 bit immediate, 2-byte aligned */
-       if (val & 0x1)
-           as_bad("16-bit immediate 2-byte alignment error: 0x%08x", val);
-       val &= ~0x1;    /* 2-byte align value */
-       /*FALLTHROUGH*/
-    case LOW0: /* 16 bit immediate, byte aligned */
-       /* check for bounds */
-       if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15)))
-           as_bad("16-bit immediate overflow: 0x%08x", val);
-       buf[2] = val >> 8;
-       buf[3] |= val;  /* perserve bottom opcode bits */       
-       break;
-
-    case NO_RELOC:
     default:
-       as_bad("bad relocation type: 0x%02x", reloc);
-       break;
+      return 0;
     }
-    return;
-}
 
-/* should never be called for i860 */
-void
-md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
-    char *ptr;
-    long from_addr, to_addr;
-fragS *frag;
-symbolS *to_symbol;
-{
-    fprintf(stderr, "i860_create_short_jmp\n");
-    abort();
+  return 1;
 }
 
-/* should never be called for i860 */
 void
-md_number_to_disp(buf,val,n)
-    char       *buf;
-    long       val;
+md_show_usage (FILE *stream)
 {
-    fprintf(stderr, "md_number_to_disp\n");
-    abort();
+  fprintf (stream, _("\
+  -EL                    generate code for little endian mode (default)\n\
+  -EB                    generate code for big endian mode\n\
+  -mwarn-expand                  warn if pseudo operations are expanded\n\
+  -mxp                   enable i860XP support (disabled by default)\n\
+  -mintel-syntax         enable Intel syntax (default to AT&T/SVR4)\n"));
+#ifdef OBJ_ELF
+  /* SVR4 compatibility flags.  */
+  fprintf (stream, _("\
+  -V                     print assembler version number\n\
+  -Qy, -Qn               ignored\n"));
+#endif
 }
 
-/* should never be called for i860 */
-void
-md_number_to_field(buf,val,fix)
-    char *buf;
-    long val;
-    void *fix;
+\f
+/* We have no need to default values of symbols.  */
+symbolS *
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 {
-    fprintf(stderr, "i860_number_to_field\n");
-    abort();
+  return 0;
 }
 
-/* the bit-field entries in the relocation_info struct plays hell 
-   with the byte-order problems of cross-assembly.  So as a hack,
-   I added this mach. dependent ri twiddler.  Ugly, but it gets
-   you there. -KWK */
-/* on i860: first 4 bytes are normal unsigned long address, next three
-   bytes are index, most sig. byte first.  Byte 7 is broken up with
-   bit 7 as pcrel, bit 6 as extern, and the lower six bits as
-   relocation type (highlow 5-4).  Next 4 bytes are long addend. */
-/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */
+/* The i860 denotes auto-increment with '++'.  */
 void
-md_ri_to_chars(ri_p, ri)
-     struct relocation_info *ri_p, ri;
+md_operand (expressionS *exp)
 {
-#if 0
-  unsigned char the_bytes[sizeof(*ri_p)];
-  
-  /* this is easy */
-  md_number_to_chars(the_bytes, ri.r_address, sizeof(ri.r_address));
-  /* now the fun stuff */
-  the_bytes[4] = (ri.r_index >> 16) & 0x0ff;
-  the_bytes[5] = (ri.r_index >> 8) & 0x0ff;
-  the_bytes[6] = ri.r_index & 0x0ff;
-  the_bytes[7] = ((ri.r_extern << 7)  & 0x80) | (0 & 0x60) | (ri.r_type & 0x1F);
-  /* Also easy */
-  md_number_to_chars(&the_bytes[8], ri.r_addend, sizeof(ri.r_addend));
-  /* now put it back where you found it, Junior... */
-  bcopy (the_bytes, (char *)ri_p, sizeof(*ri_p));
-#endif
-}
+  char *s;
 
-/* should never be called for i860 */
-void
-md_convert_frag(fragP)
-    register fragS *fragP;
-{
-    fprintf(stderr, "i860_convert_frag\n");
-    abort();
+  for (s = input_line_pointer; *s; s++)
+    {
+      if (s[0] == '+' && s[1] == '+')
+       {
+         input_line_pointer += 2;
+         exp->X_op = O_register;
+         break;
+       }
+    }
 }
 
-/* should never be called for i860 */
-void
-md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol)
-    char       *ptr;
-    long       from_addr,
-               to_addr;
-    fragS      *frag;
-    symbolS    *to_symbol;
+/* Round up a section size to the appropriate boundary.  */
+valueT
+md_section_align (segT segment ATTRIBUTE_UNUSED,
+                 valueT size ATTRIBUTE_UNUSED)
 {
-    fprintf(stderr, "i860_create_long_jump\n");
-    abort();
+  /* Byte alignment is fine.  */
+  return size;
 }
 
-/* should never be called for i860 */
-int
-md_estimate_size_before_relax(fragP, segtype)
-    register fragS *fragP;
-segT segtype;
+/* On the i860, a PC-relative offset is relative to the address of the
+   offset plus its size.  */
+long
+md_pcrel_from (fixS *fixP)
 {
-    fprintf(stderr, "i860_estimate_size_before_relax\n");
-    abort();
-    return 0;
+  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
 }
 
-/* for debugging only, must match enum reloc_type */
-static char *Reloc[] = {
-    "NO_RELOC",
-    "BRADDR", 
-    "LOW0", 
-    "LOW1", 
-    "LOW2", 
-    "LOW3", 
-    "LOW4", 
-    "SPLIT0", 
-    "SPLIT1", 
-    "SPLIT2", 
-    "RELOC_32", 
-};
-static char *Highlow[] = {
-    "NO_SPEC",
-    "PAIR", 
-    "HIGH", 
-    "HIGHADJ", 
-};
-static void
-print_insn(insn)
-    struct i860_it *insn;
+/* Determine the relocation needed for non PC-relative 16-bit immediates.
+   Also adjust the given immediate as necessary.  Finally, check that
+   all constraints (such as alignment) are satisfied.   */
+static bfd_reloc_code_real_type
+obtain_reloc_for_imm16 (fixS *fix, long *val)
 {
-    if (insn->error) {
-       fprintf(stderr, "ERROR: %s\n");
+  valueT fup = fix->fx_addnumber;
+  bfd_reloc_code_real_type reloc;
+
+  if (fix->fx_pcrel)
+    abort ();
+
+  /* Check alignment restrictions.  */
+  if ((fup & OP_ALIGN2) && (*val & 0x1))
+    as_bad_where (fix->fx_file, fix->fx_line,
+                 _("This immediate requires 0 MOD 2 alignment"));
+  else if ((fup & OP_ALIGN4) && (*val & 0x3))
+    as_bad_where (fix->fx_file, fix->fx_line,
+                 _("This immediate requires 0 MOD 4 alignment"));
+  else if ((fup & OP_ALIGN8) && (*val & 0x7))
+    as_bad_where (fix->fx_file, fix->fx_line,
+                 _("This immediate requires 0 MOD 8 alignment"));
+  else if ((fup & OP_ALIGN16) && (*val & 0xf))
+    as_bad_where (fix->fx_file, fix->fx_line,
+                 _("This immediate requires 0 MOD 16 alignment"));
+
+  if (fup & OP_SEL_HA)
+    {
+      *val = (*val >> 16) + (*val & 0x8000 ? 1 : 0);
+      reloc = BFD_RELOC_860_HIGHADJ;
     }
-    fprintf(stderr, "opcode=0x%08x\t", insn->opcode);
-    fprintf(stderr, "expand=0x%08x\t", insn->expand);
-    fprintf(stderr, "reloc = %s\t", Reloc[insn->reloc]);
-    fprintf(stderr, "highlow = %s\n", Highlow[insn->highlow]);
-    fprintf(stderr, "exp =  {\n");
-    fprintf(stderr, "\t\tX_add_symbol = %s\n",
-       insn->exp.X_add_symbol ?
-       (S_GET_NAME(insn->exp.X_add_symbol) ? 
-       S_GET_NAME(insn->exp.X_add_symbol) : "???") : "0");
-    fprintf(stderr, "\t\tX_sub_symbol = %s\n",
-       insn->exp.X_subtract_symbol ?
-           (S_GET_NAME(insn->exp.X_subtract_symbol) ? 
-               S_GET_NAME(insn->exp.X_subtract_symbol) : "???") : "0");
-    fprintf(stderr, "\t\tX_add_number = %d\n",
-       insn->exp.X_add_number);
-    fprintf(stderr, "}\n");
-    return;
-}
+  else if (fup & OP_SEL_H)
+    {
+      *val >>= 16;
+      reloc = BFD_RELOC_860_HIGH;
+    }
+  else if (fup & OP_SEL_L)
+    {
+      int num_encode;
+      if (fup & OP_IMM_SPLIT16)
+       {
+         if (fup & OP_ENCODE1)
+           {
+             num_encode = 1;
+             reloc = BFD_RELOC_860_SPLIT1;
+           }
+         else if (fup & OP_ENCODE2)
+           {
+             num_encode = 2;
+             reloc = BFD_RELOC_860_SPLIT2;
+           }
+         else
+           {
+             num_encode = 0;
+             reloc = BFD_RELOC_860_SPLIT0;
+           }
+       }
+      else
+       {
+         if (fup & OP_ENCODE1)
+           {
+             num_encode = 1;
+             reloc = BFD_RELOC_860_LOW1;
+           }
+         else if (fup & OP_ENCODE2)
+           {
+             num_encode = 2;
+             reloc = BFD_RELOC_860_LOW2;
+           }
+         else if (fup & OP_ENCODE3)
+           {
+             num_encode = 3;
+             reloc = BFD_RELOC_860_LOW3;
+           }
+         else
+           {
+             num_encode = 0;
+             reloc = BFD_RELOC_860_LOW0;
+           }
+       }
 
-int
-md_parse_option(argP,cntP,vecP)
-    char **argP;
-    int *cntP;
-    char ***vecP;
-{
-    return 1;
+      /* Preserve size encode bits.  */
+      *val &= ~((1 << num_encode) - 1);
+    }
+  else
+    {
+      /* No selector.  What reloc do we generate (???)?  */
+      reloc = BFD_RELOC_32;
+    }
+
+  return reloc;
 }
 
-/*
- * I860 relocations are completely different, so it needs
- * this machine dependent routine to emit them.
- */
+/* Attempt to simplify or eliminate a fixup. To indicate that a fixup
+   has been eliminated, set fix->fx_done. If fix->fx_addsy is non-NULL,
+   we will have to generate a reloc entry.  */
+
 void
-emit_machine_reloc(fixP, segment_address_in_file)
-    register fixS *fixP;
-    relax_addressT segment_address_in_file;
+md_apply_fix (fixS *fix, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 {
-    struct reloc_info_i860 ri;
-    register symbolS *symbolP;
-    extern char *next_object_file_charP;
-    long add_number;
+  char *buf;
+  long val = *valP;
+  unsigned long insn;
+  valueT fup;
+
+  buf = fix->fx_frag->fr_literal + fix->fx_where;
 
-    bzero((char *) &ri, sizeof(ri));
-    for (; fixP; fixP = fixP->fx_next) {
+  /* Recall that earlier we stored the opcode little-endian.  */
+  insn = bfd_getl32 (buf);
 
-       if (fixP->fx_r_type & ~0x3f) {
-           fprintf(stderr, "fixP->fx_r_type = %d\n", fixP->fx_r_type);
-           abort();
+  /* We stored a fix-up in this oddly-named scratch field.  */
+  fup = fix->fx_addnumber;
+
+  /* Determine the necessary relocations as well as inserting an
+     immediate into the instruction.   */
+  if (fup & OP_IMM_U5)
+    {
+      if (val & ~0x1f)
+       as_bad_where (fix->fx_file, fix->fx_line,
+                     _("5-bit immediate too large"));
+      if (fix->fx_addsy)
+       as_bad_where (fix->fx_file, fix->fx_line,
+                     _("5-bit field must be absolute"));
+
+      insn |= (val & 0x1f) << 11;
+      bfd_putl32 (insn, buf);
+      fix->fx_r_type = BFD_RELOC_NONE;
+      fix->fx_done = 1;
+    }
+  else if (fup & OP_IMM_S16)
+    {
+      fix->fx_r_type = obtain_reloc_for_imm16 (fix, &val);
+
+      /* Insert the immediate.  */
+      if (fix->fx_addsy)
+       fix->fx_done = 0;
+      else
+       {
+         insn |= val & 0xffff;
+         bfd_putl32 (insn, buf);
+         fix->fx_r_type = BFD_RELOC_NONE;
+         fix->fx_done = 1;
        }
-       ri.r_pcrel = fixP->fx_pcrel;
-       ri.r_type = fixP->fx_r_type;
-
-       if ((symbolP = fixP->fx_addsy) != NULL) {
-           ri.r_address = fixP->fx_frag->fr_address +
-               fixP->fx_where - segment_address_in_file;
-           if ((symbolP->sy_type & N_TYPE) == N_UNDF) {
-               ri.r_extern = 1;
-               ri.r_symbolnum = symbolP->sy_number;
-           } else {
-               ri.r_extern = 0;
-               ri.r_symbolnum = symbolP->sy_type & N_TYPE;
-           }
-           if (symbolP && symbolP->sy_frag) {
-               ri.r_addend = symbolP->sy_frag->fr_address;
-           }
-           ri.r_type = fixP->fx_r_type;
-           if (fixP->fx_pcrel) {
-               /* preserve actual offset vs. pc + 4 */
-               ri.r_addend -= (ri.r_address + 4);
-           } else {
-               ri.r_addend = fixP->fx_addnumber;
-           }
+    }
+  else if (fup & OP_IMM_U16)
+    abort ();
+
+  else if (fup & OP_IMM_SPLIT16)
+    {
+      fix->fx_r_type = obtain_reloc_for_imm16 (fix, &val);
 
-           md_ri_to_chars((char *) &ri, ri);
-           append(&next_object_file_charP, (char *)& ri, sizeof(ri));
+      /* Insert the immediate.  */
+      if (fix->fx_addsy)
+       fix->fx_done = 0;
+      else
+       {
+         insn |= val & 0x7ff;
+         insn |= (val & 0xf800) << 5;
+         bfd_putl32 (insn, buf);
+         fix->fx_r_type = BFD_RELOC_NONE;
+         fix->fx_done = 1;
        }
     }
-    return;
-}
+  else if (fup & OP_IMM_BR16)
+    {
+      if (val & 0x3)
+       as_bad_where (fix->fx_file, fix->fx_line,
+                     _("A branch offset requires 0 MOD 4 alignment"));
 
-/* Parse an operand that is machine-specific.  
-   We just return without modifying the expression if we have nothing
-   to do.  */
+      val = val >> 2;
 
-/* ARGSUSED */
-void
-md_operand (expressionP)
-     expressionS *expressionP;
-{
-}
+      /* Insert the immediate.  */
+      if (fix->fx_addsy)
+       {
+         fix->fx_done = 0;
+         fix->fx_r_type = BFD_RELOC_860_PC16;
+       }
+      else
+       {
+         insn |= (val & 0x7ff);
+         insn |= ((val & 0xf800) << 5);
+         bfd_putl32 (insn, buf);
+         fix->fx_r_type = BFD_RELOC_NONE;
+         fix->fx_done = 1;
+       }
+    }
+  else if (fup & OP_IMM_BR26)
+    {
+      if (val & 0x3)
+       as_bad_where (fix->fx_file, fix->fx_line,
+                     _("A branch offset requires 0 MOD 4 alignment"));
 
-/* We have no need to default values of symbols.  */
+      val >>= 2;
 
-/* ARGSUSED */
-symbolS *
-md_undefined_symbol (name)
-     char *name;
-{
-  return 0;
+      /* Insert the immediate.  */
+      if (fix->fx_addsy)
+       {
+         fix->fx_r_type = BFD_RELOC_860_PC26;
+         fix->fx_done = 0;
+       }
+      else
+       {
+         insn |= (val & 0x3ffffff);
+         bfd_putl32 (insn, buf);
+         fix->fx_r_type = BFD_RELOC_NONE;
+         fix->fx_done = 1;
+       }
+    }
+  else if (fup != OP_NONE)
+    {
+      as_bad_where (fix->fx_file, fix->fx_line,
+                   _("Unrecognized fix-up (0x%08lx)"), (unsigned long) fup);
+      abort ();
+    }
+  else
+    {
+      /* I believe only fix-ups such as ".long .ep.main-main+0xc8000000"
+        reach here (???).  */
+      if (fix->fx_addsy)
+       {
+         fix->fx_r_type = BFD_RELOC_32;
+         fix->fx_done = 0;
+       }
+      else
+       {
+         insn |= (val & 0xffffffff);
+         bfd_putl32 (insn, buf);
+         fix->fx_r_type = BFD_RELOC_NONE;
+         fix->fx_done = 1;
+       }
+    }
 }
 
-/* Round up a section size to the appropriate boundary.  */
-long
-md_section_align (segment, size)
-     segT segment;
-     long size;
+/* Generate a machine dependent reloc from a fixup.  */
+arelent*
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
+             fixS *fixp)
 {
-  return size;         /* Byte alignment is fine */
+  arelent *reloc;
+
+  reloc = xmalloc (sizeof (*reloc));
+  reloc->sym_ptr_ptr = (asymbol **) 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_offset;
+  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
+
+  if (! reloc->howto)
+    {
+      as_bad_where (fixp->fx_file, fixp->fx_line,
+                    "Cannot represent %s relocation in object file",
+                    bfd_get_reloc_code_name (fixp->fx_r_type));
+    }
+  return reloc;
 }
 
-/* Exactly what point is a PC-relative offset relative TO?
-   On the i860, they're relative to the address of the offset, plus
-   its size. (??? Is this right?  FIXME-SOON!) */
-long
-md_pcrel_from (fixP)
-     fixS *fixP;
+/* This is called from HANDLE_ALIGN in write.c.  Fill in the contents
+   of an rs_align_code fragment.  */
+
+void
+i860_handle_align (fragS *fragp)
 {
-  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
+  /* Instructions are always stored little-endian on the i860.  */
+  static const unsigned char le_nop[] = { 0x00, 0x00, 0x00, 0xA0 };
+
+  int bytes;
+  char *p;
+
+  if (fragp->fr_type != rs_align_code)
+    return;
+
+  bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
+  p = fragp->fr_literal + fragp->fr_fix;
+
+  /* Make sure we are on a 4-byte boundary, in case someone has been
+     putting data into a text section.  */
+  if (bytes & 3)
+    {
+      int fix = bytes & 3;
+      memset (p, 0, fix);
+      p += fix;
+      fragp->fr_fix += fix;
+    }
+
+  memcpy (p, le_nop, 4);
+  fragp->fr_var = 4;
 }
 
+/* This is called after a user-defined label is seen.  We check
+   if the label has a double colon (valid in Intel syntax mode only),
+   in which case it should be externalized.  */
+
 void
-md_apply_fix(fixP, val)
-    fixS *fixP;
-    long val;
+i860_check_label (symbolS *labelsym)
 {
-       char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
-       
-       if (!fixP->fx_bit_fixP) {
-               
-               switch (fixP->fx_im_disp) {
-               case 0:
-                       fixP->fx_addnumber = val;
-                       md_number_to_imm(place, val, fixP->fx_size, fixP);
-                       break;
-               case 1:
-                       md_number_to_disp (place,
-                                          fixP->fx_pcrel ? val+fixP->fx_pcrel_adjust:val,
-                                          fixP->fx_size);
-                       break;
-               case 2: /* fix requested for .long .word etc */
-                       md_number_to_chars (place, val, fixP->fx_size);
-                       break;
-               default:
-                       as_fatal("Internal error in md_apply_fix() in file \"%s\"", __FILE__);
-               } /* OVE: maybe one ought to put _imm _disp _chars in one md-func */
-       } else {
-               md_number_to_field (place, val, fixP->fx_bit_fixP);
-       }
-       
-       return;
-} /* md_apply_fix() */
-
-/*
- * $Log$
- * Revision 1.1  1991/04/04 18:16:48  rich
- * Initial revision
- *
- * Revision 1.2  1991/03/30  17:11:32  rich
- * Updated md_create_short_jump calling protocol.
- *
- *
- */
-
-/*
- * Local Variables:
- * fill-column: 131
- * comment-column: 0
- */
-
-/* end of i860.c */
+  /* At this point, the current line pointer is sitting on the character
+     just after the first colon on the label.  */ 
+  if (target_intel_syntax && *input_line_pointer == ':')
+    {
+      S_SET_EXTERNAL (labelsym);
+      input_line_pointer++;
+    }
+}
This page took 0.049781 seconds and 4 git commands to generate.