* tc_mips.h (MAX_GPREL_OFFSET): Change it to the maximum allowed
[deliverable/binutils-gdb.git] / gas / config / tc-fr30.c
index accb3895f33d45565c8e2f3f541fc22369c284bd..98f5729fe97894bf2363315bca2760a6e160aed8 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-fr30.c -- Assembler for the Fujitsu FR30.
-   Copyright (C) 1998 Free Software Foundation.
+   Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
 #include <stdio.h>
 #include <ctype.h>
 #include "as.h"
-#include "subsegs.h"     
+#include "subsegs.h"
 #include "symcat.h"
-#include "cgen-opc.h"
+#include "opcodes/fr30-desc.h"
+#include "opcodes/fr30-opc.h"
 #include "cgen.h"
 
-/* Linked list of symbols that are debugging symbols to be
-   defined as the beginning of the current instruction.  */
-typedef struct sym_link
-{
-  struct sym_link * next;
-  symbolS *         symbol;
-} sym_linkS;
-
-static sym_linkS *  debug_sym_link = (sym_linkS *) NULL;
-  
 /* Structure to hold all of the different components describing
    an individual instruction.  */
 typedef struct
@@ -55,13 +46,12 @@ typedef struct
   int                   num_fixups;
   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
   int                   indices [MAX_OPERAND_INSTANCES];
-  sym_linkS *           debug_sym_link;
 }
 fr30_insn;
 
 const char comment_chars[]        = ";";
 const char line_comment_chars[]   = "#";
-const char line_separator_chars[] = "";
+const char line_separator_chars[] = "|";
 const char EXP_CHARS[]            = "eE";
 const char FLT_CHARS[]            = "dD";
 \f
@@ -92,7 +82,7 @@ md_show_usage (stream)
   FILE * stream;
 {
   fprintf (stream, _(" FR30 specific command line options:\n"));
-} 
+}
 
 /* The target specific pseudo-ops which we support.  */
 const pseudo_typeS md_pseudo_table[] =
@@ -110,19 +100,23 @@ md_begin ()
   subsegT  subseg;
 
   /* Initialize the `cgen' interface.  */
-  
+
   /* Set the machine number and endian.  */
-  gas_cgen_opcode_desc = fr30_cgen_opcode_open (bfd_mach_fr30, CGEN_ENDIAN_BIG);
-  fr30_cgen_init_asm (gas_cgen_opcode_desc);
+  gas_cgen_cpu_desc = fr30_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
+                                         CGEN_CPU_OPEN_ENDIAN,
+                                         CGEN_ENDIAN_BIG,
+                                         CGEN_CPU_OPEN_END);
+  fr30_cgen_init_asm (gas_cgen_cpu_desc);
 
   /* This is a callback from cgen to gas to parse operands.  */
