From e7b715256ee90f442856b236a7586f3811b1fc48 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Thu, 10 Jul 2003 02:50:00 +0000 Subject: [PATCH] 2000-05-25 Alexandre Oliva * config/tc-mn10300.c (mn10300_insert_operand): Negate negative accumulator's shift. 2000-05-08 Alexandre Oliva * config/tc-mn10300.c (md_relax_table, md_convert_frag, md_assemble, md_estimate_size_before_relax): Handle fbCC. 2000-04-20 Alexandre Oliva * config/tc-mn10300.c (HAVE_AM33): Redefine in terms of HAVE_AM33_2. 2000-04-03 Alexandre Oliva * config/tc-mn10300.c (md_pseudo_table): Use AM33_2 constant. (HAVE_AM33): Match AM33_2 too. (HAVE_AM33_2): New macro. (md_assemble): Use it. Match 2.0 registers only if HAVE_AM33_2. 2000-04-01 Alexandre Oliva * config/tc-mn10300.c (md_pseudo_table): Added `am33_2'. (float_registers, double_registers): New variables. (float_register_name, double_register_name): New functions. (md_assemble): Recognize FP registers. Implement FMT_D3. (mn10300_insert_operand): Support FP registers. --- gas/ChangeLog | 23 +++ gas/config/tc-mn10300.c | 418 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 440 insertions(+), 1 deletion(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 21167d84304..d7ee712a3b7 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,26 @@ +2003-07-09 Alexandre Oliva + + 2000-05-25 Alexandre Oliva + * config/tc-mn10300.c (mn10300_insert_operand): Negate negative + accumulator's shift. + 2000-05-08 Alexandre Oliva + * config/tc-mn10300.c (md_relax_table, md_convert_frag, + md_assemble, md_estimate_size_before_relax): Handle fbCC. + 2000-04-20 Alexandre Oliva + * config/tc-mn10300.c (HAVE_AM33): Redefine in terms of + HAVE_AM33_2. + 2000-04-03 Alexandre Oliva + * config/tc-mn10300.c (md_pseudo_table): Use AM33_2 constant. + (HAVE_AM33): Match AM33_2 too. + (HAVE_AM33_2): New macro. + (md_assemble): Use it. Match 2.0 registers only if HAVE_AM33_2. + 2000-04-01 Alexandre Oliva + * config/tc-mn10300.c (md_pseudo_table): Added `am33_2'. + (float_registers, double_registers): New variables. + (float_register_name, double_register_name): New functions. + (md_assemble): Recognize FP registers. Implement FMT_D3. + (mn10300_insert_operand): Support FP registers. + 2003-07-08 Chris Demetriou * config/tc-mips.c (mips_validate_fix): Do not warn about branch diff --git a/gas/config/tc-mn10300.c b/gas/config/tc-mn10300.c index 5595c7662b3..ff2fffa1483 100644 --- a/gas/config/tc-mn10300.c +++ b/gas/config/tc-mn10300.c @@ -78,6 +78,11 @@ const relax_typeS md_relax_table[] = { {0x7fff, -0x8000, 3, 12}, {0x7fffffff, -0x80000000, 5, 0}, + /* fbCC relaxing */ + {0x7f, -0x80, 3, 14}, + {0x7fff, -0x8000, 6, 15}, + {0x7fffffff, -0x80000000, 8, 0}, + }; /* Local functions. */ @@ -127,11 +132,13 @@ const pseudo_typeS md_pseudo_table[] = { { "am30", set_arch_mach, AM30 }, { "am33", set_arch_mach, AM33 }, + { "am33_2", (void (*) PARAMS ((int))) set_arch_mach, AM33_2 }, { "mn10300", set_arch_mach, MN103 }, {NULL, 0, 0} }; -#define HAVE_AM33 (current_machine == AM33) +#define HAVE_AM33_2 (current_machine == AM33_2) +#define HAVE_AM33 (current_machine == AM33 || HAVE_AM33_2) #define HAVE_AM30 (current_machine == AM30) /* Opcode hash table. */ @@ -251,6 +258,69 @@ static const struct reg_name other_registers[] = #define OTHER_REG_NAME_CNT \ (sizeof (other_registers) / sizeof (struct reg_name)) +static const struct reg_name float_registers[] = +{ + { "fs0", 0 }, + { "fs1", 1 }, + { "fs10", 10 }, + { "fs11", 11 }, + { "fs12", 12 }, + { "fs13", 13 }, + { "fs14", 14 }, + { "fs15", 15 }, + { "fs16", 16 }, + { "fs17", 17 }, + { "fs18", 18 }, + { "fs19", 19 }, + { "fs2", 2 }, + { "fs20", 20 }, + { "fs21", 21 }, + { "fs22", 22 }, + { "fs23", 23 }, + { "fs24", 24 }, + { "fs25", 25 }, + { "fs26", 26 }, + { "fs27", 27 }, + { "fs28", 28 }, + { "fs29", 29 }, + { "fs3", 3 }, + { "fs30", 30 }, + { "fs31", 31 }, + { "fs4", 4 }, + { "fs5", 5 }, + { "fs6", 6 }, + { "fs7", 7 }, + { "fs8", 8 }, + { "fs9", 9 }, +}; + +#define FLOAT_REG_NAME_CNT \ + (sizeof (float_registers) / sizeof (struct reg_name)) + +static const struct reg_name double_registers[] = +{ + { "fd0", 0 }, + { "fd10", 10 }, + { "fd12", 12 }, + { "fd14", 14 }, + { "fd16", 16 }, + { "fd18", 18 }, + { "fd2", 2 }, + { "fd20", 20 }, + { "fd22", 22 }, + { "fd24", 24 }, + { "fd26", 26 }, + { "fd28", 28 }, + { "fd30", 30 }, + { "fd4", 4 }, + { "fd6", 6 }, + { "fd8", 8 }, +}; + +#define DOUBLE_REG_NAME_CNT \ + (sizeof (double_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. */ @@ -518,6 +588,101 @@ other_register_name (expressionP) return FALSE; } +static bfd_boolean double_register_name PARAMS ((expressionS *)); +static bfd_boolean float_register_name PARAMS ((expressionS *)); + +/* Summary of float_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 bfd_boolean +float_register_name (expressionP) + 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 (); + reg_number = reg_name_search (float_registers, FLOAT_REG_NAME_CNT, name); + + /* Put back the delimiting char. */ + * input_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. */ + expressionP->X_add_symbol = NULL; + expressionP->X_op_symbol = NULL; + + return TRUE; + } + + /* Reset the line as if we had not done anything. */ + input_line_pointer = start; + return FALSE; +} + +/* Summary of double_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 bfd_boolean +double_register_name (expressionP) + 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 (); + reg_number = reg_name_search (double_registers, DOUBLE_REG_NAME_CNT, name); + + /* Put back the delimiting char. */ + * input_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. */ + expressionP->X_add_symbol = NULL; + expressionP->X_op_symbol = NULL; + + 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; @@ -865,6 +1030,151 @@ md_convert_frag (abfd, sec, fragP) fragP->fr_var = 0; fragP->fr_fix += 5; } + else if (fragP->fr_subtype == 13) + { + fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol, + fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 3; + } + else if (fragP->fr_subtype == 14) + { + /* Reverse the condition of the first branch. */ + int offset = fragP->fr_fix; + int opcode = fragP->fr_literal[offset + 1] & 0xff; + + switch (opcode) + { + case 0xd0: + opcode = 0xd1; + break; + case 0xd1: + opcode = 0xd0; + break; + case 0xd2: + opcode = 0xdc; + break; + case 0xd3: + opcode = 0xdb; + break; + case 0xd4: + opcode = 0xda; + break; + case 0xd5: + opcode = 0xd9; + break; + case 0xd6: + opcode = 0xd8; + break; + case 0xd7: + opcode = 0xdd; + break; + case 0xd8: + opcode = 0xd6; + break; + case 0xd9: + opcode = 0xd5; + break; + case 0xda: + opcode = 0xd4; + break; + case 0xdb: + opcode = 0xd3; + break; + case 0xdc: + opcode = 0xd2; + break; + case 0xdd: + opcode = 0xd7; + 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 + 2, 1, BFD_RELOC_8_PCREL); + + /* Now create the unconditional branch + fixup to the + final target. */ + fragP->fr_literal[offset + 3] = 0xcc; + fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol, + fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 6; + } + else if (fragP->fr_subtype == 15) + { + /* Reverse the condition of the first branch. */ + int offset = fragP->fr_fix; + int opcode = fragP->fr_literal[offset + 1] & 0xff; + + switch (opcode) + { + case 0xd0: + opcode = 0xd1; + break; + case 0xd1: + opcode = 0xd0; + break; + case 0xd2: + opcode = 0xdc; + break; + case 0xd3: + opcode = 0xdb; + break; + case 0xd4: + opcode = 0xda; + break; + case 0xd5: + opcode = 0xd9; + break; + case 0xd6: + opcode = 0xd8; + break; + case 0xd7: + opcode = 0xdd; + break; + case 0xd8: + opcode = 0xd6; + break; + case 0xd9: + opcode = 0xd5; + break; + case 0xda: + opcode = 0xd4; + break; + case 0xdb: + opcode = 0xd3; + break; + case 0xdc: + opcode = 0xd2; + break; + case 0xdd: + opcode = 0xd7; + 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 + 2, 1, BFD_RELOC_8_PCREL); + + /* Now create the unconditional branch + fixup to the + final target. */ + fragP->fr_literal[offset + 3] = 0xdc; + fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol, + fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL); + fragP->fr_var = 0; + fragP->fr_fix += 8; + } else abort (); } @@ -965,6 +1275,7 @@ md_assemble (str) /* If the instruction is not available on the current machine then it can not possibly match. */ if (opcode->machine + && !(opcode->machine == AM33_2 && HAVE_AM33_2) && !(opcode->machine == AM33 && HAVE_AM33) && !(opcode->machine == AM30 && HAVE_AM30)) goto error; @@ -1059,6 +1370,39 @@ md_assemble (str) goto error; } } + else if (operand->flags & MN10300_OPERAND_FSREG) + { + if (!float_register_name (&ex)) + { + input_line_pointer = hold; + str = hold; + goto error; + } + } + else if (operand->flags & MN10300_OPERAND_FDREG) + { + if (!double_register_name (&ex)) + { + input_line_pointer = hold; + str = hold; + goto error; + } + } + else if (operand->flags & MN10300_OPERAND_FPCR) + { + char *start = input_line_pointer; + char c = get_symbol_end (); + + if (strcasecmp (start, "fpcr") != 0) + { + *input_line_pointer = c; + input_line_pointer = hold; + str = hold; + goto error; + } + *input_line_pointer = c; + goto keep_going; + } else if (operand->flags & MN10300_OPERAND_USP) { char *start = input_line_pointer; @@ -1298,6 +1642,18 @@ md_assemble (str) str = hold; goto error; } + else if (HAVE_AM33_2 && float_register_name (&ex)) + { + input_line_pointer = hold; + str = hold; + goto error; + } + else if (HAVE_AM33_2 && double_register_name (&ex)) + { + input_line_pointer = hold; + str = hold; + goto error; + } else if (*str == ')' || *str == '(') { input_line_pointer = hold; @@ -1324,6 +1680,8 @@ md_assemble (str) mask = MN10300_OPERAND_DREG | MN10300_OPERAND_AREG; if (HAVE_AM33) mask |= MN10300_OPERAND_RREG | MN10300_OPERAND_XRREG; + if (HAVE_AM33_2) + mask |= MN10300_OPERAND_FSREG | MN10300_OPERAND_FDREG; if ((operand->flags & mask) == 0) { input_line_pointer = hold; @@ -1491,6 +1849,9 @@ keep_going: if (opcode->format == FMT_D2) size = 4; + if (opcode->format == FMT_D3) + size = 5; + if (opcode->format == FMT_D4) size = 6; @@ -1529,6 +1890,8 @@ keep_going: /* jmp */ else if (size == 3 && opcode->opcode == 0xcc0000) type = 10; + else if (size == 3 && (opcode->opcode & 0xfff000) == 0xf8d000) + type = 13; /* bCC (uncommon cases) */ else type = 3; @@ -1635,6 +1998,12 @@ keep_going: is really two 8bit immediates. */ number_to_chars_bigendian (f, insn, 4); } + else if (opcode->format == FMT_D3) + { + number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2); + number_to_chars_littleendian (f + 2, insn & 0xffff, 2); + number_to_chars_bigendian (f + 4, extension & 0xff, 1); + } else if (opcode->format == FMT_D4) { unsigned long temp = ((insn & 0xffff) << 16) | (extension & 0xffff); @@ -1897,6 +2266,8 @@ md_estimate_size_before_relax (fragp, seg) || seg != S_GET_SEGMENT (fragp->fr_symbol))) fragp->fr_subtype = 12; + if (fragp->fr_subtype == 13) + return 3; if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0])) abort (); @@ -2075,6 +2446,51 @@ mn10300_insert_operand (insnp, extensionp, operand, val, file, line, shift) *extensionp |= ((val & ((1 << (24 - operand->bits)) - 1)) << operand->shift); } + else if ((operand->flags & (MN10300_OPERAND_FSREG | MN10300_OPERAND_FDREG))) + { + /* See devo/opcodes/m10300-opc.c just before #define FSM0 for an + explanation of these variables. Note that FMT-implied shifts + are not taken into account for FP registers. */ + unsigned long mask_low, mask_high; + int shl_low, shr_high, shl_high; + + switch (operand->bits) + { + case 5: + /* Handle regular FP registers. */ + if (operand->shift >= 0) + { + /* This is an `m' register. */ + shl_low = operand->shift; + shl_high = 8 + (8 & shl_low) + (shl_low & 4) / 4; + } + else + { + /* This is an `n' register. */ + shl_low = -operand->shift; + shl_high = shl_low / 4; + } + + mask_low = 0x0f; + mask_high = 0x10; + shr_high = 4; + break; + + case 3: + /* Handle accumulators. */ + shl_low = -operand->shift; + shl_high = 0; + mask_low = 0x03; + mask_high = 0x04; + shr_high = 2; + break; + + default: + abort (); + } + *insnp |= ((((val & mask_high) >> shr_high) << shl_high) + | ((val & mask_low) << shl_low)); + } else if ((operand->flags & MN10300_OPERAND_EXTENDED) == 0) { *insnp |= (((long) val & ((1 << operand->bits) - 1)) -- 2.30.2