/* tc-mn10300.c -- Assembler code for the Matsushita 10300
-
- Copyright (C) 1996, 1997, 1998 Free Software Foundation.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation.
This file is part of GAS, the GNU Assembler.
static boolean data_register_name PARAMS ((expressionS *expressionP));
static boolean address_register_name PARAMS ((expressionS *expressionP));
static boolean other_register_name PARAMS ((expressionS *expressionP));
+static void set_arch_mach PARAMS ((int));
+static int current_machine;
/* fixups */
#define MAX_INSN_FIXUPS (5)
};
struct mn10300_fixup fixups[MAX_INSN_FIXUPS];
static int fc;
+
+/* We must store the value of each register operand so that we can
+ verify that certain registers do not match. */
+int mn10300_reg_operands[MN10300_MAX_OPERANDS];
\f
const char *md_shortopts = "";
struct option md_longopts[] = {
/* The target specific pseudo-ops which we support. */
const pseudo_typeS md_pseudo_table[] =
{
- { NULL, NULL, 0 }
+ { "am30", set_arch_mach, AM30 },
+ { "am33", set_arch_mach, AM33 },
+ { "mn10300", set_arch_mach, MN103 },
+ {NULL, 0, 0}
};
+#define HAVE_AM33 (current_machine == AM33)
+
/* Opcode hash table. */
static struct hash_control *mn10300_hash;
};
#define ADDRESS_REG_NAME_CNT (sizeof(address_registers) / sizeof(struct reg_name))
-/* start-sanitize-am33 */
static const struct reg_name r_registers[] =
{
+ { "a0", 8 },
+ { "a1", 9 },
+ { "a2", 10 },
+ { "a3", 11 },
+ { "d0", 12 },
+ { "d1", 13 },
+ { "d2", 14 },
+ { "d3", 15 },
+ { "e0", 0 },
+ { "e1", 1 },
+ { "e10", 10 },
+ { "e11", 11 },
+ { "e12", 12 },
+ { "e13", 13 },
+ { "e14", 14 },
+ { "e15", 15 },
+ { "e2", 2 },
+ { "e3", 3 },
+ { "e4", 4 },
+ { "e5", 5 },
+ { "e6", 6 },
+ { "e7", 7 },
+ { "e8", 8 },
+ { "e9", 9 },
{ "r0", 0 },
{ "r1", 1 },
{ "r10", 10 },
static const struct reg_name xr_registers[] =
{
+ { "mcrh", 2 },
+ { "mcrl", 3 },
+ { "mcvf", 4 },
+ { "mdrq", 1 },
+ { "sp", 0 },
{ "xr0", 0 },
{ "xr1", 1 },
{ "xr10", 10 },
};
#define XR_REG_NAME_CNT (sizeof(xr_registers) / sizeof(struct reg_name))
-/* end-sanitize-am33 */
static const struct reg_name other_registers[] =
{
}
-/* start-sanitize-am33 */
/* Summary of register_name().
*
* in: Input_line_pointer points to 1st char of operand.
return false;
}
}
-/* end-sanitize-am33 */
/* Summary of register_name().
*
/* This is both a simplification (we don't have to write md_apply_fix)
and support for future optimizations (branch shortening and similar
- stuff in the linker. */
+ stuff in the linker). */
linkrelax = 1;
+
+ /* Set the default machine type. */
+ if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, MN103))
+ as_warn (_("could not set architecture and machine"));
+
+ current_machine = MN103;
}
void
for(;;)
{
- const char *errmsg = NULL;
+ const char *errmsg;
int op_idx;
char *hold;
int extra_shift = 0;
+
+ errmsg = _("Invalid opcode/operands");
+
+ /* Reset the array of register operands. */
+ memset (mn10300_reg_operands, -1, sizeof (mn10300_reg_operands));
+
relaxable = 0;
fc = 0;
match = 0;
next_opindex = 0;
insn = opcode->opcode;
extension = 0;
+
+ /* If the instruction is not available on the current machine
+ then it can not possibly match. */
+ if (opcode->machine
+ && !(opcode->machine == AM33 && HAVE_AM33))
+ goto error;
+
for (op_idx = 1, opindex_ptr = opcode->operands;
*opindex_ptr != 0;
opindex_ptr++, op_idx++)
next_opindex = 0;
}
- errmsg = NULL;
-
while (*str == ' ' || *str == ',')
++str;
*input_line_pointer = c;
goto keep_going;
}
- /* start-sanitize-am33 */
else if (operand->flags & MN10300_OPERAND_RREG)
{
if (!r_register_name (&ex))
input_line_pointer++;
goto keep_going;
}
- /* end-sanitize-am33 */
else if (operand->flags & MN10300_OPERAND_PSW)
{
char *start = input_line_pointer;
value |= 0x08;
*input_line_pointer = c;
}
- /* start-sanitize-am33 */
- else if (strcasecmp (start, "exreg0") == 0)
+ else if (HAVE_AM33
+ && strcasecmp (start, "exreg0") == 0)
{
value |= 0x04;
*input_line_pointer = c;
}
- else if (strcasecmp (start, "exreg1") == 0)
+ else if (HAVE_AM33
+ && strcasecmp (start, "exreg1") == 0)
{
value |= 0x02;
*input_line_pointer = c;
}
- else if (strcasecmp (start, "exother") == 0)
+ else if (HAVE_AM33
+ && strcasecmp (start, "exother") == 0)
{
value |= 0x01;
*input_line_pointer = c;
}
- else if (strcasecmp (start, "all") == 0)
+ else if (HAVE_AM33
+ && strcasecmp (start, "all") == 0)
{
value |= 0xff;
*input_line_pointer = c;
}
- /* end-sanitize-am33 */
else
{
input_line_pointer = hold;
str = hold;
goto error;
}
+ else if (HAVE_AM33 && r_register_name (&ex))
+ {
+ input_line_pointer = hold;
+ str = hold;
+ goto error;
+ }
+ else if (HAVE_AM33 && xr_register_name (&ex))
+ {
+ input_line_pointer = hold;
+ str = hold;
+ goto error;
+ }
else if (*str == ')' || *str == '(')
{
input_line_pointer = hold;
int mask;
mask = MN10300_OPERAND_DREG | MN10300_OPERAND_AREG;
- /* start-sanitize-am33 */
- mask |= MN10300_OPERAND_RREG | MN10300_OPERAND_XRREG;
- /* end-sanitize-am33 */
+ if (HAVE_AM33)
+ mask |= MN10300_OPERAND_RREG | MN10300_OPERAND_XRREG;
if ((operand->flags & mask) == 0)
{
input_line_pointer = hold;
|| opcode->format == FMT_S6
|| opcode->format == FMT_D5)
extra_shift = 16;
- /* start-sanitize-am33 */
else if (opcode->format == FMT_D7)
extra_shift = 8;
- /* end-sanitize-am33 */
+ else if (opcode->format == FMT_D8 || opcode->format == FMT_D9)
+ extra_shift = 8;
else
extra_shift = 0;
ex.X_add_number, (char *) NULL,
0, extra_shift);
+
+ /* And note the register number in the register array. */
+ mn10300_reg_operands[op_idx - 1] = ex.X_add_number;
break;
}
if (*str != ',')
match = 1;
+ /* If this instruction has registers that must not match, verify
+ that they do indeed not match. */
+ if (opcode->no_match_operands)
+ {
+ int i;
+
+ /* Look at each operand to see if it's marked. */
+ for (i = 0; i < MN10300_MAX_OPERANDS; i++)
+ {
+ if ((1 << i) & opcode->no_match_operands)
+ {
+ int j;
+
+ /* operand I is marked. Check that it does not match any
+ operands > I which are marked. */
+ for (j = i + 1; j < MN10300_MAX_OPERANDS; j++)
+ {
+ if (((1 << j) & opcode->no_match_operands)
+ && mn10300_reg_operands[i] == mn10300_reg_operands[j])
+ {
+ errmsg = _("Invalid register specification.");
+ match = 0;
+ goto error;
+ }
+ }
+ }
+ }
+ }
+
error:
if (match == 0)
{
if (opcode->format == FMT_S2 || opcode->format == FMT_D1)
size = 3;
- /* start-sanitize-am33 */
if (opcode->format == FMT_D6)
size = 3;
- if (opcode->format == FMT_D7)
+ if (opcode->format == FMT_D7 || opcode->format == FMT_D10)
size = 4;
- /* end-sanitize-am33 */
+
+ if (opcode->format == FMT_D8)
+ size = 6;
+
+ if (opcode->format == FMT_D9)
+ size = 7;
if (opcode->format == FMT_S4)
size = 5;
if (opcode->format == FMT_S0
|| opcode->format == FMT_S1
|| opcode->format == FMT_D0
- /* start-sanitize-am33 */
|| opcode->format == FMT_D6
|| opcode->format == FMT_D7
- /* end-sanitize-am33 */
+ || opcode->format == FMT_D10
|| opcode->format == FMT_D1)
{
number_to_chars_bigendian (f, insn, size);
number_to_chars_littleendian (f + 2, temp, 4);
number_to_chars_bigendian (f + 6, extension & 0xff, 1);
}
+ else if (opcode->format == FMT_D8)
+ {
+ unsigned long temp = ((insn & 0xff) << 16) | (extension & 0xffff);
+ number_to_chars_bigendian (f, (insn >> 8) & 0xffffff, 3);
+ number_to_chars_bigendian (f + 3, (temp & 0xff), 1);
+ number_to_chars_littleendian (f + 4, temp >> 8, 2);
+ }
+ else if (opcode->format == FMT_D9)
+ {
+ unsigned long temp = ((insn & 0xff) << 24) | (extension & 0xffffff);
+ number_to_chars_bigendian (f, (insn >> 8) & 0xffffff, 3);
+ number_to_chars_littleendian (f + 3, temp, 4);
+ }
/* Create any fixups. */
for (i = 0; i < fc; i++)
implicitly 32bits. */
if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
reloc_size = 32;
+ else if ((operand->flags & MN10300_OPERAND_24BIT) != 0)
+ reloc_size = 24;
else
reloc_size = operand->bits;
}
else
{
- reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+ reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof( asymbol *));
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->addend = fixp->fx_offset;
}
return reloc;
{
long min, max;
offsetT test;
+ int bits;
+
+ bits = operand->bits;
+ if (operand->flags & MN10300_OPERAND_24BIT)
+ bits = 24;
if ((operand->flags & MN10300_OPERAND_SIGNED) != 0)
{
- max = (1 << (operand->bits - 1)) - 1;
- min = - (1 << (operand->bits - 1));
+ max = (1 << (bits - 1)) - 1;
+ min = - (1 << (bits - 1));
}
else
{
- max = (1 << operand->bits) - 1;
+ max = (1 << bits) - 1;
min = 0;
}
*extensionp |= ((val & ((1 << (32 - operand->bits)) - 1))
<< operand->shift);
}
+ else if ((operand->flags & MN10300_OPERAND_24BIT) != 0)
+ {
+ *insnp |= (val >> (24 - operand->bits)) & ((1 << operand->bits) - 1);
+ *extensionp |= ((val & ((1 << (24 - operand->bits)) - 1))
+ << operand->shift);
+ }
else if ((operand->flags & MN10300_OPERAND_EXTENDED) == 0)
{
*insnp |= (((long) val & ((1 << operand->bits) - 1))
{
long min, max;
offsetT test;
+ int bits;
+
+ bits = operand->bits;
+ if (operand->flags & MN10300_OPERAND_24BIT)
+ bits = 24;
if ((operand->flags & MN10300_OPERAND_SIGNED) != 0)
{
- max = (1 << (operand->bits - 1)) - 1;
- min = - (1 << (operand->bits - 1));
+ max = (1 << (bits - 1)) - 1;
+ min = - (1 << (bits - 1));
}
else
{
- max = (1 << operand->bits) - 1;
+ max = (1 << bits) - 1;
min = 0;
}
}
return 1;
}
+
+static void
+set_arch_mach (mach)
+ int mach;
+{
+ if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, mach))
+ as_warn (_("could not set architecture and machine"));
+
+ current_machine = mach;
+}