diff options
author | Jing Yu <jingyu@google.com> | 2011-01-30 22:09:54 -0800 |
---|---|---|
committer | Jing Yu <jingyu@google.com> | 2011-01-30 22:09:54 -0800 |
commit | a9a8b9e7e4aee6a3846ba62703283d10849bc0a6 (patch) | |
tree | bfd550c5e600ab0c227d3615fb5183127604870d /binutils-2.20.1/gas/config/tc-fr30.c | |
parent | 8a5a8339de3149b7f99caf08e9cb72467d60cd01 (diff) | |
download | toolchain_binutils-a9a8b9e7e4aee6a3846ba62703283d10849bc0a6.zip toolchain_binutils-a9a8b9e7e4aee6a3846ba62703283d10849bc0a6.tar.gz toolchain_binutils-a9a8b9e7e4aee6a3846ba62703283d10849bc0a6.tar.bz2 |
Upgrade binutils and gold.
upgrade binutils-2.19 to binutils-2.20.1
upgrade gold to a relatively new version binutils-20100303
Before, both binutils and gold were built from binutils-2.19.
Now binutils will be built from binutils-2.20.1 and gold will
be built from binutils-20100303.
Change-Id: Ibd0130756723337d2b4783d5b1d5e5b02a1adc83
Diffstat (limited to 'binutils-2.20.1/gas/config/tc-fr30.c')
-rw-r--r-- | binutils-2.20.1/gas/config/tc-fr30.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/binutils-2.20.1/gas/config/tc-fr30.c b/binutils-2.20.1/gas/config/tc-fr30.c new file mode 100644 index 0000000..8e01fb2 --- /dev/null +++ b/binutils-2.20.1/gas/config/tc-fr30.c @@ -0,0 +1,420 @@ +/* tc-fr30.c -- Assembler for the Fujitsu FR30. + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007, 2009 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#include "as.h" +#include "safe-ctype.h" +#include "subsegs.h" +#include "symcat.h" +#include "opcodes/fr30-desc.h" +#include "opcodes/fr30-opc.h" +#include "cgen.h" + +/* Structure to hold all of the different components describing + an individual instruction. */ +typedef struct +{ + const CGEN_INSN * insn; + const CGEN_INSN * orig_insn; + CGEN_FIELDS fields; +#if CGEN_INT_INSN_P + CGEN_INSN_INT buffer [1]; +#define INSN_VALUE(buf) (*(buf)) +#else + unsigned char buffer [CGEN_MAX_INSN_SIZE]; +#define INSN_VALUE(buf) (buf) +#endif + char * addr; + fragS * frag; + int num_fixups; + fixS * fixups [GAS_CGEN_MAX_FIXUPS]; + int indices [MAX_OPERAND_INSTANCES]; +} +fr30_insn; + +const char comment_chars[] = ";"; +const char line_comment_chars[] = "#"; +const char line_separator_chars[] = "|"; +const char EXP_CHARS[] = "eE"; +const char FLT_CHARS[] = "dD"; + +#define FR30_SHORTOPTS "" +const char * md_shortopts = FR30_SHORTOPTS; + +struct option md_longopts[] = +{ + {NULL, no_argument, NULL, 0} +}; +size_t md_longopts_size = sizeof (md_longopts); + +int +md_parse_option (int c ATTRIBUTE_UNUSED, + char *arg ATTRIBUTE_UNUSED) +{ + switch (c) + { + default: + return 0; + } + return 1; +} + +void +md_show_usage (FILE * stream) +{ + fprintf (stream, _(" FR30 specific command line options:\n")); +} + +/* The target specific pseudo-ops which we support. */ +const pseudo_typeS md_pseudo_table[] = +{ + { "word", cons, 4 }, + { NULL, NULL, 0 } +}; + + +void +md_begin (void) +{ + /* Initialize the `cgen' interface. */ + + /* Set the machine number and endian. */ + gas_cgen_cpu_desc = fr30_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0, + CGEN_CPU_OPEN_ENDIAN, + CGEN_ENDIAN_BIG, + CGEN_CPU_OPEN_END); + fr30_cgen_init_asm (gas_cgen_cpu_desc); + + /* This is a callback from cgen to gas to parse operands. */ + cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand); +} + +void +md_assemble (char *str) +{ + static int last_insn_had_delay_slot = 0; + fr30_insn insn; + char *errmsg; + + /* Initialize GAS's cgen interface for a new instruction. */ + gas_cgen_init_parse (); + + insn.insn = fr30_cgen_assemble_insn + (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg); + + if (!insn.insn) + { + as_bad ("%s", errmsg); + return; + } + + /* Doesn't really matter what we pass for RELAX_P here. */ + gas_cgen_finish_insn (insn.insn, insn.buffer, + CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL); + + /* Warn about invalid insns in delay slots. */ + if (last_insn_had_delay_slot + && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_NOT_IN_DELAY_SLOT)) + as_warn (_("Instruction %s not allowed in a delay slot."), + CGEN_INSN_NAME (insn.insn)); + + last_insn_had_delay_slot + = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT); +} + +/* The syntax in the manual says constants begin with '#'. + We just ignore it. */ + +void +md_operand (expressionS * expressionP) +{ + if (* input_line_pointer == '#') + { + input_line_pointer ++; + expression (expressionP); + } +} + +valueT +md_section_align (segT segment, valueT size) +{ + int align = bfd_get_section_alignment (stdoutput, segment); + + return ((size + (1 << align) - 1) & (-1 << align)); +} + +symbolS * +md_undefined_symbol (char *name ATTRIBUTE_UNUSED) +{ + return NULL; +} + +/* Interface to relax_segment. */ + +/* FIXME: Build table by hand, get it working, then machine generate. */ + +const relax_typeS md_relax_table[] = +{ +/* The fields are: + 1) most positive reach of this state, + 2) most negative reach of this state, + 3) how many bytes this mode will add to the size of the current frag + 4) which index into the table to try if we can't fit into this one. */ + + /* The first entry must be unused because an `rlx_more' value of zero ends + each list. */ + {1, 1, 0, 0}, + + /* The displacement used by GAS is from the end of the 2 byte insn, + so we subtract 2 from the following. */ + /* 16 bit insn, 8 bit disp -> 10 bit range. + This doesn't handle a branch in the right slot at the border: + the "& -4" isn't taken into account. It's not important enough to + complicate things over it, so we subtract an extra 2 (or + 2 in -ve + case). */ + {511 - 2 - 2, -512 - 2 + 2, 0, 2 }, + /* 32 bit insn, 24 bit disp -> 26 bit range. */ + {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 }, + /* Same thing, but with leading nop for alignment. */ + {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 } +}; + +/* Return an initial guess of the length by which a fragment must grow to + hold a branch to reach its destination. + Also updates fr_type/fr_subtype as necessary. + + Called just before doing relaxation. + Any symbol that is now undefined will not become defined. + The guess for fr_var is ACTUALLY the growth beyond fr_fix. + Whatever we do to grow fr_fix or fr_var contributes to our returned value. + Although it may not be explicit in the frag, pretend fr_var starts with a + 0 value. */ + +int +md_estimate_size_before_relax (fragS * fragP, segT segment) +{ + /* The only thing we have to handle here are symbols outside of the + current segment. They may be undefined or in a different segment in + which case linker scripts may place them anywhere. + However, we can't finish the fragment here and emit the reloc as insn + alignment requirements may move the insn about. */ + + if (S_GET_SEGMENT (fragP->fr_symbol) != segment) + { + /* The symbol is undefined in this segment. + Change the relaxation subtype to the max allowable and leave + all further handling to md_convert_frag. */ + fragP->fr_subtype = 2; + + { + const CGEN_INSN * insn; + int i; + + /* Update the recorded insn. + Fortunately we don't have to look very far. + FIXME: Change this to record in the instruction the next higher + relaxable insn to use. */ + for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++) + { + if ((strcmp (CGEN_INSN_MNEMONIC (insn), + CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn)) + == 0) + && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED)) + break; + } + if (i == 4) + abort (); + + fragP->fr_cgen.insn = insn; + return 2; + } + } + + /* Return the size of the variable part of the frag. */ + return md_relax_table[fragP->fr_subtype].rlx_length; +} + +/* *fragP has been relaxed to its final size, and now needs to have + the bytes inside it modified to conform to the new size. + + Called after relaxation is finished. + fragP->fr_type == rs_machine_dependent. + fragP->fr_subtype is the subtype of what the address relaxed to. */ + +void +md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, + segT sec ATTRIBUTE_UNUSED, + fragS *fragP ATTRIBUTE_UNUSED) +{ +} + +/* Functions concerning relocs. */ + +/* The location from which a PC relative jump should be calculated, + given a PC relative reloc. */ + +long +md_pcrel_from_section (fixS * fixP, segT sec) +{ + if (fixP->fx_addsy != (symbolS *) NULL + && (! S_IS_DEFINED (fixP->fx_addsy) + || S_GET_SEGMENT (fixP->fx_addsy) != sec)) + /* The symbol is undefined (or is defined but not in this section). + Let the linker figure it out. */ + return 0; + + return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1; +} + +/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP. + Returns BFD_RELOC_NONE if no reloc type can be found. + *FIXP may be modified if desired. */ + +bfd_reloc_code_real_type +md_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED, + const CGEN_OPERAND *operand, + fixS *fixP) +{ + switch (operand->type) + { + case FR30_OPERAND_LABEL9: fixP->fx_pcrel = 1; return BFD_RELOC_FR30_9_PCREL; + case FR30_OPERAND_LABEL12: fixP->fx_pcrel = 1; return BFD_RELOC_FR30_12_PCREL; + case FR30_OPERAND_DISP10: return BFD_RELOC_FR30_10_IN_8; + case FR30_OPERAND_DISP9: return BFD_RELOC_FR30_9_IN_8; + case FR30_OPERAND_DISP8: return BFD_RELOC_FR30_8_IN_8; + case FR30_OPERAND_UDISP6: return BFD_RELOC_FR30_6_IN_4; + case FR30_OPERAND_I8: return BFD_RELOC_8; + case FR30_OPERAND_I32: return BFD_RELOC_FR30_48; + case FR30_OPERAND_I20: return BFD_RELOC_FR30_20; + default : /* Avoid -Wall warning. */ + break; + } + + return BFD_RELOC_NONE; +} + +/* Write a value out to the object file, using the appropriate endianness. */ + +void +md_number_to_chars (char * buf, valueT val, int n) +{ + number_to_chars_bigendian (buf, val, n); +} + +char * +md_atof (int type, char * litP, int * sizeP) +{ + return ieee_md_atof (type, litP, sizeP, TRUE); +} + +/* Worker function for fr30_is_colon_insn(). */ +static char +restore_colon (int advance_i_l_p_by) +{ + char c; + + /* Restore the colon, and advance input_line_pointer to + the end of the new symbol. */ + * input_line_pointer = ':'; + input_line_pointer += advance_i_l_p_by; + c = * input_line_pointer; + * input_line_pointer = 0; + + return c; +} + +/* Determines if the symbol starting at START and ending in + a colon that was at the location pointed to by INPUT_LINE_POINTER + (but which has now been replaced bu a NUL) is in fact an + LDI:8, LDI:20, LDI:32, CALL:D. JMP:D, RET:D or Bcc:D instruction. + If it is, then it restores the colon, advances INPUT_LINE_POINTER + to the real end of the instruction/symbol, and returns the character + that really terminated the symbol. Otherwise it returns 0. */ +char +fr30_is_colon_insn (char * start) +{ + char * i_l_p = input_line_pointer; + + /* Check to see if the symbol parsed so far is 'ldi'. */ + if ( (start[0] != 'l' && start[0] != 'L') + || (start[1] != 'd' && start[1] != 'D') + || (start[2] != 'i' && start[2] != 'I') + || start[3] != 0) + { + /* Nope - check to see a 'd' follows the colon. */ + if ( (i_l_p[1] == 'd' || i_l_p[1] == 'D') + && (i_l_p[2] == ' ' || i_l_p[2] == '\t' || i_l_p[2] == '\n')) + { + /* Yup - it might be delay slot instruction. */ + int i; + static char * delay_insns [] = + { + "call", "jmp", "ret", "bra", "bno", + "beq", "bne", "bc", "bnc", "bn", + "bp", "bv", "bnv", "blt", "bge", + "ble", "bgt", "bls", "bhi" + }; + + for (i = sizeof (delay_insns) / sizeof (delay_insns[0]); i--;) + { + char * insn = delay_insns[i]; + int len = strlen (insn); + + if (start [len] != 0) + continue; + + while (len --) + if (TOLOWER (start [len]) != insn [len]) + break; + + if (len == -1) + return restore_colon (1); + } + } + + /* Nope - it is a normal label. */ + return 0; + } + + /* Check to see if the text following the colon is '8'. */ + if (i_l_p[1] == '8' && (i_l_p[2] == ' ' || i_l_p[2] == '\t')) + return restore_colon (2); + + /* Check to see if the text following the colon is '20'. */ + else if (i_l_p[1] == '2' && i_l_p[2] =='0' && (i_l_p[3] == ' ' || i_l_p[3] == '\t')) + return restore_colon (3); + + /* Check to see if the text following the colon is '32'. */ + else if (i_l_p[1] == '3' && i_l_p[2] =='2' && (i_l_p[3] == ' ' || i_l_p[3] == '\t')) + return restore_colon (3); + + return 0; +} + +bfd_boolean +fr30_fix_adjustable (fixS * fixP) +{ + /* We need the symbol name for the VTABLE entries. */ + if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + return 0; + + return 1; +} |