Don't use register keyword
[deliverable/binutils-gdb.git] / gas / config / tc-i860.c
index 3317282ba42541208179f0dd717eedb2c0081c8e..dd51c26d8a31fc9c5fe2dd3edee062b782125f68 100644 (file)
@@ -1,11 +1,14 @@
-/* tc-i860.c -- Assemble for the I860
-   Copyright (C) 1989, 92, 93, 94, 95, 98, 1999 Free Software Foundation, Inc.
+/* tc-i860.c -- Assembler for the Intel i860 architecture.
+   Copyright (C) 1989-2014 Free Software Foundation, Inc.
+
+   Brought back from the dead and completely reworked
+   by Jason Eckhardt <jle@cygnus.com>.
 
    This file is part of GAS, the GNU Assembler.
 
    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, the GNU Assembler.
 
    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,
 
    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
 
    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.  */
+   Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 #include "as.h"
 
 #include "as.h"
-
+#include "safe-ctype.h"
+#include "subsegs.h"
 #include "opcode/i860.h"
 #include "opcode/i860.h"
+#include "elf/i860.h"
 
 
-void md_begin ();
-void md_number_to_chars ();
-void md_assemble ();
-char *md_atof ();
-void md_convert_frag ();
-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(); */
-
-const int md_reloc_size = sizeof (struct relocation_info);
 
 
-/* void (*md_emit_relocations)() = emit_machine_reloc; */
-
-/* handle of the OPCODE hash table */
+/* The opcode hash table.  */
 static struct hash_control *op_hash = NULL;
 
 static struct hash_control *op_hash = NULL;
 
-static void s_dual (), s_enddual ();
-static void s_atmp ();
-
-const pseudo_typeS
-  md_pseudo_table[] =
-{
-  {"dual", s_dual, 4},
-  {"enddual", s_enddual, 4},
-  {"atmp", s_atmp, 4},
-  {NULL, 0, 0},
-};
+/* These characters always start a comment.  */
+const char comment_chars[] = "#!/";
 
 
-/* This array holds the chars that always start a comment.  If the
-   pre-processor is disabled, these aren't very useful */
-const 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. */
+/* These characters start a comment at the beginning of a line.  */
 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 */
+/* Characters that can be used to separate the mantissa from the exponent
+   in floating point numbers.  */
 const char EXP_CHARS[] = "eE";
 
 const char EXP_CHARS[] = "eE";
 
-/* Chars that mean this number is a floating point constant */
-/* As in 0f12.456 */
-/* or    0d1.2345e12 */
+/* Characters that indicate this number is a floating point constant.
+   As in 0f12.456 or 0d1.2345e12.  */
 const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
 const 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);
+/* Register prefix (depends on syntax).  */
+static char reg_prefix;
 
 
-static unsigned char octal[256];
-#define isoctal(c)  octal[c]
-static unsigned char toHex[256];
+#define MAX_FIXUPS 2
 
 struct i860_it
 
 struct i860_it
+{
+  char *error;
+  unsigned long opcode;
+  enum expand_type expand;
+  struct i860_fi
   {
   {
-    char *error;
-    unsigned long opcode;
-    struct nlist *nlistp;
     expressionS exp;
     expressionS exp;
+    bfd_reloc_code_real_type reloc;
     int pcrel;
     int pcrel;
-    enum expand_type expand;
-    enum highlow_type highlow;
-    enum reloc_type reloc;
-  } the_insn;
+    valueT fup;
+  } fi[MAX_FIXUPS];
+} the_insn;
 
 
-#if __STDC__ == 1
+/* The current fixup count.  */
+static int fc;
 
 
-static void print_insn (struct i860_it *insn);
-static int getExpression (char *str);
+static char *expr_end;
 
 
-#else /* not __STDC__ */
+/* Indicates error if a pseudo operation was expanded after a branch.  */
+static char last_expand;
 
 
-static void print_insn ();
-static int getExpression ();
+/* If true, then warn if any pseudo operations were expanded.  */
+static int target_warn_expand = 0;
 
 
-#endif /* not __STDC__ */
+/* 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;
 
 
-static char *expr_end;
-static char last_expand;       /* error if expansion after branch */
 
 
+/* 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,
 };
 enum dual
 {
   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
 static void
-s_dual ()                      /* floating point instructions have dual set */
+s_dual (int ignore ATTRIBUTE_UNUSED)
 {
 {
-  dual_mode = DUAL_ON;
+  if (target_intel_syntax)
+    dual_mode = DUAL_ON;
+  else
+    as_bad (_("Directive .dual available only with -mintel-syntax option"));
 }
 
 }
 
