Home | History | Annotate | Download | only in config
      1 /* tc-ip2k.c -- Assembler for the Scenix IP2xxx.
      2    Copyright (C) 2000-2016 Free Software Foundation, Inc.
      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, 51 Franklin Street - Fifth Floor,
     19    Boston, MA 02110-1301, USA.  */
     20 
     21 #include "as.h"
     22 #include "subsegs.h"
     23 #include "symcat.h"
     24 #include "opcodes/ip2k-desc.h"
     25 #include "opcodes/ip2k-opc.h"
     26 #include "cgen.h"
     27 #include "elf/common.h"
     28 #include "elf/ip2k.h"
     29 #include "libbfd.h"
     30 
     31 /* Structure to hold all of the different components describing
     32    an individual instruction.  */
     33 typedef struct
     34 {
     35   const CGEN_INSN *	insn;
     36   const CGEN_INSN *	orig_insn;
     37   CGEN_FIELDS		fields;
     38 #if CGEN_INT_INSN_P
     39   CGEN_INSN_INT         buffer [1];
     40 #define INSN_VALUE(buf) (*(buf))
     41 #else
     42   unsigned char         buffer [CGEN_MAX_INSN_SIZE];
     43 #define INSN_VALUE(buf) (buf)
     44 #endif
     45   char *		addr;
     46   fragS *		frag;
     47   int                   num_fixups;
     48   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
     49   int                   indices [MAX_OPERAND_INSTANCES];
     50 }
     51 ip2k_insn;
     52 
     53 const char comment_chars[]        = ";";
     54 const char line_comment_chars[]   = "#";
     55 const char line_separator_chars[] = "";
     56 const char EXP_CHARS[]            = "eE";
     57 const char FLT_CHARS[]            = "dD";
     58 
     59 /* Flag to detect when switching to code section where insn alignment is
     60    implied.  */
     61 static int force_code_align = 0;
     62 
     63 /* Mach selected from command line.  */
     64 static int ip2k_mach = 0;
     65 static unsigned ip2k_mach_bitmask = 0;
     66 
     67 
     68 static void
     69 ip2k_elf_section_rtn (int i)
     70 {
     71   obj_elf_section(i);
     72 
     73   if (force_code_align)
     74     {
     75       do_align (1, NULL, 0, 0);
     76       force_code_align = 0;
     77     }
     78 }
     79 
     80 static void
     81 ip2k_elf_section_text (int i)
     82 {
     83   obj_elf_text(i);
     84 
     85   do_align (1, NULL, 0, 0);
     86   force_code_align = 0;
     87 }
     88 
     89 /* The target specific pseudo-ops which we support.  */
     90 const pseudo_typeS md_pseudo_table[] =
     91 {
     92     { "text",   ip2k_elf_section_text,  0 },
     93     { "sect",   ip2k_elf_section_rtn,   0 },
     94     { NULL, 	NULL,			0 }
     95 };
     96 
     97 
     98 
    100 enum options
    101 {
    102   OPTION_CPU_IP2022 = OPTION_MD_BASE,
    103   OPTION_CPU_IP2022EXT
    104 };
    105 
    106 struct option md_longopts[] =
    107 {
    108   { "mip2022",     no_argument, NULL, OPTION_CPU_IP2022 },
    109   { "mip2022ext",  no_argument, NULL, OPTION_CPU_IP2022EXT },
    110   { NULL,           no_argument, NULL, 0 },
    111 };
    112 size_t md_longopts_size = sizeof (md_longopts);
    113 
    114 const char * md_shortopts = "";
    115 
    116 int
    117 md_parse_option (int c ATTRIBUTE_UNUSED, const char * arg ATTRIBUTE_UNUSED)
    118 {
    119   switch (c)
    120     {
    121     case OPTION_CPU_IP2022:
    122       ip2k_mach = bfd_mach_ip2022;
    123       ip2k_mach_bitmask = 1 << MACH_IP2022;
    124       break;
    125 
    126     case OPTION_CPU_IP2022EXT:
    127       ip2k_mach = bfd_mach_ip2022ext;
    128       ip2k_mach_bitmask = 1 << MACH_IP2022EXT;
    129       break;
    130 
    131     default:
    132       return 0;
    133     }
    134 
    135   return 1;
    136 }
    137 
    138 void
    139 md_show_usage (FILE * stream)
    140 {
    141   fprintf (stream, _("IP2K specific command line options:\n"));
    142   fprintf (stream, _("  -mip2022               restrict to IP2022 insns \n"));
    143   fprintf (stream, _("  -mip2022ext            permit extended IP2022 insn\n"));
    144 }
    145 
    146 
    147 void
    149 md_begin (void)
    150 {
    151   /* Initialize the `cgen' interface.  */
    152 
    153   /* Set the machine number and endian.  */
    154   gas_cgen_cpu_desc = ip2k_cgen_cpu_open (CGEN_CPU_OPEN_MACHS,
    155 					  ip2k_mach_bitmask,
    156 					  CGEN_CPU_OPEN_ENDIAN,
    157 					  CGEN_ENDIAN_BIG,
    158 					  CGEN_CPU_OPEN_END);
    159   ip2k_cgen_init_asm (gas_cgen_cpu_desc);
    160 
    161   /* This is a callback from cgen to gas to parse operands.  */
    162   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
    163 
    164   /* Set the machine type.  */
    165   bfd_default_set_arch_mach (stdoutput, bfd_arch_ip2k, ip2k_mach);
    166 }
    167 
    168 
    169 void
    170 md_assemble (char * str)
    171 {
    172   ip2k_insn insn;
    173   char * errmsg;
    174 
    175   /* Initialize GAS's cgen interface for a new instruction.  */
    176   gas_cgen_init_parse ();
    177 
    178   insn.insn = ip2k_cgen_assemble_insn
    179       (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
    180 
    181   if (!insn.insn)
    182     {
    183       as_bad ("%s", errmsg);
    184       return;
    185     }
    186 
    187   /* Check for special relocation required by SKIP instructions.  */
    188   if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_SKIPA))
    189     /* Unconditional skip has a 1-bit relocation of the current pc, so
    190        that we emit either sb pcl.0 or snb pcl.0 depending on whether
    191        the PCL (pc + 2) >> 1 is odd or even.  */
    192     {
    193       enum cgen_parse_operand_result result_type;
    194       bfd_vma value;
    195       const char *curpc_plus_2 = ".+2";
    196       const char *err;
    197 
    198       err = cgen_parse_address (gas_cgen_cpu_desc, & curpc_plus_2,
    199 				IP2K_OPERAND_ADDR16CJP,
    200 				BFD_RELOC_IP2K_PC_SKIP,
    201 				& result_type, & value);
    202       if (err)
    203 	{
    204 	  as_bad ("%s", err);
    205 	  return;
    206 	}
    207     }
    208 
    209   /* Doesn't really matter what we pass for RELAX_P here.  */
    210   gas_cgen_finish_insn (insn.insn, insn.buffer,
    211 			CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
    212 }
    213 
    214 valueT
    215 md_section_align (segT segment, valueT size)
    216 {
    217   int align = bfd_get_section_alignment (stdoutput, segment);
    218 
    219   return ((size + (1 << align) - 1) & -(1 << align));
    220 }
    221 
    222 
    223 symbolS *
    224 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
    225 {
    226     return 0;
    227 }
    228 
    229 int
    231 md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
    232 			       segT    segment ATTRIBUTE_UNUSED)
    233 {
    234   as_fatal (_("relaxation not supported\n"));
    235   return 1;
    236 }
    237 
    238 
    239 /* *fragP has been relaxed to its final size, and now needs to have
    240    the bytes inside it modified to conform to the new size.
    241 
    242    Called after relaxation is finished.
    243    fragP->fr_type == rs_machine_dependent.
    244    fragP->fr_subtype is the subtype of what the address relaxed to.  */
    245 
    246 void
    247 md_convert_frag (bfd   * abfd  ATTRIBUTE_UNUSED,
    248 		 segT    sec   ATTRIBUTE_UNUSED,
    249 		 fragS * fragP ATTRIBUTE_UNUSED)
    250 {
    251 }
    252 
    253 
    254 /* Functions concerning relocs.  */
    256 
    257 long
    258 md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED)
    259 {
    260   abort ();
    261 }
    262 
    263 
    264 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
    265    Returns BFD_RELOC_NONE if no reloc type can be found.
    266    *FIXP may be modified if desired.  */
    267 
    268 bfd_reloc_code_real_type
    269 md_cgen_lookup_reloc (const CGEN_INSN *    insn     ATTRIBUTE_UNUSED,
    270 		      const CGEN_OPERAND * operand,
    271 		      fixS *               fixP     ATTRIBUTE_UNUSED)
    272 {
    273   bfd_reloc_code_real_type result;
    274 
    275   result = BFD_RELOC_NONE;
    276 
    277   switch (operand->type)
    278     {
    279     case IP2K_OPERAND_FR:
    280     case IP2K_OPERAND_ADDR16L:
    281     case IP2K_OPERAND_ADDR16H:
    282     case IP2K_OPERAND_LIT8:
    283       /* These may have been processed at parse time.  */
    284       if (fixP->fx_cgen.opinfo != 0)
    285 	result = fixP->fx_cgen.opinfo;
    286       fixP->fx_no_overflow = 1;
    287       break;
    288 
    289     case IP2K_OPERAND_ADDR16CJP:
    290       result = fixP->fx_cgen.opinfo;
    291       if (result == 0 || result == BFD_RELOC_NONE)
    292 	result = BFD_RELOC_IP2K_ADDR16CJP;
    293       fixP->fx_no_overflow = 1;
    294       break;
    295 
    296     case IP2K_OPERAND_ADDR16P:
    297       result = BFD_RELOC_IP2K_PAGE3;
    298       fixP->fx_no_overflow = 1;
    299       break;
    300 
    301     default:
    302       result = BFD_RELOC_NONE;
    303       break;
    304     }
    305 
    306   return result;
    307 }
    308 
    309 
    310 /* Write a value out to the object file, using the appropriate endianness.  */
    311 
    312 void
    313 md_number_to_chars (char * buf, valueT val, int n)
    314 {
    315   number_to_chars_bigendian (buf, val, n);
    316 }
    317 
    318 const char *
    319 md_atof (int type, char * litP, int *  sizeP)
    320 {
    321   return ieee_md_atof (type, litP, sizeP, TRUE);
    322 }
    323 
    324 
    325 /* See whether we need to force a relocation into the output file.
    326    Force most of them, since the linker's bfd relocation engine
    327    understands range limits better than gas' cgen fixup engine.
    328    Consider the case of a fixup intermediate value being larger than
    329    the instruction it will be eventually encoded within.  */
    330 
    331 int
    332 ip2k_force_relocation (fixS * fix)
    333 {
    334   switch (fix->fx_r_type)
    335     {
    336     case BFD_RELOC_IP2K_FR9:
    337     case BFD_RELOC_IP2K_FR_OFFSET:
    338     case BFD_RELOC_IP2K_BANK:
    339     case BFD_RELOC_IP2K_ADDR16CJP:
    340     case BFD_RELOC_IP2K_PAGE3:
    341     case BFD_RELOC_IP2K_LO8DATA:
    342     case BFD_RELOC_IP2K_HI8DATA:
    343     case BFD_RELOC_IP2K_EX8DATA:
    344     case BFD_RELOC_IP2K_LO8INSN:
    345     case BFD_RELOC_IP2K_HI8INSN:
    346     case BFD_RELOC_IP2K_PC_SKIP:
    347     case BFD_RELOC_IP2K_TEXT:
    348       return 1;
    349 
    350     case BFD_RELOC_16:
    351       if (fix->fx_subsy && S_IS_DEFINED (fix->fx_subsy)
    352 	  && fix->fx_addsy && S_IS_DEFINED (fix->fx_addsy)
    353 	  && (S_GET_SEGMENT (fix->fx_addsy)->flags & SEC_CODE))
    354 	{
    355 	  fix->fx_r_type = BFD_RELOC_IP2K_TEXT;
    356 	  return 0;
    357 	}
    358       break;
    359 
    360     default:
    361       break;
    362     }
    363 
    364   return generic_force_reloc (fix);
    365 }
    366 
    367 void
    368 ip2k_apply_fix (fixS *fixP, valueT *valueP, segT seg)
    369 {
    370   if (fixP->fx_r_type == BFD_RELOC_IP2K_TEXT
    371       && ! fixP->fx_addsy
    372       && ! fixP->fx_subsy)
    373     {
    374       *valueP = ((int)(* valueP)) / 2;
    375       fixP->fx_r_type = BFD_RELOC_16;
    376     }
    377   else if (fixP->fx_r_type == BFD_RELOC_UNUSED + IP2K_OPERAND_FR)
    378     {
    379       /* Must be careful when we are fixing up an FR.  We could be
    380 	 fixing up an offset to (SP) or (DP) in which case we don't
    381 	 want to step on the top 2 bits of the FR operand.  The
    382 	 gas_cgen_md_apply_fix doesn't know any better and overwrites
    383 	 the entire operand.  We counter this by adding the bits
    384 	 to the new value.  */
    385       char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
    386 
    387       /* Canonical name, since used a lot.  */
    388       CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
    389       CGEN_INSN_INT insn_value
    390 	= cgen_get_insn_value (cd, (unsigned char *) where,
    391 			       CGEN_INSN_BITSIZE (fixP->fx_cgen.insn));
    392       /* Preserve (DP) or (SP) specification.  */
    393       *valueP += (insn_value & 0x180);
    394     }
    395 
    396   gas_cgen_md_apply_fix (fixP, valueP, seg);
    397 }
    398 
    399 int
    400 ip2k_elf_section_flags (flagword flags,
    401 			bfd_vma attr ATTRIBUTE_UNUSED,
    402 			int type ATTRIBUTE_UNUSED)
    403 {
    404   /* This is used to detect when the section changes to an executable section.
    405      This function is called by the elf section processing.  When we note an
    406      executable section specifier we set an internal flag to denote when
    407      word alignment should be forced.  */
    408   if (flags & SEC_CODE)
    409     force_code_align = 1;
    410 
    411   return flags;
    412 }
    413 
    414