2000-05-25 Alexandre Oliva <aoliva@cygnus.com>
* config/tc-mn10300.c (mn10300_insert_operand): Negate negative accumulator's shift. 2000-05-08 Alexandre Oliva <aoliva@cygnus.com> * config/tc-mn10300.c (md_relax_table, md_convert_frag, md_assemble, md_estimate_size_before_relax): Handle fbCC. 2000-04-20 Alexandre Oliva <aoliva@cygnus.com> * config/tc-mn10300.c (HAVE_AM33): Redefine in terms of HAVE_AM33_2. 2000-04-03 Alexandre Oliva <aoliva@cygnus.com> * 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 <aoliva@cygnus.com> * 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.
This commit is contained in:
parent
e1f834a331
commit
e7b715256e
2 changed files with 440 additions and 1 deletions
|
@ -1,3 +1,26 @@
|
|||
2003-07-09 Alexandre Oliva <aoliva@redhat.com>
|
||||
|
||||
2000-05-25 Alexandre Oliva <aoliva@cygnus.com>
|
||||
* config/tc-mn10300.c (mn10300_insert_operand): Negate negative
|
||||
accumulator's shift.
|
||||
2000-05-08 Alexandre Oliva <aoliva@cygnus.com>
|
||||
* config/tc-mn10300.c (md_relax_table, md_convert_frag,
|
||||
md_assemble, md_estimate_size_before_relax): Handle fbCC.
|
||||
2000-04-20 Alexandre Oliva <aoliva@cygnus.com>
|
||||
* config/tc-mn10300.c (HAVE_AM33): Redefine in terms of
|
||||
HAVE_AM33_2.
|
||||
2000-04-03 Alexandre Oliva <aoliva@cygnus.com>
|
||||
* 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 <aoliva@cygnus.com>
|
||||
* 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 <cgd@broadcom.com>
|
||||
|
||||
* config/tc-mips.c (mips_validate_fix): Do not warn about branch
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in a new issue