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)
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. */
25 #include "opcodes/ip2k-desc.h"
26 #include "opcodes/ip2k-opc.h"
28 #include "elf/common.h"
32 /* Structure to hold all of the different components describing
33 an individual instruction. */
36 const CGEN_INSN
* insn
;
37 const CGEN_INSN
* orig_insn
;
40 CGEN_INSN_INT buffer
[1];
41 #define INSN_VALUE(buf) (*(buf))
43 unsigned char buffer
[CGEN_MAX_INSN_SIZE
];
44 #define INSN_VALUE(buf) (buf)
49 fixS
* fixups
[GAS_CGEN_MAX_FIXUPS
];
50 int indices
[MAX_OPERAND_INSTANCES
];
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 },
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
88 static int force_code_align
= 0;
90 /* Mach selected from command line. */
92 unsigned ip2k_mach_bitmask
= 0;
95 md_parse_option (c
, arg
)
96 int c ATTRIBUTE_UNUSED
;
97 char * arg ATTRIBUTE_UNUSED
;
101 case OPTION_CPU_IP2022
:
102 ip2k_mach
= bfd_mach_ip2022
;
103 ip2k_mach_bitmask
= 1 << MACH_IP2022
;
106 case OPTION_CPU_IP2022EXT
:
107 ip2k_mach
= bfd_mach_ip2022ext
;
108 ip2k_mach_bitmask
= 1 << MACH_IP2022EXT
;
120 md_show_usage (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"));
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
,
137 CGEN_CPU_OPEN_ENDIAN
,
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
);
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
);
165 as_bad ("%s", errmsg
);
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
;
177 const char *curpc_plus_2
= ".+2";
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
);
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
);
197 md_section_align (segment
, size
)
201 int align
= bfd_get_section_alignment (stdoutput
, segment
);
203 return ((size
+ (1 << align
) - 1) & (-1 << align
));
208 md_undefined_symbol (name
)
209 char * name ATTRIBUTE_UNUSED
;
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"));
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. */
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. */
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;
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;
286 case IP2K_OPERAND_ADDR16P
:
287 result
= BFD_RELOC_IP2K_PAGE3
;
288 fixP
->fx_no_overflow
= 1;
292 result
= BFD_RELOC_NONE
;
300 /* Write a value out to the object file, using the appropriate endianness. */
303 md_number_to_chars (buf
, val
, 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
316 /* Equal to MAX_PRECISION in atof-ieee.c */
317 #define MAX_LITTLENUMS 6
320 md_atof (type
, litP
, sizeP
)
326 LITTLENUM_TYPE words
[MAX_LITTLENUMS
];
327 LITTLENUM_TYPE
*wordP
;
346 /* FIXME: Some targets allow other format chars for bigger sizes here. */
350 return _("Bad call to md_atof()");
353 t
= atof_ieee (input_line_pointer
, type
, words
);
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
);
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
)
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
:
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
;
410 return generic_force_reloc (fix
);
414 ip2k_apply_fix3 (fixP
, valueP
, seg
)
419 if (fixP
->fx_r_type
== BFD_RELOC_IP2K_TEXT
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
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
)
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;
465 ip2k_elf_section_rtn (int 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
475 char *old_input_line_pointer
= input_line_pointer
;
476 input_line_pointer
= "\n";
478 force_code_align
= 0;
480 input_line_pointer
= old_input_line_pointer
;
485 ip2k_elf_section_text (int i
)
487 char *old_input_line_pointer
;
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
494 old_input_line_pointer
= input_line_pointer
;
495 input_line_pointer
= "\n";
497 force_code_align
= 0;
499 input_line_pointer
= old_input_line_pointer
;