2006-05-11 Paul Brook <paul@codesourcery.com>
[binutils.git] / gas / config / tc-xc16x.c
blob7a369b42ec29ce8e74444492f6e47de8ef10e897
1 /* tc-xc16x.c -- Assembler for the Infineon XC16X.
2 Copyright 2006 Free Software Foundation, Inc.
3 Contributed by KPIT Cummins Infosystems
5 This file is part of GAS, the GNU Assembler.
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.
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.
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. */
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"
35 #ifdef OBJ_ELF
36 #include "elf/xc16x.h"
37 #endif
39 /* Structure to hold all of the different components describing
40 an individual instruction. */
41 typedef struct
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];
59 xc16x_insn;
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";
67 #define XC16X_SHORTOPTS ""
68 const char * md_shortopts = XC16X_SHORTOPTS;
70 struct option md_longopts[] =
72 {NULL, no_argument, NULL, 0}
74 size_t md_longopts_size = sizeof (md_longopts);
76 static void
77 xc16xlmode (int arg ATTRIBUTE_UNUSED)
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"));
84 static void
85 xc16xsmode (int arg ATTRIBUTE_UNUSED)
87 if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16xs))
88 as_warn (_("could not set architecture and machine"));
91 static void
92 xc16xmode (int arg ATTRIBUTE_UNUSED)
94 if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16x))
95 as_warn (_("could not set architecture and machine"));
98 /* The target specific pseudo-ops which we support. */
99 const pseudo_typeS md_pseudo_table[] =
101 { "word", cons, 2 },
102 {"xc16xl", xc16xlmode, 0},
103 {"xc16xs", xc16xsmode, 0},
104 {"xc16x", xc16xmode, 0},
105 { NULL, NULL, 0 }
108 void
109 md_begin (void)
111 /* Initialize the `cgen' interface. */
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);
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);
124 void
125 md_assemble (char *str)
127 xc16x_insn insn;
128 char *errmsg;
130 /* Initialize GAS's cgen interface for a new instruction. */
131 gas_cgen_init_parse ();
133 insn.insn = xc16x_cgen_assemble_insn
134 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
136 if (!insn.insn)
138 as_bad (errmsg);
139 return;
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);
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. */
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)
156 switch (operand->type)
158 case XC16X_OPERAND_REL:
159 fixP->fx_where += 1;
160 fixP->fx_pcrel = 1;
161 return BFD_RELOC_8_PCREL;
163 case XC16X_OPERAND_CADDR:
164 fixP->fx_where += 2;
165 return BFD_RELOC_16;
167 case XC16X_OPERAND_UIMM7:
168 fixP->fx_where += 1;
169 fixP->fx_pcrel = 1;
170 return BFD_RELOC_8_PCREL;
172 case XC16X_OPERAND_UIMM16:
173 case XC16X_OPERAND_MEMORY:
174 fixP->fx_where += 2;
175 return BFD_RELOC_16;
177 case XC16X_OPERAND_UPOF16:
178 fixP->fx_where += 2;
179 return BFD_RELOC_XC16X_POF;
181 case XC16X_OPERAND_UPAG16:
182 fixP->fx_where += 2;
183 return BFD_RELOC_XC16X_PAG;
185 case XC16X_OPERAND_USEG8:
186 fixP->fx_where += 1;
187 return BFD_RELOC_XC16X_SEG;
189 case XC16X_OPERAND_USEG16:
190 case XC16X_OPERAND_USOF16:
191 fixP->fx_where += 2;
192 return BFD_RELOC_XC16X_SOF;
194 default : /* avoid -Wall warning */
195 break;
198 fixP->fx_where += 2;
199 return BFD_RELOC_XC16X_SOF;
202 /* Write a value out to the object file, using the appropriate endianness. */
204 void
205 md_number_to_chars (char * buf, valueT val, int n)
207 number_to_chars_littleendian (buf, val, n);
210 void
211 md_show_usage (FILE * stream)
213 fprintf (stream, _(" XC16X specific command line options:\n"));
217 md_parse_option (int c ATTRIBUTE_UNUSED,
218 char *arg ATTRIBUTE_UNUSED)
220 return 0;
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. */
228 /* Equal to MAX_PRECISION in atof-ieee.c. */
229 #define MAX_LITTLENUMS 6
231 char *
232 md_atof (int type, char *litP, int *sizeP)
234 int i;
235 int prec;
236 LITTLENUM_TYPE words[MAX_LITTLENUMS];
237 char *t;
239 switch (type)
241 case 'f':
242 case 'F':
243 case 's':
244 case 'S':
245 prec = 2;
246 break;
248 case 'd':
249 case 'D':
250 case 'r':
251 case 'R':
252 prec = 4;
253 break;
255 /* FIXME: Some targets allow other format chars for bigger sizes
256 here. */
258 default:
259 *sizeP = 0;
260 return _("Bad call to md_atof()");
263 t = atof_ieee (input_line_pointer, type, words);
264 if (t)
265 input_line_pointer = t;
266 *sizeP = prec * sizeof (LITTLENUM_TYPE);
268 for (i = prec - 1; i >= 0; i--)
270 md_number_to_chars (litP, (valueT) words[i],
271 sizeof (LITTLENUM_TYPE));
272 litP += sizeof (LITTLENUM_TYPE);
275 return NULL;
278 valueT
279 md_section_align (segT segment, valueT size)
281 int align = bfd_get_section_alignment (stdoutput, segment);
282 return ((size + (1 << align) - 1) & (-1 << align));
285 symbolS *
286 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
288 return NULL;
292 md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
293 segT segment_type ATTRIBUTE_UNUSED)
295 printf (_("call tomd_estimate_size_before_relax \n"));
296 abort ();
300 long
301 md_pcrel_from (fixS *fixP)
303 long temp_val;
304 temp_val=fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
306 return temp_val;
309 long
310 md_pcrel_from_section (fixS *fixP, segT sec)
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)))
318 return 0;
321 return md_pcrel_from (fixP);
324 arelent *
325 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
327 arelent *rel;
328 bfd_reloc_code_real_type r_type;
330 if (fixp->fx_addsy && fixp->fx_subsy)
332 if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
333 || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section)
335 as_bad_where (fixp->fx_file, fixp->fx_line,
336 "Difference of symbols in different sections is not supported");
337 return NULL;
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;
347 r_type = fixp->fx_r_type;
349 #define DEBUG 0
350 #if DEBUG
351 fprintf (stderr, "%s\n", bfd_get_reloc_code_name (r_type));
352 fflush(stderr);
353 #endif
355 rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
356 if (rel->howto == NULL)
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;
364 return rel;
367 void
368 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
370 if(!strstr (seg->name,".debug"))
372 if (*valP < 128)
373 *valP /= 2;
374 if (*valP>268435455)
376 *valP = *valP * (-1);
377 *valP /= 2;
378 *valP = 256 - (*valP);
382 gas_cgen_md_apply_fix (fixP, valP, seg);
383 return;
386 void
387 md_convert_frag (bfd *headers ATTRIBUTE_UNUSED,
388 segT seg ATTRIBUTE_UNUSED,
389 fragS *fragP ATTRIBUTE_UNUSED)
391 printf (_("call to md_convert_frag \n"));
392 abort ();