This commit was generated by cvs2svn to track changes on a CVS vendor
[deliverable/binutils-gdb.git] / gas / config / tc-d30v.c
index a14a51d6141501ca9f02207fd57f08dbd85b2c0f..25c541242425beee48d776439b9683b871f44853 100644 (file)
@@ -1,6 +1,5 @@
 /* tc-d30v.c -- Assembler code for the Mitsubishi D30V
-
-   Copyright (C) 1997, 1998 Free Software Foundation.
+   Copyright (C) 1997, 1998, 1999 Free Software Foundation.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -32,6 +31,14 @@ const char *md_shortopts = "OnNcC";
 const char EXP_CHARS[] = "eE";
 const char FLT_CHARS[] = "dD";
 
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
 #define NOP_MULTIPLY 1
 #define NOP_ALL 2
 static int warn_nops = 0;
@@ -216,7 +223,7 @@ register_name (expressionP)
     {
       expressionP->X_op = O_register;
       /* temporarily store a pointer to the string here */
-      expressionP->X_op_symbol = (struct symbol *)input_line_pointer;
+      expressionP->X_op_symbol = (symbolS *)input_line_pointer;
       expressionP->X_add_number = reg_number;
       input_line_pointer = p;
       return 1;
@@ -237,29 +244,35 @@ check_range (num, bits, flags)
   int retval=0;
 
   /* don't bother checking 32-bit values */
-  if (bits == 32)
+  if (bits == 32 && sizeof(unsigned long) * CHAR_BIT == 32)
     return 0;
 
+  /* Sign extend signed values to unsigned long */
+  if ((flags & OPERAND_SIGNED) && (num & ((unsigned long)1 << (bits - 1))))
+    num |= ((long)-1 << (bits - 1));
+
   if (flags & OPERAND_SHIFT)
     {
       /* We know that all shifts are right by three bits.... */
       
       if (flags & OPERAND_SIGNED)
-       num = (unsigned long) (((/*signed*/ long) num) >> 3);
+       num = (unsigned long) ( (long) num >= 0) 
+               ? ( ((long) num) >> 3 )
+               : ( (num >> 3) | ((unsigned long)-1 << (32 - 3)) );
       else
        num >>= 3;
     }
 
   if (flags & OPERAND_SIGNED)
     {
-      max = (1 << (bits - 1))-1; 
-      min = - (1 << (bits - 1));
+      max = ((unsigned long)1 << (bits - 1)) - 1; 
+      min = - ((unsigned long)1 << (bits - 1));
       if (((long)num > max) || ((long)num < min))
        retval = 1;
     }
   else
     {
-      max = (1 << bits) - 1;
+      max = ((unsigned long)1 << bits) - 1;
       min = 0;
       if ((num > max) || (num < min))
        retval = 1;
@@ -800,12 +813,23 @@ write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)
              fx = fx->next;
            }
        }
-      else if (opcode1->op->flags_used & (FLAG_JMP | FLAG_JSR)
-              && ((opcode1->op->flags_used & FLAG_DELAY) == 0)
-              && ((opcode1->ecc == ECC_AL) || ! Optimizing))
+      else if ((opcode1->op->flags_used & (FLAG_JMP | FLAG_JSR)
+               && ((opcode1->op->flags_used & FLAG_DELAY) == 0)
+               && ((opcode1->ecc == ECC_AL) || ! Optimizing))
+              || opcode1->op->flags_used & FLAG_RP)
        {
          /* We must emit (non-delayed) branch type instructions
             on their own with nothing in the right container.  */
+         /* We must treat repeat instructions likewise, since the
+            following instruction has to be separate from the repeat
+            in order to be repeated.  */
+         write_1_short (opcode1, insn1, fx->next, false);
+         return 1;
+       }
+      else if (prev_left_kills_right_p)
+       {
+         /* The left instruction kils the right slot, so we
+            must leave it empty.  */
          write_1_short (opcode1, insn1, fx->next, false);
          return 1;
        }
@@ -974,10 +998,28 @@ parallel_ok (op1, insn1, op2, insn2, exec_type)
        }
       flag_reg[j] = 0;
       mod_reg[j][0] = mod_reg[j][1] = 0;
-      mod_reg[j][2] = (op->flags_set & FLAG_ALL);
       used_reg[j][0] = used_reg[j][1] = 0;
-      used_reg[j][2] = (op->flags_used & FLAG_ALL);
 
