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