OSDN Git Service

Update to HEAD.
[pf3gnuchains/pf3gnuchains3x.git] / gas / config / tc-xc16x.c
1 /* tc-xc16x.c -- Assembler for the Infineon XC16X.
2    Copyright 2006, 2007, 2009  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 3, 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 "as.h"
24 #include "safe-ctype.h"
25 #include "subsegs.h"
26 #include "symcat.h"
27 #include "opcodes/xc16x-desc.h"
28 #include "opcodes/xc16x-opc.h"
29 #include "cgen.h"
30 #include "dwarf2dbg.h"
31
32
33 #ifdef OBJ_ELF
34 #include "elf/xc16x.h"
35 #endif
36
37 /* Structure to hold all of the different components describing
38    an individual instruction.  */
39 typedef struct
40 {
41   const CGEN_INSN *     insn;
42   const CGEN_INSN *     orig_insn;
43   CGEN_FIELDS           fields;
44 #if CGEN_INT_INSN_P
45   CGEN_INSN_INT         buffer [1];
46 #define INSN_VALUE(buf) (*(buf))
47 #else
48   unsigned char buffer [CGEN_MAX_INSN_SIZE];
49 #define INSN_VALUE(buf) (buf)
50 #endif
51   char *                addr;
52   fragS *               frag;
53   int                   num_fixups;
54   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
55   int                   indices [MAX_OPERAND_INSTANCES];
56 }
57 xc16x_insn;
58
59 const char comment_chars[]        = ";";
60 const char line_comment_chars[]   = "#";
61 const char line_separator_chars[] = "";
62 const char EXP_CHARS[]            = "eE";
63 const char FLT_CHARS[]            = "dD";
64
65 #define XC16X_SHORTOPTS ""
66 const char * md_shortopts = XC16X_SHORTOPTS;
67
68 struct option md_longopts[] =
69 {
70   {NULL, no_argument, NULL, 0}
71 };
72 size_t md_longopts_size = sizeof (md_longopts);
73
74 static void
75 xc16xlmode (int arg ATTRIBUTE_UNUSED)
76 {
77  if (stdoutput != NULL)
78   if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16xl))
79     as_warn (_("could not set architecture and machine"));
80 }
81
82 static void
83 xc16xsmode (int arg ATTRIBUTE_UNUSED)
84 {
85   if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16xs))
86     as_warn (_("could not set architecture and machine"));
87 }
88
89 static void
90 xc16xmode (int arg ATTRIBUTE_UNUSED)
91 {
92   if (!bfd_set_arch_mach (stdoutput, bfd_arch_xc16x, bfd_mach_xc16x))
93     as_warn (_("could not set architecture and machine"));
94 }
95
96 /* The target specific pseudo-ops which we support.  */
97 const pseudo_typeS md_pseudo_table[] =
98 {
99   { "word",     cons,           2 },
100   {"xc16xl",  xc16xlmode,  0},
101   {"xc16xs", xc16xsmode, 0},
102   {"xc16x",  xc16xmode,  0},
103   { NULL,       NULL,           0 }
104 };
105
106 void
107 md_begin (void)
108 {
109   /* Initialize the `cgen' interface.  */
110
111   /* Set the machine number and endian.  */
112   gas_cgen_cpu_desc = xc16x_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
113                                            CGEN_CPU_OPEN_ENDIAN,
114                                            CGEN_ENDIAN_LITTLE,
115                                            CGEN_CPU_OPEN_END);
116   xc16x_cgen_init_asm (gas_cgen_cpu_desc);
117
118   /* This is a callback from cgen to gas to parse operands.  */
119   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
120 }
121
122 void
123 md_assemble (char *str)
124 {
125   xc16x_insn insn;
126   char *errmsg;
127
128   /* Initialize GAS's cgen interface for a new instruction.  */
129   gas_cgen_init_parse ();
130
131   insn.insn = xc16x_cgen_assemble_insn
132     (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
133
134   if (!insn.insn)
135     {
136       as_bad ("%s", errmsg);
137       return;
138     }
139
140   /* Doesn't really matter what we pass for RELAX_P here.  */
141   gas_cgen_finish_insn (insn.insn, insn.buffer,
142                         CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
143 }
144
145 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
146    Returns BFD_RELOC_NONE if no reloc type can be found.
147    *FIXP may be modified if desired.  */
148
149 bfd_reloc_code_real_type
150 md_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED,
151                       const CGEN_OPERAND *operand,
152                       fixS *fixP)
153 {
154   switch (operand->type)
155     {
156     case XC16X_OPERAND_REL:
157       fixP->fx_where += 1;
158       fixP->fx_pcrel = 1;
159       return BFD_RELOC_8_PCREL;
160
161     case XC16X_OPERAND_CADDR:
162       fixP->fx_where += 2;
163       return BFD_RELOC_16;
164
165     case XC16X_OPERAND_UIMM7:
166       fixP->fx_where += 1;
167       fixP->fx_pcrel = 1;
168       return BFD_RELOC_8_PCREL;
169
170     case XC16X_OPERAND_UIMM16:
171     case XC16X_OPERAND_MEMORY:
172       fixP->fx_where += 2;
173       return BFD_RELOC_16;
174
175     case XC16X_OPERAND_UPOF16:
176       fixP->fx_where += 2;
177       return BFD_RELOC_XC16X_POF;
178
179     case XC16X_OPERAND_UPAG16:
180       fixP->fx_where += 2;
181       return BFD_RELOC_XC16X_PAG;
182
183     case XC16X_OPERAND_USEG8:
184       fixP->fx_where += 1;
185       return BFD_RELOC_XC16X_SEG;
186
187     case XC16X_OPERAND_USEG16:
188     case  XC16X_OPERAND_USOF16:
189       fixP->fx_where += 2;
190       return BFD_RELOC_XC16X_SOF;
191
192     default : /* Avoid -Wall warning.  */
193       break;
194     }
195
196   fixP->fx_where += 2;
197   return BFD_RELOC_XC16X_SOF;
198 }
199
200 /* Write a value out to the object file, using the appropriate endianness.  */
201
202 void
203 md_number_to_chars (char * buf, valueT val, int n)
204 {
205   number_to_chars_littleendian (buf, val, n);
206 }
207
208 void
209 md_show_usage (FILE * stream)
210 {
211   fprintf (stream, _(" XC16X specific command line options:\n"));
212 }
213
214 int
215 md_parse_option (int c ATTRIBUTE_UNUSED,
216                  char *arg ATTRIBUTE_UNUSED)
217 {
218   return 0;
219 }
220
221 char *
222 md_atof (int type, char *litP, int *sizeP)
223 {
224   return ieee_md_atof (type, litP, sizeP, FALSE);
225 }
226
227 valueT
228 md_section_align (segT segment, valueT size)
229 {
230   int align = bfd_get_section_alignment (stdoutput, segment);
231   return ((size + (1 << align) - 1) & (-1 << align));
232 }
233
234 symbolS *
235 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
236 {
237   return NULL;
238 }
239
240 int
241 md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
242                                segT segment_type ATTRIBUTE_UNUSED)
243 {
244   printf (_("call to md_estimate_size_before_relax \n"));
245   abort ();
246 }
247
248
249 long
250 md_pcrel_from (fixS *fixP)
251 {
252   long temp_val;
253   temp_val=fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
254
255   return temp_val;
256 }
257
258 long
259 md_pcrel_from_section (fixS *fixP, segT sec)
260 {
261   if (fixP->fx_addsy != (symbolS *) NULL
262       && (! S_IS_DEFINED (fixP->fx_addsy)
263           || S_GET_SEGMENT (fixP->fx_addsy) != sec
264           || S_IS_EXTERNAL (fixP->fx_addsy)
265           || S_IS_WEAK (fixP->fx_addsy)))
266     {
267       return 0;
268     }
269
270   return md_pcrel_from (fixP);
271 }
272
273 arelent *
274 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
275 {
276   arelent *rel;
277   bfd_reloc_code_real_type r_type;
278
279   if (fixp->fx_addsy && fixp->fx_subsy)
280     {
281       if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
282           || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section)
283         {
284           as_bad_where (fixp->fx_file, fixp->fx_line,
285                         _("Difference of symbols in different sections is not supported"));
286           return NULL;
287         }
288     }
289
290   rel = xmalloc (sizeof (arelent));
291   rel->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
292   *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
293   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
294   rel->addend = fixp->fx_offset;
295
296   r_type = fixp->fx_r_type;
297
298 #define DEBUG 0
299 #if DEBUG
300   fprintf (stderr, "%s\n", bfd_get_reloc_code_name (r_type));
301   fflush (stderr);
302 #endif
303
304   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
305    if (rel->howto == NULL)
306     {
307       as_bad_where (fixp->fx_file, fixp->fx_line,
308                     _("Cannot represent relocation type %s"),
309                     bfd_get_reloc_code_name (r_type));
310       return NULL;
311     }
312
313   return rel;
314 }
315
316 void
317 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
318 {
319   if (!strstr (seg->name,".debug"))
320     {
321       if (*valP < 128)
322         *valP /= 2;
323       if (*valP>268435455)
324         {
325           *valP = *valP * (-1);
326           *valP /= 2;
327           *valP = 256 - (*valP);
328         }
329     }
330   
331   gas_cgen_md_apply_fix (fixP, valP, seg);
332   return;
333 }
334
335 void
336 md_convert_frag (bfd *headers ATTRIBUTE_UNUSED,
337                  segT seg ATTRIBUTE_UNUSED,
338                  fragS *fragP ATTRIBUTE_UNUSED)
339 {
340   printf (_("call to md_convert_frag \n"));
341   abort ();
342 }