(root)/
binutils-2.41/
gas/
config/
tc-mt.c
       1  /* tc-mt.c -- Assembler for the Morpho Technologies mt .
       2     Copyright (C) 2005-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 this program; if not, write to the Free Software
      18     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
      19     MA 02110-1301, USA.  */
      20  
      21  #include "as.h"
      22  #include "dwarf2dbg.h"
      23  #include "subsegs.h"
      24  #include "symcat.h"
      25  #include "opcodes/mt-desc.h"
      26  #include "opcodes/mt-opc.h"
      27  #include "cgen.h"
      28  #include "elf/common.h"
      29  #include "elf/mt.h"
      30  
      31  /* Structure to hold all of the different components
      32     describing an individual instruction.  */
      33  typedef struct
      34  {
      35    const CGEN_INSN *	insn;
      36    const CGEN_INSN *	orig_insn;
      37    CGEN_FIELDS		fields;
      38  #if CGEN_INT_INSN_P
      39    CGEN_INSN_INT         buffer [1];
      40  #define INSN_VALUE(buf) (*(buf))
      41  #else
      42    unsigned char         buffer [CGEN_MAX_INSN_SIZE];
      43  #define INSN_VALUE(buf) (buf)
      44  #endif
      45    char *		addr;
      46    fragS *		frag;
      47    int                   num_fixups;
      48    fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
      49    int                   indices [MAX_OPERAND_INSTANCES];
      50  }
      51  mt_insn;
      52  
      53  
      54  const char comment_chars[]        = ";";
      55  const char line_comment_chars[]   = "#";
      56  const char line_separator_chars[] = "";
      57  const char EXP_CHARS[]            = "eE";
      58  const char FLT_CHARS[]            = "dD";
      59  
      60  /* The target specific pseudo-ops which we support.  */
      61  const pseudo_typeS md_pseudo_table[] =
      62  {
      63      { "word",   cons,                   4 },
      64      { NULL, 	NULL,			0 }
      65  };
      66  
      67  
      68  
      69  static int no_scheduling_restrictions = 0;
      70  
      71  struct option md_longopts[] =
      72  {
      73  #define OPTION_NO_SCHED_REST	(OPTION_MD_BASE)
      74    { "nosched",	   no_argument, NULL, OPTION_NO_SCHED_REST },
      75  #define OPTION_MARCH		(OPTION_MD_BASE + 1)
      76    { "march", required_argument, NULL, OPTION_MARCH},
      77    { NULL,	   no_argument, NULL, 0 },
      78  };
      79  size_t md_longopts_size = sizeof (md_longopts);
      80  
      81  const char * md_shortopts = "";
      82  
      83  /* Mach selected from command line.  */
      84  static int mt_mach = bfd_mach_ms1;
      85  static unsigned mt_mach_bitmask = 1 << MACH_MS1;
      86  
      87  /* Flags to set in the elf header */
      88  static flagword mt_flags = EF_MT_CPU_MRISC;
      89  
      90  /* The architecture to use.  */
      91  enum mt_architectures
      92    {
      93      ms1_64_001,
      94      ms1_16_002,
      95      ms1_16_003,
      96      ms2
      97    };
      98  
      99  /* MT architecture we are using for this output file.  */
     100  static enum mt_architectures mt_arch = ms1_16_002;
     101  
     102  int
     103  md_parse_option (int c ATTRIBUTE_UNUSED, const char * arg)
     104  {
     105    switch (c)
     106      {
     107      case OPTION_MARCH:
     108        if (strcmp (arg, "ms1-64-001") == 0)
     109   	{
     110   	  mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC;
     111   	  mt_mach = bfd_mach_ms1;
     112   	  mt_mach_bitmask = 1 << MACH_MS1;
     113   	  mt_arch = ms1_64_001;
     114   	}
     115        else if (strcmp (arg, "ms1-16-002") == 0)
     116   	{
     117   	  mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC;
     118   	  mt_mach = bfd_mach_ms1;
     119   	  mt_mach_bitmask = 1 << MACH_MS1;
     120   	  mt_arch = ms1_16_002;
     121   	}
     122        else if (strcmp (arg, "ms1-16-003") == 0)
     123   	{
     124   	  mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC2;
     125   	  mt_mach = bfd_mach_mrisc2;
     126   	  mt_mach_bitmask = 1 << MACH_MS1_003;
     127   	  mt_arch = ms1_16_003;
     128   	}
     129        else if (strcmp (arg, "ms2") == 0)
     130   	{
     131   	  mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MS2;
     132   	  mt_mach = bfd_mach_mrisc2;
     133   	  mt_mach_bitmask = 1 << MACH_MS2;
     134   	  mt_arch = ms2;
     135   	}
     136        break;
     137      case OPTION_NO_SCHED_REST:
     138        no_scheduling_restrictions = 1;
     139        break;
     140      default:
     141        return 0;
     142      }
     143  
     144    return 1;
     145  }
     146  
     147  
     148  void
     149  md_show_usage (FILE * stream)
     150  {
     151    fprintf (stream, _("MT specific command line options:\n"));
     152    fprintf (stream, _("  -march=ms1-64-001         allow ms1-64-001 instructions\n"));
     153    fprintf (stream, _("  -march=ms1-16-002         allow ms1-16-002 instructions (default)\n"));
     154    fprintf (stream, _("  -march=ms1-16-003         allow ms1-16-003 instructions\n"));
     155    fprintf (stream, _("  -march=ms2                allow ms2 instructions \n"));
     156    fprintf (stream, _("  -nosched                  disable scheduling restrictions\n"));
     157  }
     158  
     159  
     160  void
     161  md_begin (void)
     162  {
     163    /* Initialize the `cgen' interface.  */
     164  
     165    /* Set the machine number and endian.  */
     166    gas_cgen_cpu_desc = mt_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, mt_mach_bitmask,
     167  					CGEN_CPU_OPEN_ENDIAN,
     168  					CGEN_ENDIAN_BIG,
     169  					CGEN_CPU_OPEN_END);
     170    mt_cgen_init_asm (gas_cgen_cpu_desc);
     171  
     172    /* This is a callback from cgen to gas to parse operands.  */
     173    cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
     174  
     175    /* Set the ELF flags if desired. */
     176    if (mt_flags)
     177      bfd_set_private_flags (stdoutput, mt_flags);
     178  
     179    /* Set the machine type.  */
     180    bfd_default_set_arch_mach (stdoutput, bfd_arch_mt, mt_mach);
     181  
     182    literal_prefix_dollar_hex = true;
     183  }
     184  
     185  void
     186  md_assemble (char * str)
     187  {
     188    static long delayed_load_register = 0;
     189    static long prev_delayed_load_register = 0;
     190    static int last_insn_had_delay_slot = 0;
     191    static int last_insn_in_noncond_delay_slot = 0;
     192    static int last_insn_has_load_delay = 0;
     193    static int last_insn_was_memory_access = 0;
     194    static int last_insn_was_io_insn = 0;
     195    static int last_insn_was_arithmetic_or_logic = 0;
     196    static int last_insn_was_branch_insn = 0;
     197    static int last_insn_was_conditional_branch_insn = 0;
     198  
     199    mt_insn insn;
     200    char * errmsg;
     201  
     202    /* Initialize GAS's cgen interface for a new instruction.  */
     203    gas_cgen_init_parse ();
     204  
     205    insn.insn = mt_cgen_assemble_insn
     206        (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
     207  
     208    if (!insn.insn)
     209      {
     210        as_bad ("%s", errmsg);
     211        return;
     212      }
     213  
     214    /* Doesn't really matter what we pass for RELAX_P here.  */
     215    gas_cgen_finish_insn (insn.insn, insn.buffer,
     216  			CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
     217  
     218  
     219    /* Handle Scheduling Restrictions.  */
     220    if (!no_scheduling_restrictions)
     221      {
     222        /* Detect consecutive Memory Accesses.  */
     223        if (last_insn_was_memory_access
     224  	  && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS)
     225  	  && mt_mach == ms1_64_001)
     226  	as_warn (_("instruction %s may not follow another memory access instruction."),
     227  		 CGEN_INSN_NAME (insn.insn));
     228  
     229        /* Detect consecutive I/O Instructions.  */
     230        else if (last_insn_was_io_insn
     231  	       && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN))
     232  	as_warn (_("instruction %s may not follow another I/O instruction."),
     233  		 CGEN_INSN_NAME (insn.insn));
     234  
     235        /* Detect consecutive branch instructions.  */
     236        else if (last_insn_was_branch_insn
     237  	       && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN))
     238  	as_warn (_("%s may not occupy the delay slot of another branch insn."),
     239  		 CGEN_INSN_NAME (insn.insn));
     240  
     241        /* Detect data dependencies on delayed loads: memory and input insns.  */
     242        if (last_insn_has_load_delay && delayed_load_register)
     243  	{
     244  	  if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
     245  	      && insn.fields.f_sr1 == delayed_load_register)
     246  	    as_warn (_("operand references R%ld of previous load."),
     247  		     insn.fields.f_sr1);
     248  
     249  	  if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
     250  	      && insn.fields.f_sr2 == delayed_load_register)
     251  	    as_warn (_("operand references R%ld of previous load."),
     252  		     insn.fields.f_sr2);
     253  	}
     254  
     255        /* Detect JAL/RETI hazard */
     256        if (mt_mach == ms2
     257  	  && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_JAL_HAZARD))
     258  	{
     259  	  if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
     260  	       && insn.fields.f_sr1 == delayed_load_register)
     261  	      || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
     262  		  && insn.fields.f_sr2 == delayed_load_register))
     263  	    as_warn (_("operand references R%ld of previous instruction."),
     264  		     delayed_load_register);
     265  	  else if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
     266  		    && insn.fields.f_sr1 == prev_delayed_load_register)
     267  		   || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
     268  		       && insn.fields.f_sr2 == prev_delayed_load_register))
     269  	    as_warn (_("operand references R%ld of instruction before previous."),
     270  		     prev_delayed_load_register);
     271  	}
     272  
     273        /* Detect data dependency between conditional branch instruction
     274           and an immediately preceding arithmetic or logical instruction.  */
     275        if (last_insn_was_arithmetic_or_logic
     276  	  && !last_insn_in_noncond_delay_slot
     277  	  && (delayed_load_register != 0)
     278  	  && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)
     279  	  && mt_arch == ms1_64_001)
     280  	{
     281  	  if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
     282  	      && insn.fields.f_sr1 == delayed_load_register)
     283  	    as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
     284  		     insn.fields.f_sr1);
     285  
     286  	  if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
     287  	      && insn.fields.f_sr2 == delayed_load_register)
     288  	    as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
     289  		     insn.fields.f_sr2);
     290  	}
     291      }
     292  
     293    /* Keep track of details of this insn for processing next insn.  */
     294    last_insn_in_noncond_delay_slot = last_insn_was_branch_insn
     295      && !last_insn_was_conditional_branch_insn;
     296  
     297    last_insn_had_delay_slot =
     298      CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
     299    (void) last_insn_had_delay_slot;
     300  
     301    last_insn_has_load_delay =
     302      CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_LOAD_DELAY);
     303  
     304    last_insn_was_memory_access =
     305      CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS);
     306  
     307    last_insn_was_io_insn =
     308      CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN);
     309  
     310    last_insn_was_arithmetic_or_logic =
     311      CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_AL_INSN);
     312  
     313    last_insn_was_branch_insn =
     314      CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN);
     315  
     316    last_insn_was_conditional_branch_insn =
     317    CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)
     318      && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2);
     319  
     320    prev_delayed_load_register = delayed_load_register;
     321  
     322    if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDR))
     323       delayed_load_register = insn.fields.f_dr;
     324    else if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDRRR))
     325       delayed_load_register = insn.fields.f_drrr;
     326    else  /* Insns has no destination register.  */
     327       delayed_load_register = 0;
     328  
     329    /* Generate dwarf2 line numbers.  */
     330    dwarf2_emit_insn (4);
     331  }
     332  
     333  valueT
     334  md_section_align (segT segment, valueT size)
     335  {
     336    int align = bfd_section_alignment (segment);
     337  
     338    return ((size + (1 << align) - 1) & -(1 << align));
     339  }
     340  
     341  symbolS *
     342  md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
     343  {
     344      return NULL;
     345  }
     346  
     347  int
     348  md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
     349  			       segT    segment ATTRIBUTE_UNUSED)
     350  {
     351    as_fatal (_("md_estimate_size_before_relax\n"));
     352    return 1;
     353  }
     354  
     355  /* *fragP has been relaxed to its final size, and now needs to have
     356     the bytes inside it modified to conform to the new size.
     357  
     358     Called after relaxation is finished.
     359     fragP->fr_type == rs_machine_dependent.
     360     fragP->fr_subtype is the subtype of what the address relaxed to.  */
     361  
     362  void
     363  md_convert_frag (bfd   * abfd  ATTRIBUTE_UNUSED,
     364  		 segT    sec   ATTRIBUTE_UNUSED,
     365  		 fragS * fragP ATTRIBUTE_UNUSED)
     366  {
     367  }
     368  
     369  
     370  /* Functions concerning relocs.  */
     371  
     372  long
     373  md_pcrel_from_section (fixS *fixP, segT sec)
     374  {
     375    if (fixP->fx_addsy != (symbolS *) NULL
     376        && (!S_IS_DEFINED (fixP->fx_addsy)
     377  	  || S_GET_SEGMENT (fixP->fx_addsy) != sec))
     378      /* The symbol is undefined (or is defined but not in this section).
     379         Let the linker figure it out.  */
     380      return 0;
     381  
     382    /* Return the address of the opcode - cgen adjusts for opcode size
     383       itself, to be consistent with the disassembler, which must do
     384       so.  */
     385    return fixP->fx_where + fixP->fx_frag->fr_address;
     386  }
     387  
     388  
     389  /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
     390     Returns BFD_RELOC_NONE if no reloc type can be found.
     391     *FIXP may be modified if desired.  */
     392  
     393  bfd_reloc_code_real_type
     394  md_cgen_lookup_reloc (const CGEN_INSN *    insn     ATTRIBUTE_UNUSED,
     395  		      const CGEN_OPERAND * operand,
     396  		      fixS *               fixP     ATTRIBUTE_UNUSED)
     397  {
     398    bfd_reloc_code_real_type result;
     399  
     400    result = BFD_RELOC_NONE;
     401  
     402    switch (operand->type)
     403      {
     404      case MT_OPERAND_IMM16O:
     405        result = BFD_RELOC_16_PCREL;
     406        fixP->fx_pcrel = 1;
     407        /* fixP->fx_no_overflow = 1; */
     408        break;
     409      case MT_OPERAND_IMM16:
     410      case MT_OPERAND_IMM16Z:
     411        /* These may have been processed at parse time.  */
     412        if (fixP->fx_cgen.opinfo != 0)
     413          result = fixP->fx_cgen.opinfo;
     414        fixP->fx_no_overflow = 1;
     415        break;
     416      case MT_OPERAND_LOOPSIZE:
     417        result = BFD_RELOC_MT_PCINSN8;
     418        fixP->fx_pcrel = 1;
     419        /* Adjust for the delay slot, which is not part of the loop  */
     420        fixP->fx_offset -= 8;
     421        break;
     422      default:
     423        result = BFD_RELOC_NONE;
     424        break;
     425      }
     426  
     427    return result;
     428  }
     429  
     430  /* Write a value out to the object file, using the appropriate endianness.  */
     431  
     432  void
     433  md_number_to_chars (char * buf, valueT val, int n)
     434  {
     435    number_to_chars_bigendian (buf, val, n);
     436  }
     437  
     438  const char *
     439  md_atof (int type, char * litP, int * sizeP)
     440  {
     441    return ieee_md_atof (type, litP, sizeP, false);
     442  }
     443  
     444  /* See whether we need to force a relocation into the output file.  */
     445  
     446  int
     447  mt_force_relocation (fixS * fixp ATTRIBUTE_UNUSED)
     448  {
     449    return 0;
     450  }
     451  
     452  void
     453  mt_apply_fix (fixS *fixP, valueT *valueP, segT seg)
     454  {
     455    if ((fixP->fx_pcrel != 0) && (fixP->fx_r_type == BFD_RELOC_32))
     456      fixP->fx_r_type = BFD_RELOC_32_PCREL;
     457  
     458    gas_cgen_md_apply_fix (fixP, valueP, seg);
     459  }
     460  
     461  bool
     462  mt_fix_adjustable (fixS * fixP)
     463  {
     464    if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
     465      {
     466        const CGEN_INSN *insn = NULL;
     467        int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
     468        const CGEN_OPERAND *operand;
     469  
     470        operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
     471        md_cgen_lookup_reloc (insn, operand, fixP);
     472      }
     473  
     474    if (fixP->fx_addsy == NULL)
     475      return true;
     476  
     477    /* Prevent all adjustments to global symbols.  */
     478    if (S_IS_EXTERNAL (fixP->fx_addsy))
     479      return false;
     480  
     481    if (S_IS_WEAK (fixP->fx_addsy))
     482      return false;
     483  
     484    return true;
     485  }