-  cgen_set_parse_operand_fn (gas_cgen_opcode_desc, gas_cgen_parse_operand);
+  cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
 }
 
 void
 md_assemble (str)
      char * str;
 {
+  static int last_insn_had_delay_slot = 0;
   fr30_insn insn;
   char *    errmsg;
   char *    str2 = NULL;
@@ -130,12 +124,9 @@ md_assemble (str)
   /* Initialize GAS's cgen interface for a new instruction.  */
   gas_cgen_init_parse ();
 
-  insn.debug_sym_link = debug_sym_link;
-  debug_sym_link = (sym_linkS *)0;
-
   insn.insn = fr30_cgen_assemble_insn
-    (gas_cgen_opcode_desc, str, & insn.fields, insn.buffer, & errmsg);
-  
+    (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
+
   if (!insn.insn)
     {
       as_bad (errmsg);
@@ -145,12 +136,21 @@ md_assemble (str)
   /* Doesn't really matter what we pass for RELAX_P here.  */
   gas_cgen_finish_insn (insn.insn, insn.buffer,
                        CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
+
+  /* Warn about invalid insns in delay slots.  */
+  if (last_insn_had_delay_slot
+      && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_NOT_IN_DELAY_SLOT))
+    as_warn (_("Instruction %s not allowed in a delay slot."),
+            CGEN_INSN_NAME (insn.insn));
+
+  last_insn_had_delay_slot
+    = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
 }
 
 /* The syntax in the manual says constants begin with '#'.
    We just ignore it.  */
 
-void 
+void
 md_operand (expressionP)
      expressionS * expressionP;
 {
@@ -208,7 +208,8 @@ const relax_typeS md_relax_table[] =
 };
 
 long
-fr30_relax_frag (fragP, stretch)
+fr30_relax_frag (segment, fragP, stretch)
+     segT    segment;
      fragS * fragP;
      long    stretch;
 {
@@ -235,7 +236,7 @@ fr30_relax_frag (fragP, stretch)
     }
   else
     {
-      growth = relax_frag (fragP, stretch);
+      growth = relax_frag (segment, fragP, stretch);
 
       /* Long jump on odd halfword boundary?  */
       if (fragP->fr_subtype == 2 && (address & 3) != 0)
@@ -264,8 +265,6 @@ md_estimate_size_before_relax (fragP, segment)
      fragS * fragP;
      segT    segment;
 {
-  int    old_fr_fix = fragP->fr_fix;
-
   /* The only thing we have to handle here are symbols outside of the
      current segment.  They may be undefined or in a different segment in
      which case linker scripts may place them anywhere.
@@ -274,12 +273,14 @@ md_estimate_size_before_relax (fragP, segment)
 
   if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
     {
+      int    old_fr_fix = fragP->fr_fix;
+
       /* The symbol is undefined in this segment.
         Change the relaxation subtype to the max allowable and leave
         all further handling to md_convert_frag.  */
       fragP->fr_subtype = 2;
 
-#if 0 /* Can't use this, but leave in for illustration.  */     
+#if 0 /* Can't use this, but leave in for illustration.  */
       /* Change 16 bit insn to 32 bit insn.  */
       fragP->fr_opcode[0] |= 0x80;
 
@@ -296,6 +297,7 @@ md_estimate_size_before_relax (fragP, segment)
 
       /* Mark this fragment as finished.  */
       frag_wane (fragP);
+      return fragP->fr_fix - old_fr_fix;
 #else
       {
        const CGEN_INSN * insn;
@@ -310,7 +312,7 @@ md_estimate_size_before_relax (fragP, segment)
            if ((strcmp (CGEN_INSN_MNEMONIC (insn),
                         CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
                 == 0)
-               && CGEN_INSN_ATTR (insn, CGEN_INSN_RELAX))
+               && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAX))
              break;
          }
        if (i == 4)
@@ -322,8 +324,9 @@ md_estimate_size_before_relax (fragP, segment)
 #endif
     }
 
-  return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
-} 
+  /* Return the size of the variable part of the frag.  */
+  return md_relax_table[fragP->fr_subtype].rlx_length;
+}
 
 /* *fragP has been relaxed to its final size, and now needs to have
    the bytes inside it modified to conform to the new size.
@@ -384,7 +387,6 @@ md_convert_frag (abfd, sec, fragP)
     {
       /* Address we want to reach in file space.  */
       target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
-      target_address += fragP->fr_symbol->sy_frag->fr_address;
       addend = (target_address - (opcode_address & -4)) >> 2;
     }
 
@@ -438,7 +440,7 @@ md_pcrel_from_section (fixP, sec)
       return 0;
     }
 
-  return (fixP->fx_frag->fr_address + fixP->fx_where) & -4L;
+  return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
 }
 
 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
@@ -451,15 +453,17 @@ md_cgen_lookup_reloc (insn, operand, fixP)
      const CGEN_OPERAND * operand;
      fixS *               fixP;
 {
-  switch (CGEN_OPERAND_TYPE (operand))
+  switch (operand->type)
     {
-    case FR30_OPERAND_PC :   return BFD_RELOC_FR30_12_PCREL;
-    case FR30_OPERAND_RI :   
-    case FR30_OPERAND_RJ :   
-    case FR30_OPERAND_NBIT : 
-    case FR30_OPERAND_VBIT :
-    case FR30_OPERAND_ZBIT :
-    case FR30_OPERAND_CBIT :
+    case FR30_OPERAND_LABEL9:  fixP->fx_pcrel = 1; return BFD_RELOC_FR30_9_PCREL;
+    case FR30_OPERAND_LABEL12: fixP->fx_pcrel = 1; return BFD_RELOC_FR30_12_PCREL;
+    case FR30_OPERAND_DISP10:  return BFD_RELOC_FR30_10_IN_8;
+    case FR30_OPERAND_DISP9:   return BFD_RELOC_FR30_9_IN_8;
+    case FR30_OPERAND_DISP8:   return BFD_RELOC_FR30_8_IN_8;
+    case FR30_OPERAND_UDISP6:  return BFD_RELOC_FR30_6_IN_4;
+    case FR30_OPERAND_I8:      return BFD_RELOC_8;
+    case FR30_OPERAND_I32:     return BFD_RELOC_FR30_48;
+    case FR30_OPERAND_I20:     return BFD_RELOC_FR30_20;
     default : /* avoid -Wall warning */
       break;
     }
@@ -467,12 +471,6 @@ md_cgen_lookup_reloc (insn, operand, fixP)
   return BFD_RELOC_NONE;
 }
 
