]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-a29k.c
* config/sh/tm-sh.h (BELIEVE_PCC_PROMOTION): Define, so that
[thirdparty/binutils-gdb.git] / gas / config / tc-a29k.c
index 877a924997eeab4da43b05e69db8e77491595546..600fec58857cbf2c0c1d0bb00823cb6c24ab3266 100644 (file)
@@ -1,5 +1,6 @@
 /* tc-a29k.c -- Assemble for the AMD 29000.
-   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1989, 90, 91, 92, 93, 94, 95, 1998
+   Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GAS; see the file COPYING.  If not, write to
-   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   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.  */
 
 /* John Gilmore has reorganized this module somewhat, to make it easier
    to convert it to new machines' assemblers as desired.  There was too
    much bloody rewriting required before.  There still probably is.  */
 
-#include "ctype.h"
+#include <ctype.h>
 #include "as.h"
 
 #include "opcode/a29k.h"
 #define        machine_ip      a29k_ip
 #define        machine_it      a29k_it
 
-const relax_typeS md_relax_table[] =
-{
-  { 0, 0, 0, 0 }
-};
-
 #define        IMMEDIATE_BIT   0x01000000      /* Turns RB into Immediate */
 #define        ABSOLUTE_BIT    0x01000000      /* Turns PC-relative to Absolute */
 #define        CE_BIT          0x00800000      /* Coprocessor enable in LOAD */
@@ -82,8 +79,6 @@ md_pseudo_table[] =
   {NULL, 0, 0},
 };
 
-int md_short_jump_size = 4;
-int md_long_jump_size = 4;
 #if defined(BFD_HEADERS)
 #ifdef RELSZ
 const int md_reloc_size = RELSZ;       /* Coff headers */
@@ -123,10 +118,6 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
    changed in read.c.  Ideally it shouldn't have to know about it at
    all, but nothing is ideal around here.  */
 
-static unsigned char octal[256];
-#define isoctal(c)  octal[c]
-static unsigned char toHex[256];
-
 /*
  *  anull bit - causes the branch delay slot instructions to not be executed
  */
@@ -166,9 +157,8 @@ s_use (ignore)
       return;
     }
 
-  as_bad ("Unknown segment type");
+  as_bad (_("Unknown segment type"));
   demand_empty_rest_of_line ();
-  return;
 }
 
 static void
@@ -176,7 +166,6 @@ s_data1 ()
 {
   subseg_set (SEG_DATA, 1);
   demand_empty_rest_of_line ();
-  return;
 }
 
 #endif /* OBJ_COFF */
@@ -245,6 +234,12 @@ define_some_regs ()
   insert_sreg ("iba1", SREG + 25);
   insert_sreg ("ibc1", SREG + 26);
 
+  /* Additional registers for the 29040.  */
+  insert_sreg ("dba", SREG + 27);
+  insert_sreg ("dbc", SREG + 28);
+  insert_sreg ("cir", SREG + 29);
+  insert_sreg ("cdr", SREG + 30);
+
   /* Unprotected special-purpose register names */
   insert_sreg ("ipc", SREG + 128);
   insert_sreg ("ipa", SREG + 129);
@@ -332,26 +327,11 @@ md_begin ()
     }
 
   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 (_("Broken assembler.  No assembly attempted."));
 
   define_some_regs ();
 }
 
-void
-md_end ()
-{
-  return;
-}
-
 /* Assemble a single instruction.  Its label has already been handled
    by the generic front end.  We just parse opcode and operands, and
    produce the bytes of data and relocation.  */
@@ -381,17 +361,18 @@ md_assemble (str)
 }
 
 char *
-parse_operand (s, operandp)
+parse_operand (s, operandp, opt)
      char *s;
      expressionS *operandp;
+     int opt;
 {
   char *save = input_line_pointer;
   char *new;
 
   input_line_pointer = s;
   expression (operandp);
-  if (operandp->X_op == O_absent)
-    as_bad ("missing operand");
+  if (operandp->X_op == O_absent && ! opt)
+    as_bad (_("missing operand"));
   new = input_line_pointer;
   input_line_pointer = save;
   return new;
@@ -431,12 +412,12 @@ machine_ip (str)
       break;
 
     default:
-      as_bad ("Unknown opcode: `%s'", str);
+      as_bad (_("Unknown opcode: `%s'"), str);
       return;
     }
   if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL)
     {
-      as_bad ("Unknown opcode `%s'.", str);
+      as_bad (_("Unknown opcode `%s'."), str);
       return;
     }
   argsStart = s;
