update copyright dates
[deliverable/binutils-gdb.git] / gas / config / tc-i860.c
index 2418997e874abd78540ea100e62fa448155c8395..ec9bda8a33e840a939fb3f72f443f08192f920a1 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-i860.c -- Assembler for the Intel i860 architecture.
 /* tc-i860.c -- Assembler for the Intel i860 architecture.
-   Copyright 1989, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003
-   Free Software Foundation, Inc.
+   Copyright 1989, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2002,
+   2003, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
    Brought back from the dead and completely reworked
    by Jason Eckhardt <jle@cygnus.com>.
 
    Brought back from the dead and completely reworked
    by Jason Eckhardt <jle@cygnus.com>.
@@ -9,7 +9,7 @@
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    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 <stdio.h>
-#include <string.h>
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
@@ -91,6 +89,7 @@ static void i860_process_insn (char *);
 static void s_dual (int);
 static void s_enddual (int);
 static void s_atmp (int);
 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 int i860_get_expression (char *);
 static bfd_reloc_code_real_type obtain_reloc_for_imm16 (fixS *, long *); 
 #ifdef DEBUG_I860
@@ -99,13 +98,11 @@ static void print_insn (struct i860_it *);
 
 const pseudo_typeS md_pseudo_table[] =
 {
 
 const pseudo_typeS md_pseudo_table[] =
 {
-#ifdef OBJ_ELF
-  {"align",   s_align_bytes, 0},
-#endif
-  {"dual",    s_dual,        0},
-  {"enddual", s_enddual,     0},
-  {"atmp",    s_atmp,        0},
-  {NULL,      0,             0},
+  {"align",   s_align_wrapper, 0},
+  {"dual",    s_dual,          0},
+  {"enddual", s_enddual,       0},
+  {"atmp",    s_atmp,          0},
+  {NULL,      0,               0},
 };
 
 /* Dual-instruction mode handling.  */
 };
 
 /* Dual-instruction mode handling.  */
@@ -176,6 +173,39 @@ s_atmp (int ignore ATTRIBUTE_UNUSED)
   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
    set up all the tables and data structures that the MD part of the
    assembler will need.  */
 /* This function is called once, at assembler startup time.  It should
    set up all the tables and data structures that the MD part of the
    assembler will need.  */
@@ -191,7 +221,7 @@ md_begin (void)
   while (i860_opcodes[i].name != NULL)
     {
       const char *name = i860_opcodes[i].name;
   while (i860_opcodes[i].name != NULL)
     {
       const char *name = i860_opcodes[i].name;
-      retval = hash_insert (op_hash, name, (PTR)&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"),
@@ -231,7 +261,7 @@ md_assemble (char *str)
   int i;
   struct i860_it pseudo[3];
 
   int i;
   struct i860_it pseudo[3];
 
-  assert (str);
+  gas_assert (str);
   fc = 0;
 
   /* Assemble the instruction.  */
   fc = 0;
 
   /* Assemble the instruction.  */
@@ -280,8 +310,9 @@ md_assemble (char *str)
                  && the_insn.fi[0].exp.X_add_number >= -(1 << 15)))
            break;
 
                  && the_insn.fi[0].exp.X_add_number >= -(1 << 15)))
            break;
 
-         /* Emit "orh ha%addr_expr,r0,r31".  */
-         pseudo[0].opcode = 0xec000000 | (atmp << 16);
+         /* 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
          pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_HA);
 
          /* Emit "l%addr_expr(r31),ireg_dest".  We pick up the fixup
@@ -638,12 +669,6 @@ i860_process_insn (char *str)
 
                    case 'g':
                      opcode |= mask << 16;
 
                    case 'g':
                      opcode |= mask << 16;
-                     if (dual_mode != DUAL_OFF)
-                       opcode |= (1 << 9);
-                     if (dual_mode == DUAL_DDOT)
-                       dual_mode = DUAL_OFF;
-                     if (dual_mode == DUAL_ONDDOT)
-                       dual_mode = DUAL_ON;
                      if ((opcode & (1 << 10)) && mask != 0
                          && (mask == ((opcode >> 11) & 0x1f)))
                        as_warn (_("Pipelined instruction: fsrc1 = fdest"));
                      if ((opcode & (1 << 10)) && mask != 0
                          && (mask == ((opcode >> 11) & 0x1f)))
                        as_warn (_("Pipelined instruction: fsrc1 = fdest"));
@@ -934,6 +959,27 @@ i860_process_insn (char *str)
       break;
     }
 
       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;
 
   /* Only recognize XP instructions when the user has requested it.  */
   the_insn.opcode = opcode;
 
   /* Only recognize XP instructions when the user has requested it.  */
@@ -964,62 +1010,10 @@ i860_get_expression (char *str)
   return 0;
 }
 
   return 0;
 }
 
-/* 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 (int type, char *litP, int *sizeP)
 {
 char *
 md_atof (int type, char *litP, int *sizeP)
 {
-  int prec;
-  LITTLENUM_TYPE words[MAX_LITTLENUMS];
-  LITTLENUM_TYPE *wordP;
-  char *t;
-
-  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 in current endian mode.  */
 }
 
 /* Write out in current endian mode.  */
@@ -1037,7 +1031,7 @@ int
 md_estimate_size_before_relax (register fragS *fragP ATTRIBUTE_UNUSED,
                               segT segtype ATTRIBUTE_UNUSED)
 {
 md_estimate_size_before_relax (register fragS *fragP ATTRIBUTE_UNUSED,
                               segT segtype ATTRIBUTE_UNUSED)
 {
-  as_fatal (_("i860_estimate_size_before_relax\n"));
+  as_fatal (_("relaxation not supported\n"));
 }
 
 #ifdef DEBUG_I860
 }
 
 #ifdef DEBUG_I860
@@ -1185,7 +1179,7 @@ md_section_align (segT segment ATTRIBUTE_UNUSED,
 }
 
 /* On the i860, a PC-relative offset is relative to the address of the
 }
 
 /* On the i860, a PC-relative offset is relative to the address of the
-   of the offset plus its size.  */
+   offset plus its size.  */
 long
 md_pcrel_from (fixS *fixP)
 {
 long
 md_pcrel_from (fixS *fixP)
 {
@@ -1290,7 +1284,7 @@ obtain_reloc_for_imm16 (fixS *fix, long *val)
    we will have to generate a reloc entry.  */
 
 void
    we will have to generate a reloc entry.  */
 
 void
-md_apply_fix3 (fixS *fix, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+md_apply_fix (fixS *fix, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 {
   char *buf;
   long val = *valP;
 {
   char *buf;
   long val = *valP;
@@ -1447,3 +1441,51 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
     }
   return reloc;
 }
     }
   return reloc;
 }
+
+/* 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)
+{
+  /* 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
+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.03663 seconds and 4 git commands to generate.