(root)/
binutils-2.41/
gas/
config/
tc-fr30.c
       1  /* tc-fr30.c -- Assembler for the Fujitsu FR30.
       2     Copyright (C) 1998-2023 Free Software Foundation, Inc.
       3  
       4     This file is part of GAS, the GNU Assembler.
       5  
       6     GAS is free software; you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation; either version 3, or (at your option)
       9     any later version.
      10  
      11     GAS is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14     GNU General Public License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with GAS; see the file COPYING.  If not, write to
      18     the Free Software Foundation, 51 Franklin Street - Fifth Floor,
      19     Boston, MA 02110-1301, USA.  */
      20  
      21  #include "as.h"
      22  #include "safe-ctype.h"
      23  #include "subsegs.h"
      24  #include "symcat.h"
      25  #include "opcodes/fr30-desc.h"
      26  #include "opcodes/fr30-opc.h"
      27  #include "cgen.h"
      28  
      29  /* Structure to hold all of the different components describing
      30     an individual instruction.  */
      31  typedef struct
      32  {
      33    const CGEN_INSN *	insn;
      34    const CGEN_INSN *	orig_insn;
      35    CGEN_FIELDS		fields;
      36  #if CGEN_INT_INSN_P
      37    CGEN_INSN_INT         buffer [1];
      38  #define INSN_VALUE(buf) (*(buf))
      39  #else
      40    unsigned char         buffer [CGEN_MAX_INSN_SIZE];
      41  #define INSN_VALUE(buf) (buf)
      42  #endif
      43    char *		addr;
      44    fragS *		frag;
      45    int                   num_fixups;
      46    fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
      47    int                   indices [MAX_OPERAND_INSTANCES];
      48  }
      49  fr30_insn;
      50  
      51  const char comment_chars[]        = ";";
      52  const char line_comment_chars[]   = "#";
      53  const char line_separator_chars[] = "|";
      54  const char EXP_CHARS[]            = "eE";
      55  const char FLT_CHARS[]            = "dD";
      56  
      57  #define FR30_SHORTOPTS ""
      58  const char * md_shortopts = FR30_SHORTOPTS;
      59  
      60  struct option md_longopts[] =
      61  {
      62    {NULL, no_argument, NULL, 0}
      63  };
      64  size_t md_longopts_size = sizeof (md_longopts);
      65  
      66  int
      67  md_parse_option (int c ATTRIBUTE_UNUSED,
      68  		 const char *arg ATTRIBUTE_UNUSED)
      69  {
      70    switch (c)
      71      {
      72      default:
      73        return 0;
      74      }
      75    return 1;
      76  }
      77  
      78  void
      79  md_show_usage (FILE * stream)
      80  {
      81    fprintf (stream, _(" FR30 specific command line options:\n"));
      82  }
      83  
      84  /* The target specific pseudo-ops which we support.  */
      85  const pseudo_typeS md_pseudo_table[] =
      86  {
      87    { "word",	cons,		4 },
      88    { NULL, 	NULL, 		0 }
      89  };
      90  
      91  
      92  void
      93  md_begin (void)
      94  {
      95    /* Initialize the `cgen' interface.  */
      96  
      97    /* Set the machine number and endian.  */
      98    gas_cgen_cpu_desc = fr30_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
      99  					  CGEN_CPU_OPEN_ENDIAN,
     100  					  CGEN_ENDIAN_BIG,
     101  					  CGEN_CPU_OPEN_END);
     102    fr30_cgen_init_asm (gas_cgen_cpu_desc);
     103  
     104    /* This is a callback from cgen to gas to parse operands.  */
     105    cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
     106  }
     107  
     108  void
     109  md_assemble (char *str)
     110  {
     111    static int last_insn_had_delay_slot = 0;
     112    fr30_insn insn;
     113    char *errmsg;
     114  
     115    /* Initialize GAS's cgen interface for a new instruction.  */
     116    gas_cgen_init_parse ();
     117  
     118    insn.insn = fr30_cgen_assemble_insn
     119      (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
     120  
     121    if (!insn.insn)
     122      {
     123        as_bad ("%s", errmsg);
     124        return;
     125      }
     126  
     127    /* Doesn't really matter what we pass for RELAX_P here.  */
     128    gas_cgen_finish_insn (insn.insn, insn.buffer,
     129  			CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
     130  
     131    /* Warn about invalid insns in delay slots.  */
     132    if (last_insn_had_delay_slot
     133        && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_NOT_IN_DELAY_SLOT))
     134      as_warn (_("Instruction %s not allowed in a delay slot."),
     135  	     CGEN_INSN_NAME (insn.insn));
     136  
     137    last_insn_had_delay_slot
     138      = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
     139  }
     140  
     141  /* The syntax in the manual says constants begin with '#'.
     142     We just ignore it.  */
     143  
     144  void
     145  md_operand (expressionS * expressionP)
     146  {
     147    if (* input_line_pointer == '#')
     148      {
     149        input_line_pointer ++;
     150        expression (expressionP);
     151      }
     152  }
     153  
     154  valueT
     155  md_section_align (segT segment, valueT size)
     156  {
     157    int align = bfd_section_alignment (segment);
     158  
     159    return ((size + (1 << align) - 1) & -(1 << align));
     160  }
     161  
     162  symbolS *
     163  md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
     164  {
     165    return NULL;
     166  }
     167  
     168  /* Interface to relax_segment.  */
     169  
     170  /* FIXME: Build table by hand, get it working, then machine generate.  */
     171  
     172  const relax_typeS md_relax_table[] =
     173  {
     174  /* The fields are:
     175     1) most positive reach of this state,
     176     2) most negative reach of this state,
     177     3) how many bytes this mode will add to the size of the current frag
     178     4) which index into the table to try if we can't fit into this one.  */
     179  
     180    /* The first entry must be unused because an `rlx_more' value of zero ends
     181       each list.  */
     182    {1, 1, 0, 0},
     183  
     184    /* The displacement used by GAS is from the end of the 2 byte insn,
     185       so we subtract 2 from the following.  */
     186    /* 16 bit insn, 8 bit disp -> 10 bit range.
     187       This doesn't handle a branch in the right slot at the border:
     188       the "& -4" isn't taken into account.  It's not important enough to
     189       complicate things over it, so we subtract an extra 2 (or + 2 in -ve
     190       case).  */
     191    {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
     192    /* 32 bit insn, 24 bit disp -> 26 bit range.  */
     193    {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
     194    /* Same thing, but with leading nop for alignment.  */
     195    {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
     196  };
     197  
     198  /* Return an initial guess of the length by which a fragment must grow to
     199     hold a branch to reach its destination.
     200     Also updates fr_type/fr_subtype as necessary.
     201  
     202     Called just before doing relaxation.
     203     Any symbol that is now undefined will not become defined.
     204     The guess for fr_var is ACTUALLY the growth beyond fr_fix.
     205     Whatever we do to grow fr_fix or fr_var contributes to our returned value.
     206     Although it may not be explicit in the frag, pretend fr_var starts with a
     207     0 value.  */
     208  
     209  int
     210  md_estimate_size_before_relax (fragS * fragP, segT segment)
     211  {
     212    /* The only thing we have to handle here are symbols outside of the
     213       current segment.  They may be undefined or in a different segment in
     214       which case linker scripts may place them anywhere.
     215       However, we can't finish the fragment here and emit the reloc as insn
     216       alignment requirements may move the insn about.  */
     217  
     218    if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
     219      {
     220        /* The symbol is undefined in this segment.
     221  	 Change the relaxation subtype to the max allowable and leave
     222  	 all further handling to md_convert_frag.  */
     223        fragP->fr_subtype = 2;
     224  
     225        {
     226  	const CGEN_INSN * insn;
     227  	int               i;
     228  
     229  	/* Update the recorded insn.
     230  	   Fortunately we don't have to look very far.
     231  	   FIXME: Change this to record in the instruction the next higher
     232  	   relaxable insn to use.  */
     233  	for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++)
     234  	  {
     235  	    if ((strcmp (CGEN_INSN_MNEMONIC (insn),
     236  			 CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
     237  		 == 0)
     238  		&& CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED))
     239  	      break;
     240  	  }
     241  	if (i == 4)
     242  	  abort ();
     243  
     244  	fragP->fr_cgen.insn = insn;
     245  	return 2;
     246        }
     247      }
     248  
     249    /* Return the size of the variable part of the frag.  */
     250    return md_relax_table[fragP->fr_subtype].rlx_length;
     251  }
     252  
     253  /* *fragP has been relaxed to its final size, and now needs to have
     254     the bytes inside it modified to conform to the new size.
     255  
     256     Called after relaxation is finished.
     257     fragP->fr_type == rs_machine_dependent.
     258     fragP->fr_subtype is the subtype of what the address relaxed to.  */
     259  
     260  void
     261  md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
     262  		 segT sec ATTRIBUTE_UNUSED,
     263  		 fragS *fragP ATTRIBUTE_UNUSED)
     264  {
     265  }
     266  
     267  /* Functions concerning relocs.  */
     268  
     269  /* The location from which a PC relative jump should be calculated,
     270     given a PC relative reloc.  */
     271  
     272  long
     273  md_pcrel_from_section (fixS * fixP, segT sec)
     274  {
     275    if (fixP->fx_addsy != (symbolS *) NULL
     276        && (! S_IS_DEFINED (fixP->fx_addsy)
     277  	  || S_GET_SEGMENT (fixP->fx_addsy) != sec))
     278      /* The symbol is undefined (or is defined but not in this section).
     279         Let the linker figure it out.  */
     280      return 0;
     281  
     282    return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
     283  }
     284  
     285  /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
     286     Returns BFD_RELOC_NONE if no reloc type can be found.
     287     *FIXP may be modified if desired.  */
     288  
     289  bfd_reloc_code_real_type
     290  md_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED,
     291  		      const CGEN_OPERAND *operand,
     292  		      fixS *fixP)
     293  {
     294    switch (operand->type)
     295      {
     296      case FR30_OPERAND_LABEL9:  fixP->fx_pcrel = 1; return BFD_RELOC_FR30_9_PCREL;
     297      case FR30_OPERAND_LABEL12: fixP->fx_pcrel = 1; return BFD_RELOC_FR30_12_PCREL;
     298      case FR30_OPERAND_DISP10:  return BFD_RELOC_FR30_10_IN_8;
     299      case FR30_OPERAND_DISP9:   return BFD_RELOC_FR30_9_IN_8;
     300      case FR30_OPERAND_DISP8:   return BFD_RELOC_FR30_8_IN_8;
     301      case FR30_OPERAND_UDISP6:  return BFD_RELOC_FR30_6_IN_4;
     302      case FR30_OPERAND_I8:      return BFD_RELOC_8;
     303      case FR30_OPERAND_I32:     return BFD_RELOC_FR30_48;
     304      case FR30_OPERAND_I20:     return BFD_RELOC_FR30_20;
     305      default : /* Avoid -Wall warning.  */
     306        break;
     307      }
     308  
     309    return BFD_RELOC_NONE;
     310  }
     311  
     312  /* Write a value out to the object file, using the appropriate endianness.  */
     313  
     314  void
     315  md_number_to_chars (char * buf, valueT val, int n)
     316  {
     317    number_to_chars_bigendian (buf, val, n);
     318  }
     319  
     320  const char *
     321  md_atof (int type, char * litP, int * sizeP)
     322  {
     323    return ieee_md_atof (type, litP, sizeP, true);
     324  }
     325  
     326  /* Worker function for fr30_is_colon_insn().  */
     327  static int
     328  restore_colon (char *next_i_l_p, char *nul_char)
     329  {
     330    /* Restore the colon, and advance input_line_pointer to
     331       the end of the new symbol.  */
     332    *input_line_pointer = *nul_char;
     333    input_line_pointer = next_i_l_p;
     334    *nul_char = *next_i_l_p;
     335    *next_i_l_p = 0;
     336    return 1;
     337  }
     338  
     339  /* Determines if the symbol starting at START and ending in
     340     a colon that was at the location pointed to by INPUT_LINE_POINTER
     341     (but which has now been replaced bu a NUL) is in fact an
     342     LDI:8, LDI:20, LDI:32, CALL:D. JMP:D, RET:D or Bcc:D instruction.
     343     If it is, then it restores the colon, advances INPUT_LINE_POINTER
     344     to the real end of the instruction/symbol, saves the char there to
     345     NUL_CHAR and pokes a NUL, and returns 1.  Otherwise it returns 0.  */
     346  int
     347  fr30_is_colon_insn (char *start, char *nul_char)
     348  {
     349    char * i_l_p = input_line_pointer;
     350  
     351    if (*nul_char == '"')
     352      ++i_l_p;
     353  
     354    /* Check to see if the symbol parsed so far is 'ldi'.  */
     355    if (   (start[0] != 'l' && start[0] != 'L')
     356        || (start[1] != 'd' && start[1] != 'D')
     357        || (start[2] != 'i' && start[2] != 'I')
     358        || start[3] != 0)
     359      {
     360        /* Nope - check to see a 'd' follows the colon.  */
     361        if (   (i_l_p[1] == 'd' || i_l_p[1] == 'D')
     362  	  && (i_l_p[2] == ' ' || i_l_p[2] == '\t' || i_l_p[2] == '\n'))
     363  	{
     364  	  /* Yup - it might be delay slot instruction.  */
     365  	  int           i;
     366  	  static const char * delay_insns [] =
     367  	  {
     368  	    "call", "jmp", "ret", "bra", "bno",
     369  	    "beq",  "bne", "bc",  "bnc", "bn",
     370  	    "bp",   "bv",  "bnv", "blt", "bge",
     371  	    "ble",  "bgt", "bls", "bhi"
     372  	  };
     373  
     374  	  for (i = sizeof (delay_insns) / sizeof (delay_insns[0]); i--;)
     375  	    {
     376  	      const char * insn = delay_insns[i];
     377  	      int    len  = strlen (insn);
     378  
     379  	      if (start [len] != 0)
     380  		continue;
     381  
     382  	      while (len --)
     383  		if (TOLOWER (start [len]) != insn [len])
     384  		  break;
     385  
     386  	      if (len == -1)
     387  		return restore_colon (i_l_p + 1, nul_char);
     388  	    }
     389  	}
     390  
     391        /* Nope - it is a normal label.  */
     392        return 0;
     393      }
     394  
     395    /* Check to see if the text following the colon is '8'.  */
     396    if (i_l_p[1] == '8' && (i_l_p[2] == ' ' || i_l_p[2] == '\t'))
     397      return restore_colon (i_l_p + 2, nul_char);
     398  
     399    /* Check to see if the text following the colon is '20'.  */
     400    else if (i_l_p[1] == '2' && i_l_p[2] =='0'
     401  	   && (i_l_p[3] == ' ' || i_l_p[3] == '\t'))
     402      return restore_colon (i_l_p + 3, nul_char);
     403  
     404    /* Check to see if the text following the colon is '32'.  */
     405    else if (i_l_p[1] == '3' && i_l_p[2] =='2'
     406  	   && (i_l_p[3] == ' ' || i_l_p[3] == '\t'))
     407      return restore_colon (i_l_p + 3, nul_char);
     408  
     409    return 0;
     410  }
     411  
     412  bool
     413  fr30_fix_adjustable (fixS * fixP)
     414  {
     415    /* We need the symbol name for the VTABLE entries.  */
     416    if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
     417        || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     418      return 0;
     419  
     420    return 1;
     421  }