@@ -451,7 +432,10 @@ machine_ip (str)
      and do a "continue".  If an operand fails to match, we "break".  */
 
   if (insn->args[0] != '\0')
-    s = parse_operand (s, operand);    /* Prime the pump */
+    {
+      /* Prime the pump.  */
+      s = parse_operand (s, operand, insn->args[0] == 'I');
+    }
 
   for (args = insn->args;; ++args)
     {
@@ -465,13 +449,14 @@ machine_ip (str)
              the_insn.opcode = opcode;
              return;
            }
-         as_bad ("Too many operands: %s", s);
+         as_bad (_("Too many operands: %s"), s);
          break;
 
        case ',':               /* Must match a comma */
          if (*s++ == ',')
            {
-             s = parse_operand (s, operand);   /* Parse next opnd */
+             /* Parse next operand.  */
+             s = parse_operand (s, operand, args[1] == 'I');
              continue;
            }
          break;
@@ -486,7 +471,7 @@ machine_ip (str)
                }
              else
                {
-                 as_bad ("Immediate value of %ld is too large",
+                 as_bad (_("Immediate value of %ld is too large"),
                          (long) operand->X_add_number);
                  continue;
                }
@@ -517,7 +502,7 @@ machine_ip (str)
                }
              else
                {
-                 as_bad ("Immediate value of %ld is too large",
+                 as_bad (_("Immediate value of %ld is too large"),
                          (long) operand->X_add_number);
                  continue;
                }
@@ -556,7 +541,7 @@ machine_ip (str)
              opcode |= reg << 16;
              continue;
            }
-         as_fatal ("failed sanity check.");
+         as_fatal (_("failed sanity check."));
          break;
 
        case 'x':               /* 16 bit constant, zero-extended */
@@ -592,6 +577,13 @@ machine_ip (str)
              /* Make sure the 'A' case really exists.  */
              if ((insn->opcode | ABSOLUTE_BIT) != (insn + 1)->opcode)
                break;
+             {
+               bfd_vma v, mask;
+               mask = 0x1ffff;
+               v = operand->X_add_number & ~ mask;
+               if (v)
+                 as_bad ("call/jmp target out of range");
+             }
              opcode |= ABSOLUTE_BIT |
                (operand->X_add_number & 0x0003FC00) << 6 |
                ((operand->X_add_number & 0x000003FC) >> 2);
@@ -656,6 +648,18 @@ machine_ip (str)
            }
          break;
 
+       case 'I':               /* ID bits of INV and IRETINV.  */
+         /* This operand is optional.  */
+         if (operand->X_op == O_absent)
+           continue;
+         else if (operand->X_op == O_constant
+                  && operand->X_add_number < 4)
+           {
+             opcode |= operand->X_add_number << 16;
+             continue;
+           }
+         break;
+
        case 'd':               /* FD bits of CONVERT */
          if (operand->X_op == O_constant &&
              operand->X_add_number < 4)
@@ -776,23 +780,7 @@ md_number_to_chars (buf, val, n)
      valueT val;
      int n;
 {
-
-  switch (n)
-    {
-
-    case 4:
-      *buf++ = val >> 24;
-      *buf++ = val >> 16;
-    case 2:
-      *buf++ = val >> 8;
-    case 1:
-      *buf = val;
-      break;
-
-    default:
-      as_fatal ("failed sanity check.");
-    }
-  return;
+  number_to_chars_bigendian (buf, val, n);
 }
 
 void
@@ -861,16 +849,30 @@ md_apply_fix (fixP, val)
       buf[3] = val;
       break;
 
-#if 0
-    case RELOC_PC10:
-    case RELOC_PC22:
-    case RELOC_JMP_TBL:
-    case RELOC_SEGOFF16:
-    case RELOC_GLOB_DAT:
-    case RELOC_JMP_SLOT:
-    case RELOC_RELATIVE:
-#endif
     case RELOC_JUMPTARG:       /* 00XX00XX pattern in a word */
+      if (!fixP->fx_done)
+       {
+         /* The linker tries to support both AMD and old GNU style
+             R_IREL relocs.  That means that if the addend is exactly
+             the negative of the address within the section, the
+             linker will not handle it correctly.  */
+         if (fixP->fx_pcrel
+             && val != 0
+             && val == - (fixP->fx_frag->fr_address + fixP->fx_where))
+           as_bad_where
+             (fixP->fx_file, fixP->fx_line,
+              "the linker will not handle this relocation correctly");
+       }
+      else if (fixP->fx_pcrel)
+       {
+         long v = val >> 17;
+         if (v != 0 && v != -1)
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         "call/jmp target out of range");
+       }
+      else
+       /* this case was supposed to be handled in machine_ip */
+       abort ();
       buf[1] = val >> 10;      /* Holds bits 0003FFFC of address */
       buf[3] = val >> 2;
       break;