+/* Handle ".enddual" directive.  */
 static void
 static void
-s_enddual ()                   /* floating point instructions have dual set */
+s_enddual (int ignore ATTRIBUTE_UNUSED)
 {
 {
-  dual_mode = DUAL_OFF;
+  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
 
 static void
-s_atmp ()
+s_atmp (int ignore ATTRIBUTE_UNUSED)
 {
 {
-  register int temp;
+  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;
   if (strncmp (input_line_pointer, "sp", 2) == 0)
     {
       input_line_pointer += 2;
@@ -163,21 +172,55 @@ s_atmp ()
   demand_empty_rest_of_line ();
 }
 
   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
 /* 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
 void
-md_begin ()
+md_begin (void)
 {
 {
-  register char *retval = NULL;
+  const char *retval = NULL;
   int lose = 0;
   int lose = 0;
-  register unsigned int i = 0;
+  unsigned int i = 0;
 
   op_hash = hash_new ();
 
 
   op_hash = hash_new ();
 
-  while (i < NUMOPCODES)
+  while (i860_opcodes[i].name != NULL)
     {
       const char *name = i860_opcodes[i].name;
     {
       const char *name = i860_opcodes[i].name;
-      retval = hash_insert (op_hash, name, &i860_opcodes[i]);
+      retval = hash_insert (op_hash, name, (void *) &i860_opcodes[i]);
       if (retval != NULL)
        {
          fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
       if (retval != NULL)
        {
          fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
@@ -188,147 +231,161 @@ md_begin ()
        {
          if (i860_opcodes[i].match & i860_opcodes[i].lose)
            {
        {
          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;
        }
                       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)
     }
 
   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."));
+
+  /* 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
 void
-md_assemble (str)
-     char *str;
+md_assemble (char *str)
 {
 {
-  char *toP;
-  int rsd;
-  int no_opcodes = 1;
+  char *destp;
+  int num_opcodes = 1;
   int i;
   struct i860_it pseudo[3];
 
   int i;
   struct i860_it pseudo[3];
 
-  assert (str);
-  i860_ip (str);
+  gas_assert (str);
+  fc = 0;
+
+  /* Assemble the instruction.  */
+  i860_process_insn (str);
 
 
-  /* check for expandable flag to produce pseudo-instructions */
-  if (the_insn.expand != 0 && the_insn.highlow == NO_SPEC)
+  /* 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;
 
     {
       for (i = 0; i < 3; i++)
        pseudo[i] = the_insn;
 
+      fc = 1;
       switch (the_insn.expand)
        {
 
        case E_DELAY:
       switch (the_insn.expand)
        {
 
        case E_DELAY:
-         no_opcodes = 1;
+         num_opcodes = 1;
          break;
 
        case E_MOV:
          break;
 
        case E_MOV:
-         if (the_insn.exp.X_add_symbol == NULL &&
-             the_insn.exp.X_op_symbol == NULL &&
-             (the_insn.exp.X_add_number < (1 << 15) &&
-              the_insn.exp.X_add_number >= -(1 << 15)))
+         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;
            break;
-         /* or l%const,r0,ireg_dest */
+
+         /* Emit "or l%const,r0,ireg_dest".  */
          pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000;
          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;
+         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:
          break;
 
        case E_ADDR:
-         if (the_insn.exp.X_add_symbol == NULL &&
-             the_insn.exp.X_op_symbol == NULL)
+         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;
            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;
+
+         /* 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;
 
          break;
 
-       case E_U32:             /* 2nd version emulates Intel as, not doc. */
-         if (the_insn.exp.X_add_symbol == NULL &&
-             the_insn.exp.X_op_symbol == NULL &&
-             (the_insn.exp.X_add_number < (1 << 16) &&
-              the_insn.exp.X_add_number >= 0))
+       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;
            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 "$(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;
 
          break;
 
-       case E_AND:             /* 2nd version emulates Intel as, not doc. */
-         if (the_insn.exp.X_add_symbol == NULL &&
-             the_insn.exp.X_op_symbol == NULL &&
-             (the_insn.exp.X_add_number < (1 << 16) &&
-              the_insn.exp.X_add_number >= 0))
+       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;
            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 "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:
          break;
 
        case E_S32:
-         if (the_insn.exp.X_add_symbol == NULL &&
-             the_insn.exp.X_op_symbol == NULL &&
-             (the_insn.exp.X_add_number < (1 << 15) &&
-              the_insn.exp.X_add_number >= -(1 << 15)))
+         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;
            break;
-         /* orh h%const,r0,r31 */
+
+         /* Emit "orh h%const,r0,r31".  */
          pseudo[0].opcode = 0xec000000 | (atmp << 16);
          pseudo[0].opcode = 0xec000000 | (atmp << 16);
-         pseudo[0].highlow = HIGH;
-         /* or l%const,r31,r31 */
+         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].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16);
-         pseudo[1].highlow = PAIR;
-         /* r31,ireg_src2,ireg_dest */
+         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].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11);
-         pseudo[2].reloc = NO_RELOC;
-         no_opcodes = 3;
+         pseudo[2].fi[0].fup = OP_IMM_S16;
+
+         num_opcodes = 3;
          break;
 
        default:
          break;
 
        default:
@@ -336,61 +393,87 @@ md_assemble (str)
        }
 
       the_insn = pseudo[0];
        }
 
       the_insn = pseudo[0];
-      /* check for expanded opcode after branch or in dual */
-      if (no_opcodes > 1 && last_expand == 1)
+
+      /* 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);
        as_warn (_("Expanded opcode after delayed branch: `%s'"), str);
-      if (no_opcodes > 1 && dual_mode != DUAL_OFF)
+
+      /* 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);
        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);
     }
 
     }
 
+  dwarf2_emit_insn (0);
   i = 0;
   do
   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,
-                  the_insn.pcrel,
-         /* merge bit fields into one argument */
-         (int) (((the_insn.highlow & 0x3) << 4) | (the_insn.reloc & 0xf)));
-       }
+    {
+      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];
     }
       the_insn = pseudo[++i];
     }
-  while (--no_opcodes > 0);
+  while (--num_opcodes > 0);
 
 }
 
 
 }
 
+/* Assemble the instruction pointed to by STR.  */
 static void
 static void
-i860_ip (str)
-     char *str;
+i860_process_insn (char *str)
 {
   char *s;
   const char *args;
   char c;
 {
   char *s;
   const char *args;
   char c;
-  unsigned long i;
   struct i860_opcode *insn;
   struct i860_opcode *insn;
-  char *argsStart;
+  char *args_start;
   unsigned long opcode;
   unsigned int mask;
   int match = 0;
   int comma = 0;
 
   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)
+  for (s = str; ISLOWER (*s) || *s == '.' || *s == '3'
+       || *s == '2' || *s == '1'; ++s)
     ;
     ;
+
   switch (*s)
     {
   switch (*s)
     {
-
     case '\0':
       break;
 
     case '\0':
       break;
 
@@ -407,8 +490,9 @@ i860_ip (str)
       as_fatal (_("Unknown opcode: `%s'"), str);
     }
 
       as_fatal (_("Unknown opcode: `%s'"), str);
     }
 
+  /* Check for dual mode ("d.") opcode prefix.  */
   if (strncmp (str, "d.", 2) == 0)
   if (strncmp (str, "d.", 2) == 0)
-    {                          /* check for d. opcode prefix */
+    {
       if (dual_mode == DUAL_ON)
        dual_mode = DUAL_ONDDOT;
       else
       if (dual_mode == DUAL_ON)
        dual_mode = DUAL_ONDDOT;
       else
@@ -423,35 +507,42 @@ i860_ip (str)
       as_bad (_("Unknown opcode: `%s'"), str);
       return;
     }
       as_bad (_("Unknown opcode: `%s'"), str);
       return;
     }
+
   if (comma)
   if (comma)
-    {
-      *--s = ',';
-    }
-  argsStart = s;
+    *--s = ',';
+
+  args_start = s;
   for (;;)
     {
   for (;;)
     {
+      int t;
       opcode = insn->match;
       memset (&the_insn, '\0', sizeof (the_insn));
       opcode = insn->match;
       memset (&the_insn, '\0', 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)
+      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)
            {
 
          switch (*args)
            {
 
-           case '\0':          /* end of args */
+           /* End of args.  */
+           case '\0':
              if (*s == '\0')
              if (*s == '\0')
-               {
-                 match = 1;
-               }
+               match = 1;
              break;
 
              break;
 
+           /* These must match exactly.  */
            case '+':
            case '+':
-           case '(':           /* these must match exactly */
+           case '(':
            case ')':
            case ',':
            case ' ':
            case ')':
            case ',':
            case ' ':
@@ -459,24 +550,30 @@ i860_ip (str)
                continue;
              break;
 
                continue;
              break;
 
-           case '#':           /* must be at least one digit */
-             if (isdigit (*s++))
+           /* Must be at least one digit.  */
+           case '#':
+             if (ISDIGIT (*s++))
                {
                {
-                 while (isdigit (*s))
-                   {
-                     ++s;
-                   }
+                 while (ISDIGIT (*s))
+                   ++s;
                  continue;
                }
              break;
 
                  continue;
                }
              break;
 
-           case '1':           /* next operand must be a register */
+           /* Next operand must be a register.  */
+           case '1':
            case '2':
            case 'd':
            case '2':
            case 'd':
+             /* Check for register prefix if necessary.  */
+             if (reg_prefix && *s != reg_prefix)
+               goto error;
+             else if (reg_prefix)
+               s++;
+
              switch (*s)
                {
              switch (*s)
                {
-
-               case 'f':       /* frame pointer */
+               /* Frame pointer.  */
+               case 'f':
                  s++;
                  if (*s++ == 'p')
                    {
                  s++;
                  if (*s++ == 'p')
                    {
@@ -485,7 +582,8 @@ i860_ip (str)
                    }
                  goto error;
 
                    }
                  goto error;
 
-               case 's':       /* stack pointer */
+               /* Stack pointer.  */
+               case 's':
                  s++;
                  if (*s++ == 'p')
                    {
                  s++;
                  if (*s++ == 'p')
                    {
@@ -494,36 +592,31 @@ i860_ip (str)
                    }
                  goto error;
 
                    }
                  goto error;
 
-               case 'r':       /* any register */
+               /* Any register r0..r31.  */
+               case 'r':
                  s++;
                  s++;
-                 if (!isdigit (c = *s++))
+                 if (!ISDIGIT (c = *s++))
                    {
                      goto error;
                    }
                    {
                      goto error;
                    }
-                 if (isdigit (*s))
+                 if (ISDIGIT (*s))
                    {
                      if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32)
                    {
                      if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32)
-                       {
-                         goto error;
-                       }
+                       goto error;
                    }
                  else
                    }
                  else
-                   {
-                     c -= '0';
-                   }
+                   c -= '0';
                  mask = c;
                  break;
 
                  mask = c;
                  break;
 
-               default:        /* not this opcode */
+               /* Not this opcode.  */
+               default:
                  goto error;
                }
                  goto error;
                }
-             /*
-                                * Got the register, now figure out where
-                                * it goes in the opcode.
-                                */
+
+             /* Obtained the register, now place it in the opcode.  */
              switch (*args)
                {
              switch (*args)
                {
-
                case '1':
                  opcode |= mask << 11;
                  continue;
                case '1':
                  opcode |= mask << 11;
                  continue;
@@ -539,13 +632,20 @@ i860_ip (str)
                }
              break;
 
                }
              break;
 
-           case 'e':           /* next operand is a floating point register */
+           /* Next operand is a floating point register.  */
+           case 'e':
            case 'f':
            case 'g':
            case 'f':
            case 'g':
-             if (*s++ == 'f' && isdigit (*s))
+             /* 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++;
                {
                  mask = *s++;
-                 if (isdigit (*s))
+                 if (ISDIGIT (*s))
                    {
                      mask = 10 * (mask - '0') + (*s++ - '0');
                      if (mask >= 32)
                    {
                      mask = 10 * (mask - '0') + (*s++ - '0');
                      if (mask >= 32)
@@ -554,9 +654,8 @@ i860_ip (str)
                        }
                    }
                  else
                        }
                    }
                  else
-                   {
-                     mask -= '0';
-                   }
+                   mask -= '0';
+
                  switch (*args)
                    {
 
                  switch (*args)
                    {
 
@@ -570,20 +669,22 @@ i860_ip (str)
 
                    case 'g':
                      opcode |= mask << 16;
 
                    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"));
+                     if ((opcode & (1 << 10)) && mask != 0
+                         && (mask == ((opcode >> 11) & 0x1f)))
+                       as_warn (_("Pipelined instruction: fsrc1 = fdest"));
                      continue;
                    }
                }
              break;
 
                      continue;
                    }
                }
              break;
 
-           case 'c':           /* next operand must be a control register */
+           /* 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;
              if (strncmp (s, "fir", 3) == 0)
                {
                  opcode |= 0x0 << 21;
@@ -620,87 +721,216 @@ i860_ip (str)
                  s += 4;
                  continue;
                }
                  s += 4;
                  continue;
                }
+             /* The remaining control registers are XP only.  */
+             if (target_xp && strncmp (s, "bear", 4) == 0)
+               {
+                 opcode |= 0x6 << 21;
+                 s += 4;
+                 continue;
+               }
+             if (target_xp && strncmp (s, "ccr", 3) == 0)
+               {
+                 opcode |= 0x7 << 21;
+                 s += 3;
+                 continue;
+               }
+             if (target_xp && strncmp (s, "p0", 2) == 0)
+               {
+                 opcode |= 0x8 << 21;
+                 s += 2;
+                 continue;
+               }
+             if (target_xp && strncmp (s, "p1", 2) == 0)
+               {
+                 opcode |= 0x9 << 21;
+                 s += 2;
+                 continue;
+               }
+             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;
 
              break;
 
-           case '5':           /* 5 bit immediate in src1 */
-             memset (&the_insn, '\0', sizeof (the_insn));
-             if (!getExpression (s))
+           /* 5-bit immediate in src1.  */
+           case '5':
+             if (! i860_get_expression (s))
                {
                  s = expr_end;
                {
                  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;
-                 memset (&the_insn, '\0', sizeof (the_insn));
-                 the_insn.reloc = NO_RELOC;
+                 the_insn.fi[fc].fup |= OP_IMM_U5;
+                 fc++;
                  continue;
                }
              break;
 
                  continue;
                }
              break;
 
-           case 'l':           /* 26 bit immediate, relative branch */
-             the_insn.reloc = BRADDR;
-             the_insn.pcrel = 1;
+           /* 26-bit immediate, relative branch (lbroff).  */
+           case 'l':
+             the_insn.fi[fc].pcrel = 1;
+             the_insn.fi[fc].fup |= OP_IMM_BR26;
              goto immediate;
 
              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;
+           /* 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;
 
              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;
+           /* 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;
 
              goto immediate;
 
-           case 'I':           /* 16 bit immediate, aligned */
-             if (opcode & (1 << 28))
-               if (opcode & 0x1)
-                 the_insn.reloc = LOW2;
-               else
-                 the_insn.reloc = LOW1;
+           /* 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
              else
-               the_insn.reloc = LOW0;
+               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;
 
              goto immediate;
 
-           case 'i':           /* 16 bit immediate */
-             the_insn.reloc = LOW0;
+           /* 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*/
 
 
              /*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:
            immediate:
-             if (*s == ' ')
-               s++;
-             if (strncmp (s, "ha%", 3) == 0)
-               {
-                 the_insn.highlow = HIGHADJ;
-                 s += 3;
-               }
-             else if (strncmp (s, "h%", 2) == 0)
+             if (target_intel_syntax == 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;
-
-             /* 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. */
+                 /* AT&T/SVR4 syntax.  */
+                 if (*s == ' ')
+                   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;
+                 else
+                   goto error;
+
+                 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;
+                   }
 
 
-             if (!getExpression (s))
+                 the_insn.expand = insn->expand;
+                  fc++;
+              
+                 continue;
+               }
+             else
                {
                {
-                 s = expr_end;
-                 continue;
+                 /* 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;
+
+                 /* 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;
+                 else
+                   goto error;
+
+                  fc++;
+                 continue;
                }
              break;
 
                }
              break;
 
@@ -713,35 +943,59 @@ i860_ip (str)
       if (match == 0)
        {
          /* Args don't match.  */
       if (match == 0)
        {
          /* Args don't match.  */
-         if (&insn[1] - i860_opcodes < NUMOPCODES
-             && !strcmp (insn->name, insn[1].name))
+         if (insn[1].name != NULL
+             && ! strcmp (insn->name, insn[1].name))
            {
              ++insn;
            {
              ++insn;
-             s = argsStart;
+             s = args_start;
              continue;
            }
          else
            {
              continue;
            }
          else
            {
-             as_bad (_("Illegal operands"));
+             as_bad (_("Illegal operands for %s"), insn->name);
              return;
            }
        }
       break;
     }
 
              return;
            }
        }
       break;
     }
 
