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
xc16xlmode(int arg ATTRIBUTE_UNUSED)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
xc16xsmode(int arg ATTRIBUTE_UNUSED)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
xc16xmode(int arg ATTRIBUTE_UNUSED)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
md_begin(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
md_assemble(char * str)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
md_cgen_lookup_reloc(const CGEN_INSN * insn ATTRIBUTE_UNUSED,const CGEN_OPERAND * operand,fixS * fixP)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
md_number_to_chars(char * buf,valueT val,int n)205 md_number_to_chars (char * buf, valueT val, int n)
206 {
207   number_to_chars_littleendian (buf, val, n);
208 }
209 
210 void
md_show_usage(FILE * stream)211 md_show_usage (FILE * stream)
212 {
213   fprintf (stream, _(" XC16X specific command line options:\n"));
214 }
215 
216 int
md_parse_option(int c ATTRIBUTE_UNUSED,char * arg ATTRIBUTE_UNUSED)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 *
md_atof(int type,char * litP,int * sizeP)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
md_section_align(segT segment,valueT size)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 *
md_undefined_symbol(char * name ATTRIBUTE_UNUSED)286 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
287 {
288   return NULL;
289 }
290 
291 int
md_estimate_size_before_relax(fragS * fragP ATTRIBUTE_UNUSED,segT segment_type ATTRIBUTE_UNUSED)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
md_pcrel_from(fixS * fixP)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
md_pcrel_from_section(fixS * fixP,segT sec)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 *
tc_gen_reloc(asection * section ATTRIBUTE_UNUSED,fixS * fixp)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
md_apply_fix(fixS * fixP,valueT * valP,segT seg ATTRIBUTE_UNUSED)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
md_convert_frag(bfd * headers ATTRIBUTE_UNUSED,segT seg ATTRIBUTE_UNUSED,fragS * fragP ATTRIBUTE_UNUSED)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