1/* tc-xc16x.c -- Assembler for the Infineon XC16X. 2 Copyright (C) 2006-2020 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. */ 39typedef 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} 57xc16x_insn; 58 59const char comment_chars[] = ";"; 60const char line_comment_chars[] = "#"; 61const char line_separator_chars[] = ""; 62const char EXP_CHARS[] = "eE"; 63const char FLT_CHARS[] = "dD"; 64 65#define XC16X_SHORTOPTS "" 66const char * md_shortopts = XC16X_SHORTOPTS; 67 68struct option md_longopts[] = 69{ 70 {NULL, no_argument, NULL, 0} 71}; 72size_t md_longopts_size = sizeof (md_longopts); 73 74static void 75xc16xlmode (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 82static void 83xc16xsmode (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 89static void 90xc16xmode (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. */ 97const 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 106void 107md_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 122void 123md_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 149bfd_reloc_code_real_type 150md_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 209void 210md_number_to_chars (char * buf, valueT val, int n) 211{ 212 number_to_chars_littleendian (buf, val, n); 213} 214 215void 216md_show_usage (FILE * stream) 217{ 218 fprintf (stream, _(" XC16X specific command line options:\n")); 219} 220 221int 222md_parse_option (int c ATTRIBUTE_UNUSED, 223 const char *arg ATTRIBUTE_UNUSED) 224{ 225 return 0; 226} 227 228const char * 229md_atof (int type, char *litP, int *sizeP) 230{ 231 return ieee_md_atof (type, litP, sizeP, FALSE); 232} 233 234valueT 235md_section_align (segT segment, valueT size) 236{ 237 int align = bfd_section_alignment (segment); 238 return ((size + (1 << align) - 1) & -(1 << align)); 239} 240 241symbolS * 242md_undefined_symbol (char *name ATTRIBUTE_UNUSED) 243{ 244 return NULL; 245} 246 247int 248md_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 256long 257md_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 265long 266md_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 280arelent * 281tc_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 = XNEW (arelent); 298 rel->sym_ptr_ptr = XNEW (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 323void 324md_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 342void 343md_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