@@ -887,10 +889,9 @@ md_apply_fix (fixP, val)
 
     case NO_RELOC:
     default:
-      as_bad ("bad relocation type: 0x%02x", fixP->fx_r_type);
+      as_bad (_("bad relocation type: 0x%02x"), fixP->fx_r_type);
       break;
     }
-  return;
 }
 
 #ifdef OBJ_COFF
@@ -912,7 +913,7 @@ tc_coff_fix2rtype (fixP)
     case RELOC_JUMPTARG:
       return (R_IREL);
     default:
-      printf ("need %o3\n", fixP->fx_r_type);
+      printf (_("need %o3\n"), fixP->fx_r_type);
       abort ();
     }                          /* switch on type */
 
@@ -923,34 +924,12 @@ tc_coff_fix2rtype (fixP)
 
 /* should never be called for 29k */
 void
-md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
-     char *ptr;
-     addressT from_addr, to_addr;
-     fragS *frag;
-     symbolS *to_symbol;
-{
-  as_fatal ("a29k_create_short_jmp\n");
-}
-
-/* should never be called for 29k */
-void
-md_convert_frag (headers, fragP)
+md_convert_frag (headers, seg, fragP)
      object_headers *headers;
+     segT seg;
      register fragS *fragP;
 {
-  as_fatal ("a29k_convert_frag\n");
-}
-
-/* should never be called for 29k */
-void
-md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
-     char *ptr;
-     addressT from_addr;
-     addressT to_addr;
-     fragS *frag;
-     symbolS *to_symbol;
-{
-  as_fatal ("a29k_create_long_jump\n");
+  as_fatal (_("a29k_convert_frag\n"));
 }
 
 /* should never be called for a29k */
@@ -959,7 +938,7 @@ md_estimate_size_before_relax (fragP, segtype)
      register fragS *fragP;
      segT segtype;
 {
-  as_fatal ("a29k_estimate_size_before_relax\n");
+  as_fatal (_("a29k_estimate_size_before_relax\n"));
   return 0;
 }
 
@@ -1016,7 +995,6 @@ print_insn (insn)
   fprintf (stderr, "\t\tX_add_number = %d\n",
           insn->exp.X_add_number);
   fprintf (stderr, "}\n");
-  return;
 }
 
 #endif
@@ -1059,16 +1037,68 @@ tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
 }
 
 #endif /* OBJ_AOUT */
+\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 (argP, cntP, vecP)
-     char **argP;
-     int *cntP;
-     char ***vecP;
+md_parse_option (c, arg)
+     int c;
+     char *arg;
 {
   return 0;
 }
 
+void
+md_show_usage (stream)
+     FILE *stream;
+{
+}
+\f
+/* This is called when a line is unrecognized.  This is used to handle
+   definitions of a29k style local labels.  */
+
+int
+a29k_unrecognized_line (c)
+     int c;
+{
+  int lab;
+  char *s;
+
+  if (c != '$'
+      || ! isdigit ((unsigned char) input_line_pointer[0]))
+    return 0;
+
+  s = input_line_pointer;
+
+  lab = 0;
+  while (isdigit ((unsigned char) *s))
+    {
+      lab = lab * 10 + *s - '0';
+      ++s;
+    }
+
+  if (*s != ':')
+    {
+      /* Not a label definition.  */
+      return 0;
+    }
+
+  if (dollar_label_defined (lab))
+    {
+      as_bad (_("label \"$%d\" redefined"), lab);
+      return 0;
+    }
+
+  define_dollar_label (lab);
+  colon (dollar_label_name (lab, 0));
+  input_line_pointer = s + 1;
+
+  return 1;
+}
 
 /* Default the values of symbols known that should be "predefined".  We
    don't bother to predefine them unless you actually use one, since there
@@ -1081,29 +1111,41 @@ md_undefined_symbol (name)
   long regnum;
   char testbuf[5 + /*SLOP*/ 5];
 
