Commit | Line | Data |
---|---|---|
d70c5fc7 NC |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
205 | md_number_to_chars (char * buf, valueT val, int n) | |
206 | { | |
207 | number_to_chars_littleendian (buf, val, n); | |
208 | } | |
209 | ||
210 | void | |
211 | md_show_usage (FILE * stream) | |
212 | { | |
213 | fprintf (stream, _(" XC16X specific command line options:\n")); | |
214 | } | |
215 | ||
216 | int | |
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 * | |
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 | |
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 * | |
286 | md_undefined_symbol (char *name ATTRIBUTE_UNUSED) | |
287 | { | |
288 | return NULL; | |
289 | } | |
290 | ||
291 | int | |
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 | |
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 | |
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 * | |
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 | |
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 | |
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 |