daily update
[binutils.git] / gas / config / tc-ip2k.c
bloba57bc969f3b9821e80bb8ce2f0755ba02755f033
1 /* tc-ip2k.c -- Assembler for the Scenix IP2xxx.
2 Copyright (C) 2000, 2002, 2003 Free Software Foundation.
4 This file is part of GAS, the GNU Assembler.
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GAS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GAS; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #include <stdio.h>
22 #include "as.h"
23 #include "subsegs.h"
24 #include "symcat.h"
25 #include "opcodes/ip2k-desc.h"
26 #include "opcodes/ip2k-opc.h"
27 #include "cgen.h"
28 #include "elf/common.h"
29 #include "elf/ip2k.h"
30 #include "libbfd.h"
32 /* Structure to hold all of the different components describing
33 an individual instruction. */
34 typedef struct
36 const CGEN_INSN * insn;
37 const CGEN_INSN * orig_insn;
38 CGEN_FIELDS fields;
39 #if CGEN_INT_INSN_P
40 CGEN_INSN_INT buffer [1];
41 #define INSN_VALUE(buf) (*(buf))
42 #else
43 unsigned char buffer [CGEN_MAX_INSN_SIZE];
44 #define INSN_VALUE(buf) (buf)
45 #endif
46 char * addr;
47 fragS * frag;
48 int num_fixups;
49 fixS * fixups [GAS_CGEN_MAX_FIXUPS];
50 int indices [MAX_OPERAND_INSTANCES];
52 ip2k_insn;
54 const char comment_chars[] = ";";
55 const char line_comment_chars[] = "#";
56 const char line_separator_chars[] = "";
57 const char EXP_CHARS[] = "eE";
58 const char FLT_CHARS[] = "dD";
60 static void ip2k_elf_section_text (int);
61 static void ip2k_elf_section_rtn (int);
63 /* The target specific pseudo-ops which we support. */
64 const pseudo_typeS md_pseudo_table[] =
66 { "text", ip2k_elf_section_text, 0 },
67 { "sect", ip2k_elf_section_rtn, 0 },
68 { NULL, NULL, 0 }
73 #define OPTION_CPU_IP2022 (OPTION_MD_BASE)
74 #define OPTION_CPU_IP2022EXT (OPTION_MD_BASE+1)
76 struct option md_longopts[] =
78 { "mip2022", no_argument, NULL, OPTION_CPU_IP2022 },
79 { "mip2022ext", no_argument, NULL, OPTION_CPU_IP2022EXT },
80 { NULL, no_argument, NULL, 0 },
82 size_t md_longopts_size = sizeof (md_longopts);
84 const char * md_shortopts = "";
86 /* Flag to detect when switching to code section where insn alignment is
87 implied. */
88 static int force_code_align = 0;
90 /* Mach selected from command line. */
91 int ip2k_mach = 0;
92 unsigned ip2k_mach_bitmask = 0;
94 int
95 md_parse_option (c, arg)
96 int c ATTRIBUTE_UNUSED;
97 char * arg ATTRIBUTE_UNUSED;
99 switch (c)
101 case OPTION_CPU_IP2022:
102 ip2k_mach = bfd_mach_ip2022;
103 ip2k_mach_bitmask = 1 << MACH_IP2022;
104 break;
106 case OPTION_CPU_IP2022EXT:
107 ip2k_mach = bfd_mach_ip2022ext;
108 ip2k_mach_bitmask = 1 << MACH_IP2022EXT;
109 break;
111 default:
112 return 0;
115 return 1;
119 void
120 md_show_usage (stream)
121 FILE * stream;
123 fprintf (stream, _("IP2K specific command line options:\n"));
124 fprintf (stream, _(" -mip2022 restrict to IP2022 insns \n"));
125 fprintf (stream, _(" -mip2022ext permit extended IP2022 insn\n"));
129 void
130 md_begin ()
132 /* Initialize the `cgen' interface. */
134 /* Set the machine number and endian. */
135 gas_cgen_cpu_desc = ip2k_cgen_cpu_open (CGEN_CPU_OPEN_MACHS,
136 ip2k_mach_bitmask,
137 CGEN_CPU_OPEN_ENDIAN,
138 CGEN_ENDIAN_BIG,
139 CGEN_CPU_OPEN_END);
140 ip2k_cgen_init_asm (gas_cgen_cpu_desc);
142 /* This is a callback from cgen to gas to parse operands. */
143 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
145 /* Set the machine type. */
146 bfd_default_set_arch_mach (stdoutput, bfd_arch_ip2k, ip2k_mach);
150 void
151 md_assemble (str)
152 char * str;
154 ip2k_insn insn;
155 char * errmsg;
157 /* Initialize GAS's cgen interface for a new instruction. */
158 gas_cgen_init_parse ();
160 insn.insn = ip2k_cgen_assemble_insn
161 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
163 if (!insn.insn)
165 as_bad ("%s", errmsg);
166 return;
169 /* Check for special relocation required by SKIP instructions. */
170 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_SKIPA))
171 /* Unconditional skip has a 1-bit relocation of the current pc, so
172 that we emit either sb pcl.0 or snb pcl.0 depending on whether
173 the PCL (pc + 2) >> 1 is odd or even. */
175 enum cgen_parse_operand_result result_type;
176 long value;
177 const char *curpc_plus_2 = ".+2";
178 const char *err;
180 err = cgen_parse_address (gas_cgen_cpu_desc, & curpc_plus_2,
181 IP2K_OPERAND_ADDR16CJP,
182 BFD_RELOC_IP2K_PC_SKIP,
183 & result_type, & value);
184 if (err)
186 as_bad ("%s", err);
187 return;
191 /* Doesn't really matter what we pass for RELAX_P here. */
192 gas_cgen_finish_insn (insn.insn, insn.buffer,
193 CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
196 valueT
197 md_section_align (segment, size)
198 segT segment;
199 valueT size;
201 int align = bfd_get_section_alignment (stdoutput, segment);
203 return ((size + (1 << align) - 1) & (-1 << align));
207 symbolS *
208 md_undefined_symbol (name)
209 char * name ATTRIBUTE_UNUSED;
211 return 0;
215 md_estimate_size_before_relax (fragP, segment)
216 fragS * fragP ATTRIBUTE_UNUSED;
217 segT segment ATTRIBUTE_UNUSED;
219 as_fatal (_("md_estimate_size_before_relax\n"));
220 return 1;
224 /* *fragP has been relaxed to its final size, and now needs to have
225 the bytes inside it modified to conform to the new size.
227 Called after relaxation is finished.
228 fragP->fr_type == rs_machine_dependent.
229 fragP->fr_subtype is the subtype of what the address relaxed to. */
231 void
232 md_convert_frag (abfd, sec, fragP)
233 bfd * abfd ATTRIBUTE_UNUSED;
234 segT sec ATTRIBUTE_UNUSED;
235 fragS * fragP ATTRIBUTE_UNUSED;
240 /* Functions concerning relocs. */
242 long
243 md_pcrel_from (fixP)
244 fixS *fixP;
246 as_fatal (_("md_pcrel_from\n"));
248 /* Return the address of the delay slot. */
249 return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
253 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
254 Returns BFD_RELOC_NONE if no reloc type can be found.
255 *FIXP may be modified if desired. */
257 bfd_reloc_code_real_type
258 md_cgen_lookup_reloc (insn, operand, fixP)
259 const CGEN_INSN * insn ATTRIBUTE_UNUSED;
260 const CGEN_OPERAND * operand;
261 fixS * fixP ATTRIBUTE_UNUSED;
263 bfd_reloc_code_real_type result;
265 result = BFD_RELOC_NONE;
267 switch (operand->type)
269 case IP2K_OPERAND_FR:
270 case IP2K_OPERAND_ADDR16L:
271 case IP2K_OPERAND_ADDR16H:
272 case IP2K_OPERAND_LIT8:
273 /* These may have been processed at parse time. */
274 if (fixP->fx_cgen.opinfo != 0)
275 result = fixP->fx_cgen.opinfo;
276 fixP->fx_no_overflow = 1;
277 break;
279 case IP2K_OPERAND_ADDR16CJP:
280 result = fixP->fx_cgen.opinfo;
281 if (result == 0 || result == BFD_RELOC_NONE)
282 result = BFD_RELOC_IP2K_ADDR16CJP;
283 fixP->fx_no_overflow = 1;
284 break;
286 case IP2K_OPERAND_ADDR16P:
287 result = BFD_RELOC_IP2K_PAGE3;
288 fixP->fx_no_overflow = 1;
289 break;
291 default:
292 result = BFD_RELOC_NONE;
293 break;
296 return result;
300 /* Write a value out to the object file, using the appropriate endianness. */
302 void
303 md_number_to_chars (buf, val, n)
304 char * buf;
305 valueT val;
306 int n;
308 number_to_chars_bigendian (buf, val, n);
311 /* Turn a string in input_line_pointer into a floating point constant of type
312 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
313 emitted is stored in *sizeP . An error message is returned, or NULL on
314 OK. */
316 /* Equal to MAX_PRECISION in atof-ieee.c */
317 #define MAX_LITTLENUMS 6
319 char *
320 md_atof (type, litP, sizeP)
321 char type;
322 char * litP;
323 int * sizeP;
325 int prec;
326 LITTLENUM_TYPE words [MAX_LITTLENUMS];
327 LITTLENUM_TYPE *wordP;
328 char * t;
330 switch (type)
332 case 'f':
333 case 'F':
334 case 's':
335 case 'S':
336 prec = 2;
337 break;
339 case 'd':
340 case 'D':
341 case 'r':
342 case 'R':
343 prec = 4;
344 break;
346 /* FIXME: Some targets allow other format chars for bigger sizes here. */
348 default:
349 * sizeP = 0;
350 return _("Bad call to md_atof()");
353 t = atof_ieee (input_line_pointer, type, words);
354 if (t)
355 input_line_pointer = t;
356 * sizeP = prec * sizeof (LITTLENUM_TYPE);
358 /* This loops outputs the LITTLENUMs in REVERSE order; in accord with
359 the ip2k endianness. */
360 for (wordP = words; prec--;)
362 md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
363 litP += sizeof (LITTLENUM_TYPE);
366 return 0;
370 /* See whether we need to force a relocation into the output file.
371 Force most of them, since the linker's bfd relocation engine
372 understands range limits better than gas' cgen fixup engine.
373 Consider the case of a fixup intermediate value being larger than
374 the instruction it will be eventually encoded within. */
377 ip2k_force_relocation (fix)
378 fixS * fix;
380 switch (fix->fx_r_type)
382 case BFD_RELOC_IP2K_FR9:
383 case BFD_RELOC_IP2K_FR_OFFSET:
384 case BFD_RELOC_IP2K_BANK:
385 case BFD_RELOC_IP2K_ADDR16CJP:
386 case BFD_RELOC_IP2K_PAGE3:
387 case BFD_RELOC_IP2K_LO8DATA:
388 case BFD_RELOC_IP2K_HI8DATA:
389 case BFD_RELOC_IP2K_EX8DATA:
390 case BFD_RELOC_IP2K_LO8INSN:
391 case BFD_RELOC_IP2K_HI8INSN:
392 case BFD_RELOC_IP2K_PC_SKIP:
393 case BFD_RELOC_IP2K_TEXT:
394 return 1;
396 case BFD_RELOC_16:
397 if (fix->fx_subsy && S_IS_DEFINED (fix->fx_subsy)
398 && fix->fx_addsy && S_IS_DEFINED (fix->fx_addsy)
399 && (S_GET_SEGMENT (fix->fx_addsy)->flags & SEC_CODE))
401 fix->fx_r_type = BFD_RELOC_IP2K_TEXT;
402 return 0;
404 break;
406 default:
407 break;
410 return generic_force_reloc (fix);
413 void
414 ip2k_apply_fix3 (fixP, valueP, seg)
415 fixS *fixP;
416 valueT *valueP;
417 segT seg;
419 if (fixP->fx_r_type == BFD_RELOC_IP2K_TEXT
420 && ! fixP->fx_addsy
421 && ! fixP->fx_subsy)
423 *valueP = ((int)(*valueP)) / 2;
424 fixP->fx_r_type = BFD_RELOC_16;
426 else if (fixP->fx_r_type == BFD_RELOC_UNUSED + IP2K_OPERAND_FR)
428 /* Must be careful when we are fixing up an FR. We could be
429 fixing up an offset to (SP) or (DP) in which case we don't
430 want to step on the top 2 bits of the FR operand. The
431 gas_cgen_md_apply_fix3 doesn't know any better and overwrites
432 the entire operand. We counter this by adding the bits
433 to the new value. */
434 char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
436 /* Canonical name, since used a lot. */
437 CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
438 CGEN_INSN_INT insn_value
439 = cgen_get_insn_value (cd, where,
440 CGEN_INSN_BITSIZE (fixP->fx_cgen.insn));
441 /* Preserve (DP) or (SP) specification. */
442 *valueP += (insn_value & 0x180);
445 gas_cgen_md_apply_fix3 (fixP, valueP, seg);
449 ip2k_elf_section_flags (flags, attr, type)
450 int flags;
451 int attr ATTRIBUTE_UNUSED;
452 int type ATTRIBUTE_UNUSED;
454 /* This is used to detect when the section changes to an executable section.
455 This function is called by the elf section processing. When we note an
456 executable section specifier we set an internal flag to denote when
457 word alignment should be forced. */
458 if (flags & SEC_CODE)
459 force_code_align = 1;
461 return flags;
464 static void
465 ip2k_elf_section_rtn (int i)
467 obj_elf_section(i);
469 if (force_code_align)
471 /* The s_align_ptwo function expects that we are just after a .align
472 directive and it will either try and read the align value or stop
473 if end of line so we must fake it out so it thinks we are at the
474 end of the line. */
475 char *old_input_line_pointer = input_line_pointer;
476 input_line_pointer = "\n";
477 s_align_ptwo (1);
478 force_code_align = 0;
479 /* Restore. */
480 input_line_pointer = old_input_line_pointer;
484 static void
485 ip2k_elf_section_text (int i)
487 char *old_input_line_pointer;
488 obj_elf_text(i);
490 /* the s_align_ptwo function expects that we are just after a .align
491 directive and it will either try and read the align value or stop if
492 end of line so we must fake it out so it thinks we are at the end of
493 the line. */
494 old_input_line_pointer = input_line_pointer;
495 input_line_pointer = "\n";
496 s_align_ptwo (1);
497 force_code_align = 0;
498 /* Restore. */
499 input_line_pointer = old_input_line_pointer;