Sanitize support for the ESA sparc simulator.
[deliverable/binutils-gdb.git] / gas / config / tc-a29k.c
index ef929e4ffad3f482a29a126dd79f33bfe7570b8f..4c3ede1195b087f2d90985a98b8bfbbfeb3089fc 100644 (file)
 
    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.  */
+   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 */
@@ -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
  */
@@ -243,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,23 +329,9 @@ 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';
-
   define_some_regs ();
 }
 
-void
-md_end ()
-{
-}
-
 /* 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.  */
@@ -378,16 +361,17 @@ 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)
+  if (operandp->X_op == O_absent && ! opt)
     as_bad ("missing operand");
   new = input_line_pointer;
   input_line_pointer = save;
@@ -448,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)
     {
@@ -468,7 +455,8 @@ machine_ip (str)
        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;
@@ -589,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);
@@ -653,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)
@@ -842,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;
@@ -914,8 +935,9 @@ md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
 
 /* 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");
@@ -1038,16 +1060,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
@@ -1060,29 +1134,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.  */
@@ -1114,6 +1200,101 @@ md_operand (expressionP)
       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.  */
This page took 0.027976 seconds and 4 git commands to generate.