125723Stegge/* tc-xc16x.c -- Assembler for the Infineon XC16X. 225723Stegge Copyright (C) 2006-2017 Free Software Foundation, Inc. 3139823Simp Contributed by KPIT Cummins Infosystems 425723Stegge 525723Stegge This file is part of GAS, the GNU Assembler. 625723Stegge 725723Stegge GAS is free software; you can redistribute it and/or modify 825723Stegge it under the terms of the GNU General Public License as published by 925723Stegge the Free Software Foundation; either version 3, or (at your option) 1025723Stegge any later version. 1125723Stegge 1225723Stegge GAS is distributed in the hope that it will be useful, 1325723Stegge but WITHOUT ANY WARRANTY; without even the implied warranty of 1425723Stegge MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1525723Stegge GNU General Public License for more details. 1625723Stegge 1725723Stegge You should have received a copy of the GNU General Public License 1825723Stegge along with GAS; see the file COPYING. If not, write to the Free 1925723Stegge Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 2025723Stegge 02110-1301, USA. */ 2125723Stegge 2225723Stegge 2325723Stegge#include "as.h" 2425723Stegge#include "safe-ctype.h" 2525723Stegge#include "subsegs.h" 2625723Stegge#include "symcat.h" 2725723Stegge#include "opcodes/xc16x-desc.h" 2825723Stegge#include "opcodes/xc16x-opc.h" 2925723Stegge#include "cgen.h" 3025723Stegge#include "dwarf2dbg.h" 3125723Stegge 3225723Stegge 3325723Stegge#ifdef OBJ_ELF 3425723Stegge#include "elf/xc16x.h" 3525723Stegge#endif 3625723Stegge 3725723Stegge/* Structure to hold all of the different components describing 3825723Stegge an individual instruction. */ 3925723Steggetypedef struct 4025723Stegge{ 4125723Stegge const CGEN_INSN * insn; 4225723Stegge const CGEN_INSN * orig_insn; 4325723Stegge CGEN_FIELDS fields; 4425723Stegge#if CGEN_INT_INSN_P 4583651Speter CGEN_INSN_INT buffer [1]; 4683651Speter#define INSN_VALUE(buf) (*(buf)) 4783651Speter#else 4825723Stegge unsigned char buffer [CGEN_MAX_INSN_SIZE]; 4925723Stegge#define INSN_VALUE(buf) (buf) 50201044Sbz#endif 5130354Sphk char * addr; 5225723Stegge fragS * frag; 5388743Srwatson int num_fixups; 5425723Stegge fixS * fixups [GAS_CGEN_MAX_FIXUPS]; 5525723Stegge int indices [MAX_OPERAND_INSTANCES]; 5634924Sbde} 5725723Steggexc16x_insn; 5825723Stegge 59200471Sbzconst char comment_chars[] = ";"; 60200471Sbzconst char line_comment_chars[] = "#"; 6125723Steggeconst char line_separator_chars[] = ""; 6225723Steggeconst char EXP_CHARS[] = "eE"; 63195202Sdfrconst char FLT_CHARS[] = "dD"; 64195202Sdfr 65195202Sdfr#define XC16X_SHORTOPTS "" 6683651Speterconst char * md_shortopts = XC16X_SHORTOPTS; 6725723Stegge 6825723Steggestruct option md_longopts[] = 6925723Stegge{ 7025723Stegge {NULL, no_argument, NULL, 0} 7125723Stegge}; 7225723Steggesize_t md_longopts_size = sizeof (md_longopts); 7325723Stegge 7425723Steggestatic void 7525723Steggexc16xlmode (int arg ATTRIBUTE_UNUSED) 7625723Stegge{ 7725723Stegge if (stdoutput != NULL) 7825723Stegge if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16xl)) 7925723Stegge as_warn (_("could not set architecture and machine")); 8025723Stegge} 8125723Stegge 8225723Steggestatic void 8325723Steggexc16xsmode (int arg ATTRIBUTE_UNUSED) 8425723Stegge{ 8525723Stegge if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16xs)) 8625723Stegge as_warn (_("could not set architecture and machine")); 8725723Stegge} 8825723Stegge 8925723Steggestatic void 9025723Steggexc16xmode (int arg ATTRIBUTE_UNUSED) 9125723Stegge{ 92122719Salfred if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16x)) 9325723Stegge as_warn (_("could not set architecture and machine")); 9425723Stegge} 9525723Stegge 9625723Stegge/* The target specific pseudo-ops which we support. */ 9725723Steggeconst pseudo_typeS md_pseudo_table[] = 9825723Stegge{ 9925723Stegge { "word", cons, 2 }, 10025723Stegge {"xc16xl", xc16xlmode, 0}, 10125723Stegge {"xc16xs", xc16xsmode, 0}, 10225723Stegge {"xc16x", xc16xmode, 0}, 10325723Stegge { NULL, NULL, 0 } 104122719Salfred}; 10525723Stegge 10625723Steggevoid 10725723Steggemd_begin (void) 10825723Stegge{ 10925723Stegge /* Initialize the `cgen' interface. */ 11025723Stegge 11125723Stegge /* Set the machine number and endian. */ 11225723Stegge gas_cgen_cpu_desc = xc16x_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0, 11325723Stegge CGEN_CPU_OPEN_ENDIAN, 11425723Stegge CGEN_ENDIAN_LITTLE, 11525723Stegge CGEN_CPU_OPEN_END); 11625723Stegge xc16x_cgen_init_asm (gas_cgen_cpu_desc); 11725723Stegge 11825723Stegge /* This is a callback from cgen to gas to parse operands. */ 11925723Stegge cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand); 12025723Stegge} 12125723Stegge 12225723Steggevoid 12325723Steggemd_assemble (char *str) 12425723Stegge{ 12525723Stegge xc16x_insn insn; 12625723Stegge char *errmsg; 12725723Stegge 12825723Stegge /* Initialize GAS's cgen interface for a new instruction. */ 12925723Stegge gas_cgen_init_parse (); 13025723Stegge 13125723Stegge insn.insn = xc16x_cgen_assemble_insn 13225723Stegge (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg); 13325723Stegge 13425723Stegge if (!insn.insn) 13583651Speter { 13683651Speter as_bad ("%s", errmsg); 13725723Stegge return; 13825723Stegge } 13925723Stegge 14025723Stegge /* Doesn't really matter what we pass for RELAX_P here. */ 14125723Stegge gas_cgen_finish_insn (insn.insn, insn.buffer, 14225723Stegge CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL); 14325723Stegge} 14425723Stegge 14525723Stegge/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP. 14625723Stegge Returns BFD_RELOC_NONE if no reloc type can be found. 14725723Stegge *FIXP may be modified if desired. */ 14825723Stegge 14925723Steggebfd_reloc_code_real_type 15025723Steggemd_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED, 15125723Stegge const CGEN_OPERAND *operand, 15225723Stegge fixS *fixP) 15325723Stegge{ 15425723Stegge switch (operand->type) 15525723Stegge { 15625723Stegge case XC16X_OPERAND_REL: 157177599Sru /* ??? Adjust size? */ 15825723Stegge fixP->fx_where += 1; 15925723Stegge fixP->fx_pcrel = 1; 16025723Stegge return BFD_RELOC_8_PCREL; 16125723Stegge 16225723Stegge case XC16X_OPERAND_CADDR: 16325723Stegge fixP->fx_size = 2; 16425723Stegge fixP->fx_where += 2; 16525723Stegge return BFD_RELOC_16; 16625723Stegge 16725723Stegge case XC16X_OPERAND_UIMM7: 16825723Stegge /* ??? Adjust size? */ 16983366Sjulian fixP->fx_where += 1; 17083651Speter fixP->fx_pcrel = 1; 17125723Stegge return BFD_RELOC_8_PCREL; 17225723Stegge 17325723Stegge case XC16X_OPERAND_UIMM16: 17425723Stegge case XC16X_OPERAND_MEMORY: 17525723Stegge fixP->fx_size = 2; 17625723Stegge fixP->fx_where += 2; 17725723Stegge return BFD_RELOC_16; 17825723Stegge 17925723Stegge case XC16X_OPERAND_UPOF16: 18025723Stegge fixP->fx_size = 2; 18125723Stegge fixP->fx_where += 2; 18225723Stegge return BFD_RELOC_XC16X_POF; 18325723Stegge 18425723Stegge case XC16X_OPERAND_UPAG16: 18525723Stegge fixP->fx_size = 2; 18625723Stegge fixP->fx_where += 2; 18725723Stegge return BFD_RELOC_XC16X_PAG; 18825723Stegge 18925723Stegge case XC16X_OPERAND_USEG8: 19025723Stegge /* ??? This is an 8 bit field, why the 16 bit reloc? */ 19183651Speter fixP->fx_where += 1; 19283651Speter return BFD_RELOC_XC16X_SEG; 19325723Stegge 19425723Stegge case XC16X_OPERAND_USEG16: 19528270Swollman case XC16X_OPERAND_USOF16: 19628270Swollman fixP->fx_size = 2; 19728270Swollman fixP->fx_where += 2; 198122719Salfred return BFD_RELOC_XC16X_SOF; 199122719Salfred 20038482Swollman default : /* Avoid -Wall warning. */ 20138482Swollman break; 20225723Stegge } 20325723Stegge 20425723Stegge return BFD_RELOC_NONE; 20525723Stegge} 20667529Stegge 20725723Stegge/* Write a value out to the object file, using the appropriate endianness. */ 20825723Stegge 20925723Steggevoid 21025723Steggemd_number_to_chars (char * buf, valueT val, int n) 21125723Stegge{ 21225723Stegge number_to_chars_littleendian (buf, val, n); 21325723Stegge} 21425723Stegge 21525723Steggevoid 21625723Steggemd_show_usage (FILE * stream) 21725723Stegge{ 21825723Stegge fprintf (stream, _(" XC16X specific command line options:\n")); 219200471Sbz} 220200471Sbz 22125723Steggeint 22225723Steggemd_parse_option (int c ATTRIBUTE_UNUSED, 22325723Stegge const char *arg ATTRIBUTE_UNUSED) 22491406Sjhb{ 22525723Stegge return 0; 22625723Stegge} 22738482Swollman 22838482Swollmanconst char * 22938482Swollmanmd_atof (int type, char *litP, int *sizeP) 230120755Sjeff{ 23138482Swollman return ieee_md_atof (type, litP, sizeP, FALSE); 23238482Swollman} 23338482Swollman 23438482SwollmanvalueT 23538482Swollmanmd_section_align (segT segment, valueT size) 23643309Sdillon{ 23725723Stegge int align = bfd_get_section_alignment (stdoutput, segment); 23825723Stegge return ((size + (1 << align) - 1) & -(1 << align)); 23925723Stegge} 24025723Stegge 24125723SteggesymbolS * 24225723Steggemd_undefined_symbol (char *name ATTRIBUTE_UNUSED) 24338482Swollman{ 24438482Swollman return NULL; 24538482Swollman} 24638482Swollman 24743309Sdillonint 24825723Steggemd_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED, 24925723Stegge segT segment_type ATTRIBUTE_UNUSED) 25025723Stegge{ 25125723Stegge printf (_("call to md_estimate_size_before_relax \n")); 25225723Stegge abort (); 25325723Stegge} 25425723Stegge 25525723Stegge 25628270Swollmanlong 25728270Swollmanmd_pcrel_from (fixS *fixP) 25828270Swollman{ 25925723Stegge long temp_val; 26025723Stegge temp_val=fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; 26125723Stegge 26225723Stegge return temp_val; 26325723Stegge} 26425723Stegge 26583366Sjulianlong 26625723Steggemd_pcrel_from_section (fixS *fixP, segT sec) 26725723Stegge{ 26825723Stegge if (fixP->fx_addsy != (symbolS *) NULL 26925723Stegge && (! S_IS_DEFINED (fixP->fx_addsy) 27025723Stegge || S_GET_SEGMENT (fixP->fx_addsy) != sec 27125723Stegge || S_IS_EXTERNAL (fixP->fx_addsy) 27225723Stegge || S_IS_WEAK (fixP->fx_addsy))) 27325723Stegge { 27425723Stegge return 0; 27525723Stegge } 27625723Stegge 27725723Stegge return md_pcrel_from (fixP); 27825723Stegge} 27925723Stegge 280177599Sruarelent * 28125723Steggetc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) 282122719Salfred{ 28325723Stegge arelent *rel; 28425723Stegge bfd_reloc_code_real_type r_type; 28525723Stegge 28625723Stegge if (fixp->fx_addsy && fixp->fx_subsy) 28725723Stegge { 28825723Stegge if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy)) 28925723Stegge || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section) 29025723Stegge { 29125723Stegge as_bad_where (fixp->fx_file, fixp->fx_line, 29225723Stegge _("Difference of symbols in different sections is not supported")); 29325723Stegge return NULL; 294195202Sdfr } 29525723Stegge } 29625723Stegge 29725723Stegge rel = XNEW (arelent); 29825723Stegge rel->sym_ptr_ptr = XNEW (asymbol *); 29925723Stegge *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); 30025723Stegge rel->address = fixp->fx_frag->fr_address + fixp->fx_where; 30125723Stegge rel->addend = fixp->fx_offset; 30225723Stegge 303143687Sjmg r_type = fixp->fx_r_type; 30425723Stegge 30525723Stegge#define DEBUG 0 30625723Stegge#if DEBUG 30725723Stegge fprintf (stderr, "%s\n", bfd_get_reloc_code_name (r_type)); 30825723Stegge fflush (stderr); 30925723Stegge#endif 31025723Stegge 31125723Stegge rel->howto = bfd_reloc_type_lookup (stdoutput, r_type); 31225723Stegge if (rel->howto == NULL) 31325723Stegge { 314177599Sru as_bad_where (fixp->fx_file, fixp->fx_line, 31528270Swollman _("Cannot represent relocation type %s"), 31683366Sjulian bfd_get_reloc_code_name (r_type)); 31725723Stegge return NULL; 31825723Stegge } 31925723Stegge 32025723Stegge return rel; 32125723Stegge} 32225723Stegge 32325723Steggevoid 32425723Steggemd_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) 32525723Stegge{ 32667529Stegge if (!strstr (seg->name,".debug")) 32767529Stegge { 32867529Stegge if (*valP < 128) 32967529Stegge *valP /= 2; 33067529Stegge if (*valP>268435455) 33167529Stegge { 33267529Stegge *valP = *valP * (-1); 33367529Stegge *valP /= 2; 33425723Stegge *valP = 256 - (*valP); 33525723Stegge } 33625723Stegge } 33725723Stegge 33825723Stegge gas_cgen_md_apply_fix (fixP, valP, seg); 33925723Stegge return; 34025723Stegge} 34125723Stegge 342184205Sdesvoid 34325723Steggemd_convert_frag (bfd *headers ATTRIBUTE_UNUSED, 34425723Stegge segT seg ATTRIBUTE_UNUSED, 34525723Stegge fragS *fragP ATTRIBUTE_UNUSED) 34625723Stegge{ 34725723Stegge printf (_("call to md_convert_frag \n")); 34825723Stegge abort (); 34983651Speter} 35025723Stegge