Home | History | Annotate | Line # | Download | only in config
tc-mt.c revision 1.1
      1 /* tc-mt.c -- Assembler for the Morpho Technologies mt .
      2    Copyright (C) 2005, 2006, 2007 Free Software Foundation.
      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 instrutcion."),
    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 instructcion 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 
    300   last_insn_has_load_delay =
    301     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_LOAD_DELAY);
    302 
    303   last_insn_was_memory_access =
    304     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS);
    305 
    306   last_insn_was_io_insn =
    307     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN);
    308 
    309   last_insn_was_arithmetic_or_logic =
    310     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_AL_INSN);
    311 
    312   last_insn_was_branch_insn =
    313     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN);
    314 
    315   last_insn_was_conditional_branch_insn =
    316   CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)
    317     && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2);
    318 
    319   prev_delayed_load_register = delayed_load_register;
    320 
    321   if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDR))
    322      delayed_load_register = insn.fields.f_dr;
    323   else if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDRRR))
    324      delayed_load_register = insn.fields.f_drrr;
    325   else  /* Insns has no destination register.  */
    326      delayed_load_register = 0;
    327 
    328   /* Generate dwarf2 line numbers.  */
    329   dwarf2_emit_insn (4);
    330 }
    331 
    332 valueT
    333 md_section_align (segT segment, valueT size)
    334 {
    335   int align = bfd_get_section_alignment (stdoutput, segment);
    336 
    337   return ((size + (1 << align) - 1) & (-1 << align));
    338 }
    339 
    340 symbolS *
    341 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
    342 {
    343     return NULL;
    344 }
    345 
    346 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.  */
    372 
    373 long
    374 md_pcrel_from_section (fixS *fixP, segT sec)
    375 {
    376   if (fixP->fx_addsy != (symbolS *) NULL
    377       && (!S_IS_DEFINED (fixP->fx_addsy)
    378 	  || S_GET_SEGMENT (fixP->fx_addsy) != sec))
    379     /* The symbol is undefined (or is defined but not in this section).
    380        Let the linker figure it out.  */
    381     return 0;
    382 
    383   /* Return the address of the opcode - cgen adjusts for opcode size
    384      itself, to be consistent with the disassembler, which must do
    385      so.  */
    386   return fixP->fx_where + fixP->fx_frag->fr_address;
    387 }
    388 
    389 
    390 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
    391    Returns BFD_RELOC_NONE if no reloc type can be found.
    392    *FIXP may be modified if desired.  */
    393 
    394 bfd_reloc_code_real_type
    395 md_cgen_lookup_reloc (const CGEN_INSN *    insn     ATTRIBUTE_UNUSED,
    396 		      const CGEN_OPERAND * operand,
    397 		      fixS *               fixP     ATTRIBUTE_UNUSED)
    398 {
    399   bfd_reloc_code_real_type result;
    400 
    401   result = BFD_RELOC_NONE;
    402 
    403   switch (operand->type)
    404     {
    405     case MT_OPERAND_IMM16O:
    406       result = BFD_RELOC_16_PCREL;
    407       fixP->fx_pcrel = 1;
    408       /* fixP->fx_no_overflow = 1; */
    409       break;
    410     case MT_OPERAND_IMM16:
    411     case MT_OPERAND_IMM16Z:
    412       /* These may have been processed at parse time.  */
    413       if (fixP->fx_cgen.opinfo != 0)
    414         result = fixP->fx_cgen.opinfo;
    415       fixP->fx_no_overflow = 1;
    416       break;
    417     case MT_OPERAND_LOOPSIZE:
    418       result = BFD_RELOC_MT_PCINSN8;
    419       fixP->fx_pcrel = 1;
    420       /* Adjust for the delay slot, which is not part of the loop  */
    421       fixP->fx_offset -= 8;
    422       break;
    423     default:
    424       result = BFD_RELOC_NONE;
    425       break;
    426     }
    427 
    428   return result;
    429 }
    430 
    431 /* Write a value out to the object file, using the appropriate endianness.  */
    432 
    433 void
    434 md_number_to_chars (char * buf, valueT val, int n)
    435 {
    436   number_to_chars_bigendian (buf, val, n);
    437 }
    438 
    439 char *
    440 md_atof (int type, char * litP, int * sizeP)
    441 {
    442   return ieee_md_atof (type, litP, sizeP, FALSE);
    443 }
    444 
    445 /* See whether we need to force a relocation into the output file.  */
    446 
    447 int
    448 mt_force_relocation (fixS * fixp ATTRIBUTE_UNUSED)
    449 {
    450   return 0;
    451 }
    452 
    453 void
    454 mt_apply_fix (fixS *fixP, valueT *valueP, segT seg)
    455 {
    456   if ((fixP->fx_pcrel != 0) && (fixP->fx_r_type == BFD_RELOC_32))
    457     fixP->fx_r_type = BFD_RELOC_32_PCREL;
    458 
    459   gas_cgen_md_apply_fix (fixP, valueP, seg);
    460 }
    461 
    462 bfd_boolean
    463 mt_fix_adjustable (fixS * fixP)
    464 {
    465   bfd_reloc_code_real_type reloc_type;
    466 
    467   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
    468     {
    469       const CGEN_INSN *insn = NULL;
    470       int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
    471       const CGEN_OPERAND *operand;
    472 
    473       operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
    474       reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
    475     }
    476   else
    477     reloc_type = fixP->fx_r_type;
    478 
    479   if (fixP->fx_addsy == NULL)
    480     return TRUE;
    481 
    482   /* Prevent all adjustments to global symbols.  */
    483   if (S_IS_EXTERNAL (fixP->fx_addsy))
    484     return FALSE;
    485 
    486   if (S_IS_WEAK (fixP->fx_addsy))
    487     return FALSE;
    488 
    489   return 1;
    490 }
    491