+  /* 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;
   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
 }
 
 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;
 {
   char *save_in;
   segT seg;
 
   save_in = input_line_pointer;
   input_line_pointer = str;
-  seg = expression (&the_insn.exp);
+  seg = expression (&the_insn.fi[fc].exp);
   if (seg != absolute_section
       && seg != undefined_section
       && ! SEG_NORMAL (seg))
   if (seg != absolute_section
       && seg != undefined_section
       && ! SEG_NORMAL (seg))
@@ -756,508 +1010,482 @@ getExpression (str)
   return 0;
 }
 
   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 *
 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 0;
+  return ieee_md_atof (type, litP, sizeP, TRUE);
 }
 
 }
 
-/*
- * Write out big-endian.
- */
+/* Write out in current endian mode.  */
 void
 void
-md_number_to_chars (buf, val, n)
-     char *buf;
-     valueT val;
-     int n;
+md_number_to_chars (char *buf, valueT val, int n)
 {
 {
-  number_to_chars_bigendian (buf, val, n);
+  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 (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;
+  as_fatal (_("relaxation not supported\n"));
+}
 
 
-  assert (buf);
-  assert (n == 4);             /* always on i860 */
+#ifdef DEBUG_I860
+static void
+print_insn (struct i860_it *insn)
+{
+  if (insn->error)
+    fprintf (stderr, "ERROR: %s\n", insn->error);
 
 
-  switch (highlow)
-    {
+  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 */
+
+\f
+#ifdef OBJ_ELF
+const char *md_shortopts = "VQ:";
+#else
+const char *md_shortopts = "";
+#endif
 
 
-    case HIGHADJ:              /* adjusts the high-order 16-bits */
-      if (val & (1 << 15))
-       val += (1 << 16);
+#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)
 
 
-      /*FALLTHROUGH*/
+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);
 
 
-    case HIGH:                 /* selects the high-order 16-bits */
-      val >>= 16;
+int
+md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
+{
+  switch (c)
+    {
+    case OPTION_EB:
+      target_big_endian = 1;
       break;
 
       break;
 
-    case PAIR:                 /* selects the low-order 16-bits */
-      val = val & 0xffff;
+    case OPTION_EL:
+      target_big_endian = 0;
       break;
 
       break;
 
-    default:
+    case OPTION_WARN_EXPAND:
+      target_warn_expand = 1;
       break;
       break;
-    }
 
 
-  switch (reloc)
-    {
+    case OPTION_XP:
+      target_xp = 1;
+      break;
 
 
-    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;
+    case OPTION_INTEL_SYNTAX:
+      target_intel_syntax = 1;
       break;
 
       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 */
+#ifdef OBJ_ELF
+    /* SVR4 argument compatibility (-V): print version ID.  */
+    case 'V':
+      print_version_id ();
       break;
 
       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 */
+    /* SVR4 argument compatibility (-Qy, -Qn): controls whether
+       a .comment section should be emitted or not (ignored).  */
+    case 'Q':
       break;
       break;
+#endif
 
 
-    case NO_RELOC:
     default:
     default:
-      as_bad (_("bad relocation type: 0x%02x"), reloc);
-      break;
+      return 0;
     }
     }
-}
 
 
-/* should never be called for i860 */
-void
-md_number_to_disp (buf, val, n)
-     char *buf;
-     long val;
-{
-  as_fatal (_("md_number_to_disp\n"));
-}
-
-/* should never be called for i860 */
-void
-md_number_to_field (buf, val, fix)
-     char *buf;
-     long val;
-     void *fix;
-{
-  as_fatal (_("i860_number_to_field\n"));
+  return 1;
 }
 
 }
 
-/* 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 */
 void
 void
-md_ri_to_chars (ri_p, ri)
-     struct relocation_info *ri_p, ri;
+md_show_usage (FILE *stream)
 {
 {
-#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... */
-  memcpy ((char *) ri_p, the_bytes, sizeof (*ri_p));
+  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
 }
 
 #endif
 }
 
-/* should never be called for i860 */
-void
-md_convert_frag (headers, seg, fragP)
-     object_headers *headers;
-     segT seg;
-     register fragS *fragP;
+\f
+/* We have no need to default values of symbols.  */
+symbolS *
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 {
 {
-  as_fatal (_("i860_convert_frag\n"));
+  return 0;
 }
 
 }
 
-/* should never be called for i860 */
-int
-md_estimate_size_before_relax (fragP, segtype)
-     register fragS *fragP;
-     segT segtype;
+/* The i860 denotes auto-increment with '++'.  */
+void
+md_operand (expressionS *exp)
 {
 {
-  as_fatal (_("i860_estimate_size_before_relax\n"));
-}
+  char *s;
 
 
-/* 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;
-{
-  if (insn->error)
+  for (s = input_line_pointer; *s; s++)
     {
     {
-      fprintf (stderr, "ERROR: %s\n");
+      if (s[0] == '+' && s[1] == '+')
+       {
+         input_line_pointer += 2;
+         exp->X_op = O_register;
+         break;
+       }
     }
     }
-  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_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 = %d\n",
-          insn->exp.X_add_number);
-  fprintf (stderr, "}\n");
 }
 }
-\f
-CONST char *md_shortopts = "";
-struct option md_longopts[] = {
-  {NULL, no_argument, NULL, 0}
-};
-size_t md_longopts_size = sizeof(md_longopts);
 
 
-int
-md_parse_option (c, arg)
-     int c;
-     char *arg;
+/* Round up a section size to the appropriate boundary.  */
+valueT
+md_section_align (segT segment ATTRIBUTE_UNUSED,
+                 valueT size ATTRIBUTE_UNUSED)
 {
 {
-  return 0;
+  /* Byte alignment is fine.  */
+  return size;
 }
 
 }
 
-void
-md_show_usage (stream)
-     FILE *stream;
+/* On the i860, a PC-relative offset is relative to the address of the
+   offset plus its size.  */
+long
+md_pcrel_from (fixS *fixP)
 {
 {
+  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
 }
 }
-\f
-#ifdef comment
-/*
- * I860 relocations are completely different, so it needs
- * this machine dependent routine to emit them.
- */
-void
-emit_machine_reloc (fixP, segment_address_in_file)
-     register fixS *fixP;
-     relax_addressT segment_address_in_file;
-{
-  struct reloc_info_i860 ri;
-  register symbolS *symbolP;
-  extern char *next_object_file_charP;
-  long add_number;
 
 
-  memset ((char *) &ri, '\0', sizeof (ri));
-  for (; fixP; fixP = fixP->fx_next)
+/* 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)
+{
+  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)
     {
     {
-
-      if (fixP->fx_r_type & ~0x3f)
-       {
-         as_fatal ("fixP->fx_r_type = %d\n", fixP->fx_r_type);
-       }
-      ri.r_pcrel = fixP->fx_pcrel;
-      ri.r_type = fixP->fx_r_type;
-
-      if ((symbolP = fixP->fx_addsy) != NULL)
+      *val = (*val >> 16) + (*val & 0x8000 ? 1 : 0);
+      reloc = BFD_RELOC_860_HIGHADJ;
+    }
+  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)
        {
        {
-         ri.r_address = fixP->fx_frag->fr_address +
-           fixP->fx_where - segment_address_in_file;
-         if (!S_IS_DEFINED (symbolP))
+         if (fup & OP_ENCODE1)
            {
            {
-             ri.r_extern = 1;
-             ri.r_symbolnum = symbolP->sy_number;
+             num_encode = 1;
+             reloc = BFD_RELOC_860_SPLIT1;
+           }
+         else if (fup & OP_ENCODE2)
+           {
+             num_encode = 2;
+             reloc = BFD_RELOC_860_SPLIT2;
            }
          else
            {
            }
          else
            {
-             ri.r_extern = 0;
-             ri.r_symbolnum = S_GET_TYPE (symbolP);
+             num_encode = 0;
+             reloc = BFD_RELOC_860_SPLIT0;
            }
            }
-         if (symbolP && symbol_get_frag (symbolP))
+       }
+      else
+       {
+         if (fup & OP_ENCODE1)
            {
            {
-             ri.r_addend = symbol_get_frag (symbolP)->fr_address;
+             num_encode = 1;
+             reloc = BFD_RELOC_860_LOW1;
            }
            }
-         ri.r_type = fixP->fx_r_type;
-         if (fixP->fx_pcrel)
+         else if (fup & OP_ENCODE2)
            {
            {
-             /* preserve actual offset vs. pc + 4 */
-             ri.r_addend -= (ri.r_address + 4);
+             num_encode = 2;
+             reloc = BFD_RELOC_860_LOW2;
+           }
+         else if (fup & OP_ENCODE3)
+           {
+             num_encode = 3;
+             reloc = BFD_RELOC_860_LOW3;
            }
          else
            {
            }
          else
            {
-             ri.r_addend = fixP->fx_addnumber;
+             num_encode = 0;
+             reloc = BFD_RELOC_860_LOW0;
            }
            }
-
-         md_ri_to_chars ((char *) &ri, ri);
-         append (&next_object_file_charP, (char *) &ri, sizeof (ri));
        }
        }
