Back to index

cell-binutils  2.17cvs20070401
tc-xc16x.c
Go to the documentation of this file.
00001 /* tc-xc16x.c -- Assembler for the Infineon XC16X.
00002    Copyright 2006 Free Software Foundation, Inc.
00003    Contributed by KPIT Cummins Infosystems 
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 the Free
00019    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
00020    02110-1301, USA.  */
00021 
00022 
00023 #include "as.h"
00024 #include "safe-ctype.h"
00025 #include "subsegs.h"
00026 #include "symcat.h"
00027 #include "opcodes/xc16x-desc.h"
00028 #include "opcodes/xc16x-opc.h"
00029 #include "cgen.h"
00030 #include "dwarf2dbg.h"
00031 
00032 
00033 #ifdef OBJ_ELF
00034 #include "elf/xc16x.h"
00035 #endif
00036 
00037 /* Structure to hold all of the different components describing
00038    an individual instruction.  */
00039 typedef struct
00040 {
00041   const CGEN_INSN *  insn;
00042   const CGEN_INSN *  orig_insn;
00043   CGEN_FIELDS        fields;
00044 #if CGEN_INT_INSN_P
00045   CGEN_INSN_INT         buffer [1];
00046 #define INSN_VALUE(buf) (*(buf))
00047 #else
00048   unsigned char buffer [CGEN_MAX_INSN_SIZE];
00049 #define INSN_VALUE(buf) (buf)
00050 #endif
00051   char *             addr;
00052   fragS *            frag;
00053   int                       num_fixups;
00054   fixS *             fixups [GAS_CGEN_MAX_FIXUPS];
00055   int                       indices [MAX_OPERAND_INSTANCES];
00056 }
00057 xc16x_insn;
00058 
00059 const char comment_chars[]        = ";";
00060 const char line_comment_chars[]   = "#";
00061 const char line_separator_chars[] = "";
00062 const char EXP_CHARS[]            = "eE";
00063 const char FLT_CHARS[]            = "dD";
00064 
00065 #define XC16X_SHORTOPTS ""
00066 const char * md_shortopts = XC16X_SHORTOPTS;
00067 
00068 struct option md_longopts[] =
00069 {
00070   {NULL, no_argument, NULL, 0}
00071 };
00072 size_t md_longopts_size = sizeof (md_longopts);
00073 
00074 static void
00075 xc16xlmode (int arg ATTRIBUTE_UNUSED)
00076 {
00077  if (stdoutput != NULL)
00078   if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16xl))
00079     as_warn (_("could not set architecture and machine"));
00080 }
00081 
00082 static void
00083 xc16xsmode (int arg ATTRIBUTE_UNUSED)
00084 {
00085   if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16xs))
00086     as_warn (_("could not set architecture and machine"));
00087 }
00088 
00089 static void
00090 xc16xmode (int arg ATTRIBUTE_UNUSED)
00091 {
00092   if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16x))
00093     as_warn (_("could not set architecture and machine"));
00094 }
00095 
00096 /* The target specific pseudo-ops which we support.  */
00097 const pseudo_typeS md_pseudo_table[] =
00098 {
00099   { "word",   cons,         2 },
00100   {"xc16xl",  xc16xlmode,  0},
00101   {"xc16xs", xc16xsmode, 0},
00102   {"xc16x",  xc16xmode,  0},
00103   { NULL,     NULL,         0 }
00104 };
00105 
00106 void
00107 md_begin (void)
00108 {
00109   /* Initialize the `cgen' interface.  */
00110 
00111   /* Set the machine number and endian.  */
00112   gas_cgen_cpu_desc = xc16x_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
00113                                       CGEN_CPU_OPEN_ENDIAN,
00114                                       CGEN_ENDIAN_LITTLE,
00115                                       CGEN_CPU_OPEN_END);
00116   xc16x_cgen_init_asm (gas_cgen_cpu_desc);
00117 
00118   /* This is a callback from cgen to gas to parse operands.  */
00119   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
00120 }
00121 
00122 void
00123 md_assemble (char *str)
00124 {
00125   xc16x_insn insn;
00126   char *errmsg;
00127 
00128   /* Initialize GAS's cgen interface for a new instruction.  */
00129   gas_cgen_init_parse ();
00130 
00131   insn.insn = xc16x_cgen_assemble_insn
00132     (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
00133 
00134   if (!insn.insn)
00135     {
00136       as_bad (errmsg);
00137       return;
00138     }
00139 
00140   /* Doesn't really matter what we pass for RELAX_P here.  */
00141   gas_cgen_finish_insn (insn.insn, insn.buffer,
00142                      CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
00143 }
00144 
00145 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
00146    Returns BFD_RELOC_NONE if no reloc type can be found.
00147    *FIXP may be modified if desired.  */
00148 
00149 bfd_reloc_code_real_type
00150 md_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED,
00151                     const CGEN_OPERAND *operand,
00152                     fixS *fixP)
00153 {
00154   switch (operand->type)
00155     {
00156     case XC16X_OPERAND_REL:
00157       fixP->fx_where += 1;
00158       fixP->fx_pcrel = 1;
00159       return BFD_RELOC_8_PCREL;
00160 
00161     case XC16X_OPERAND_CADDR:
00162       fixP->fx_where += 2;
00163       return BFD_RELOC_16;
00164 
00165     case XC16X_OPERAND_UIMM7:
00166       fixP->fx_where += 1;
00167       fixP->fx_pcrel = 1;
00168       return BFD_RELOC_8_PCREL;
00169 
00170     case XC16X_OPERAND_UIMM16:
00171     case XC16X_OPERAND_MEMORY:
00172       fixP->fx_where += 2;
00173       return BFD_RELOC_16;
00174 
00175     case XC16X_OPERAND_UPOF16:
00176       fixP->fx_where += 2;
00177       return BFD_RELOC_XC16X_POF;
00178 
00179     case XC16X_OPERAND_UPAG16:
00180       fixP->fx_where += 2;
00181       return BFD_RELOC_XC16X_PAG;
00182 
00183     case XC16X_OPERAND_USEG8:
00184       fixP->fx_where += 1;
00185       return BFD_RELOC_XC16X_SEG;
00186 
00187     case XC16X_OPERAND_USEG16:
00188     case  XC16X_OPERAND_USOF16:
00189       fixP->fx_where += 2;
00190       return BFD_RELOC_XC16X_SOF;
00191 
00192     default : /* avoid -Wall warning */
00193       break;
00194     }
00195 
00196   fixP->fx_where += 2;
00197   return BFD_RELOC_XC16X_SOF;
00198 }
00199 
00200 /* Write a value out to the object file, using the appropriate endianness.  */
00201 
00202 void
00203 md_number_to_chars (char * buf, valueT val, int n)
00204 {
00205   number_to_chars_littleendian (buf, val, n);
00206 }
00207 
00208 void
00209 md_show_usage (FILE * stream)
00210 {
00211   fprintf (stream, _(" XC16X specific command line options:\n"));
00212 }
00213 
00214 int
00215 md_parse_option (int c ATTRIBUTE_UNUSED,
00216                char *arg ATTRIBUTE_UNUSED)
00217 {
00218   return 0;
00219 }
00220 
00221 /* Turn a string in input_line_pointer into a floating point constant
00222    of type TYPE, and store the appropriate bytes in *LITP.  The number
00223    of LITTLENUMS emitted is stored in *SIZEP.  An error message is
00224    returned, or NULL on OK.  */
00225 
00226 /* Equal to MAX_PRECISION in atof-ieee.c.  */
00227 #define MAX_LITTLENUMS 6
00228 
00229 char *
00230 md_atof (int type, char *litP, int *sizeP)
00231 {
00232   int i;
00233   int prec;
00234   LITTLENUM_TYPE words[MAX_LITTLENUMS];
00235   char *t;
00236 
00237   switch (type)
00238     {
00239     case 'f':
00240     case 'F':
00241     case 's':
00242     case 'S':
00243       prec = 2;
00244       break;
00245 
00246     case 'd':
00247     case 'D':
00248     case 'r':
00249     case 'R':
00250       prec = 4;
00251       break;
00252 
00253       /* FIXME: Some targets allow other format chars for bigger sizes
00254          here.  */
00255 
00256     default:
00257       *sizeP = 0;
00258       return _("Bad call to md_atof()");
00259     }
00260 
00261   t = atof_ieee (input_line_pointer, type, words);
00262   if (t)
00263     input_line_pointer = t;
00264   *sizeP = prec * sizeof (LITTLENUM_TYPE);
00265 
00266    for (i = prec - 1; i >= 0; i--)
00267      {
00268        md_number_to_chars (litP, (valueT) words[i],
00269                         sizeof (LITTLENUM_TYPE));
00270        litP += sizeof (LITTLENUM_TYPE);
00271      }
00272 
00273   return NULL;
00274 }
00275 
00276 valueT
00277 md_section_align (segT segment, valueT size)
00278 {
00279   int align = bfd_get_section_alignment (stdoutput, segment);
00280   return ((size + (1 << align) - 1) & (-1 << align));
00281 }
00282 
00283 symbolS *
00284 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
00285 {
00286   return NULL;
00287 }
00288 
00289 int
00290 md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
00291                             segT segment_type ATTRIBUTE_UNUSED)
00292 {
00293   printf (_("call tomd_estimate_size_before_relax \n"));
00294   abort ();
00295 }
00296 
00297 
00298 long
00299 md_pcrel_from (fixS *fixP)
00300 {
00301   long temp_val;
00302   temp_val=fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
00303 
00304   return temp_val;
00305 }
00306 
00307 long
00308 md_pcrel_from_section (fixS *fixP, segT sec)
00309 {
00310   if (fixP->fx_addsy != (symbolS *) NULL
00311       && (! S_IS_DEFINED (fixP->fx_addsy)
00312          || S_GET_SEGMENT (fixP->fx_addsy) != sec
00313           || S_IS_EXTERNAL (fixP->fx_addsy)
00314           || S_IS_WEAK (fixP->fx_addsy)))
00315     {
00316       return 0;
00317     }
00318 
00319   return md_pcrel_from (fixP);
00320 }
00321 
00322 arelent *
00323 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
00324 {
00325   arelent *rel;
00326   bfd_reloc_code_real_type r_type;
00327 
00328   if (fixp->fx_addsy && fixp->fx_subsy)
00329     {
00330       if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
00331          || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section)
00332        {
00333          as_bad_where (fixp->fx_file, fixp->fx_line,
00334                      "Difference of symbols in different sections is not supported");
00335          return NULL;
00336        }
00337     }
00338 
00339   rel = xmalloc (sizeof (arelent));
00340   rel->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
00341   *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
00342   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
00343   rel->addend = fixp->fx_offset;
00344 
00345   r_type = fixp->fx_r_type;
00346 
00347 #define DEBUG 0
00348 #if DEBUG
00349   fprintf (stderr, "%s\n", bfd_get_reloc_code_name (r_type));
00350   fflush(stderr);
00351 #endif
00352 
00353   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
00354    if (rel->howto == NULL)
00355     {
00356       as_bad_where (fixp->fx_file, fixp->fx_line,
00357                   _("Cannot represent relocation type %s"),
00358                   bfd_get_reloc_code_name (r_type));
00359       return NULL;
00360     }
00361 
00362   return rel;
00363 }
00364 
00365 void
00366 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
00367 {
00368   if(!strstr (seg->name,".debug"))
00369     {
00370       if (*valP < 128)
00371        *valP /= 2;
00372       if (*valP>268435455)
00373        {
00374          *valP = *valP * (-1);
00375          *valP /= 2;
00376          *valP = 256 - (*valP);
00377        }
00378     }
00379   
00380   gas_cgen_md_apply_fix (fixP, valP, seg);
00381   return;
00382 }
00383 
00384 void
00385 md_convert_frag (bfd *headers ATTRIBUTE_UNUSED,
00386                segT seg ATTRIBUTE_UNUSED,
00387                fragS *fragP ATTRIBUTE_UNUSED)
00388 {
00389   printf (_("call to md_convert_frag \n"));
00390   abort ();
00391 }
00392 
00393