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.
-   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>.
@@ -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
-   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,
 
    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"
@@ -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_align_wrapper (int);
 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[] =
 {
-#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.  */
@@ -176,6 +173,39 @@ s_atmp (int ignore ATTRIBUTE_UNUSED)
   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.  */
@@ -191,7 +221,7 @@ md_begin (void)
   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"),
@@ -231,7 +261,7 @@ md_assemble (char *str)
   int i;
   struct i860_it pseudo[3];
 
-  assert (str);
+  gas_assert (str);
   fc = 0;
 
   /* Assemble the instruction.  */
@@ -280,8 +310,9 @@ md_assemble (char *str)
                  && 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
@@ -638,12 +669,6 @@ i860_process_insn (char *str)
 
                    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"));
@@ -934,6 +959,27 @@ i860_process_insn (char *str)
       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.  */
@@ -964,62 +1010,10 @@ i860_get_expression (char *str)
   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)
 {
-  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.  */
@@ -1037,7 +1031,7 @@ int
 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
@@ -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
-   of the offset plus its size.  */
+   offset plus its size.  */
 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
-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;
@@ -1447,3 +1441,51 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
     }
   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.028586 seconds and 4 git commands to generate.