X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-mn10200.c;h=0558a3751d9bcce7ca0f7d27f0d8107eb61adc73;hb=de54374205650be71237ce51ef7981d30ddd78dc;hp=dcb3e7d214924af1bb433a5b174749d092ae6537;hpb=5545556dc85e221ea02f29e53d424b36f40f9542;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-mn10200.c b/gas/config/tc-mn10200.c index dcb3e7d214..0558a3751d 100644 --- a/gas/config/tc-mn10200.c +++ b/gas/config/tc-mn10200.c @@ -1,12 +1,11 @@ /* tc-mn10200.c -- Assembler code for the Matsushita 10200 - - Copyright (C) 1996 Free Software Foundation. + Copyright (C) 1996-2020 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 2, or (at your option) + 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, @@ -16,13 +15,12 @@ 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, 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + the Free Software Foundation, 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ -#include -#include #include "as.h" -#include "subsegs.h" +#include "safe-ctype.h" +#include "subsegs.h" #include "opcode/mn10200.h" /* Structure to hold information about predefined registers. */ @@ -32,57 +30,69 @@ struct reg_name int value; }; -/* Generic assembler global variables which must be defined by all targets. */ +/* Generic assembler global variables which must be defined by all + targets. */ -/* Characters which always start a comment. */ +/* Characters which always start a comment. */ const char comment_chars[] = "#"; /* Characters which start a comment at the beginning of a line. */ const char line_comment_chars[] = ";#"; -/* Characters which may be used to separate multiple commands on a +/* Characters which may be used to separate multiple commands on a single line. */ const char line_separator_chars[] = ";"; -/* Characters which are used to indicate an exponent in a floating +/* Characters which are used to indicate an exponent in a floating point number. */ const char EXP_CHARS[] = "eE"; -/* Characters which mean that a number is a floating point constant, +/* Characters which mean that a number is a floating point constant, as in 0d1.0. */ const char FLT_CHARS[] = "dD"; +const relax_typeS md_relax_table[] = + { + /* bCC relaxing */ + {0x81, -0x7e, 2, 1}, + {0x8004, -0x7ffb, 5, 2}, + {0x800006, -0x7ffff9, 7, 0}, + /* bCCx relaxing */ + {0x81, -0x7e, 3, 4}, + {0x8004, -0x7ffb, 6, 5}, + {0x800006, -0x7ffff9, 8, 0}, + /* jsr relaxing */ + {0x8004, -0x7ffb, 3, 7}, + {0x800006, -0x7ffff9, 5, 0}, + /* jmp relaxing */ + {0x81, -0x7e, 2, 9}, + {0x8004, -0x7ffb, 3, 10}, + {0x800006, -0x7ffff9, 5, 0}, + +}; + + +/* Fixups. */ +#define MAX_INSN_FIXUPS 5 -/* local functions */ -static void mn10200_insert_operand PARAMS ((unsigned long *, unsigned long *, - const struct mn10200_operand *, - offsetT, char *, unsigned, - unsigned)); -static unsigned long check_operand PARAMS ((unsigned long, - const struct mn10200_operand *, - offsetT)); -static int reg_name_search PARAMS ((const struct reg_name *, int, const char *)); -static boolean data_register_name PARAMS ((expressionS *expressionP)); -static boolean address_register_name PARAMS ((expressionS *expressionP)); -static boolean other_register_name PARAMS ((expressionS *expressionP)); - - -/* fixups */ -#define MAX_INSN_FIXUPS (5) struct mn10200_fixup { expressionS exp; int opindex; bfd_reloc_code_real_type reloc; }; + struct mn10200_fixup fixups[MAX_INSN_FIXUPS]; static int fc; const char *md_shortopts = ""; -struct option md_longopts[] = { + +struct option md_longopts[] = +{ {NULL, no_argument, NULL, 0} }; -size_t md_longopts_size = sizeof(md_longopts); + +size_t md_longopts_size = sizeof (md_longopts); /* The target specific pseudo-ops which we support. */ const pseudo_typeS md_pseudo_table[] = @@ -93,7 +103,7 @@ const pseudo_typeS md_pseudo_table[] = /* Opcode hash table. */ static struct hash_control *mn10200_hash; -/* This table is sorted. Suitable for searching by a binary search. */ +/* This table is sorted. Suitable for searching by a binary search. */ static const struct reg_name data_registers[] = { { "d0", 0 }, @@ -101,7 +111,8 @@ static const struct reg_name data_registers[] = { "d2", 2 }, { "d3", 3 }, }; -#define DATA_REG_NAME_CNT (sizeof(data_registers) / sizeof(struct reg_name)) +#define DATA_REG_NAME_CNT \ + (sizeof (data_registers) / sizeof (struct reg_name)) static const struct reg_name address_registers[] = { @@ -110,24 +121,25 @@ static const struct reg_name address_registers[] = { "a2", 2 }, { "a3", 3 }, }; -#define ADDRESS_REG_NAME_CNT (sizeof(address_registers) / sizeof(struct reg_name)) +#define ADDRESS_REG_NAME_CNT \ + (sizeof (address_registers) / sizeof (struct reg_name)) static const struct reg_name other_registers[] = { { "mdr", 0 }, { "psw", 0 }, }; -#define OTHER_REG_NAME_CNT (sizeof(other_registers) / sizeof(struct reg_name)) +#define OTHER_REG_NAME_CNT \ + (sizeof (other_registers) / sizeof (struct reg_name)) /* reg_name_search does a binary search of the given register table - to see if "name" is a valid regiter name. Returns the register - number from the array on success, or -1 on failure. */ + to see if "name" is a valid register name. Returns the register + number from the array on success, or -1 on failure. */ static int -reg_name_search (regs, regcount, name) - const struct reg_name *regs; - int regcount; - const char *name; +reg_name_search (const struct reg_name *regs, + int regcount, + const char *name) { int middle, low, high; int cmp; @@ -143,243 +155,537 @@ reg_name_search (regs, regcount, name) high = middle - 1; else if (cmp > 0) low = middle + 1; - else - return regs[middle].value; + else + return regs[middle].value; } while (low <= high); return -1; } - /* Summary of register_name(). - * - * in: Input_line_pointer points to 1st char of operand. - * - * out: A expressionS. - * The operand may have been a register: in this case, X_op == O_register, - * X_add_number is set to the register number, and truth is returned. - * Input_line_pointer->(next non-blank) char after operand, or is in - * its original state. - */ -static boolean -data_register_name (expressionP) - expressionS *expressionP; + + in: Input_line_pointer points to 1st char of operand. + + out: An expressionS. + The operand may have been a register: in this case, X_op == O_register, + X_add_number is set to the register number, and truth is returned. + Input_line_pointer->(next non-blank) char after operand, or is in + its original state. */ + +static bfd_boolean +data_register_name (expressionS *expressionP) { int reg_number; char *name; char *start; char c; - /* Find the spelling of the operand */ - start = name = input_line_pointer; - - c = get_symbol_end (); + /* Find the spelling of the operand. */ + start = input_line_pointer; + c = get_symbol_name (&name); reg_number = reg_name_search (data_registers, DATA_REG_NAME_CNT, name); - /* look to see if it's in the register table */ - if (reg_number >= 0) + /* Put back the delimiting char. */ + (void) restore_line_pointer (c); + + /* Look to see if it's in the register table. */ + if (reg_number >= 0) { expressionP->X_op = O_register; expressionP->X_add_number = reg_number; - /* make the rest nice */ + /* Make the rest nice. */ expressionP->X_add_symbol = NULL; expressionP->X_op_symbol = NULL; - *input_line_pointer = c; /* put back the delimiting char */ - return true; - } - else - { - /* reset the line as if we had not done anything */ - *input_line_pointer = c; /* put back the delimiting char */ - input_line_pointer = start; /* reset input_line pointer */ - return false; + + return TRUE; } + + /* Reset the line as if we had not done anything. */ + input_line_pointer = start; + return FALSE; } /* Summary of register_name(). - * - * in: Input_line_pointer points to 1st char of operand. - * - * out: A expressionS. - * The operand may have been a register: in this case, X_op == O_register, - * X_add_number is set to the register number, and truth is returned. - * Input_line_pointer->(next non-blank) char after operand, or is in - * its original state. - */ -static boolean -address_register_name (expressionP) - expressionS *expressionP; + + in: Input_line_pointer points to 1st char of operand. + + out: An expressionS. + The operand may have been a register: in this case, X_op == O_register, + X_add_number is set to the register number, and truth is returned. + Input_line_pointer->(next non-blank) char after operand, or is in + its original state. */ + +static bfd_boolean +address_register_name (expressionS *expressionP) { int reg_number; char *name; char *start; char c; - /* Find the spelling of the operand */ - start = name = input_line_pointer; - - c = get_symbol_end (); + /* Find the spelling of the operand. */ + start = input_line_pointer; + c = get_symbol_name (&name); reg_number = reg_name_search (address_registers, ADDRESS_REG_NAME_CNT, name); - /* look to see if it's in the register table */ - if (reg_number >= 0) + /* Put back the delimiting char. */ + (void) restore_line_pointer (c); + + /* Look to see if it's in the register table. */ + if (reg_number >= 0) { expressionP->X_op = O_register; expressionP->X_add_number = reg_number; - /* make the rest nice */ + /* Make the rest nice. */ expressionP->X_add_symbol = NULL; expressionP->X_op_symbol = NULL; - *input_line_pointer = c; /* put back the delimiting char */ - return true; - } - else - { - /* reset the line as if we had not done anything */ - *input_line_pointer = c; /* put back the delimiting char */ - input_line_pointer = start; /* reset input_line pointer */ - return false; + + return TRUE; } + + /* Reset the line as if we had not done anything. */ + input_line_pointer = start; + return FALSE; } /* Summary of register_name(). - * - * in: Input_line_pointer points to 1st char of operand. - * - * out: A expressionS. - * The operand may have been a register: in this case, X_op == O_register, - * X_add_number is set to the register number, and truth is returned. - * Input_line_pointer->(next non-blank) char after operand, or is in - * its original state. - */ -static boolean -other_register_name (expressionP) - expressionS *expressionP; + + in: Input_line_pointer points to 1st char of operand. + + out: An expressionS. + The operand may have been a register: in this case, X_op == O_register, + X_add_number is set to the register number, and truth is returned. + Input_line_pointer->(next non-blank) char after operand, or is in + its original state. */ + +static bfd_boolean +other_register_name (expressionS *expressionP) { int reg_number; char *name; char *start; char c; - /* Find the spelling of the operand */ - start = name = input_line_pointer; - - c = get_symbol_end (); + /* Find the spelling of the operand. */ + start = input_line_pointer; + c = get_symbol_name (&name); reg_number = reg_name_search (other_registers, OTHER_REG_NAME_CNT, name); - /* look to see if it's in the register table */ - if (reg_number >= 0) + /* Put back the delimiting char. */ + (void) restore_line_pointer (c); + + /* Look to see if it's in the register table. */ + if (reg_number >= 0) { expressionP->X_op = O_register; expressionP->X_add_number = reg_number; - /* make the rest nice */ + /* Make the rest nice. */ expressionP->X_add_symbol = NULL; expressionP->X_op_symbol = NULL; - *input_line_pointer = c; /* put back the delimiting char */ - return true; - } - else - { - /* reset the line as if we had not done anything */ - *input_line_pointer = c; /* put back the delimiting char */ - input_line_pointer = start; /* reset input_line pointer */ - return false; + + return TRUE; } + + /* Reset the line as if we had not done anything. */ + input_line_pointer = start; + return FALSE; } void -md_show_usage (stream) - FILE *stream; +md_show_usage (FILE *stream) { - fprintf(stream, "MN10200 options:\n\ -none yet\n"); -} + fprintf (stream, _("MN10200 options:\n\ +none yet\n")); +} int -md_parse_option (c, arg) - int c; - char *arg; +md_parse_option (int c ATTRIBUTE_UNUSED, + const char *arg ATTRIBUTE_UNUSED) { return 0; } symbolS * -md_undefined_symbol (name) - char *name; +md_undefined_symbol (char *name ATTRIBUTE_UNUSED) { return 0; } -char * -md_atof (type, litp, sizep) - int type; - char *litp; - int *sizep; +const char * +md_atof (int type, char *litp, int *sizep) { - int prec; - LITTLENUM_TYPE words[4]; - char *t; - int i; - - switch (type) - { - case 'f': - prec = 2; - break; + return ieee_md_atof (type, litp, sizep, FALSE); +} - case 'd': - prec = 4; - break; +void +md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, + fragS *fragP) +{ + static unsigned long label_count = 0; + char buf[40]; - default: - *sizep = 0; - return "bad call to md_atof"; + subseg_change (sec, 0); + if (fragP->fr_subtype == 0) + { + fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol, + fragP->fr_offset, 1, BFD_RELOC_8_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 2; } - - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; + else if (fragP->fr_subtype == 1) + { + /* Reverse the condition of the first branch. */ + int offset = fragP->fr_fix; + int opcode = fragP->fr_literal[offset] & 0xff; - *sizep = prec * 2; + switch (opcode) + { + case 0xe8: + opcode = 0xe9; + break; + case 0xe9: + opcode = 0xe8; + break; + case 0xe0: + opcode = 0xe2; + break; + case 0xe2: + opcode = 0xe0; + break; + case 0xe3: + opcode = 0xe1; + break; + case 0xe1: + opcode = 0xe3; + break; + case 0xe4: + opcode = 0xe6; + break; + case 0xe6: + opcode = 0xe4; + break; + case 0xe7: + opcode = 0xe5; + break; + case 0xe5: + opcode = 0xe7; + break; + default: + abort (); + } + fragP->fr_literal[offset] = opcode; + + /* Create a fixup for the reversed conditional branch. */ + sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++); + fix_new (fragP, fragP->fr_fix + 1, 1, + symbol_new (buf, sec, 0, fragP->fr_next), + fragP->fr_offset, 1, BFD_RELOC_8_PCREL); + + /* Now create the unconditional branch + fixup to the + final target. */ + fragP->fr_literal[offset + 2] = 0xfc; + fix_new (fragP, fragP->fr_fix + 3, 2, fragP->fr_symbol, + fragP->fr_offset, 1, BFD_RELOC_16_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 5; + } + else if (fragP->fr_subtype == 2) + { + /* Reverse the condition of the first branch. */ + int offset = fragP->fr_fix; + int opcode = fragP->fr_literal[offset] & 0xff; - for (i = prec - 1; i >= 0; i--) + switch (opcode) + { + case 0xe8: + opcode = 0xe9; + break; + case 0xe9: + opcode = 0xe8; + break; + case 0xe0: + opcode = 0xe2; + break; + case 0xe2: + opcode = 0xe0; + break; + case 0xe3: + opcode = 0xe1; + break; + case 0xe1: + opcode = 0xe3; + break; + case 0xe4: + opcode = 0xe6; + break; + case 0xe6: + opcode = 0xe4; + break; + case 0xe7: + opcode = 0xe5; + break; + case 0xe5: + opcode = 0xe7; + break; + default: + abort (); + } + fragP->fr_literal[offset] = opcode; + + /* Create a fixup for the reversed conditional branch. */ + sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++); + fix_new (fragP, fragP->fr_fix + 1, 1, + symbol_new (buf, sec, 0, fragP->fr_next), + fragP->fr_offset, 1, BFD_RELOC_8_PCREL); + + /* Now create the unconditional branch + fixup to the + final target. */ + fragP->fr_literal[offset + 2] = 0xf4; + fragP->fr_literal[offset + 3] = 0xe0; + fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol, + fragP->fr_offset, 1, BFD_RELOC_24_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 7; + } + else if (fragP->fr_subtype == 3) { - md_number_to_chars (litp, (valueT) words[i], 2); - litp += 2; + fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol, + fragP->fr_offset, 1, BFD_RELOC_8_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 3; } + else if (fragP->fr_subtype == 4) + { + /* Reverse the condition of the first branch. */ + int offset = fragP->fr_fix; + int opcode = fragP->fr_literal[offset + 1] & 0xff; - return NULL; -} + switch (opcode) + { + case 0xfc: + opcode = 0xfd; + break; + case 0xfd: + opcode = 0xfc; + break; + case 0xfe: + opcode = 0xff; + break; + case 0xff: + opcode = 0xfe; + break; + case 0xe8: + opcode = 0xe9; + break; + case 0xe9: + opcode = 0xe8; + break; + case 0xe0: + opcode = 0xe2; + break; + case 0xe2: + opcode = 0xe0; + break; + case 0xe3: + opcode = 0xe1; + break; + case 0xe1: + opcode = 0xe3; + break; + case 0xe4: + opcode = 0xe6; + break; + case 0xe6: + opcode = 0xe4; + break; + case 0xe7: + opcode = 0xe5; + break; + case 0xe5: + opcode = 0xe7; + break; + case 0xec: + opcode = 0xed; + break; + case 0xed: + opcode = 0xec; + break; + case 0xee: + opcode = 0xef; + break; + case 0xef: + opcode = 0xee; + break; + default: + abort (); + } + fragP->fr_literal[offset + 1] = opcode; + + /* Create a fixup for the reversed conditional branch. */ + sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++); + fix_new (fragP, fragP->fr_fix + 2, 1, + symbol_new (buf, sec, 0, fragP->fr_next), + fragP->fr_offset, 1, BFD_RELOC_8_PCREL); + + /* Now create the unconditional branch + fixup to the + final target. */ + fragP->fr_literal[offset + 3] = 0xfc; + fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol, + fragP->fr_offset, 1, BFD_RELOC_16_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 6; + } + else if (fragP->fr_subtype == 5) + { + /* Reverse the condition of the first branch. */ + int offset = fragP->fr_fix; + int opcode = fragP->fr_literal[offset + 1] & 0xff; + switch (opcode) + { + case 0xfc: + opcode = 0xfd; + break; + case 0xfd: + opcode = 0xfc; + break; + case 0xfe: + opcode = 0xff; + break; + case 0xff: + opcode = 0xfe; + break; + case 0xe8: + opcode = 0xe9; + break; + case 0xe9: + opcode = 0xe8; + break; + case 0xe0: + opcode = 0xe2; + break; + case 0xe2: + opcode = 0xe0; + break; + case 0xe3: + opcode = 0xe1; + break; + case 0xe1: + opcode = 0xe3; + break; + case 0xe4: + opcode = 0xe6; + break; + case 0xe6: + opcode = 0xe4; + break; + case 0xe7: + opcode = 0xe5; + break; + case 0xe5: + opcode = 0xe7; + break; + case 0xec: + opcode = 0xed; + break; + case 0xed: + opcode = 0xec; + break; + case 0xee: + opcode = 0xef; + break; + case 0xef: + opcode = 0xee; + break; + default: + abort (); + } + fragP->fr_literal[offset + 1] = opcode; + + /* Create a fixup for the reversed conditional branch. */ + sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++); + fix_new (fragP, fragP->fr_fix + 2, 1, + symbol_new (buf, sec, 0, fragP->fr_next), + fragP->fr_offset, 1, BFD_RELOC_8_PCREL); + + /* Now create the unconditional branch + fixup to the + final target. */ + fragP->fr_literal[offset + 3] = 0xf4; + fragP->fr_literal[offset + 4] = 0xe0; + fix_new (fragP, fragP->fr_fix + 5, 4, fragP->fr_symbol, + fragP->fr_offset, 1, BFD_RELOC_24_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 8; + } + else if (fragP->fr_subtype == 6) + { + fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol, + fragP->fr_offset, 1, BFD_RELOC_16_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 3; + } + else if (fragP->fr_subtype == 7) + { + int offset = fragP->fr_fix; + fragP->fr_literal[offset] = 0xf4; + fragP->fr_literal[offset + 1] = 0xe1; + + fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol, + fragP->fr_offset, 1, BFD_RELOC_24_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 5; + } + else if (fragP->fr_subtype == 8) + { + fragP->fr_literal[fragP->fr_fix] = 0xea; + fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol, + fragP->fr_offset, 1, BFD_RELOC_8_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 2; + } + else if (fragP->fr_subtype == 9) + { + int offset = fragP->fr_fix; + fragP->fr_literal[offset] = 0xfc; -void -md_convert_frag (abfd, sec, fragP) - bfd *abfd; - asection *sec; - fragS *fragP; -{ - /* printf ("call to md_convert_frag \n"); */ - abort (); + fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol, + fragP->fr_offset, 1, BFD_RELOC_16_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 3; + } + else if (fragP->fr_subtype == 10) + { + int offset = fragP->fr_fix; + fragP->fr_literal[offset] = 0xf4; + fragP->fr_literal[offset + 1] = 0xe0; + + fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol, + fragP->fr_offset, 1, BFD_RELOC_24_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 5; + } + else + abort (); } valueT -md_section_align (seg, addr) - asection *seg; - valueT addr; +md_section_align (asection *seg, valueT addr) { - int align = bfd_get_section_alignment (stdoutput, seg); - return ((addr + (1 << align) - 1) & (-1 << align)); + int align = bfd_section_alignment (seg); + return ((addr + (1 << align) - 1) & -(1 << align)); } void -md_begin () +md_begin (void) { - char *prev_name = ""; - register const struct mn10200_opcode *op; + const char *prev_name = ""; + const struct mn10200_opcode *op; - mn10200_hash = hash_new(); + mn10200_hash = hash_new (); /* Insert unique names into hash table. The MN10200 instruction set has many identical opcode names that have different opcodes based @@ -389,7 +695,7 @@ md_begin () op = mn10200_opcodes; while (op->name) { - if (strcmp (prev_name, op->name)) + if (strcmp (prev_name, op->name)) { prev_name = (char *) op->name; hash_insert (mn10200_hash, op->name, (char *) op); @@ -403,47 +709,208 @@ md_begin () linkrelax = 1; } +static unsigned long +check_operand (unsigned long insn ATTRIBUTE_UNUSED, + const struct mn10200_operand *operand, + offsetT val) +{ + /* No need to check 24bit or 32bit operands for a bit. */ + if (operand->bits < 24 + && (operand->flags & MN10200_OPERAND_NOCHECK) == 0) + { + long min, max; + offsetT test; + + if ((operand->flags & MN10200_OPERAND_SIGNED) != 0) + { + max = (1 << (operand->bits - 1)) - 1; + min = - (1 << (operand->bits - 1)); + } + else + { + max = (1 << operand->bits) - 1; + min = 0; + } + + test = val; + + if (test < (offsetT) min || test > (offsetT) max) + return 0; + else + return 1; + } + return 1; +} +/* If while processing a fixup, a reloc really needs to be created + Then it is done here. */ + +arelent * +tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) +{ + arelent *reloc; + reloc = XNEW (arelent); + + if (fixp->fx_subsy != NULL) + { + if (S_GET_SEGMENT (fixp->fx_addsy) == S_GET_SEGMENT (fixp->fx_subsy) + && S_IS_DEFINED (fixp->fx_subsy)) + { + fixp->fx_offset -= S_GET_VALUE (fixp->fx_subsy); + fixp->fx_subsy = NULL; + } + else + /* FIXME: We should try more ways to resolve difference expressions + here. At least this is better than silently ignoring the + subtrahend. */ + as_bad_where (fixp->fx_file, fixp->fx_line, + _("can't resolve `%s' {%s section} - `%s' {%s section}"), + fixp->fx_addsy ? S_GET_NAME (fixp->fx_addsy) : "0", + segment_name (fixp->fx_addsy + ? S_GET_SEGMENT (fixp->fx_addsy) + : absolute_section), + S_GET_NAME (fixp->fx_subsy), + segment_name (S_GET_SEGMENT (fixp->fx_addsy))); + } + + reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); + if (reloc->howto == NULL) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + _("reloc %d not supported by object file format"), + (int) fixp->fx_r_type); + return NULL; + } + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + reloc->sym_ptr_ptr = XNEW (asymbol *); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); + reloc->addend = fixp->fx_offset; + return reloc; +} + +int +md_estimate_size_before_relax (fragS *fragp, asection *seg) +{ + if (fragp->fr_subtype == 6 + && (!S_IS_DEFINED (fragp->fr_symbol) + || seg != S_GET_SEGMENT (fragp->fr_symbol))) + fragp->fr_subtype = 7; + else if (fragp->fr_subtype == 8 + && (!S_IS_DEFINED (fragp->fr_symbol) + || seg != S_GET_SEGMENT (fragp->fr_symbol))) + fragp->fr_subtype = 10; + + if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0])) + abort (); + + return md_relax_table[fragp->fr_subtype].rlx_length; +} + +long +md_pcrel_from (fixS *fixp) +{ + return fixp->fx_frag->fr_address; +} + void -md_assemble (str) - char *str; +md_apply_fix (fixS * fixP, valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED) +{ + /* We shouldn't ever get here because linkrelax is nonzero. */ + abort (); + fixP->fx_done = 1; +} + +/* Insert an operand value into an instruction. */ + +static void +mn10200_insert_operand (unsigned long *insnp, + unsigned long *extensionp, + const struct mn10200_operand *operand, + offsetT val, + char *file, + unsigned int line, + unsigned int shift) +{ + /* No need to check 24 or 32bit operands for a bit. */ + if (operand->bits < 24 + && (operand->flags & MN10200_OPERAND_NOCHECK) == 0) + { + long min, max; + offsetT test; + + if ((operand->flags & MN10200_OPERAND_SIGNED) != 0) + { + max = (1 << (operand->bits - 1)) - 1; + min = - (1 << (operand->bits - 1)); + } + else + { + max = (1 << operand->bits) - 1; + min = 0; + } + + test = val; + + if (test < (offsetT) min || test > (offsetT) max) + as_warn_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line); + } + + if ((operand->flags & MN10200_OPERAND_EXTENDED) == 0) + { + *insnp |= (((long) val & ((1 << operand->bits) - 1)) + << (operand->shift + shift)); + + if ((operand->flags & MN10200_OPERAND_REPEATED) != 0) + *insnp |= (((long) val & ((1 << operand->bits) - 1)) + << (operand->shift + shift + 2)); + } + else + { + *extensionp |= (val >> 16) & 0xff; + *insnp |= val & 0xffff; + } +} + +void +md_assemble (char *str) { char *s; struct mn10200_opcode *opcode; struct mn10200_opcode *next_opcode; const unsigned char *opindex_ptr; - int next_opindex; + int next_opindex, relaxable; unsigned long insn, extension, size = 0; char *f; int i; int match; /* Get the opcode. */ - for (s = str; *s != '\0' && ! isspace (*s); s++) + for (s = str; *s != '\0' && !ISSPACE (*s); s++) ; if (*s != '\0') *s++ = '\0'; - /* find the first opcode with the proper name */ - opcode = (struct mn10200_opcode *)hash_find (mn10200_hash, str); + /* Find the first opcode with the proper name. */ + opcode = (struct mn10200_opcode *) hash_find (mn10200_hash, str); if (opcode == NULL) { - as_bad ("Unrecognized opcode: `%s'", str); + as_bad (_("Unrecognized opcode: `%s'"), str); return; } str = s; - while (isspace (*str)) + while (ISSPACE (*str)) ++str; input_line_pointer = str; - for(;;) + for (;;) { const char *errmsg = NULL; int op_idx; char *hold; int extra_shift = 0; + relaxable = 0; fc = 0; match = 0; next_opindex = 0; @@ -471,7 +938,10 @@ md_assemble (str) while (*str == ' ' || *str == ',') ++str; - /* Gather the operand. */ + if (operand->flags & MN10200_OPERAND_RELAX) + relaxable = 1; + + /* Gather the operand. */ hold = input_line_pointer; input_line_pointer = str; @@ -507,32 +977,32 @@ md_assemble (str) } else if (operand->flags & MN10200_OPERAND_PSW) { - char *start = input_line_pointer; - char c = get_symbol_end (); + char *start; + char c = get_symbol_name (&start); if (strcmp (start, "psw") != 0) { - *input_line_pointer = c; + (void) restore_line_pointer (c); input_line_pointer = hold; str = hold; goto error; } - *input_line_pointer = c; + (void) restore_line_pointer (c); goto keep_going; } else if (operand->flags & MN10200_OPERAND_MDR) { - char *start = input_line_pointer; - char c = get_symbol_end (); + char *start; + char c = get_symbol_name (&start); if (strcmp (start, "mdr") != 0) { - *input_line_pointer = c; + (void) restore_line_pointer (c); input_line_pointer = hold; str = hold; goto error; } - *input_line_pointer = c; + (void) restore_line_pointer (c); goto keep_going; } else if (data_register_name (&ex)) @@ -564,23 +1034,23 @@ md_assemble (str) expression (&ex); } - switch (ex.X_op) + switch (ex.X_op) { case O_illegal: - errmsg = "illegal operand"; + errmsg = _("illegal operand"); goto error; case O_absent: - errmsg = "missing operand"; + errmsg = _("missing operand"); goto error; case O_register: if ((operand->flags - & (MN10200_OPERAND_DREG | MN10200_OPERAND_AREG)) == 0) + & (MN10200_OPERAND_DREG | MN10200_OPERAND_AREG)) == 0) { input_line_pointer = hold; str = hold; goto error; } - + if (opcode->format == FMT_2 || opcode->format == FMT_5) extra_shift = 8; else if (opcode->format == FMT_3 || opcode->format == FMT_6 @@ -588,9 +1058,9 @@ md_assemble (str) extra_shift = 16; else extra_shift = 0; - + mn10200_insert_operand (&insn, &extension, operand, - ex.X_add_number, (char *) NULL, + ex.X_add_number, NULL, 0, extra_shift); break; @@ -599,8 +1069,9 @@ md_assemble (str) /* If this operand can be promoted, and it doesn't fit into the allocated bitfield for this insn, then promote it (ie this opcode does not match). */ - if (operand->flags & MN10200_OPERAND_PROMOTE - && ! check_operand (insn, operand, ex.X_add_number)) + if (operand->flags + & (MN10200_OPERAND_PROMOTE | MN10200_OPERAND_RELAX) + && !check_operand (insn, operand, ex.X_add_number)) { input_line_pointer = hold; str = hold; @@ -608,7 +1079,7 @@ md_assemble (str) } mn10200_insert_operand (&insn, &extension, operand, - ex.X_add_number, (char *) NULL, + ex.X_add_number, NULL, 0, 0); break; @@ -624,7 +1095,7 @@ md_assemble (str) /* We need to generate a fixup for this expression. */ if (fc >= MAX_INSN_FIXUPS) - as_fatal ("too many fixups"); + as_fatal (_("too many fixups")); fixups[fc].exp = ex; fixups[fc].opindex = *opindex_ptr; fixups[fc].reloc = BFD_RELOC_UNUSED; @@ -632,7 +1103,7 @@ md_assemble (str) break; } -keep_going: + keep_going: str = input_line_pointer; input_line_pointer = hold; @@ -647,25 +1118,25 @@ keep_going: error: if (match == 0) - { + { next_opcode = opcode + 1; - if (!strcmp(next_opcode->name, opcode->name)) + if (!strcmp (next_opcode->name, opcode->name)) { opcode = next_opcode; continue; } - + as_bad ("%s", errmsg); return; - } + } break; } - - while (isspace (*str)) + + while (ISSPACE (*str)) ++str; if (*str != '\0') - as_bad ("junk at end of line: `%s'", str); + as_bad (_("junk at end of line: `%s'"), str); input_line_pointer = str; @@ -681,294 +1152,185 @@ keep_going: size = 5; else abort (); - - /* Write out the instruction. */ - - f = frag_more (size); - /* Oh, what a mess. The instruction is in big endian format, but - 16 and 24bit immediates are little endian! */ - if (opcode->format == FMT_3) - { - number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1); - number_to_chars_littleendian (f + 1, insn & 0xffff, 2); - } - else if (opcode->format == FMT_6) - { - number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2); - number_to_chars_littleendian (f + 2, insn & 0xffff, 2); - } - else if (opcode->format == FMT_7) - { - number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2); - number_to_chars_littleendian (f + 2, insn & 0xffff, 2); - number_to_chars_littleendian (f + 4, extension & 0xff, 1); - } - else - { - number_to_chars_bigendian (f, insn, size > 4 ? 4 : size); - } - -#if 0 - /* Create any fixups. */ - for (i = 0; i < fc; i++) + /* Write out the instruction. */ + dwarf2_emit_insn (size); + if (relaxable && fc > 0) { - const struct mn10200_operand *operand; - - operand = &mn10200_operands[fixups[i].opindex]; - if (fixups[i].reloc != BFD_RELOC_UNUSED) + /* On a 64-bit host the size of an 'int' is not the same + as the size of a pointer, so we need a union to convert + the opindex field of the fr_cgen structure into a char * + so that it can be stored in the frag. We do not have + to worry about losing accuracy as we are not going to + be even close to the 32bit limit of the int. */ + union + { + int opindex; + char * ptr; + } + opindex_converter; + int type; + + /* bCC */ + if (size == 2 && opcode->opcode != 0xfc0000) { - reloc_howto_type *reloc_howto; - int size; - int offset; - fixS *fixP; - - reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc); - - if (!reloc_howto) - abort(); - - size = bfd_get_reloc_size (reloc_howto); - - if (size < 1 || size > 4) - abort(); - - offset = 4 - size; - fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size, - &fixups[i].exp, - reloc_howto->pc_relative, - fixups[i].reloc); + /* Handle bra specially. Basically treat it like jmp so + that we automatically handle 8, 16 and 32 bit offsets + correctly as well as jumps to an undefined address. + + It is also important to not treat it like other bCC + instructions since the long forms of bra is different + from other bCC instructions. */ + if (opcode->opcode == 0xea00) + type = 8; + else + type = 0; } + /* jsr */ + else if (size == 3 && opcode->opcode == 0xfd0000) + type = 6; + /* jmp */ + else if (size == 3 && opcode->opcode == 0xfc0000) + type = 8; + /* bCCx */ else + type = 3; + + opindex_converter.opindex = fixups[0].opindex; + f = frag_var (rs_machine_dependent, 8, 8 - size, type, + fixups[0].exp.X_add_symbol, + fixups[0].exp.X_add_number, + opindex_converter.ptr); + number_to_chars_bigendian (f, insn, size); + if (8 - size > 4) { - int reloc, pcrel, reloc_size, offset; - - reloc = BFD_RELOC_NONE; - /* How big is the reloc? Remember SPLIT relocs are - implicitly 32bits. */ - reloc_size = operand->bits; - - /* Is the reloc pc-relative? */ - pcrel = (operand->flags & MN10200_OPERAND_PCREL) != 0; - - /* Gross. This disgusting hack is to make sure we - get the right offset for the 16/32 bit reloc in - "call" instructions. Basically they're a pain - because the reloc isn't at the end of the instruction. */ - if ((size == 5 || size == 7) - && (((insn >> 24) & 0xff) == 0xcd - || ((insn >> 24) & 0xff) == 0xdd)) - size -= 2; - - /* Similarly for certain bit instructions which don't - hav their 32bit reloc at the tail of the instruction. */ - if (size == 7 - && (((insn >> 16) & 0xffff) == 0xfe00 - || ((insn >> 16) & 0xffff) == 0xfe01 - || ((insn >> 16) & 0xffff) == 0xfe02)) - size -= 1; - - offset = size - reloc_size / 8; - - /* Choose a proper BFD relocation type. */ - if (pcrel) - { - if (size == 6) - reloc = BFD_RELOC_MN10200_32_PCREL; - else if (size == 4) - reloc = BFD_RELOC_MN10200_16_PCREL; - else if (reloc_size == 32) - reloc = BFD_RELOC_32_PCREL; - else if (reloc_size == 16) - reloc = BFD_RELOC_16_PCREL; - else if (reloc_size == 8) - reloc = BFD_RELOC_8_PCREL; - else - abort (); - } - else - { - if (reloc_size == 32) - reloc = BFD_RELOC_MN10200_32B; - else if (reloc_size == 16) - reloc = BFD_RELOC_MN10200_16B; - else if (reloc_size == 8) - reloc = BFD_RELOC_8; - else - abort (); - } - - /* Convert the size of the reloc into what fix_new_exp wants. */ - reloc_size = reloc_size / 8; - if (reloc_size == 8) - reloc_size = 0; - else if (reloc_size == 16) - reloc_size = 1; - else if (reloc_size == 32) - reloc_size = 2; - - fix_new_exp (frag_now, f - frag_now->fr_literal + offset, reloc_size, - &fixups[i].exp, pcrel, - ((bfd_reloc_code_real_type) reloc)); + number_to_chars_bigendian (f + size, 0, 4); + number_to_chars_bigendian (f + size + 4, 0, 8 - size - 4); } + else + number_to_chars_bigendian (f + size, 0, 8 - size); } -#endif -} - - -/* if while processing a fixup, a reloc really needs to be created */ -/* then it is done here */ - -arelent * -tc_gen_reloc (seg, fixp) - asection *seg; - fixS *fixp; -{ - arelent *reloc; - reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent)); - reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym; - reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); - if (reloc->howto == (reloc_howto_type *) NULL) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - "reloc %d not supported by object file format", (int)fixp->fx_r_type); - return NULL; - } - reloc->addend = fixp->fx_offset; - /* printf("tc_gen_reloc: addr=%x addend=%x\n", reloc->address, reloc->addend); */ - return reloc; -} - -int -md_estimate_size_before_relax (fragp, seg) - fragS *fragp; - asection *seg; -{ - return 0; -} - -long -md_pcrel_from (fixp) - fixS *fixp; -{ - return fixp->fx_frag->fr_address; -#if 0 - if (fixp->fx_addsy != (symbolS *) NULL && ! S_IS_DEFINED (fixp->fx_addsy)) - { - /* The symbol is undefined. Let the linker figure it out. */ - return 0; - } - return fixp->fx_frag->fr_address + fixp->fx_where; -#endif -} - -int -md_apply_fix3 (fixp, valuep, seg) - fixS *fixp; - valueT *valuep; - segT seg; -{ - /* We shouldn't ever get here because linkrelax is nonzero. */ - abort (); - fixp->fx_done = 1; - return 0; -} - -/* Insert an operand value into an instruction. */ - -static void -mn10200_insert_operand (insnp, extensionp, operand, val, file, line, shift) - unsigned long *insnp; - unsigned long *extensionp; - const struct mn10200_operand *operand; - offsetT val; - char *file; - unsigned int line; - unsigned int shift; -{ - /* No need to check 24 or 32bit operands for a bit. */ - if (operand->bits < 24 - && (operand->flags & MN10200_OPERAND_NOCHECK) == 0) + else { - long min, max; - offsetT test; + f = frag_more (size); - if ((operand->flags & MN10200_OPERAND_SIGNED) != 0) + /* Oh, what a mess. The instruction is in big endian format, but + 16 and 24bit immediates are little endian! */ + if (opcode->format == FMT_3) { - max = (1 << (operand->bits - 1)) - 1; - min = - (1 << (operand->bits - 1)); + number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1); + number_to_chars_littleendian (f + 1, insn & 0xffff, 2); + } + else if (opcode->format == FMT_6) + { + number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2); + number_to_chars_littleendian (f + 2, insn & 0xffff, 2); + } + else if (opcode->format == FMT_7) + { + number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2); + number_to_chars_littleendian (f + 2, insn & 0xffff, 2); + number_to_chars_littleendian (f + 4, extension & 0xff, 1); } else - { - max = (1 << operand->bits) - 1; - min = 0; - } + number_to_chars_bigendian (f, insn, size > 4 ? 4 : size); - test = val; + /* Create any fixups. */ + for (i = 0; i < fc; i++) + { + const struct mn10200_operand *operand; + int reloc_size; + operand = &mn10200_operands[fixups[i].opindex]; + if (fixups[i].reloc != BFD_RELOC_UNUSED) + { + reloc_howto_type *reloc_howto; + int offset; + fixS *fixP; - if (test < (offsetT) min || test > (offsetT) max) - { - const char *err = - "operand out of range (%s not between %ld and %ld)"; - char buf[100]; - - sprint_value (buf, test); - if (file == (char *) NULL) - as_warn (err, buf, min, max); - else - as_warn_where (file, line, err, buf, min, max); - } - } + reloc_howto = bfd_reloc_type_lookup (stdoutput, + fixups[i].reloc); - if ((operand->flags & MN10200_OPERAND_EXTENDED) == 0) - { - *insnp |= (((long) val & ((1 << operand->bits) - 1)) - << (operand->shift + shift)); + if (!reloc_howto) + abort (); - if ((operand->flags & MN10200_OPERAND_REPEATED) != 0) - *insnp |= (((long) val & ((1 << operand->bits) - 1)) - << (operand->shift + shift + 2)); - } - else - { - *extensionp |= (val >> 16) & 0xff; - *insnp |= val & 0xffff; - } -} + reloc_size = bfd_get_reloc_size (reloc_howto); -static unsigned long -check_operand (insn, operand, val) - unsigned long insn; - const struct mn10200_operand *operand; - offsetT val; -{ - /* No need to check 24bit or 32bit operands for a bit. */ - if (operand->bits < 24 - && (operand->flags & MN10200_OPERAND_NOCHECK) == 0) - { - long min, max; - offsetT test; + if (reloc_size < 1 || reloc_size > 4) + abort (); - if ((operand->flags & MN10200_OPERAND_SIGNED) != 0) - { - max = (1 << (operand->bits - 1)) - 1; - min = - (1 << (operand->bits - 1)); - } - else - { - max = (1 << operand->bits) - 1; - min = 0; - } + offset = 4 - reloc_size; + fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, + reloc_size, + &fixups[i].exp, + reloc_howto->pc_relative, + fixups[i].reloc); + + /* PC-relative offsets are from the first byte of the + next instruction, not from the start of the current + instruction. */ + if (reloc_howto->pc_relative) + fixP->fx_offset += reloc_size; + } + else + { + int reloc, pcrel, offset; + fixS *fixP; - test = val; + reloc = BFD_RELOC_NONE; + /* How big is the reloc? Remember SPLIT relocs are + implicitly 32bits. */ + reloc_size = operand->bits; + offset = size - reloc_size / 8; - if (test < (offsetT) min || test > (offsetT) max) - return 0; - else - return 1; + /* Is the reloc pc-relative? */ + pcrel = (operand->flags & MN10200_OPERAND_PCREL) != 0; + + /* Choose a proper BFD relocation type. */ + if (pcrel) + { + if (reloc_size == 8) + reloc = BFD_RELOC_8_PCREL; + else if (reloc_size == 24) + reloc = BFD_RELOC_24_PCREL; + else + abort (); + } + else + { + if (reloc_size == 32) + reloc = BFD_RELOC_32; + else if (reloc_size == 16) + reloc = BFD_RELOC_16; + else if (reloc_size == 8) + reloc = BFD_RELOC_8; + else if (reloc_size == 24) + reloc = BFD_RELOC_24; + else + abort (); + } + + /* Convert the size of the reloc into what fix_new_exp + wants. */ + reloc_size = reloc_size / 8; + if (reloc_size == 8) + reloc_size = 0; + else if (reloc_size == 16) + reloc_size = 1; + else if (reloc_size == 32 || reloc_size == 24) + reloc_size = 2; + + fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, + reloc_size, &fixups[i].exp, pcrel, + ((bfd_reloc_code_real_type) reloc)); + + /* PC-relative offsets are from the first byte of the + next instruction, not from the start of the current + instruction. */ + if (pcrel) + fixP->fx_offset += size; + } + } } - return 1; }