Home | History | Annotate | Download | only in config
      1 /* tc-xc16x.c -- Assembler for the Infineon XC16X.
      2    Copyright (C) 2006-2014 Free Software Foundation, Inc.
      3    Contributed by KPIT Cummins Infosystems
      4 
      5    This file is part of GAS, the GNU Assembler.
      6 
      7    GAS is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3, or (at your option)
     10    any later version.
     11 
     12    GAS is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18     along with GAS; see the file COPYING.  If not, write to the Free
     19    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
     20    02110-1301, USA.  */
     21 
     22 
     23 #include "as.h"
     24 #include "safe-ctype.h"
     25 #include "subsegs.h"
     26 #include "symcat.h"
     27 #include "opcodes/xc16x-desc.h"
     28 #include "opcodes/xc16x-opc.h"
     29 #include "cgen.h"
     30 #include "dwarf2dbg.h"
     31 
     32 
     33 #ifdef OBJ_ELF
     34 #include "elf/xc16x.h"
     35 #endif
     36 
     37 /* Structure to hold all of the different components describing
     38    an individual instruction.  */
     39 typedef struct
     40 {
     41   const CGEN_INSN *	insn;
     42   const CGEN_INSN *	orig_insn;
     43   CGEN_FIELDS		fields;
     44 #if CGEN_INT_INSN_P
     45   CGEN_INSN_INT         buffer [1];
     46 #define INSN_VALUE(buf) (*(buf))
     47 #else
     48   unsigned char buffer [CGEN_MAX_INSN_SIZE];
     49 #define INSN_VALUE(buf) (buf)
     50 #endif
     51   char *		addr;
     52   fragS *		frag;
     53   int  			num_fixups;
     54   fixS *		fixups [GAS_CGEN_MAX_FIXUPS];
     55   int  			indices [MAX_OPERAND_INSTANCES];
     56 }
     57 xc16x_insn;
     58 
     59 const char comment_chars[]        = ";";
     60 const char line_comment_chars[]   = "#";
     61 const char line_separator_chars[] = "";
     62 const char EXP_CHARS[]            = "eE";
     63 const char FLT_CHARS[]            = "dD";
     64 
     65 #define XC16X_SHORTOPTS ""
     66 const char * md_shortopts = XC16X_SHORTOPTS;
     67 
     68 struct option md_longopts[] =
     69 {
     70   {NULL, no_argument, NULL, 0}
     71 };
     72 size_t md_longopts_size = sizeof (md_longopts);
     73 
     74 static void
     75 xc16xlmode (int arg ATTRIBUTE_UNUSED)
     76 {
     77  if (stdoutput != NULL)
     78   if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16xl))
     79     as_warn (_("could not set architecture and machine"));
     80 }
     81 
     82 static void
     83 xc16xsmode (int arg ATTRIBUTE_UNUSED)
     84 {
     85   if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16xs))
     86     as_warn (_("could not set architecture and machine"));
     87 }
     88 
     89 static void
     90 xc16xmode (int arg ATTRIBUTE_UNUSED)
     91 {
     92   if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16x))
     93     as_warn (_("could not set architecture and machine"));
     94 }
     95 
     96 /* The target specific pseudo-ops which we support.  */
     97 const pseudo_typeS md_pseudo_table[] =
     98 {
     99   { "word",	cons,		2 },
    100   {"xc16xl",  xc16xlmode,  0},
    101   {"xc16xs", xc16xsmode, 0},
    102   {"xc16x",  xc16xmode,  0},
    103   { NULL, 	NULL, 		0 }
    104 };
    105 
    106 void
    107 md_begin (void)
    108 {
    109   /* Initialize the `cgen' interface.  */
    110 
    111   /* Set the machine number and endian.  */
    112   gas_cgen_cpu_desc = xc16x_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
    113 					   CGEN_CPU_OPEN_ENDIAN,
    114 					   CGEN_ENDIAN_LITTLE,
    115 					   CGEN_CPU_OPEN_END);
    116   xc16x_cgen_init_asm (gas_cgen_cpu_desc);
    117 
    118   /* This is a callback from cgen to gas to parse operands.  */
    119   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
    120 }
    121 
    122 void
    123 md_assemble (char *str)
    124 {
    125   xc16x_insn insn;
    126   char *errmsg;
    127 
    128   /* Initialize GAS's cgen interface for a new instruction.  */
    129   gas_cgen_init_parse ();
    130 
    131   insn.insn = xc16x_cgen_assemble_insn
    132     (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
    133 
    134   if (!insn.insn)
    135     {
    136       as_bad ("%s", errmsg);
    137       return;
    138     }
    139 
    140   /* Doesn't really matter what we pass for RELAX_P here.  */
    141   gas_cgen_finish_insn (insn.insn, insn.buffer,
    142 			CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
    143 }
    144 
    145 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
    146    Returns BFD_RELOC_NONE if no reloc type can be found.
    147    *FIXP may be modified if desired.  */
    148 
    149 bfd_reloc_code_real_type
    150 md_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED,
    151 		      const CGEN_OPERAND *operand,
    152 		      fixS *fixP)
    153 {
    154   switch (operand->type)
    155     {
    156     case XC16X_OPERAND_REL:
    157       /* ??? Adjust size?  */
    158       fixP->fx_where += 1;
    159       fixP->fx_pcrel = 1;
    160       return BFD_RELOC_8_PCREL;
    161 
    162     case XC16X_OPERAND_CADDR:
    163       fixP->fx_size = 2;
    164       fixP->fx_where += 2;
    165       return BFD_RELOC_16;
    166 
    167     case XC16X_OPERAND_UIMM7:
    168       /* ??? Adjust size?  */
    169       fixP->fx_where += 1;
    170       fixP->fx_pcrel = 1;
    171       return BFD_RELOC_8_PCREL;
    172 
    173     case XC16X_OPERAND_UIMM16:
    174     case XC16X_OPERAND_MEMORY:
    175       fixP->fx_size = 2;
    176       fixP->fx_where += 2;
    177       return BFD_RELOC_16;
    178 
    179     case XC16X_OPERAND_UPOF16:
    180       fixP->fx_size = 2;
    181       fixP->fx_where += 2;
    182       return BFD_RELOC_XC16X_POF;
    183 
    184     case XC16X_OPERAND_UPAG16:
    185       fixP->fx_size = 2;
    186       fixP->fx_where += 2;
    187       return BFD_RELOC_XC16X_PAG;
    188 
    189     case XC16X_OPERAND_USEG8:
    190       /* ??? This is an 8 bit field, why the 16 bit reloc?  */
    191       fixP->fx_where += 1;
    192       return BFD_RELOC_XC16X_SEG;
    193 
    194     case XC16X_OPERAND_USEG16:
    195     case  XC16X_OPERAND_USOF16:
    196       fixP->fx_size = 2;
    197       fixP->fx_where += 2;
    198       return BFD_RELOC_XC16X_SOF;
    199 
    200     default : /* Avoid -Wall warning.  */
    201       break;
    202     }
    203 
    204   return BFD_RELOC_NONE;
    205 }
    206 
    207 /* Write a value out to the object file, using the appropriate endianness.  */
    208 
    209 void
    210 md_number_to_chars (char * buf, valueT val, int n)
    211 {
    212   number_to_chars_littleendian (buf, val, n);
    213 }
    214 
    215 void
    216 md_show_usage (FILE * stream)
    217 {
    218   fprintf (stream, _(" XC16X specific command line options:\n"));
    219 }
    220 
    221 int
    222 md_parse_option (int c ATTRIBUTE_UNUSED,
    223 		 char *arg ATTRIBUTE_UNUSED)
    224 {
    225   return 0;
    226 }
    227 
    228 char *
    229 md_atof (int type, char *litP, int *sizeP)
    230 {
    231   return ieee_md_atof (type, litP, sizeP, FALSE);
    232 }
    233 
    234 valueT
    235 md_section_align (segT segment, valueT size)
    236 {
    237   int align = bfd_get_section_alignment (stdoutput, segment);
    238   return ((size + (1 << align) - 1) & (-1 << align));
    239 }
    240 
    241 symbolS *
    242 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
    243 {
    244   return NULL;
    245 }
    246 
    247 int
    248 md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
    249 			       segT segment_type ATTRIBUTE_UNUSED)
    250 {
    251   printf (_("call to md_estimate_size_before_relax \n"));
    252   abort ();
    253 }
    254 
    255 
    256 long
    257 md_pcrel_from (fixS *fixP)
    258 {
    259   long temp_val;
    260   temp_val=fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
    261 
    262   return temp_val;
    263 }
    264 
    265 long
    266 md_pcrel_from_section (fixS *fixP, segT sec)
    267 {
    268   if (fixP->fx_addsy != (symbolS *) NULL
    269       && (! S_IS_DEFINED (fixP->fx_addsy)
    270 	  || S_GET_SEGMENT (fixP->fx_addsy) != sec
    271           || S_IS_EXTERNAL (fixP->fx_addsy)
    272           || S_IS_WEAK (fixP->fx_addsy)))
    273     {
    274       return 0;
    275     }
    276 
    277   return md_pcrel_from (fixP);
    278 }
    279 
    280 arelent *
    281 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
    282 {
    283   arelent *rel;
    284   bfd_reloc_code_real_type r_type;
    285 
    286   if (fixp->fx_addsy && fixp->fx_subsy)
    287     {
    288       if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
    289 	  || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section)
    290 	{
    291 	  as_bad_where (fixp->fx_file, fixp->fx_line,
    292 			_("Difference of symbols in different sections is not supported"));
    293 	  return NULL;
    294 	}
    295     }
    296 
    297   rel = xmalloc (sizeof (arelent));
    298   rel->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
    299   *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
    300   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
    301   rel->addend = fixp->fx_offset;
    302 
    303   r_type = fixp->fx_r_type;
    304 
    305 #define DEBUG 0
    306 #if DEBUG
    307   fprintf (stderr, "%s\n", bfd_get_reloc_code_name (r_type));
    308   fflush (stderr);
    309 #endif
    310 
    311   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
    312    if (rel->howto == NULL)
    313     {
    314       as_bad_where (fixp->fx_file, fixp->fx_line,
    315 		    _("Cannot represent relocation type %s"),
    316 		    bfd_get_reloc_code_name (r_type));
    317       return NULL;
    318     }
    319 
    320   return rel;
    321 }
    322 
    323 void
    324 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
    325 {
    326   if (!strstr (seg->name,".debug"))
    327     {
    328       if (*valP < 128)
    329 	*valP /= 2;
    330       if (*valP>268435455)
    331 	{
    332 	  *valP = *valP * (-1);
    333 	  *valP /= 2;
    334 	  *valP = 256 - (*valP);
    335 	}
    336     }
    337 
    338   gas_cgen_md_apply_fix (fixP, valP, seg);
    339   return;
    340 }
    341 
    342 void
    343 md_convert_frag (bfd *headers ATTRIBUTE_UNUSED,
    344 		 segT seg ATTRIBUTE_UNUSED,
    345 		 fragS *fragP ATTRIBUTE_UNUSED)
    346 {
    347   printf (_("call to md_convert_frag \n"));
    348   abort ();
    349 }
    350