1 /* tc-xc16x.c -- Assembler for the Infineon XC16X. 2 Copyright 2006 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 2, 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 <stdio.h> 24 #include "as.h" 25 #include "safe-ctype.h" 26 #include "subsegs.h" 27 #include "symcat.h" 28 #include "opcodes/xc16x-desc.h" 29 #include "opcodes/xc16x-opc.h" 30 #include "cgen.h" 31 #include "bfd.h" 32 #include "dwarf2dbg.h" 33 34 35 #ifdef OBJ_ELF 36 #include "elf/xc16x.h" 37 #endif 38 39 /* Structure to hold all of the different components describing 40 an individual instruction. */ 41 typedef struct 42 { 43 const CGEN_INSN * insn; 44 const CGEN_INSN * orig_insn; 45 CGEN_FIELDS fields; 46 #if CGEN_INT_INSN_P 47 CGEN_INSN_INT buffer [1]; 48 #define INSN_VALUE(buf) (*(buf)) 49 #else 50 unsigned char buffer [CGEN_MAX_INSN_SIZE]; 51 #define INSN_VALUE(buf) (buf) 52 #endif 53 char * addr; 54 fragS * frag; 55 int num_fixups; 56 fixS * fixups [GAS_CGEN_MAX_FIXUPS]; 57 int indices [MAX_OPERAND_INSTANCES]; 58 } 59 xc16x_insn; 60 61 const char comment_chars[] = ";"; 62 const char line_comment_chars[] = "#"; 63 const char line_separator_chars[] = ""; 64 const char EXP_CHARS[] = "eE"; 65 const char FLT_CHARS[] = "dD"; 66 67 #define XC16X_SHORTOPTS "" 68 const char * md_shortopts = XC16X_SHORTOPTS; 69 70 struct option md_longopts[] = 71 { 72 {NULL, no_argument, NULL, 0} 73 }; 74 size_t md_longopts_size = sizeof (md_longopts); 75 76 static void 77 xc16xlmode (int arg ATTRIBUTE_UNUSED) 78 { 79 if (stdoutput != NULL) 80 if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16xl)) 81 as_warn (_("could not set architecture and machine")); 82 } 83 84 static void 85 xc16xsmode (int arg ATTRIBUTE_UNUSED) 86 { 87 if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16xs)) 88 as_warn (_("could not set architecture and machine")); 89 } 90 91 static void 92 xc16xmode (int arg ATTRIBUTE_UNUSED) 93 { 94 if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16x)) 95 as_warn (_("could not set architecture and machine")); 96 } 97 98 /* The target specific pseudo-ops which we support. */ 99 const pseudo_typeS md_pseudo_table[] = 100 { 101 { "word", cons, 2 }, 102 {"xc16xl", xc16xlmode, 0}, 103 {"xc16xs", xc16xsmode, 0}, 104 {"xc16x", xc16xmode, 0}, 105 { NULL, NULL, 0 } 106 }; 107 108 void 109 md_begin (void) 110 { 111 /* Initialize the `cgen' interface. */ 112 113 /* Set the machine number and endian. */ 114 gas_cgen_cpu_desc = xc16x_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0, 115 CGEN_CPU_OPEN_ENDIAN, 116 CGEN_ENDIAN_LITTLE, 117 CGEN_CPU_OPEN_END); 118 xc16x_cgen_init_asm (gas_cgen_cpu_desc); 119 120 /* This is a callback from cgen to gas to parse operands. */ 121 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand); 122 } 123 124 void 125 md_assemble (char *str) 126 { 127 xc16x_insn insn; 128 char *errmsg; 129 130 /* Initialize GAS's cgen interface for a new instruction. */ 131 gas_cgen_init_parse (); 132 133 insn.insn = xc16x_cgen_assemble_insn 134 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg); 135 136 if (!insn.insn) 137 { 138 as_bad (errmsg); 139 return; 140 } 141 142 /* Doesn't really matter what we pass for RELAX_P here. */ 143 gas_cgen_finish_insn (insn.insn, insn.buffer, 144 CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL); 145 } 146 147 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP. 148 Returns BFD_RELOC_NONE if no reloc type can be found. 149 *FIXP may be modified if desired. */ 150 151 bfd_reloc_code_real_type 152 md_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED, 153 const CGEN_OPERAND *operand, 154 fixS *fixP) 155 { 156 switch (operand->type) 157 { 158 case XC16X_OPERAND_REL: 159 fixP->fx_where += 1; 160 fixP->fx_pcrel = 1; 161 return BFD_RELOC_8_PCREL; 162 163 case XC16X_OPERAND_CADDR: 164 fixP->fx_where += 2; 165 return BFD_RELOC_16; 166 167 case XC16X_OPERAND_UIMM7: 168 fixP->fx_where += 1; 169 fixP->fx_pcrel = 1; 170 return BFD_RELOC_8_PCREL; 171 172 case XC16X_OPERAND_UIMM16: 173 case XC16X_OPERAND_MEMORY: 174 fixP->fx_where += 2; 175 return BFD_RELOC_16; 176 177 case XC16X_OPERAND_UPOF16: 178 fixP->fx_where += 2; 179 return BFD_RELOC_XC16X_POF; 180 181 case XC16X_OPERAND_UPAG16: 182 fixP->fx_where += 2; 183 return BFD_RELOC_XC16X_PAG; 184 185 case XC16X_OPERAND_USEG8: 186 fixP->fx_where += 1; 187 return BFD_RELOC_XC16X_SEG; 188 189 case XC16X_OPERAND_USEG16: 190 case XC16X_OPERAND_USOF16: 191 fixP->fx_where += 2; 192 return BFD_RELOC_XC16X_SOF; 193 194 default : /* avoid -Wall warning */ 195 break; 196 } 197 198 fixP->fx_where += 2; 199 return BFD_RELOC_XC16X_SOF; 200 } 201 202 /* Write a value out to the object file, using the appropriate endianness. */ 203 204 void 205 md_number_to_chars (char * buf, valueT val, int n) 206 { 207 number_to_chars_littleendian (buf, val, n); 208 } 209 210 void 211 md_show_usage (FILE * stream) 212 { 213 fprintf (stream, _(" XC16X specific command line options:\n")); 214 } 215 216 int 217 md_parse_option (int c ATTRIBUTE_UNUSED, 218 char *arg ATTRIBUTE_UNUSED) 219 { 220 return 0; 221 } 222 223 /* Turn a string in input_line_pointer into a floating point constant 224 of type TYPE, and store the appropriate bytes in *LITP. The number 225 of LITTLENUMS emitted is stored in *SIZEP. An error message is 226 returned, or NULL on OK. */ 227 228 /* Equal to MAX_PRECISION in atof-ieee.c. */ 229 #define MAX_LITTLENUMS 6 230 231 char * 232 md_atof (int type, char *litP, int *sizeP) 233 { 234 int i; 235 int prec; 236 LITTLENUM_TYPE words[MAX_LITTLENUMS]; 237 char *t; 238 239 switch (type) 240 { 241 case 'f': 242 case 'F': 243 case 's': 244 case 'S': 245 prec = 2; 246 break; 247 248 case 'd': 249 case 'D': 250 case 'r': 251 case 'R': 252 prec = 4; 253 break; 254 255 /* FIXME: Some targets allow other format chars for bigger sizes 256 here. */ 257 258 default: 259 *sizeP = 0; 260 return _("Bad call to md_atof()"); 261 } 262 263 t = atof_ieee (input_line_pointer, type, words); 264 if (t) 265 input_line_pointer = t; 266 *sizeP = prec * sizeof (LITTLENUM_TYPE); 267 268 for (i = prec - 1; i >= 0; i--) 269 { 270 md_number_to_chars (litP, (valueT) words[i], 271 sizeof (LITTLENUM_TYPE)); 272 litP += sizeof (LITTLENUM_TYPE); 273 } 274 275 return NULL; 276 } 277 278 valueT 279 md_section_align (segT segment, valueT size) 280 { 281 int align = bfd_get_section_alignment (stdoutput, segment); 282 return ((size + (1 << align) - 1) & (-1 << align)); 283 } 284 285 symbolS * 286 md_undefined_symbol (char *name ATTRIBUTE_UNUSED) 287 { 288 return NULL; 289 } 290 291 int 292 md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED, 293 segT segment_type ATTRIBUTE_UNUSED) 294 { 295 printf (_("call tomd_estimate_size_before_relax \n")); 296 abort (); 297 } 298 299 300 long 301 md_pcrel_from (fixS *fixP) 302 { 303 long temp_val; 304 temp_val=fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; 305 306 return temp_val; 307 } 308 309 long 310 md_pcrel_from_section (fixS *fixP, segT sec) 311 { 312 if (fixP->fx_addsy != (symbolS *) NULL 313 && (! S_IS_DEFINED (fixP->fx_addsy) 314 || S_GET_SEGMENT (fixP->fx_addsy) != sec 315 || S_IS_EXTERNAL (fixP->fx_addsy) 316 || S_IS_WEAK (fixP->fx_addsy))) 317 { 318 return 0; 319 } 320 321 return md_pcrel_from (fixP); 322 } 323 324 arelent * 325 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) 326 { 327 arelent *rel; 328 bfd_reloc_code_real_type r_type; 329 330 if (fixp->fx_addsy && fixp->fx_subsy) 331 { 332 if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy)) 333 || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section) 334 { 335 as_bad_where (fixp->fx_file, fixp->fx_line, 336 "Difference of symbols in different sections is not supported"); 337 return NULL; 338 } 339 } 340 341 rel = xmalloc (sizeof (arelent)); 342 rel->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); 343 *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); 344 rel->address = fixp->fx_frag->fr_address + fixp->fx_where; 345 rel->addend = fixp->fx_offset; 346 347 r_type = fixp->fx_r_type; 348 349 #define DEBUG 0 350 #if DEBUG 351 fprintf (stderr, "%s\n", bfd_get_reloc_code_name (r_type)); 352 fflush(stderr); 353 #endif 354 355 rel->howto = bfd_reloc_type_lookup (stdoutput, r_type); 356 if (rel->howto == NULL) 357 { 358 as_bad_where (fixp->fx_file, fixp->fx_line, 359 _("Cannot represent relocation type %s"), 360 bfd_get_reloc_code_name (r_type)); 361 return NULL; 362 } 363 364 return rel; 365 } 366 367 void 368 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) 369 { 370 if(!strstr (seg->name,".debug")) 371 { 372 if (*valP < 128) 373 *valP /= 2; 374 if (*valP>268435455) 375 { 376 *valP = *valP * (-1); 377 *valP /= 2; 378 *valP = 256 - (*valP); 379 } 380 } 381 382 gas_cgen_md_apply_fix (fixP, valP, seg); 383 return; 384 } 385 386 void 387 md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, 388 segT seg ATTRIBUTE_UNUSED, 389 fragS *fragP ATTRIBUTE_UNUSED) 390 { 391 printf (_("call to md_convert_frag \n")); 392 abort (); 393 } 394 395 396