+      if (flag_explicitly_parallel)
+       {
+         /* For human specified parallel instructions we have been asked
+            to ignore the possibility that both instructions could modify
+            bits in the PSW, so we initialise the mod & used arrays to 0.
+            We have been asked, however, to refuse to allow parallel
+            instructions which explicitly set the same flag register,
+            eg "cmpne f0,r1,0x10 || cmpeq f0, r5, 0x2", so further on we test
+            for the use of a flag register and set a bit in the mod or used
+            array appropriately.  */
+            
+         mod_reg[j][2]  = 0;
+         used_reg[j][2] = 0;
+       }
+      else
+       {
+         mod_reg[j][2] = (op->flags_set & FLAG_ALL);
+         used_reg[j][2] = (op->flags_used & FLAG_ALL);
+       }
+      
       /* BSR/JSR always sets R62 */
       if (op->flags_used & FLAG_JSR)
        mod_reg[j][1] = (1L << (62-32));
@@ -1223,7 +1265,7 @@ md_assemble (str)
          prev_insn = do_assemble (str, &prev_opcode, 1, 0);
          if (prev_insn == -1)
            as_bad (_("Cannot assemble instruction"));
-         if (prev_opcode.form->form >= LONG)
+         if (prev_opcode.form != NULL && prev_opcode.form->form >= LONG)
            as_bad (_("First opcode is long.  Unable to mix instructions as specified.")); 
          fixups = fixups->next;
          str = str2 + 2;
@@ -1238,11 +1280,9 @@ md_assemble (str)
   if (insn == -1)
     {
       if (extype != EXEC_UNKNOWN)
-       {
-         etype = extype;
-         return;
-       }
+       etype = extype;
       as_bad (_("Cannot assemble instruction"));
+      return;
     }
 
   if (etype != EXEC_UNKNOWN)
@@ -1358,6 +1398,8 @@ md_assemble (str)
 /* do_assemble assembles a single instruction and returns an opcode */
 /* it returns -1 (an invalid opcode) on error */
 
+#define NAME_BUF_LEN   20
+
 static long long
 do_assemble (str, opcode, shortp, is_parallel) 
      char *str;
@@ -1365,22 +1407,25 @@ do_assemble (str, opcode, shortp, is_parallel)
      int shortp;
      int is_parallel;
 {
-  unsigned char *op_start, *save;
-  unsigned char *op_end;
-  char name[20];
-  int cmp_hack, nlen = 0, fsize = (shortp ? FORCE_SHORT : 0);
-  expressionS myops[6];
-  long long insn;
+  unsigned char * op_start;
+  unsigned char * save;
+  unsigned char * op_end;
+  char            name [NAME_BUF_LEN];
+  int             cmp_hack;
+  int             nlen = 0;
+  int             fsize = (shortp ? FORCE_SHORT : 0);
+  expressionS     myops [6];
+  long long       insn;
 
   /* Drop leading whitespace */
-  while (*str == ' ')
-    str++;
+  while (* str == ' ')
+    str ++;
 
   /* find the opcode end */
   for (op_start = op_end = (unsigned char *) (str);
-       *op_end
-       && nlen < 20
-       && *op_end != '/'
+       * op_end
+       && nlen < (NAME_BUF_LEN - 1)
+       && * op_end != '/'
        && !is_end_of_line[*op_end] && *op_end != ' ';
        op_end++)
     {
@@ -1471,15 +1516,21 @@ do_assemble (str, opcode, shortp, is_parallel)
   /* find the first opcode with the proper name */  
   opcode->op = (struct d30v_opcode *)hash_find (d30v_hash, name);
   if (opcode->op == NULL)
-    as_bad (_("unknown opcode: %s"),name);
+    {
+      as_bad (_("unknown opcode: %s"),name);
+      return -1;
+    }
 
   save = input_line_pointer;
   input_line_pointer = op_end;
   while (!(opcode->form = find_format (opcode->op, myops, fsize, cmp_hack)))
     {
       opcode->op++;
-      if (strcmp (opcode->op->name, name))
-       as_bad (_("operands for opcode `%s' do not match any valid format"), name);
+      if (opcode->op->name == NULL || strcmp (opcode->op->name, name))
+       {
+         as_bad (_("operands for opcode `%s' do not match any valid format"), name);
+         return -1;
+       }
     }
   input_line_pointer = save;
 
@@ -1535,7 +1586,6 @@ do_assemble (str, opcode, shortp, is_parallel)
        cur_left_kills_right_p = 0;
     }
 
-
   return insn;
 }
 
@@ -1554,6 +1604,9 @@ find_format (opcode, myops, fsize, cmp_hack)
   int numops, match, index, i=0, j, k;
   struct d30v_format *fm;
 
+  if (opcode == NULL)
+    return NULL;
+  
   /* Get all the operands and save them as expressions.  */
   numops = get_operands (myops, cmp_hack);
 
