Back to index

cell-binutils  2.17cvs20070401
tc-openrisc.c
Go to the documentation of this file.
00001 /* tc-openrisc.c -- Assembler for the OpenRISC family.
00002    Copyright 2001, 2002, 2003, 2005, 2006 Free Software Foundation.
00003    Contributed by Johan Rydberg, jrydberg@opencores.org
00004 
00005    This file is part of GAS, the GNU Assembler.
00006 
00007    GAS is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2, or (at your option)
00010    any later version.
00011 
00012    GAS is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with GAS; see the file COPYING.  If not, write to
00019    the Free Software Foundation, 51 Franklin Street - Fifth Floor,
00020    Boston, MA 02110-1301, USA.  */
00021 
00022 #include "as.h"
00023 #include "subsegs.h"
00024 #include "symcat.h"
00025 #include "opcodes/openrisc-desc.h"
00026 #include "opcodes/openrisc-opc.h"
00027 #include "cgen.h"
00028 
00029 /* Structure to hold all of the different components describing
00030    an individual instruction.  */
00031 typedef struct openrisc_insn openrisc_insn;
00032 
00033 struct openrisc_insn
00034 {
00035   const CGEN_INSN *  insn;
00036   const CGEN_INSN *  orig_insn;
00037   CGEN_FIELDS        fields;
00038 #if CGEN_INT_INSN_P
00039   CGEN_INSN_INT         buffer [1];
00040 #define INSN_VALUE(buf) (*(buf))
00041 #else
00042   unsigned char         buffer [CGEN_MAX_INSN_SIZE];
00043 #define INSN_VALUE(buf) (buf)
00044 #endif
00045   char *             addr;
00046   fragS *            frag;
00047   int                   num_fixups;
00048   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
00049   int                   indices [MAX_OPERAND_INSTANCES];
00050 };
00051 
00052 
00053 const char comment_chars[]        = "#";
00054 const char line_comment_chars[]   = "#";
00055 const char line_separator_chars[] = ";";
00056 const char EXP_CHARS[]            = "eE";
00057 const char FLT_CHARS[]            = "dD";
00058 
00059 
00060 #define OPENRISC_SHORTOPTS "m:"
00061 const char * md_shortopts = OPENRISC_SHORTOPTS;
00062 
00063 struct option md_longopts[] =
00064 {
00065   {NULL, no_argument, NULL, 0}
00066 };
00067 size_t md_longopts_size = sizeof (md_longopts);
00068 
00069 unsigned long openrisc_machine = 0; /* default */
00070 
00071 int
00072 md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED)
00073 {
00074   return 0;
00075 }
00076 
00077 void
00078 md_show_usage (FILE * stream ATTRIBUTE_UNUSED)
00079 {
00080 }
00081 
00082 static void
00083 ignore_pseudo (int val ATTRIBUTE_UNUSED)
00084 {
00085   discard_rest_of_line ();
00086 }
00087 
00088 const char openrisc_comment_chars [] = ";#";
00089 
00090 /* The target specific pseudo-ops which we support.  */
00091 const pseudo_typeS md_pseudo_table[] =
00092 {
00093   { "word",     cons,           4 },
00094   { "proc",     ignore_pseudo,  0 },
00095   { "endproc",  ignore_pseudo,  0 },
00096   { NULL,     NULL,         0 }
00097 };
00098 
00099 
00100 
00101 void
00102 md_begin (void)
00103 {
00104   /* Initialize the `cgen' interface.  */
00105 
00106   /* Set the machine number and endian.  */
00107   gas_cgen_cpu_desc = openrisc_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
00108                                               CGEN_CPU_OPEN_ENDIAN,
00109                                               CGEN_ENDIAN_BIG,
00110                                               CGEN_CPU_OPEN_END);
00111   openrisc_cgen_init_asm (gas_cgen_cpu_desc);
00112 
00113   /* This is a callback from cgen to gas to parse operands.  */
00114   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
00115 }
00116 
00117 void
00118 md_assemble (char * str)
00119 {
00120   static int last_insn_had_delay_slot = 0;
00121   openrisc_insn insn;
00122   char *    errmsg;
00123 
00124   /* Initialize GAS's cgen interface for a new instruction.  */
00125   gas_cgen_init_parse ();
00126 
00127   insn.insn = openrisc_cgen_assemble_insn
00128     (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
00129 
00130   if (!insn.insn)
00131     {
00132       as_bad (errmsg);
00133       return;
00134     }
00135 
00136   /* Doesn't really matter what we pass for RELAX_P here.  */
00137   gas_cgen_finish_insn (insn.insn, insn.buffer,
00138                      CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
00139 
00140   last_insn_had_delay_slot
00141     = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
00142 }
00143 
00144 
00145 /* The syntax in the manual says constants begin with '#'.
00146    We just ignore it.  */
00147 
00148 void
00149 md_operand (expressionS * expressionP)
00150 {
00151   if (* input_line_pointer == '#')
00152     {
00153       input_line_pointer ++;
00154       expression (expressionP);
00155     }
00156 }
00157 
00158 valueT
00159 md_section_align (segT segment, valueT size)
00160 {
00161   int align = bfd_get_section_alignment (stdoutput, segment);
00162   return ((size + (1 << align) - 1) & (-1 << align));
00163 }
00164 
00165 symbolS *
00166 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
00167 {
00168   return 0;
00169 }
00170 
00171 
00172 /* Interface to relax_segment.  */
00173 
00174 /* FIXME: Look through this.  */
00175 
00176 const relax_typeS md_relax_table[] =
00177 {
00178 /* The fields are:
00179    1) most positive reach of this state,
00180    2) most negative reach of this state,
00181    3) how many bytes this mode will add to the size of the current frag
00182    4) which index into the table to try if we can't fit into this one.  */
00183 
00184   /* The first entry must be unused because an `rlx_more' value of zero ends
00185      each list.  */
00186   {1, 1, 0, 0},
00187 
00188   /* The displacement used by GAS is from the end of the 2 byte insn,
00189      so we subtract 2 from the following.  */
00190   /* 16 bit insn, 8 bit disp -> 10 bit range.
00191      This doesn't handle a branch in the right slot at the border:
00192      the "& -4" isn't taken into account.  It's not important enough to
00193      complicate things over it, so we subtract an extra 2 (or + 2 in -ve
00194      case).  */
00195   {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
00196   /* 32 bit insn, 24 bit disp -> 26 bit range.  */
00197   {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
00198   /* Same thing, but with leading nop for alignment.  */
00199   {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
00200 };
00201 
00202 /* Return an initial guess of the length by which a fragment must grow to
00203    hold a branch to reach its destination.
00204    Also updates fr_type/fr_subtype as necessary.
00205 
00206    Called just before doing relaxation.
00207    Any symbol that is now undefined will not become defined.
00208    The guess for fr_var is ACTUALLY the growth beyond fr_fix.
00209    Whatever we do to grow fr_fix or fr_var contributes to our returned value.
00210    Although it may not be explicit in the frag, pretend fr_var starts with a
00211    0 value.  */
00212 
00213 int
00214 md_estimate_size_before_relax (fragS * fragP, segT segment)
00215 {
00216   /* The only thing we have to handle here are symbols outside of the
00217      current segment.  They may be undefined or in a different segment in
00218      which case linker scripts may place them anywhere.
00219      However, we can't finish the fragment here and emit the reloc as insn
00220      alignment requirements may move the insn about.  */
00221 
00222   if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
00223     {
00224       /* The symbol is undefined in this segment.
00225         Change the relaxation subtype to the max allowable and leave
00226         all further handling to md_convert_frag.  */
00227       fragP->fr_subtype = 2;
00228 
00229       {
00230        const CGEN_INSN * insn;
00231        int               i;
00232 
00233        /* Update the recorded insn.
00234           Fortunately we don't have to look very far.
00235           FIXME: Change this to record in the instruction the next higher
00236           relaxable insn to use.  */
00237        for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++)
00238          {
00239            if ((strcmp (CGEN_INSN_MNEMONIC (insn),
00240                       CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
00241                == 0)
00242               && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED))
00243              break;
00244          }
00245        if (i == 4)
00246          abort ();
00247 
00248        fragP->fr_cgen.insn = insn;
00249        return 2;
00250       }
00251     }
00252 
00253   return md_relax_table[fragP->fr_subtype].rlx_length;
00254 }
00255 
00256 /* *fragP has been relaxed to its final size, and now needs to have
00257    the bytes inside it modified to conform to the new size.
00258 
00259    Called after relaxation is finished.
00260    fragP->fr_type == rs_machine_dependent.
00261    fragP->fr_subtype is the subtype of what the address relaxed to.  */
00262 
00263 void
00264 md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
00265                segT    sec  ATTRIBUTE_UNUSED,
00266                fragS * fragP ATTRIBUTE_UNUSED)
00267 {
00268   /* FIXME */
00269 }
00270 
00271 
00272 /* Functions concerning relocs.  */
00273 
00274 /* The location from which a PC relative jump should be calculated,
00275    given a PC relative reloc.  */
00276 
00277 long
00278 md_pcrel_from_section (fixS * fixP, segT sec)
00279 {
00280   if (fixP->fx_addsy != (symbolS *) NULL
00281       && (! S_IS_DEFINED (fixP->fx_addsy)
00282          || S_GET_SEGMENT (fixP->fx_addsy) != sec))
00283     /* The symbol is undefined (or is defined but not in this section).
00284        Let the linker figure it out.  */
00285     return 0;
00286 
00287   return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
00288 }
00289 
00290 
00291 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
00292    Returns BFD_RELOC_NONE if no reloc type can be found.
00293    *FIXP may be modified if desired.  */
00294 
00295 bfd_reloc_code_real_type
00296 md_cgen_lookup_reloc (const CGEN_INSN *    insn ATTRIBUTE_UNUSED,
00297                     const CGEN_OPERAND * operand,
00298                     fixS *               fixP)
00299 {
00300   bfd_reloc_code_real_type type;
00301 
00302   switch (operand->type)
00303     {
00304     case OPENRISC_OPERAND_ABS_26:
00305       fixP->fx_pcrel = 0;
00306       type = BFD_RELOC_OPENRISC_ABS_26;
00307       goto emit;
00308     case OPENRISC_OPERAND_DISP_26:
00309       fixP->fx_pcrel = 1;
00310       type = BFD_RELOC_OPENRISC_REL_26;
00311       goto emit;
00312 
00313     case OPENRISC_OPERAND_HI16:
00314       type = BFD_RELOC_HI16;
00315       goto emit;
00316 
00317     case OPENRISC_OPERAND_LO16:
00318       type = BFD_RELOC_LO16;
00319       goto emit;
00320 
00321     emit:
00322       return type;
00323 
00324     default : /* avoid -Wall warning */
00325       break;
00326     }
00327 
00328   return BFD_RELOC_NONE;
00329 }
00330 
00331 /* Write a value out to the object file, using the appropriate endianness.  */
00332 
00333 void
00334 md_number_to_chars (char * buf, valueT val, int n)
00335 {
00336   number_to_chars_bigendian (buf, val, n);
00337 }
00338 
00339 /* Turn a string in input_line_pointer into a floating point constant of type
00340    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
00341    emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
00342 */
00343 
00344 /* Equal to MAX_PRECISION in atof-ieee.c */
00345 #define MAX_LITTLENUMS 6
00346 
00347 char *
00348 md_atof (int type, char * litP, int *  sizeP)
00349 {
00350   int              i;
00351   int              prec;
00352   LITTLENUM_TYPE   words [MAX_LITTLENUMS];
00353   char *           t;
00354 
00355   switch (type)
00356     {
00357     case 'f':
00358     case 'F':
00359     case 's':
00360     case 'S':
00361       prec = 2;
00362       break;
00363 
00364     case 'd':
00365     case 'D':
00366     case 'r':
00367     case 'R':
00368       prec = 4;
00369       break;
00370 
00371    /* FIXME: Some targets allow other format chars for bigger sizes here.  */
00372 
00373     default:
00374       * sizeP = 0;
00375       return _("Bad call to md_atof()");
00376     }
00377 
00378   t = atof_ieee (input_line_pointer, type, words);
00379   if (t)
00380     input_line_pointer = t;
00381   * sizeP = prec * sizeof (LITTLENUM_TYPE);
00382 
00383   for (i = 0; i < prec; i++)
00384     {
00385       md_number_to_chars (litP, (valueT) words[i],
00386                        sizeof (LITTLENUM_TYPE));
00387       litP += sizeof (LITTLENUM_TYPE);
00388     }
00389 
00390   return 0;
00391 }
00392 
00393 bfd_boolean
00394 openrisc_fix_adjustable (fixS * fixP)
00395 {
00396   /* We need the symbol name for the VTABLE entries.  */
00397   if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
00398       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
00399     return 0;
00400 
00401   return 1;
00402 }