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