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