aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-mn10300.c
diff options
context:
space:
mode:
authorAlexandre Oliva <aoliva@redhat.com>2003-07-10 02:50:00 +0000
committerAlexandre Oliva <aoliva@redhat.com>2003-07-10 02:50:00 +0000
commite7b715256ee90f442856b236a7586f3811b1fc48 (patch)
tree62f704a63caa6fbffbb616590775522d300a2e8f /gas/config/tc-mn10300.c
parente1f834a331437a34ef43aeb6a2204591192e4ab0 (diff)
downloadfsf-binutils-gdb-e7b715256ee90f442856b236a7586f3811b1fc48.zip
fsf-binutils-gdb-e7b715256ee90f442856b236a7586f3811b1fc48.tar.gz
fsf-binutils-gdb-e7b715256ee90f442856b236a7586f3811b1fc48.tar.bz2
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.
Diffstat (limited to 'gas/config/tc-mn10300.c')
-rw-r--r--gas/config/tc-mn10300.c418
1 files changed, 417 insertions, 1 deletions
diff --git a/gas/config/tc-mn10300.c b/gas/config/tc-mn10300.c
index 5595c76..ff2fffa 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))