Back to index

cell-binutils  2.17cvs20070401
tc-mt.c
Go to the documentation of this file.
00001 /* tc-mt.c -- Assembler for the Morpho Technologies mt .
00002    Copyright (C) 2005, 2006 Free Software Foundation.
00003 
00004    This file is part of GAS, the GNU Assembler.
00005 
00006    GAS is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2, or (at your option)
00009    any later version.
00010 
00011    GAS is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License
00017    along with GAS; see the file COPYING.  If not, write to
00018    the Free Software Foundation, 59 Temple Place - Suite 330,
00019    Boston, MA 02111-1307, USA.  */
00020 
00021 #include "as.h"
00022 #include "dwarf2dbg.h"
00023 #include "subsegs.h"     
00024 #include "symcat.h"
00025 #include "opcodes/mt-desc.h"
00026 #include "opcodes/mt-opc.h"
00027 #include "cgen.h"
00028 #include "elf/common.h"
00029 #include "elf/mt.h"
00030 #include "libbfd.h"
00031 
00032 /* Structure to hold all of the different components
00033    describing an individual instruction.  */
00034 typedef struct
00035 {
00036   const CGEN_INSN *  insn;
00037   const CGEN_INSN *  orig_insn;
00038   CGEN_FIELDS        fields;
00039 #if CGEN_INT_INSN_P
00040   CGEN_INSN_INT         buffer [1];
00041 #define INSN_VALUE(buf) (*(buf))
00042 #else
00043   unsigned char         buffer [CGEN_MAX_INSN_SIZE];
00044 #define INSN_VALUE(buf) (buf)
00045 #endif
00046   char *             addr;
00047   fragS *            frag;
00048   int                   num_fixups;
00049   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
00050   int                   indices [MAX_OPERAND_INSTANCES];
00051 }
00052 mt_insn;
00053 
00054 
00055 const char comment_chars[]        = ";";
00056 const char line_comment_chars[]   = "#";
00057 const char line_separator_chars[] = ""; 
00058 const char EXP_CHARS[]            = "eE";
00059 const char FLT_CHARS[]            = "dD";
00060 
00061 /* The target specific pseudo-ops which we support.  */
00062 const pseudo_typeS md_pseudo_table[] =
00063 {
00064     { "word",   cons,                   4 }, 
00065     { NULL,   NULL,                0 }
00066 };
00067 
00068 
00069 
00070 static int no_scheduling_restrictions = 0;
00071 
00072 struct option md_longopts[] = 
00073 {
00074 #define OPTION_NO_SCHED_REST       (OPTION_MD_BASE)
00075   { "nosched",          no_argument, NULL, OPTION_NO_SCHED_REST },
00076 #define OPTION_MARCH        (OPTION_MD_BASE + 1)
00077   { "march", required_argument, NULL, OPTION_MARCH},
00078   { NULL,        no_argument, NULL, 0 },
00079 };
00080 size_t md_longopts_size = sizeof (md_longopts);
00081 
00082 const char * md_shortopts = "";
00083 
00084 /* Mach selected from command line.  */
00085 static int mt_mach = bfd_mach_ms1;
00086 static unsigned mt_mach_bitmask = 1 << MACH_MS1;
00087 
00088 /* Flags to set in the elf header */
00089 static flagword mt_flags = EF_MT_CPU_MRISC;
00090 
00091 /* The architecture to use.  */
00092 enum mt_architectures
00093   {
00094     ms1_64_001,
00095     ms1_16_002,
00096     ms1_16_003,
00097     ms2
00098   };
00099 
00100 /* MT architecture we are using for this output file.  */
00101 static enum mt_architectures mt_arch = ms1_16_002;
00102 
00103 int
00104 md_parse_option (int c ATTRIBUTE_UNUSED, char * arg)
00105 {
00106   switch (c)
00107     {
00108     case OPTION_MARCH:
00109       if (strcmp (arg, "ms1-64-001") == 0)
00110        {
00111          mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC;
00112          mt_mach = bfd_mach_ms1;
00113          mt_mach_bitmask = 1 << MACH_MS1;
00114          mt_arch = ms1_64_001;
00115        }
00116       else if (strcmp (arg, "ms1-16-002") == 0)
00117        {
00118          mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC;
00119          mt_mach = bfd_mach_ms1;
00120          mt_mach_bitmask = 1 << MACH_MS1;
00121          mt_arch = ms1_16_002;
00122        }
00123       else if (strcmp (arg, "ms1-16-003") == 0)
00124        {
00125          mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC2;
00126          mt_mach = bfd_mach_mrisc2;
00127          mt_mach_bitmask = 1 << MACH_MS1_003;
00128          mt_arch = ms1_16_003;
00129        }
00130       else if (strcmp (arg, "ms2") == 0)
00131        {
00132          mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MS2;
00133          mt_mach = bfd_mach_mrisc2;
00134          mt_mach_bitmask = 1 << MACH_MS2;
00135          mt_arch = ms2;
00136        }
00137     case OPTION_NO_SCHED_REST:
00138       no_scheduling_restrictions = 1;
00139       break;
00140     default:
00141       return 0;
00142     }
00143 
00144   return 1;
00145 }
00146 
00147 
00148 void
00149 md_show_usage (FILE * stream)
00150 {
00151   fprintf (stream, _("MT specific command line options:\n"));
00152   fprintf (stream, _("  -march=ms1-64-001         allow ms1-64-001 instructions\n"));
00153   fprintf (stream, _("  -march=ms1-16-002         allow ms1-16-002 instructions (default)\n"));
00154   fprintf (stream, _("  -march=ms1-16-003         allow ms1-16-003 instructions\n"));
00155   fprintf (stream, _("  -march=ms2                allow ms2 instructions \n"));
00156   fprintf (stream, _("  -nosched                  disable scheduling restrictions\n"));
00157 }
00158 
00159 
00160 void
00161 md_begin (void)
00162 {
00163   /* Initialize the `cgen' interface.  */
00164   
00165   /* Set the machine number and endian.  */
00166   gas_cgen_cpu_desc = mt_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, mt_mach_bitmask,
00167                                    CGEN_CPU_OPEN_ENDIAN,
00168                                    CGEN_ENDIAN_BIG,
00169                                    CGEN_CPU_OPEN_END);
00170   mt_cgen_init_asm (gas_cgen_cpu_desc);
00171 
00172   /* This is a callback from cgen to gas to parse operands.  */
00173   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
00174 
00175   /* Set the ELF flags if desired. */
00176   if (mt_flags)
00177     bfd_set_private_flags (stdoutput, mt_flags);
00178 
00179   /* Set the machine type.  */
00180   bfd_default_set_arch_mach (stdoutput, bfd_arch_mt, mt_mach);
00181 }
00182 
00183 void
00184 md_assemble (char * str)
00185 {
00186   static long delayed_load_register = 0;
00187   static long prev_delayed_load_register = 0;
00188   static int last_insn_had_delay_slot = 0;
00189   static int last_insn_in_noncond_delay_slot = 0;
00190   static int last_insn_has_load_delay = 0;
00191   static int last_insn_was_memory_access = 0;
00192   static int last_insn_was_io_insn = 0;
00193   static int last_insn_was_arithmetic_or_logic = 0;
00194   static int last_insn_was_branch_insn = 0;
00195   static int last_insn_was_conditional_branch_insn = 0;
00196 
00197   mt_insn insn;
00198   char * errmsg;
00199 
00200   /* Initialize GAS's cgen interface for a new instruction.  */
00201   gas_cgen_init_parse ();
00202 
00203   insn.insn = mt_cgen_assemble_insn
00204       (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
00205 
00206   if (!insn.insn)
00207     {
00208       as_bad ("%s", errmsg);
00209       return;
00210     }
00211 
00212   /* Doesn't really matter what we pass for RELAX_P here.  */
00213   gas_cgen_finish_insn (insn.insn, insn.buffer,
00214                      CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
00215 
00216 
00217   /* Handle Scheduling Restrictions.  */
00218   if (!no_scheduling_restrictions)
00219     {
00220       /* Detect consecutive Memory Accesses.  */
00221       if (last_insn_was_memory_access
00222          && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS)
00223          && mt_mach == ms1_64_001)
00224        as_warn (_("instruction %s may not follow another memory access instruction."),
00225                CGEN_INSN_NAME (insn.insn));
00226 
00227       /* Detect consecutive I/O Instructions.  */
00228       else if (last_insn_was_io_insn
00229               && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN))
00230        as_warn (_("instruction %s may not follow another I/O instruction."),
00231                CGEN_INSN_NAME (insn.insn));
00232 
00233       /* Detect consecutive branch instructions.  */
00234       else if (last_insn_was_branch_insn
00235               && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN))
00236        as_warn (_("%s may not occupy the delay slot of another branch insn."),
00237                CGEN_INSN_NAME (insn.insn));
00238 
00239       /* Detect data dependencies on delayed loads: memory and input insns.  */
00240       if (last_insn_has_load_delay && delayed_load_register)
00241        {
00242          if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
00243              && insn.fields.f_sr1 == delayed_load_register)
00244            as_warn (_("operand references R%ld of previous load."),
00245                    insn.fields.f_sr1);
00246 
00247          if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
00248              && insn.fields.f_sr2 == delayed_load_register)
00249            as_warn (_("operand references R%ld of previous load."),
00250                    insn.fields.f_sr2);
00251        }
00252 
00253       /* Detect JAL/RETI hazard */
00254       if (mt_mach == ms2
00255          && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_JAL_HAZARD))
00256        {
00257          if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
00258               && insn.fields.f_sr1 == delayed_load_register)
00259              || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
00260                 && insn.fields.f_sr2 == delayed_load_register))
00261            as_warn (_("operand references R%ld of previous instrutcion."),
00262                    delayed_load_register);
00263          else if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
00264                   && insn.fields.f_sr1 == prev_delayed_load_register)
00265                  || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
00266                      && insn.fields.f_sr2 == prev_delayed_load_register))
00267            as_warn (_("operand references R%ld of instructcion before previous."),
00268                    prev_delayed_load_register);
00269        }
00270       
00271       /* Detect data dependency between conditional branch instruction
00272          and an immediately preceding arithmetic or logical instruction.  */
00273       if (last_insn_was_arithmetic_or_logic
00274          && !last_insn_in_noncond_delay_slot
00275          && (delayed_load_register != 0)
00276          && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)
00277          && mt_arch == ms1_64_001)
00278        {
00279          if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
00280              && insn.fields.f_sr1 == delayed_load_register)
00281            as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
00282                    insn.fields.f_sr1);
00283 
00284          if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
00285              && insn.fields.f_sr2 == delayed_load_register)
00286            as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
00287                    insn.fields.f_sr2);
00288        }
00289     }
00290 
00291   /* Keep track of details of this insn for processing next insn.  */
00292   last_insn_in_noncond_delay_slot = last_insn_was_branch_insn
00293     && !last_insn_was_conditional_branch_insn;
00294 
00295   last_insn_had_delay_slot =
00296     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
00297 
00298   last_insn_has_load_delay =
00299     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_LOAD_DELAY);
00300 
00301   last_insn_was_memory_access =
00302     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS);
00303 
00304   last_insn_was_io_insn =
00305     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN);
00306 
00307   last_insn_was_arithmetic_or_logic =
00308     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_AL_INSN);
00309 
00310   last_insn_was_branch_insn =
00311     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN);
00312   
00313   last_insn_was_conditional_branch_insn =
00314   CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)
00315     && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2);
00316   
00317   prev_delayed_load_register = delayed_load_register;
00318   
00319   if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDR))
00320      delayed_load_register = insn.fields.f_dr; 
00321   else if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDRRR))
00322      delayed_load_register = insn.fields.f_drrr; 
00323   else  /* Insns has no destination register.  */
00324      delayed_load_register = 0; 
00325 
00326   /* Generate dwarf2 line numbers.  */
00327   dwarf2_emit_insn (4); 
00328 }
00329 
00330 valueT
00331 md_section_align (segT segment, valueT size)
00332 {
00333   int align = bfd_get_section_alignment (stdoutput, segment);
00334 
00335   return ((size + (1 << align) - 1) & (-1 << align));
00336 }
00337 
00338 symbolS *
00339 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
00340 {
00341     return NULL;
00342 }
00343 
00344 int
00345 md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
00346                             segT    segment ATTRIBUTE_UNUSED)
00347 {
00348   as_fatal (_("md_estimate_size_before_relax\n"));
00349   return 1;
00350 } 
00351 
00352 /* *fragP has been relaxed to its final size, and now needs to have
00353    the bytes inside it modified to conform to the new size.
00354 
00355    Called after relaxation is finished.
00356    fragP->fr_type == rs_machine_dependent.
00357    fragP->fr_subtype is the subtype of what the address relaxed to.  */
00358 
00359 void
00360 md_convert_frag (bfd   * abfd  ATTRIBUTE_UNUSED,
00361                segT    sec   ATTRIBUTE_UNUSED,
00362                fragS * fragP ATTRIBUTE_UNUSED)
00363 {
00364 }
00365 
00366 
00367 /* Functions concerning relocs.  */
00368 
00369 long
00370 md_pcrel_from_section (fixS *fixP, segT sec)
00371 {
00372   if (fixP->fx_addsy != (symbolS *) NULL
00373       && (!S_IS_DEFINED (fixP->fx_addsy)
00374          || S_GET_SEGMENT (fixP->fx_addsy) != sec))
00375     /* The symbol is undefined (or is defined but not in this section).
00376        Let the linker figure it out.  */
00377     return 0;
00378 
00379   /* Return the address of the opcode - cgen adjusts for opcode size
00380      itself, to be consistent with the disassembler, which must do
00381      so.  */
00382   return fixP->fx_where + fixP->fx_frag->fr_address;
00383 }
00384 
00385 
00386 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
00387    Returns BFD_RELOC_NONE if no reloc type can be found.
00388    *FIXP may be modified if desired.  */
00389 
00390 bfd_reloc_code_real_type
00391 md_cgen_lookup_reloc (const CGEN_INSN *    insn     ATTRIBUTE_UNUSED,
00392                     const CGEN_OPERAND * operand,
00393                     fixS *               fixP     ATTRIBUTE_UNUSED)
00394 {
00395   bfd_reloc_code_real_type result;
00396 
00397   result = BFD_RELOC_NONE;
00398 
00399   switch (operand->type)
00400     {
00401     case MT_OPERAND_IMM16O:
00402       result = BFD_RELOC_16_PCREL;
00403       fixP->fx_pcrel = 1;
00404       /* fixP->fx_no_overflow = 1; */
00405       break;
00406     case MT_OPERAND_IMM16:
00407     case MT_OPERAND_IMM16Z:
00408       /* These may have been processed at parse time.  */
00409       if (fixP->fx_cgen.opinfo != 0)
00410         result = fixP->fx_cgen.opinfo;
00411       fixP->fx_no_overflow = 1;
00412       break;
00413     case MT_OPERAND_LOOPSIZE:
00414       result = BFD_RELOC_MT_PCINSN8;
00415       fixP->fx_pcrel = 1;
00416       /* Adjust for the delay slot, which is not part of the loop  */
00417       fixP->fx_offset -= 8;
00418       break;
00419     default:
00420       result = BFD_RELOC_NONE;
00421       break;
00422     }
00423 
00424   return result;
00425 }
00426 
00427 /* Write a value out to the object file, using the appropriate endianness.  */
00428 
00429 void
00430 md_number_to_chars (char * buf, valueT val, int n)
00431 {
00432   number_to_chars_bigendian (buf, val, n);
00433 }
00434 
00435 /* Turn a string in input_line_pointer into a floating point constant of type
00436    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
00437    emitted is stored in *sizeP .  An error message is returned, or NULL on OK.  */
00438 
00439 /* Equal to MAX_PRECISION in atof-ieee.c.  */
00440 #define MAX_LITTLENUMS 6
00441 
00442 char *
00443 md_atof (type, litP, sizeP)
00444      char   type;
00445      char * litP;
00446      int *  sizeP;
00447 {
00448   int              prec;
00449   LITTLENUM_TYPE   words [MAX_LITTLENUMS];
00450   LITTLENUM_TYPE * wordP;
00451   char *           t;
00452 
00453   switch (type)
00454     {
00455     case 'f':
00456     case 'F':
00457     case 's':
00458     case 'S':
00459       prec = 2;
00460       break;
00461 
00462     case 'd':
00463     case 'D':
00464     case 'r':
00465     case 'R':
00466       prec = 4;
00467       break;
00468 
00469    /* FIXME: Some targets allow other format chars for bigger sizes here.  */
00470 
00471     default:
00472       * sizeP = 0;
00473       return _("Bad call to md_atof()");
00474     }
00475 
00476   t = atof_ieee (input_line_pointer, type, words);
00477   if (t)
00478     input_line_pointer = t;
00479   * sizeP = prec * sizeof (LITTLENUM_TYPE);
00480 
00481   /* This loops outputs the LITTLENUMs in REVERSE order;
00482      in accord with the mt endianness.  */
00483   for (wordP = words; prec--;)
00484     {
00485       md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
00486       litP += sizeof (LITTLENUM_TYPE);
00487     }
00488      
00489   return 0;
00490 }
00491 
00492 /* See whether we need to force a relocation into the output file.  */
00493 
00494 int
00495 mt_force_relocation (fixS * fixp ATTRIBUTE_UNUSED)
00496 {
00497   return 0;
00498 }
00499 
00500 void
00501 mt_apply_fix (fixS *fixP, valueT *valueP, segT seg)
00502 {
00503   if ((fixP->fx_pcrel != 0) && (fixP->fx_r_type == BFD_RELOC_32))
00504     fixP->fx_r_type = BFD_RELOC_32_PCREL;
00505 
00506   gas_cgen_md_apply_fix (fixP, valueP, seg);
00507 }
00508 
00509 bfd_boolean
00510 mt_fix_adjustable (fixS * fixP)
00511 {
00512   bfd_reloc_code_real_type reloc_type;
00513 
00514   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
00515     {
00516       const CGEN_INSN *insn = NULL;
00517       int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
00518       const CGEN_OPERAND *operand;
00519 
00520       operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
00521       reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
00522     }
00523   else
00524     reloc_type = fixP->fx_r_type;
00525 
00526   if (fixP->fx_addsy == NULL)
00527     return TRUE;
00528   
00529   /* Prevent all adjustments to global symbols.  */
00530   if (S_IS_EXTERNAL (fixP->fx_addsy))
00531     return FALSE;
00532   
00533   if (S_IS_WEAK (fixP->fx_addsy))
00534     return FALSE;
00535   
00536   return 1;
00537 }