@@ -1709,7 +1762,8 @@ tc_gen_reloc (seg, fixp)
 {
   arelent *reloc;
   reloc = (arelent *) xmalloc (sizeof (arelent));
-  reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+  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->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
   if (reloc->howto == (reloc_howto_type *) NULL)
@@ -1783,30 +1837,38 @@ md_apply_fix3 (fixp, valuep, seg)
   
   switch (fixp->fx_r_type)
     {
-    case BFD_RELOC_8:  /* Caused by a bad .byte directive.  */
-      /* Drop trhough.  */
+    case BFD_RELOC_8:  /* Check for a bad .byte directive.  */
+      if (fixp->fx_addsy != NULL)
+       as_bad (_("line %d: unable to place address of symbol '%s' into a byte"),
+               fixp->fx_line, S_GET_NAME (fixp->fx_addsy));
+      else if (((unsigned)value) > 0xff)
+         as_bad (_("line %d: unable to place value %x into a byte"),
+                   fixp->fx_line, value);
+      else
+       * (unsigned char *) where = value;
+      break;
       
-    case BFD_RELOC_16:  /* Caused by a bad .short directive.  */
-      /* Drop through.  */
+    case BFD_RELOC_16:  /* Check for a bad .short directive.  */
+      if (fixp->fx_addsy != NULL)
+       as_bad (_("line %d: unable to place address of symbol '%s' into a short"),
+               fixp->fx_line, S_GET_NAME (fixp->fx_addsy));
+      else if (((unsigned)value) > 0xffff)
+         as_bad (_("line %d: unable to place value %x into a short"),
+                   fixp->fx_line, value);
+      else
+       bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
+      break;
       
-    case BFD_RELOC_64:  /* Caused by a bad .quad directive.  */
-      {
-       char * size;
-
-       size = (fixp->fx_r_type == BFD_RELOC_8) ? _("byte")
-         : (fixp->fx_r_type == BFD_RELOC_16) ? _("short")
-         : _("quad");
-
-       if (fixp->fx_addsy == NULL)
-         as_bad (_("line %d: unable to place address into a %s"),
-                   fixp->fx_line, size);
-       else
-         as_bad (_("line %d: unable to place address of symbol '%s' into a %s"),
-                   fixp->fx_line,
-                   S_GET_NAME (fixp->fx_addsy),
-                   size);
-       break;
-      }
+    case BFD_RELOC_64:  /* Check for a bad .quad directive.  */
+      if (fixp->fx_addsy != NULL)
+       as_bad (_("line %d: unable to place address of symbol '%s' into a quad"),
+               fixp->fx_line, S_GET_NAME (fixp->fx_addsy));
+      else
+       {
+         bfd_putb32 ((bfd_vma) value, (unsigned char *) where);
+         bfd_putb32 (0, ((unsigned char *) where) + 4);
+       }
+      break;
       
     case BFD_RELOC_D30V_6:
       check_size (value, 6, fixp->fx_file, fixp->fx_line);
@@ -1984,7 +2046,7 @@ d30v_frob_label (lab)
   d30v_cleanup (false);
 
   /* Update the label's address with the current output pointer.  */
-  lab->sy_frag = frag_now;
+  symbol_set_frag (lab, frag_now);
   S_SET_VALUE (lab, (valueT) frag_now_fix ());
 
   /* Record this label for future adjustment after we find out what
@@ -2066,7 +2128,7 @@ d30v_align (n, pfill, label)
       
       assert (S_GET_SEGMENT (label) == now_seg);
 
-      old_frag  = label->sy_frag;
+      old_frag  = symbol_get_frag (label);
       old_value = S_GET_VALUE (label);
       new_value = (valueT) frag_now_fix ();
       
@@ -2081,15 +2143,16 @@ d30v_align (n, pfill, label)
         in the target fragment.  Note, this search is guaranteed to
         find at least one match when sym == label, so no special case
         code is necessary.  */
-      for (sym = symbol_lastP; sym != NULL; sym = sym->sy_previous)
+      for (sym = symbol_lastP; sym != NULL; sym = symbol_previous (sym))
        {
-         if (sym->sy_frag == old_frag && S_GET_VALUE (sym) == old_value)
+         if (symbol_get_frag (sym) == old_frag
+             && S_GET_VALUE (sym) == old_value)
            {
              label_seen = true;
-             sym->sy_frag = frag_now;
+             symbol_set_frag (sym, frag_now);
              S_SET_VALUE (sym, new_value);
            }
-         else if (label_seen && sym->sy_frag != old_frag)
+         else if (label_seen && symbol_get_frag (sym) != old_frag)
            break;
        }
     }
This page took 0.027984 seconds and 4 git commands to generate.