-    }
-}
 
 
-#endif /* comment */
+      /* Preserve size encode bits.  */
+      *val &= ~((1 << num_encode) - 1);
+    }
+  else
+    {
+      /* No selector.  What reloc do we generate (???)?  */
+      reloc = BFD_RELOC_32;
+    }
 
 
-#ifdef OBJ_AOUT
+  return reloc;
+}
 
 
-/* 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. */
+/* 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
 
 void
-tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
-     char *where;
-     fixS *fixP;
-     relax_addressT segment_address_in_file;
+md_apply_fix (fixS *fix, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 {
 {
-  long r_index;
-  long r_extern;
-  long r_addend = 0;
-  long r_address;
+  char *buf;
+  long val = *valP;
+  unsigned long insn;
+  valueT fup;
+
+  buf = fix->fx_frag->fr_literal + fix->fx_where;
+
+  /* Recall that earlier we stored the opcode little-endian.  */
+  insn = bfd_getl32 (buf);
 
 
-  know (fixP->fx_addsy);
-  know (!(fixP->fx_r_type & ~0x3f));
+  /* We stored a fix-up in this oddly-named scratch field.  */
+  fup = fix->fx_addnumber;
 
 
-  if (!S_IS_DEFINED (fixP->fx_addsy))
+  /* Determine the necessary relocations as well as inserting an
+     immediate into the instruction.   */
+  if (fup & OP_IMM_U5)
     {
     {
-      r_extern = 1;
-      r_index = fixP->fx_addsy->sy_number;
+      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
+  else if (fup & OP_IMM_S16)
     {
     {
-      r_extern = 0;
-      r_index = S_GET_TYPE (fixP->fx_addsy);
-    }
+      fix->fx_r_type = obtain_reloc_for_imm16 (fix, &val);
 
 
-  md_number_to_chars (where,
-                     r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
-                     4);
+      /* 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;
+       }
+    }
+  else if (fup & OP_IMM_U16)
+    abort ();
 
 
-  where[4] = (r_index >> 16) & 0x0ff;
-  where[5] = (r_index >> 8) & 0x0ff;
-  where[6] = r_index & 0x0ff;
-  where[7] = (((fixP->fx_pcrel << 7) & 0x80)
-             | ((r_extern << 6) & 0x40)
-             | (fixP->fx_r_type & 0x3F));
+  else if (fup & OP_IMM_SPLIT16)
+    {
+      fix->fx_r_type = obtain_reloc_for_imm16 (fix, &val);
 
 
-  if (symbol_get_frag (fixP->fx_addsy))
+      /* 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;
+       }
+    }
+  else if (fup & OP_IMM_BR16)
     {
     {
-      r_addend = symbol_get_frag (fixP->fx_addsy)->fr_address;
+      if (val & 0x3)
+       as_bad_where (fix->fx_file, fix->fx_line,
+                     _("A branch offset requires 0 MOD 4 alignment"));
+
+      val = val >> 2;
+
+      /* 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"));
+
+      val >>= 2;
 
 
-  if (fixP->fx_pcrel)
+      /* 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)
     {
     {
-      /* preserve actual offset vs. pc + 4 */
-      r_addend -= (r_address + 4);
+      as_bad_where (fix->fx_file, fix->fx_line,
+                   _("Unrecognized fix-up (0x%08lx)"), (unsigned long) fup);
+      abort ();
     }
   else
     {
     }
   else
     {
-      r_addend = fixP->fx_addnumber;
+      /* 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;
+       }
     }
     }
-
-  md_number_to_chars (&where[8], r_addend, 4);
 }
 
 }
 
-#endif /* OBJ_AOUT */
-
-/* We have no need to default values of symbols.  */
-
-/* ARGSUSED */
-symbolS *
-md_undefined_symbol (name)
-     char *name;
+/* Generate a machine dependent reloc from a fixup.  */
+arelent*
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
+             fixS *fixp)
 {
 {
-  return 0;
-}
+  arelent *reloc;
 
 
-/* Round up a section size to the appropriate boundary.  */
-valueT
-md_section_align (segment, size)
-     segT segment;
-     valueT size;
-{
-  return size;                 /* Byte alignment is fine */
-}
+  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);
 
 
-/* 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;
-{
-  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
+  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;
 }
 
 }
 
+/* This is called from HANDLE_ALIGN in write.c.  Fill in the contents
+   of an rs_align_code fragment.  */
+
 void
 void
-md_apply_fix (fixP, val)
-     fixS *fixP;
-     long val;
+i860_handle_align (fragS *fragp)
 {
 {
-  char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
+  /* Instructions are always stored little-endian on the i860.  */
+  static const unsigned char le_nop[] = { 0x00, 0x00, 0x00, 0xA0 };
 
 
-  /* looks to me like i860 never has bit fixes. Let's see. xoxorich. */
-  know (fixP->fx_bit_fixP == NULL);
-  if (!fixP->fx_bit_fixP)
-    {
-      fixP->fx_addnumber = val;
-      md_number_to_imm (place, val, fixP->fx_size, fixP);
-    }
-  else
+  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)
     {
     {
-      md_number_to_field (place, val, fixP->fx_bit_fixP);
+      int fix = bytes & 3;
+      memset (p, 0, fix);
+      p += fix;
+      fragp->fr_fix += fix;
     }
     }
+
+  memcpy (p, le_nop, 4);
+  fragp->fr_var = 4;
 }
 
 }
 
-/*
- * Local Variables:
- * fill-column: 131
- * comment-column: 0
- * End:
- */
+/* 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.  */
 
 
-/* end of tc-i860.c */
+void
+i860_check_label (symbolS *labelsym)
+{
+  /* 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.045838 seconds and 4 git commands to generate.