-
-/* Return BFD reloc type from opinfo field in a fixS.
-   It's tricky using fx_r_type in fr30_frob_file because the values
-   are BFD_RELOC_UNUSED + operand number.  */
-#define FX_OPINFO_R_TYPE(f) ((f)->tc_fix_data.opinfo)
-
 /* See whether we need to force a relocation into the output file.
    This is used to force out switch and PC relative relocations when
    relaxing.  */
@@ -481,11 +479,11 @@ int
 fr30_force_relocation (fix)
      fixS * fix;
 {
-  if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+  if (   fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT
       || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 1;
 
-  return fix->fx_pcrel;
+  return 0;
 }
 \f
 /* Write a value out to the object file, using the appropriate endianness.  */
@@ -553,7 +551,116 @@ md_atof (type, litP, sizeP)
                          sizeof (LITTLENUM_TYPE));
       litP += sizeof (LITTLENUM_TYPE);
     }
-     
+
+  return 0;
+}
+
+/* Worker function for fr30_is_colon_insn().  */
+static char
+restore_colon (advance_i_l_p_by)
+     int advance_i_l_p_by;
+{
+  char c;
+
+  /* Restore the colon, and advance input_line_pointer to
+     the end of the new symbol.  */
+  * input_line_pointer = ':';
+  input_line_pointer += advance_i_l_p_by;
+  c = * input_line_pointer;
+  * input_line_pointer = 0;
+
+  return c;
+}
+
+/* Determines if the symbol starting at START and ending in
+   a colon that was at the location pointed to by INPUT_LINE_POINTER
+   (but which has now been replaced bu a NUL) is in fact an
+   LDI:8, LDI:20, LDI:32, CALL:D. JMP:D, RET:D or Bcc:D instruction.
+   If it is, then it restores the colon, advances INPUT_LINE_POINTER
+   to the real end of the instruction/symbol, and returns the character
+   that really terminated the symbol.  Otherwise it returns 0.  */
+char
+fr30_is_colon_insn (start)
+     char *  start;
+{
+  char * i_l_p = input_line_pointer;
+
+  /* Check to see if the symbol parsed so far is 'ldi'  */
+  if (   (start[0] != 'l' && start[0] != 'L')
+      || (start[1] != 'd' && start[1] != 'D')
+      || (start[2] != 'i' && start[2] != 'I')
+      || start[3] != 0)
+    {
+      /* Nope - check to see a 'd' follows the colon.  */
+      if (   (i_l_p[1] == 'd' || i_l_p[1] == 'D')
+         && (i_l_p[2] == ' ' || i_l_p[2] == '\t' || i_l_p[2] == '\n'))
+       {
+         /* Yup - it might be delay slot instruction.  */
+         int           i;
+         static char * delay_insns [] =
+         {
+           "call", "jmp", "ret", "bra", "bno",
+           "beq",  "bne", "bc",  "bnc", "bn",
+           "bp",   "bv",  "bnv", "blt", "bge",
+           "ble",  "bgt", "bls", "bhi"
+         };
+
+         for (i = sizeof (delay_insns) / sizeof (delay_insns[0]); i--;)
+           {
+             char * insn = delay_insns[i];
+             int    len  = strlen (insn);
+
+             if (start [len] != 0)
+               continue;
+
+             while (len --)
+               if (tolower (start [len]) != insn [len])
+                 break;
+
+             if (len == -1)
+               return restore_colon (1);
+           }
+       }
+
+      /* Nope - it is a normal label.  */
+      return 0;
+    }
+
+  /* Check to see if the text following the colon is '8' */
+  if (i_l_p[1] == '8' && (i_l_p[2] == ' ' || i_l_p[2] == '\t'))
+    return restore_colon (2);
+
+  /* Check to see if the text following the colon is '20' */
+  else if (i_l_p[1] == '2' && i_l_p[2] =='0' && (i_l_p[3] == ' ' || i_l_p[3] == '\t'))
+    return restore_colon (3);
+
+  /* Check to see if the text following the colon is '32' */
+  else if (i_l_p[1] == '3' && i_l_p[2] =='2' && (i_l_p[3] == ' ' || i_l_p[3] == '\t'))
+    return restore_colon (3);
+
   return 0;
 }
 
+boolean
+fr30_fix_adjustable (fixP)
+   fixS * fixP;
+{
+  if (fixP->fx_addsy == NULL)
+    return 1;
+
+#if 0
+  /* Prevent all adjustments to global symbols.  */
+  if (S_IS_EXTERN (fixP->fx_addsy))
+    return 0;
+
+  if (S_IS_WEAK (fixP->fx_addsy))
+    return 0;
+#endif
+
+  /* We need the symbol name for the VTABLE entries */
+  if (   fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    return 0;
+
+  return 1;
+}
This page took 0.027625 seconds and 4 git commands to generate.