Home | History | Annotate | Download | only in config
      1 /* tc-mt.c -- Assembler for the Morpho Technologies mt .
      2    Copyright (C) 2005-2014 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, 59 Temple Place - Suite 330,
     19    Boston, MA 02111-1307, 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 #include "libbfd.h"
     31 
     32 /* Structure to hold all of the different components
     33    describing an individual instruction.  */
     34 typedef struct
     35 {
     36   const CGEN_INSN *	insn;
     37   const CGEN_INSN *	orig_insn;
     38   CGEN_FIELDS		fields;
     39 #if CGEN_INT_INSN_P
     40   CGEN_INSN_INT         buffer [1];
     41 #define INSN_VALUE(buf) (*(buf))
     42 #else
     43   unsigned char         buffer [CGEN_MAX_INSN_SIZE];
     44 #define INSN_VALUE(buf) (buf)
     45 #endif
     46   char *		addr;
     47   fragS *		frag;
     48   int                   num_fixups;
     49   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
     50   int                   indices [MAX_OPERAND_INSTANCES];
     51 }
     52 mt_insn;
     53 
     54 
     55 const char comment_chars[]        = ";";
     56 const char line_comment_chars[]   = "#";
     57 const char line_separator_chars[] = "";
     58 const char EXP_CHARS[]            = "eE";
     59 const char FLT_CHARS[]            = "dD";
     60 
     61 /* The target specific pseudo-ops which we support.  */
     62 const pseudo_typeS md_pseudo_table[] =
     63 {
     64     { "word",   cons,                   4 },
     65     { NULL, 	NULL,			0 }
     66 };
     67 
     68 
     69 
     71 static int no_scheduling_restrictions = 0;
     72 
     73 struct option md_longopts[] =
     74 {
     75 #define OPTION_NO_SCHED_REST	(OPTION_MD_BASE)
     76   { "nosched",	   no_argument, NULL, OPTION_NO_SCHED_REST },
     77 #define OPTION_MARCH		(OPTION_MD_BASE + 1)
     78   { "march", required_argument, NULL, OPTION_MARCH},
     79   { NULL,	   no_argument, NULL, 0 },
     80 };
     81 size_t md_longopts_size = sizeof (md_longopts);
     82 
     83 const char * md_shortopts = "";
     84 
     85 /* Mach selected from command line.  */
     86 static int mt_mach = bfd_mach_ms1;
     87 static unsigned mt_mach_bitmask = 1 << MACH_MS1;
     88 
     89 /* Flags to set in the elf header */
     90 static flagword mt_flags = EF_MT_CPU_MRISC;
     91 
     92 /* The architecture to use.  */
     93 enum mt_architectures
     94   {
     95     ms1_64_001,
     96     ms1_16_002,
     97     ms1_16_003,
     98     ms2
     99   };
    100 
    101 /* MT architecture we are using for this output file.  */
    102 static enum mt_architectures mt_arch = ms1_16_002;
    103 
    104 int
    105 md_parse_option (int c ATTRIBUTE_UNUSED, char * arg)
    106 {
    107   switch (c)
    108     {
    109     case OPTION_MARCH:
    110       if (strcmp (arg, "ms1-64-001") == 0)
    111  	{
    112  	  mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC;
    113  	  mt_mach = bfd_mach_ms1;
    114  	  mt_mach_bitmask = 1 << MACH_MS1;
    115  	  mt_arch = ms1_64_001;
    116  	}
    117       else if (strcmp (arg, "ms1-16-002") == 0)
    118  	{
    119  	  mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC;
    120  	  mt_mach = bfd_mach_ms1;
    121  	  mt_mach_bitmask = 1 << MACH_MS1;
    122  	  mt_arch = ms1_16_002;
    123  	}
    124       else if (strcmp (arg, "ms1-16-003") == 0)
    125  	{
    126  	  mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC2;
    127  	  mt_mach = bfd_mach_mrisc2;
    128  	  mt_mach_bitmask = 1 << MACH_MS1_003;
    129  	  mt_arch = ms1_16_003;
    130  	}
    131       else if (strcmp (arg, "ms2") == 0)
    132  	{
    133  	  mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MS2;
    134  	  mt_mach = bfd_mach_mrisc2;
    135  	  mt_mach_bitmask = 1 << MACH_MS2;
    136  	  mt_arch = ms2;
    137  	}
    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 
    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_get_section_alignment (stdoutput, 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
    349 md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
    350 			       segT    segment ATTRIBUTE_UNUSED)
    351 {
    352   as_fatal (_("md_estimate_size_before_relax\n"));
    353   return 1;
    354 }
    355 
    356 /* *fragP has been relaxed to its final size, and now needs to have
    357    the bytes inside it modified to conform to the new size.
    358 
    359    Called after relaxation is finished.
    360    fragP->fr_type == rs_machine_dependent.
    361    fragP->fr_subtype is the subtype of what the address relaxed to.  */
    362 
    363 void
    364 md_convert_frag (bfd   * abfd  ATTRIBUTE_UNUSED,
    365 		 segT    sec   ATTRIBUTE_UNUSED,
    366 		 fragS * fragP ATTRIBUTE_UNUSED)
    367 {
    368 }
    369 
    370 
    371 /* Functions concerning relocs.  */
    373 
    374 long
    375 md_pcrel_from_section (fixS *fixP, segT sec)
    376 {
    377   if (fixP->fx_addsy != (symbolS *) NULL
    378       && (!S_IS_DEFINED (fixP->fx_addsy)
    379 	  || S_GET_SEGMENT (fixP->fx_addsy) != sec))
    380     /* The symbol is undefined (or is defined but not in this section).
    381        Let the linker figure it out.  */
    382     return 0;
    383 
    384   /* Return the address of the opcode - cgen adjusts for opcode size
    385      itself, to be consistent with the disassembler, which must do
    386      so.  */
    387   return fixP->fx_where + fixP->fx_frag->fr_address;
    388 }
    389 
    390 
    391 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
    392    Returns BFD_RELOC_NONE if no reloc type can be found.
    393    *FIXP may be modified if desired.  */
    394 
    395 bfd_reloc_code_real_type
    396 md_cgen_lookup_reloc (const CGEN_INSN *    insn     ATTRIBUTE_UNUSED,
    397 		      const CGEN_OPERAND * operand,
    398 		      fixS *               fixP     ATTRIBUTE_UNUSED)
    399 {
    400   bfd_reloc_code_real_type result;
    401 
    402   result = BFD_RELOC_NONE;
    403 
    404   switch (operand->type)
    405     {
    406     case MT_OPERAND_IMM16O:
    407       result = BFD_RELOC_16_PCREL;
    408       fixP->fx_pcrel = 1;
    409       /* fixP->fx_no_overflow = 1; */
    410       break;
    411     case MT_OPERAND_IMM16:
    412     case MT_OPERAND_IMM16Z:
    413       /* These may have been processed at parse time.  */
    414       if (fixP->fx_cgen.opinfo != 0)
    415         result = fixP->fx_cgen.opinfo;
    416       fixP->fx_no_overflow = 1;
    417       break;
    418     case MT_OPERAND_LOOPSIZE:
    419       result = BFD_RELOC_MT_PCINSN8;
    420       fixP->fx_pcrel = 1;
    421       /* Adjust for the delay slot, which is not part of the loop  */
    422       fixP->fx_offset -= 8;
    423       break;
    424     default:
    425       result = BFD_RELOC_NONE;
    426       break;
    427     }
    428 
    429   return result;
    430 }
    431 
    432 /* Write a value out to the object file, using the appropriate endianness.  */
    433 
    434 void
    435 md_number_to_chars (char * buf, valueT val, int n)
    436 {
    437   number_to_chars_bigendian (buf, val, n);
    438 }
    439 
    440 char *
    441 md_atof (int type, char * litP, int * sizeP)
    442 {
    443   return ieee_md_atof (type, litP, sizeP, FALSE);
    444 }
    445 
    446 /* See whether we need to force a relocation into the output file.  */
    447 
    448 int
    449 mt_force_relocation (fixS * fixp ATTRIBUTE_UNUSED)
    450 {
    451   return 0;
    452 }
    453 
    454 void
    455 mt_apply_fix (fixS *fixP, valueT *valueP, segT seg)
    456 {
    457   if ((fixP->fx_pcrel != 0) && (fixP->fx_r_type == BFD_RELOC_32))
    458     fixP->fx_r_type = BFD_RELOC_32_PCREL;
    459 
    460   gas_cgen_md_apply_fix (fixP, valueP, seg);
    461 }
    462 
    463 bfd_boolean
    464 mt_fix_adjustable (fixS * fixP)
    465 {
    466   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
    467     {
    468       const CGEN_INSN *insn = NULL;
    469       int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
    470       const CGEN_OPERAND *operand;
    471 
    472       operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
    473       md_cgen_lookup_reloc (insn, operand, fixP);
    474     }
    475 
    476   if (fixP->fx_addsy == NULL)
    477     return TRUE;
    478 
    479   /* Prevent all adjustments to global symbols.  */
    480   if (S_IS_EXTERNAL (fixP->fx_addsy))
    481     return FALSE;
    482 
    483   if (S_IS_WEAK (fixP->fx_addsy))
    484     return FALSE;
    485 
    486   return 1;
    487 }
    488