-  if (name[0] == 'g' || name[0] == 'G' || name[0] == 'l' || name[0] == 'L')
+  if (name[0] == 'g' || name[0] == 'G'
+      || name[0] == 'l' || name[0] == 'L'
+      || name[0] == 's' || name[0] == 'S')
     {
       /* Perhaps a global or local register name */
       if (name[1] == 'r' || name[1] == 'R')
        {
-         /* Parse the number, make sure it has no extra zeroes or trailing
-                                  chars */
+         long maxreg;
+
+         /* Parse the number, make sure it has no extra zeroes or
+            trailing chars. */
          regnum = atol (&name[2]);
-         if (regnum > 127)
-           return 0;
+
+         if (name[0] == 's' || name[0] == 'S')
+           maxreg = 255;
+         else
+           maxreg = 127;
+         if (regnum > maxreg)
+           return NULL;
+
          sprintf (testbuf, "%ld", regnum);
          if (strcmp (testbuf, &name[2]) != 0)
-           return 0;           /* gr007 or lr7foo or whatever */
+           return NULL;        /* gr007 or lr7foo or whatever */
 
          /* We have a wiener!  Define and return a new symbol for it.  */
          if (name[0] == 'l' || name[0] == 'L')
            regnum += 128;
+         else if (name[0] == 's' || name[0] == 'S')
+           regnum += SREG;
          return (symbol_new (name, SEG_REGISTER, (valueT) regnum,
                              &zero_address_frag));
        }
     }
 
-  return 0;
+  return NULL;
 }
 
 /* Parse an operand that is machine-specific.  */
@@ -1120,7 +1162,7 @@ md_operand (expressionP)
       (void) expression (expressionP);
       if (expressionP->X_op != O_constant
          || expressionP->X_add_number > 255)
-       as_bad ("Invalid expression after %%%%\n");
+       as_bad (_("Invalid expression after %%%%\n"));
       expressionP->X_op = O_register;
     }
   else if (input_line_pointer[0] == '&')
@@ -1131,10 +1173,105 @@ md_operand (expressionP)
       input_line_pointer++;    /* Skip & */
       (void) expression (expressionP);
       if (expressionP->X_op != O_register)
-       as_bad ("Invalid register in & expression");
+       as_bad (_("Invalid register in & expression"));
       else
        expressionP->X_op = O_constant;
     }
+  else if (input_line_pointer[0] == '$'
+          && isdigit ((unsigned char) input_line_pointer[1]))
+    {
+      long lab;
+      char *name;
+      symbolS *sym;
+
+      /* This is a local label.  */
+      ++input_line_pointer;
+      lab = (long) get_absolute_expression ();
+      if (dollar_label_defined (lab))
+       {
+         name = dollar_label_name (lab, 0);
+         sym = symbol_find (name);
+       }
+      else
+       {
+         name = dollar_label_name (lab, 1);
+         sym = symbol_find_or_make (name);
+       }
+
+      expressionP->X_op = O_symbol;
+      expressionP->X_add_symbol = sym;
+      expressionP->X_add_number = 0;
+    }
+  else if (input_line_pointer[0] == '$')
+    {
+      char *s;
+      char type;
+      int fieldnum, fieldlimit;
+      LITTLENUM_TYPE floatbuf[8];
+
+      /* $float(), $doubleN(), or $extendN() convert floating values
+        to integers.  */
+
+      s = input_line_pointer;
+
+      ++s;
+
+      fieldnum = 0;
+      if (strncmp (s, "double", sizeof "double" - 1) == 0)
+       {
+         s += sizeof "double" - 1;
+         type = 'd';
+         fieldlimit = 2;
+       }
+      else if (strncmp (s, "float", sizeof "float" - 1) == 0)
+       {
+         s += sizeof "float" - 1;
+         type = 'f';
+         fieldlimit = 1;
+       }
+      else if (strncmp (s, "extend", sizeof "extend" - 1) == 0)
+       {
+         s += sizeof "extend" - 1;
+         type = 'x';
+         fieldlimit = 4;
+       }
+      else 
+       {
+         return;
+       }
+
+      if (isdigit (*s))
+       {
+         fieldnum = *s - '0';
+         ++s;
+       }
+      if (fieldnum >= fieldlimit)
+       return;
+
+      SKIP_WHITESPACE ();
+      if (*s != '(')
+       return;
+      ++s;
+      SKIP_WHITESPACE ();
+
+      s = atof_ieee (s, type, floatbuf);
+      if (s == NULL)
+       return;
+      s = s;
+
+      SKIP_WHITESPACE ();
+      if (*s != ')')
+       return;
+      ++s;
+      SKIP_WHITESPACE ();
+
+      input_line_pointer = s;
+      expressionP->X_op = O_constant; 
+      expressionP->X_unsigned = 1;
+      expressionP->X_add_number = ((floatbuf[fieldnum * 2]
+                                   << LITTLENUM_NUMBER_OF_BITS)
+                                  + floatbuf[fieldnum * 2 + 1]);
+    }
 }
 
 /* Round up a section size to the appropriate boundary.  */