/* tc-d10v.c -- Assembler code for the Mitsubishi D10V
-
- Copyright (C) 1996, 1997 Free Software Foundation.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
Boston, MA 02111-1307, USA. */
#include <stdio.h>
-#include <ctype.h>
#include "as.h"
-#include "subsegs.h"
+#include "safe-ctype.h"
+#include "subsegs.h"
#include "opcode/d10v.h"
#include "elf/ppc.h"
+//#include "read.h"
const char comment_chars[] = ";";
const char line_comment_chars[] = "#";
int Optimizing = 0;
-#define AT_WORD (-1)
+#define AT_WORD_P(X) ((X)->X_op == O_right_shift \
+ && (X)->X_op_symbol != NULL \
+ && symbol_constant_p ((X)->X_op_symbol) \
+ && S_GET_VALUE ((X)->X_op_symbol) == AT_WORD_RIGHT_SHIFT)
+#define AT_WORD_RIGHT_SHIFT 2
-/* fixups */
+/* Fixups. */
#define MAX_INSN_FIXUPS (5)
struct d10v_fixup
{
static Fixups FixUps[2];
static Fixups *fixups;
-/* local functions */
+static int do_not_ignore_hash = 0;
+
+typedef int packing_type;
+#define PACK_UNSPEC (0) /* Packing order not specified. */
+#define PACK_PARALLEL (1) /* "||" */
+#define PACK_LEFT_RIGHT (2) /* "->" */
+#define PACK_RIGHT_LEFT (3) /* "<-" */
+static packing_type etype = PACK_UNSPEC; /* Used by d10v_cleanup. */
+
+/* True if instruction swapping warnings should be inhibited.
+ --nowarnswap. */
+static boolean flag_warn_suppress_instructionswap;
+
+/* True if instruction packing should be performed when --gstabs is specified.
+ --gstabs-packing, --no-gstabs-packing. */
+static boolean flag_allow_gstabs_packing = 1;
+
+/* Local functions. */
static int reg_name_search PARAMS ((char *name));
static int register_name PARAMS ((expressionS *expressionP));
static int check_range PARAMS ((unsigned long num, int bits, int flags));
static int get_operands PARAMS ((expressionS exp[]));
static struct d10v_opcode *find_opcode PARAMS ((struct d10v_opcode *opcode, expressionS ops[]));
static unsigned long build_insn PARAMS ((struct d10v_opcode *opcode, expressionS *opers, unsigned long insn));
-static void write_long PARAMS ((struct d10v_opcode *opcode, unsigned long insn, Fixups *fx));
+static void write_long PARAMS ((unsigned long insn, Fixups *fx));
static void write_1_short PARAMS ((struct d10v_opcode *opcode, unsigned long insn, Fixups *fx));
-static int write_2_short PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1,
- struct d10v_opcode *opcode2, unsigned long insn2, int exec_type, Fixups *fx));
+static int write_2_short PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1,
+ struct d10v_opcode *opcode2, unsigned long insn2, packing_type exec_type, Fixups *fx));
static unsigned long do_assemble PARAMS ((char *str, struct d10v_opcode **opcode));
static unsigned long d10v_insert_operand PARAMS (( unsigned long insn, int op_type,
offsetT value, int left, fixS *fix));
-static int parallel_ok PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1,
+static int parallel_ok PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1,
struct d10v_opcode *opcode2, unsigned long insn2,
- int exec_type));
+ packing_type exec_type));
+static symbolS * find_symbol_matching_register PARAMS ((expressionS *));
-struct option md_longopts[] = {
+struct option md_longopts[] =
+{
+#define OPTION_NOWARNSWAP (OPTION_MD_BASE)
+ {"nowarnswap", no_argument, NULL, OPTION_NOWARNSWAP},
+#define OPTION_GSTABSPACKING (OPTION_MD_BASE + 1)
+ {"gstabspacking", no_argument, NULL, OPTION_GSTABSPACKING},
+ {"gstabs-packing", no_argument, NULL, OPTION_GSTABSPACKING},
+#define OPTION_NOGSTABSPACKING (OPTION_MD_BASE + 2)
+ {"nogstabspacking", no_argument, NULL, OPTION_NOGSTABSPACKING},
+ {"no-gstabs-packing", no_argument, NULL, OPTION_NOGSTABSPACKING},
{NULL, no_argument, NULL, 0}
};
-size_t md_longopts_size = sizeof(md_longopts);
+
+size_t md_longopts_size = sizeof (md_longopts);
static void d10v_dot_word PARAMS ((int));
/* Opcode hash table. */
static struct hash_control *d10v_hash;
-/* reg_name_search does a binary search of the d10v_predefined_registers
- array to see if "name" is a valid regiter name. Returns the register
- number from the array on success, or -1 on failure. */
+/* Do a binary search of the d10v_predefined_registers array to see if
+ NAME is a valid regiter name. Return the register number from the
+ array on success, or -1 on failure. */
static int
reg_name_search (name)
int cmp;
low = 0;
- high = d10v_reg_name_cnt() - 1;
+ high = d10v_reg_name_cnt () - 1;
do
{
high = middle - 1;
else if (cmp > 0)
low = middle + 1;
- else
- return d10v_predefined_registers[middle].value;
+ else
+ return d10v_predefined_registers[middle].value;
}
while (low <= high);
return -1;
}
-/* register_name() checks the string at input_line_pointer
- to see if it is a valid register name */
+/* Check the string at input_line_pointer
+ to see if it is a valid register name. */
static int
register_name (expressionP)
{
int reg_number;
char c, *p = input_line_pointer;
-
- while (*p && *p!='\n' && *p!='\r' && *p !=',' && *p!=' ' && *p!=')')
+
+ while (*p
+ && *p != '\n' && *p != '\r' && *p != ',' && *p != ' ' && *p != ')')
p++;
c = *p;
if (c)
*p++ = 0;
- /* look to see if it's in the register table */
+ /* Look to see if it's in the register table. */
reg_number = reg_name_search (input_line_pointer);
- if (reg_number >= 0)
+ if (reg_number >= 0)
{
expressionP->X_op = O_register;
- /* temporarily store a pointer to the string here */
- expressionP->X_op_symbol = (struct symbol *)input_line_pointer;
+ /* Temporarily store a pointer to the string here. */
+ expressionP->X_op_symbol = (symbolS *) input_line_pointer;
expressionP->X_add_number = reg_number;
input_line_pointer = p;
return 1;
}
if (c)
- *(p-1) = c;
+ *(p - 1) = c;
return 0;
}
-
static int
check_range (num, bits, flags)
unsigned long num;
int bits;
int flags;
{
- long min, max, bit1;
- int retval=0;
+ long min, max;
+ int retval = 0;
- /* don't bother checking 16-bit values */
+ /* Don't bother checking 16-bit values. */
if (bits == 16)
return 0;
if (flags & OPERAND_SHIFT)
{
- /* all special shift operands are unsigned */
- /* and <= 16. We allow 0 for now. */
- if (num>16)
+ /* All special shift operands are unsigned and <= 16.
+ We allow 0 for now. */
+ if (num > 16)
return 1;
else
return 0;
if (flags & OPERAND_SIGNED)
{
- max = (1 << (bits - 1))-1;
- min = - (1 << (bits - 1));
- if (((long)num > max) || ((long)num < min))
- retval = 1;
+ /* Signed 3-bit integers are restricted to the (-2, 3) range. */
+ if (flags & RESTRICTED_NUM3)
+ {
+ if ((long) num < -2 || (long) num > 3)
+ retval = 1;
+ }
+ else
+ {
+ max = (1 << (bits - 1)) - 1;
+ min = - (1 << (bits - 1));
+ if (((long) num > max) || ((long) num < min))
+ retval = 1;
+ }
}
else
{
max = (1 << bits) - 1;
min = 0;
- if ((num > max) || (num < min))
+ if (((long) num > max) || ((long) num < min))
retval = 1;
}
return retval;
}
-
void
md_show_usage (stream)
- FILE *stream;
+ FILE *stream;
{
- fprintf(stream, "D10V options:\n\
--O optimize. Will do some operations in parallel.\n");
-}
+ fprintf (stream, _("D10V options:\n\
+-O Optimize. Will do some operations in parallel.\n\
+--gstabs-packing Pack adjacent short instructions together even\n\
+ when --gstabs is specified. On by default.\n\
+--no-gstabs-packing If --gstabs is specified, do not pack adjacent\n\
+ instructions together.\n"));
+}
int
md_parse_option (c, arg)
int c;
- char *arg;
+ char *arg ATTRIBUTE_UNUSED;
{
switch (c)
{
case 'O':
- /* Optimize. Will attempt to parallelize operations */
+ /* Optimize. Will attempt to parallelize operations. */
Optimizing = 1;
break;
+ case OPTION_NOWARNSWAP:
+ flag_warn_suppress_instructionswap = 1;
+ break;
+ case OPTION_GSTABSPACKING:
+ flag_allow_gstabs_packing = 1;
+ break;
+ case OPTION_NOGSTABSPACKING:
+ flag_allow_gstabs_packing = 0;
+ break;
default:
return 0;
}
symbolS *
md_undefined_symbol (name)
- char *name;
+ char *name ATTRIBUTE_UNUSED;
{
return 0;
}
-/* Turn a string in input_line_pointer into a floating point constant of type
- type, and store the appropriate bytes in *litP. The number of LITTLENUMS
- emitted is stored in *sizeP . An error message is returned, or NULL on OK.
- */
+/* Turn a string in input_line_pointer into a floating point constant
+ of type TYPE, and store the appropriate bytes in *LITP. The number
+ of LITTLENUMS emitted is stored in *SIZEP. An error message is
+ returned, or NULL on OK. */
+
char *
md_atof (type, litP, sizeP)
int type;
LITTLENUM_TYPE words[4];
char *t;
int i;
-
+
switch (type)
{
case 'f':
break;
default:
*sizeP = 0;
- return "bad call to md_atof";
+ return _("bad call to md_atof");
}
t = atof_ieee (input_line_pointer, type, words);
if (t)
input_line_pointer = t;
-
+
*sizeP = prec * 2;
-
+
for (i = 0; i < prec; i++)
{
md_number_to_chars (litP, (valueT) words[i], 2);
- litP += 2;
+ litP += 2;
}
return NULL;
}
void
md_convert_frag (abfd, sec, fragP)
- bfd *abfd;
- asection *sec;
- fragS *fragP;
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *sec ATTRIBUTE_UNUSED;
+ fragS *fragP ATTRIBUTE_UNUSED;
{
abort ();
}
return ((addr + (1 << align) - 1) & (-1 << align));
}
-
void
md_begin ()
{
char *prev_name = "";
struct d10v_opcode *opcode;
- d10v_hash = hash_new();
+ d10v_hash = hash_new ();
/* Insert unique names into hash table. The D10v instruction set
has many identical opcode names that have different opcodes based
on the operands. This hash table then provides a quick index to
the first opcode with a particular name in the opcode table. */
- for (opcode = (struct d10v_opcode *)d10v_opcodes; opcode->name; opcode++)
+ for (opcode = (struct d10v_opcode *) d10v_opcodes; opcode->name; opcode++)
{
if (strcmp (prev_name, opcode->name))
{
- prev_name = (char *)opcode->name;
+ prev_name = (char *) opcode->name;
hash_insert (d10v_hash, opcode->name, (char *) opcode);
}
}
FixUps[1].next = &FixUps[0];
}
+/* Remove the postincrement or postdecrement operator ( '+' or '-' )
+ from an expression. */
-/* this function removes the postincrement or postdecrement
- operator ( '+' or '-' ) from an expression */
-
-static int postfix (p)
+static int
+postfix (p)
char *p;
{
- while (*p != '-' && *p != '+')
+ while (*p != '-' && *p != '+')
{
- if (*p==0 || *p=='\n' || *p=='\r')
+ if (*p == 0 || *p == '\n' || *p == '\r')
break;
p++;
}
- if (*p == '-')
+ if (*p == '-')
{
*p = ' ';
return (-1);
}
- if (*p == '+')
+ if (*p == '+')
{
*p = ' ';
return (1);
return (0);
}
-
-static bfd_reloc_code_real_type
-get_reloc (op)
+static bfd_reloc_code_real_type
+get_reloc (op)
struct d10v_operand *op;
{
int bits = op->bits;
- if (bits <= 4)
+ if (bits <= 4)
return (0);
-
- if (op->flags & OPERAND_ADDR)
+
+ if (op->flags & OPERAND_ADDR)
{
if (bits == 8)
return (BFD_RELOC_D10V_10_PCREL_R);
return (BFD_RELOC_16);
}
-
-/* get_operands parses a string of operands and returns
- an array of expressions */
+/* Parse a string of operands. Return an array of expressions. */
static int
-get_operands (exp)
+get_operands (exp)
expressionS exp[];
{
char *p = input_line_pointer;
int numops = 0;
int post = 0;
+ int uses_at = 0;
- while (*p)
+ while (*p)
{
- while (*p == ' ' || *p == '\t' || *p == ',')
+ while (*p == ' ' || *p == '\t' || *p == ',')
p++;
- if (*p==0 || *p=='\n' || *p=='\r')
+ if (*p == 0 || *p == '\n' || *p == '\r')
break;
-
- if (*p == '@')
+
+ if (*p == '@')
{
+ uses_at = 1;
+
p++;
exp[numops].X_op = O_absent;
- if (*p == '(')
+ if (*p == '(')
{
p++;
exp[numops].X_add_number = OPERAND_ATPAR;
}
- else if (*p == '-')
+ else if (*p == '-')
{
p++;
exp[numops].X_add_number = OPERAND_ATMINUS;
continue;
}
- if (*p == ')')
+ if (*p == ')')
{
- /* just skip the trailing paren */
+ /* Just skip the trailing paren. */
p++;
continue;
}
input_line_pointer = p;
- /* check to see if it might be a register name */
+ /* Check to see if it might be a register name. */
if (!register_name (&exp[numops]))
{
- /* parse as an expression */
- expression (&exp[numops]);
+ /* Parse as an expression. */
+ if (uses_at)
+ {
+ /* Any expression that involves the indirect addressing
+ cannot also involve immediate addressing. Therefore
+ the use of the hash character is illegal. */
+ int save = do_not_ignore_hash;
+ do_not_ignore_hash = 1;
+
+ expression (&exp[numops]);
+
+ do_not_ignore_hash = save;
+ }
+ else
+ expression (&exp[numops]);
}
- if (!strncasecmp (input_line_pointer, "@word", 5))
+ if (strncasecmp (input_line_pointer, "@word", 5) == 0)
{
+ input_line_pointer += 5;
if (exp[numops].X_op == O_register)
{
- /* if it looked like a register name but was followed by "@word" */
- /* then it was really a symbol, so change it to one */
+ /* If it looked like a register name but was followed by
+ "@word" then it was really a symbol, so change it to
+ one. */
exp[numops].X_op = O_symbol;
- exp[numops].X_add_symbol = symbol_find_or_make ((char *)exp[numops].X_op_symbol);
+ exp[numops].X_add_symbol =
+ symbol_find_or_make ((char *) exp[numops].X_op_symbol);
}
- exp[numops].X_op_symbol = (struct symbol *)-1;
- exp[numops].X_add_number = AT_WORD;
- input_line_pointer += 5;
+
+ /* Check for identifier@word+constant. */
+ if (*input_line_pointer == '-' || *input_line_pointer == '+')
+ {
+ expressionS new_exp;
+ expression (&new_exp);
+ exp[numops].X_add_number = new_exp.X_add_number;
+ }
+
+ /* Convert expr into a right shift by AT_WORD_RIGHT_SHIFT. */
+ {
+ expressionS new_exp;
+ memset (&new_exp, 0, sizeof new_exp);
+ new_exp.X_add_number = AT_WORD_RIGHT_SHIFT;
+ new_exp.X_op = O_constant;
+ new_exp.X_unsigned = 1;
+ exp[numops].X_op_symbol = make_expr_symbol (&new_exp);
+ exp[numops].X_op = O_right_shift;
+ }
+
+ know (AT_WORD_P (&exp[numops]));
}
-
- if (exp[numops].X_op == O_illegal)
- as_bad ("illegal operand");
- else if (exp[numops].X_op == O_absent)
- as_bad ("missing operand");
+
+ if (exp[numops].X_op == O_illegal)
+ as_bad (_("illegal operand"));
+ else if (exp[numops].X_op == O_absent)
+ as_bad (_("missing operand"));
numops++;
p = input_line_pointer;
}
- switch (post)
+ switch (post)
{
- case -1: /* postdecrement mode */
+ case -1: /* Postdecrement mode. */
exp[numops].X_op = O_absent;
exp[numops++].X_add_number = OPERAND_MINUS;
break;
- case 1: /* postincrement mode */
+ case 1: /* Postincrement mode. */
exp[numops].X_op = O_absent;
exp[numops++].X_add_number = OPERAND_PLUS;
break;
}
static unsigned long
-d10v_insert_operand (insn, op_type, value, left, fix)
+d10v_insert_operand (insn, op_type, value, left, fix)
unsigned long insn;
int op_type;
offsetT value;
bits = d10v_operands[op_type].bits;
- /* truncate to the proper number of bits */
+ /* Truncate to the proper number of bits. */
if (check_range (value, bits, d10v_operands[op_type].flags))
- as_bad_where (fix->fx_file, fix->fx_line, "operand out of range: %d", value);
+ as_bad_where (fix->fx_file, fix->fx_line,
+ _("operand out of range: %d"), value);
value &= 0x7FFFFFFF >> (31 - bits);
insn |= (value << shift);
return insn;
}
-
-/* build_insn takes a pointer to the opcode entry in the opcode table
- and the array of operand expressions and returns the instruction */
+/* Take a pointer to the opcode entry in the opcode table and the
+ array of operand expressions. Return the instruction. */
static unsigned long
-build_insn (opcode, opers, insn)
+build_insn (opcode, opers, insn)
struct d10v_opcode *opcode;
expressionS *opers;
unsigned long insn;
{
int i, bits, shift, flags, format;
unsigned long number;
-
- /* the insn argument is only used for the DIVS kludge */
+
+ /* The insn argument is only used for the DIVS kludge. */
if (insn)
format = LONG_R;
else
insn = opcode->opcode;
format = opcode->format;
}
-
- for (i=0;opcode->operands[i];i++)
+
+ for (i = 0; opcode->operands[i]; i++)
{
flags = d10v_operands[opcode->operands[i]].flags;
bits = d10v_operands[opcode->operands[i]].bits;
shift = d10v_operands[opcode->operands[i]].shift;
number = opers[i].X_add_number;
- if (flags & OPERAND_REG)
+ if (flags & OPERAND_REG)
{
number &= REGISTER_MASK;
if (format == LONG_L)
shift += 15;
}
- if (opers[i].X_op != O_register && opers[i].X_op != O_constant)
+ if (opers[i].X_op != O_register && opers[i].X_op != O_constant)
{
- /* now create a fixup */
+ /* Now create a fixup. */
if (fixups->fc >= MAX_INSN_FIXUPS)
- as_fatal ("too many fixups");
+ as_fatal (_("too many fixups"));
- if (opers[i].X_op == O_symbol && number == AT_WORD &&
- opers[i].X_op_symbol == (struct symbol *)-1 )
+ if (AT_WORD_P (&opers[i]))
{
- number = opers[i].X_add_number = 0;
+ /* Reconize XXX>>1+N aka XXX@word+N as special (AT_WORD). */
fixups->fix[fixups->fc].reloc = BFD_RELOC_D10V_18;
- } else
- fixups->fix[fixups->fc].reloc =
- get_reloc((struct d10v_operand *)&d10v_operands[opcode->operands[i]]);
+ opers[i].X_op = O_symbol;
+ opers[i].X_op_symbol = NULL; /* Should free it. */
+ /* number is left shifted by AT_WORD_RIGHT_SHIFT so
+ that, it is aligned with the symbol's value. Later,
+ BFD_RELOC_D10V_18 will right shift (symbol_value +
+ X_add_number). */
+ number <<= AT_WORD_RIGHT_SHIFT;
+ opers[i].X_add_number = number;
+ }
+ else
+ fixups->fix[fixups->fc].reloc =
+ get_reloc ((struct d10v_operand *) &d10v_operands[opcode->operands[i]]);
- if (fixups->fix[fixups->fc].reloc == BFD_RELOC_16 ||
+ if (fixups->fix[fixups->fc].reloc == BFD_RELOC_16 ||
fixups->fix[fixups->fc].reloc == BFD_RELOC_D10V_18)
- fixups->fix[fixups->fc].size = 2;
+ fixups->fix[fixups->fc].size = 2;
else
fixups->fix[fixups->fc].size = 4;
-
+
fixups->fix[fixups->fc].exp = opers[i];
fixups->fix[fixups->fc].operand = opcode->operands[i];
- fixups->fix[fixups->fc].pcrel = (flags & OPERAND_ADDR) ? true : false;
+ fixups->fix[fixups->fc].pcrel =
+ (flags & OPERAND_ADDR) ? true : false;
(fixups->fc)++;
}
- /* truncate to the proper number of bits */
+ /* Truncate to the proper number of bits. */
if ((opers[i].X_op == O_constant) && check_range (number, bits, flags))
- as_bad("operand out of range: %d",number);
+ as_bad (_("operand out of range: %d"), number);
number &= 0x7FFFFFFF >> (31 - bits);
insn = insn | (number << shift);
}
- /* kludge: for DIVS, we need to put the operands in twice */
- /* on the second pass, format is changed to LONG_R to force */
- /* the second set of operands to not be shifted over 15 */
- if ((opcode->opcode == OPCODE_DIVS) && (format==LONG_L))
+ /* kludge: for DIVS, we need to put the operands in twice */
+ /* on the second pass, format is changed to LONG_R to force
+ the second set of operands to not be shifted over 15. */
+ if ((opcode->opcode == OPCODE_DIVS) && (format == LONG_L))
insn = build_insn (opcode, opers, insn);
-
+
return insn;
}
-/* write out a long form instruction */
+/* Write out a long form instruction. */
+
static void
-write_long (opcode, insn, fx)
- struct d10v_opcode *opcode;
+write_long (insn, fx)
unsigned long insn;
Fixups *fx;
{
int i, where;
- char *f = frag_more(4);
+ char *f = frag_more (4);
insn |= FM11;
number_to_chars_bigendian (f, insn, 4);
- for (i=0; i < fx->fc; i++)
+ for (i = 0; i < fx->fc; i++)
{
if (fx->fix[i].reloc)
- {
- where = f - frag_now->fr_literal;
+ {
+ where = f - frag_now->fr_literal;
if (fx->fix[i].size == 2)
where += 2;
if (fx->fix[i].reloc == BFD_RELOC_D10V_18)
- fx->fix[i].operand |= 4096;
+ fx->fix[i].operand |= 4096;
fix_new_exp (frag_now,
where,
fx->fc = 0;
}
+/* Write out a short form instruction by itself. */
-/* write out a short form instruction by itself */
static void
-write_1_short (opcode, insn, fx)
+write_1_short (opcode, insn, fx)
struct d10v_opcode *opcode;
unsigned long insn;
Fixups *fx;
{
- char *f = frag_more(4);
+ char *f = frag_more (4);
int i, where;
if (opcode->exec_type & PARONLY)
- as_fatal ("Instruction must be executed in parallel with another instruction.");
+ as_fatal (_("Instruction must be executed in parallel with another instruction."));
- /* the other container needs to be NOP */
- /* according to 4.3.1: for FM=00, sub-instructions performed only
- by IU cannot be encoded in L-container. */
+ /* The other container needs to be NOP. */
+ /* According to 4.3.1: for FM=00, sub-instructions performed only
+ by IU cannot be encoded in L-container. */
if (opcode->unit == IU)
- insn |= FM00 | (NOP << 15); /* right container */
+ insn |= FM00 | (NOP << 15); /* Right container. */
else
- insn = FM00 | (insn << 15) | NOP; /* left container */
+ insn = FM00 | (insn << 15) | NOP; /* Left container. */
number_to_chars_bigendian (f, insn, 4);
- for (i=0; i < fx->fc; i++)
+ for (i = 0; i < fx->fc; i++)
{
if (fx->fix[i].reloc)
- {
- where = f - frag_now->fr_literal;
+ {
+ where = f - frag_now->fr_literal;
if (fx->fix[i].size == 2)
where += 2;
if (fx->fix[i].reloc == BFD_RELOC_D10V_18)
- fx->fix[i].operand |= 4096;
+ fx->fix[i].operand |= 4096;
- /* if it's an R reloc, we may have to switch it to L */
- if ( (fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R) && (opcode->unit != IU) )
+ /* If it's an R reloc, we may have to switch it to L. */
+ if ((fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R)
+ && (opcode->unit != IU))
fx->fix[i].operand |= 1024;
fix_new_exp (frag_now,
- where,
+ where,
fx->fix[i].size,
&(fx->fix[i].exp),
fx->fix[i].pcrel,
fx->fc = 0;
}
-/* write out a short form instruction if possible */
-/* return number of instructions not written out */
+/* Expects two short instructions.
+ If possible, writes out both as a single packed instruction.
+ Otherwise, writes out the first one, packed with a NOP.
+ Returns number of instructions not written out. */
+
static int
-write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)
+write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)
struct d10v_opcode *opcode1, *opcode2;
unsigned long insn1, insn2;
- int exec_type;
+ packing_type exec_type;
Fixups *fx;
{
unsigned long insn;
char *f;
- int i,j, where;
+ int i, j, where;
- if ( (exec_type != 1) && ((opcode1->exec_type & PARONLY)
- || (opcode2->exec_type & PARONLY)))
- as_fatal("Instruction must be executed in parallel");
-
- if ( (opcode1->format & LONG_OPCODE) || (opcode2->format & LONG_OPCODE))
- as_fatal ("Long instructions may not be combined.");
+ if ((exec_type != PACK_PARALLEL)
+ && ((opcode1->exec_type & PARONLY) || (opcode2->exec_type & PARONLY)))
+ as_fatal (_("Instruction must be executed in parallel"));
- if(opcode1->exec_type & BRANCH_LINK && exec_type == 0)
- {
- /* Instructions paired with a subroutine call are executed before the
- subroutine, so don't do these pairings unless explicitly requested. */
- write_1_short (opcode1, insn1, fx->next);
- return (1);
- }
+ if ((opcode1->format & LONG_OPCODE) || (opcode2->format & LONG_OPCODE))
+ as_fatal (_("Long instructions may not be combined."));
- switch (exec_type)
+ switch (exec_type)
{
- case 0: /* order not specified */
- if ( Optimizing && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type))
+ case PACK_UNSPEC: /* Order not specified. */
+ if (opcode1->exec_type & ALONE)
{
- /* parallel */
+ /* Case of a short branch on a separate GAS line.
+ Pack with NOP. */
+ write_1_short (opcode1, insn1, fx->next);
+ return 1;
+ }
+ if (Optimizing
+ && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type))
+ {
+ /* Parallel. */
if (opcode1->unit == IU)
insn = FM00 | (insn2 << 15) | insn1;
else if (opcode2->unit == MU)
insn = FM00 | (insn2 << 15) | insn1;
else
{
- insn = FM00 | (insn1 << 15) | insn2;
+ insn = FM00 | (insn1 << 15) | insn2;
+ /* Advance over dummy fixup since packed insn1 in L. */
fx = fx->next;
}
}
- else if (opcode1->unit == IU)
- {
- /* reverse sequential */
- insn = FM10 | (insn2 << 15) | insn1;
- }
+ else if (opcode1->unit == IU)
+ /* Reverse sequential with IU opcode1 on right and done first. */
+ insn = FM10 | (insn2 << 15) | insn1;
else
{
- /* sequential */
+ /* Sequential with non-IU opcode1 on left and done first. */
insn = FM01 | (insn1 << 15) | insn2;
- fx = fx->next;
+ /* Advance over dummy fixup since packed insn1 in L. */
+ fx = fx->next;
}
break;
- case 1: /* parallel */
- if (opcode1->exec_type & SEQ || opcode2->exec_type & SEQ)
- as_fatal ("One of these instructions may not be executed in parallel.");
+ case PACK_PARALLEL:
+ if (opcode1->exec_type & SEQ || opcode2->exec_type & SEQ)
+ as_fatal
+ (_("One of these instructions may not be executed in parallel."));
if (opcode1->unit == IU)
{
if (opcode2->unit == IU)
- as_fatal ("Two IU instructions may not be executed in parallel");
- if (flag_warn_instructionswap)
- as_warn ("Swapping instruction order");
- insn = FM00 | (insn2 << 15) | insn1;
+ as_fatal (_("Two IU instructions may not be executed in parallel"));
+ if (!flag_warn_suppress_instructionswap)
+ as_warn (_("Swapping instruction order"));
+ insn = FM00 | (insn2 << 15) | insn1;
}
else if (opcode2->unit == MU)
{
if (opcode1->unit == MU)
- as_fatal ("Two MU instructions may not be executed in parallel");
- if (flag_warn_instructionswap)
- as_warn ("Swapping instruction order");
+ as_fatal (_("Two MU instructions may not be executed in parallel"));
+ if (!flag_warn_suppress_instructionswap)
+ as_warn (_("Swapping instruction order"));
insn = FM00 | (insn2 << 15) | insn1;
}
else
{
- insn = FM00 | (insn1 << 15) | insn2;
+ insn = FM00 | (insn1 << 15) | insn2;
+ /* Advance over dummy fixup since packed insn1 in L. */
fx = fx->next;
}
break;
- case 2: /* sequential */
- if (opcode1->unit == IU)
- as_fatal ("IU instruction may not be in the left container");
- insn = FM01 | (insn1 << 15) | insn2;
+
+ case PACK_LEFT_RIGHT:
+ if (opcode1->unit != IU)
+ insn = FM01 | (insn1 << 15) | insn2;
+ else if (opcode2->unit == MU || opcode2->unit == EITHER)
+ {
+ if (!flag_warn_suppress_instructionswap)
+ as_warn (_("Swapping instruction order"));
+ insn = FM10 | (insn2 << 15) | insn1;
+ }
+ else
+ as_fatal (_("IU instruction may not be in the left container"));
+ if (opcode1->exec_type & ALONE)
+ as_warn (_("Instruction in R container is squashed by flow control instruction in L container."));
+ /* Advance over dummy fixup. */
fx = fx->next;
break;
- case 3: /* reverse sequential */
- if (opcode2->unit == MU)
- as_fatal ("MU instruction may not be in the right container");
- insn = FM10 | (insn1 << 15) | insn2;
+
+ case PACK_RIGHT_LEFT:
+ if (opcode2->unit != MU)
+ insn = FM10 | (insn1 << 15) | insn2;
+ else if (opcode1->unit == IU || opcode1->unit == EITHER)
+ {
+ if (!flag_warn_suppress_instructionswap)
+ as_warn (_("Swapping instruction order"));
+ insn = FM01 | (insn2 << 15) | insn1;
+ }
+ else
+ as_fatal (_("MU instruction may not be in the right container"));
+ if (opcode2->exec_type & ALONE)
+ as_warn (_("Instruction in R container is squashed by flow control instruction in L container."));
+ /* Advance over dummy fixup. */
fx = fx->next;
break;
+
default:
- as_fatal("unknown execution type passed to write_2_short()");
+ as_fatal (_("unknown execution type passed to write_2_short()"));
}
- f = frag_more(4);
+ f = frag_more (4);
number_to_chars_bigendian (f, insn, 4);
- for (j=0; j<2; j++)
+ /* Process fixup chains.
+ Note that the packing code above advanced fx conditionally.
+ dlindsay@cygnus.com: There's something subtle going on here involving
+ _dummy_first_bfd_reloc_code_real. This is related to the
+ difference between BFD_RELOC_D10V_10_PCREL_R and _L, ie whether
+ a fixup is done in the L or R container. A bug in this code
+ can pass Plum Hall fine, yet still affect hand-written assembler. */
+
+ for (j = 0; j < 2; j++)
{
- for (i=0; i < fx->fc; i++)
+ for (i = 0; i < fx->fc; i++)
{
if (fx->fix[i].reloc)
{
- where = f - frag_now->fr_literal;
+ where = f - frag_now->fr_literal;
if (fx->fix[i].size == 2)
where += 2;
-
- if ( (fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R) && (j == 0) )
+
+ if ((fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R) && (j == 0))
fx->fix[i].operand |= 1024;
-
+
if (fx->fix[i].reloc == BFD_RELOC_D10V_18)
- fx->fix[i].operand |= 4096;
+ fx->fix[i].operand |= 4096;
fix_new_exp (frag_now,
- where,
+ where,
fx->fix[i].size,
&(fx->fix[i].exp),
fx->fix[i].pcrel,
return (0);
}
+/* Check 2 instructions and determine if they can be safely
+ executed in parallel. Return 1 if they can be. */
-/* Check 2 instructions and determine if they can be safely */
-/* executed in parallel. Returns 1 if they can be. */
static int
parallel_ok (op1, insn1, op2, insn2, exec_type)
struct d10v_opcode *op1, *op2;
unsigned long insn1, insn2;
- int exec_type;
+ packing_type exec_type;
{
int i, j, flags, mask, shift, regno;
unsigned long ins, mod[2], used[2];
|| (op1->unit == MU && op2->unit == MU))
return 0;
- /* If the first instruction is a branch and this is auto parallazation,
- don't combine with any second instruction. */
- if (exec_type == 0 && (op1->exec_type & BRANCH) != 0)
+ /* If this is auto parallization, and either instruction is a branch,
+ don't parallel. */
+ if (exec_type == PACK_UNSPEC
+ && (op1->exec_type & ALONE || op2->exec_type & ALONE))
return 0;
/* The idea here is to create two sets of bitmasks (mod and used)
memory and the second reads, then they cannot be done in
parallel. Likewise, if the first instruction mucks with the psw
and the second reads the PSW (which includes C, F0, and F1), then
- they cannot operate safely in parallel. */
+ they cannot operate safely in parallel. */
- /* the bitmasks (mod and used) look like this (bit 31 = MSB) */
- /* r0-r15 0-15 */
- /* a0-a1 16-17 */
- /* cr (not psw) 18 */
- /* psw 19 */
- /* mem 20 */
+ /* The bitmasks (mod and used) look like this (bit 31 = MSB). */
+ /* r0-r15 0-15 */
+ /* a0-a1 16-17 */
+ /* cr (not psw) 18 */
+ /* psw 19 */
+ /* mem 20 */
- for (j=0;j<2;j++)
+ for (j = 0; j < 2; j++)
{
if (j == 0)
{
if (flags & OPERAND_REG)
{
regno = (ins >> shift) & mask;
- if (flags & OPERAND_ACC)
+ if (flags & (OPERAND_ACC0 | OPERAND_ACC1))
regno += 16;
- else if (flags & OPERAND_CONTROL) /* mvtc or mvfc */
- {
+ else if (flags & OPERAND_CONTROL) /* mvtc or mvfc. */
+ {
if (regno == 0)
regno = 19;
else
- regno = 18;
+ regno = 18;
}
- else if (flags & (OPERAND_FFLAG|OPERAND_CFLAG))
+ else if (flags & (OPERAND_FFLAG | OPERAND_CFLAG))
regno = 19;
-
- if ( flags & OPERAND_DEST )
+
+ if (flags & OPERAND_DEST)
{
mod[j] |= 1 << regno;
if (flags & OPERAND_EVEN)
}
else
{
- used[j] |= 1 << regno ;
+ used[j] |= 1 << regno;
if (flags & OPERAND_EVEN)
used[j] |= 1 << (regno + 1);
/* Auto inc/dec also modifies the register. */
- if (op->operands[i+1] != 0
- && (d10v_operands[op->operands[i+1]].flags
+ if (op->operands[i + 1] != 0
+ && (d10v_operands[op->operands[i + 1]].flags
& (OPERAND_PLUS | OPERAND_MINUS)) != 0)
mod[j] |= 1 << regno;
}
}
else if (flags & OPERAND_ATMINUS)
{
- /* SP implicitly used/modified */
+ /* SP implicitly used/modified. */
mod[j] |= 1 << 15;
used[j] |= 1 << 15;
}
return 0;
}
-
-/* This is the main entry point for the machine-dependent assembler. str points to a
- machine-dependent instruction. This function is supposed to emit the frags/bytes
- it assembles to. For the D10V, it mostly handles the special VLIW parsing and packing
- and leaves the difficult stuff to do_assemble().
- */
+/* This is the main entry point for the machine-dependent assembler.
+ STR points to a machine-dependent instruction. This function is
+ supposed to emit the frags/bytes it assembles to. For the D10V, it
+ mostly handles the special VLIW parsing and packing and leaves the
+ difficult stuff to do_assemble(). */
static unsigned long prev_insn;
static struct d10v_opcode *prev_opcode = 0;
md_assemble (str)
char *str;
{
+ /* etype is saved extype. For multi-line instructions. */
+
+ packing_type extype = PACK_UNSPEC; /* Parallel, etc. */
+
struct d10v_opcode *opcode;
unsigned long insn;
- int extype=0; /* execution type; parallel, etc */
- static int etype=0; /* saved extype. used for multiline instructions */
char *str2;
- if (etype == 0)
+ if (etype == PACK_UNSPEC)
{
- /* look for the special multiple instruction separators */
+ /* Look for the special multiple instruction separators. */
str2 = strstr (str, "||");
- if (str2)
- extype = 1;
+ if (str2)
+ extype = PACK_PARALLEL;
else
{
str2 = strstr (str, "->");
- if (str2)
- extype = 2;
+ if (str2)
+ extype = PACK_LEFT_RIGHT;
else
{
str2 = strstr (str, "<-");
- if (str2)
- extype = 3;
+ if (str2)
+ extype = PACK_RIGHT_LEFT;
}
}
- /* str2 points to the separator, if one */
- if (str2)
+ /* STR2 points to the separator, if there is one. */
+ if (str2)
{
*str2 = 0;
-
- /* if two instructions are present and we already have one saved
- then first write it out */
- d10v_cleanup();
-
- /* assemble first instruction and save it */
+
+ /* If two instructions are present and we already have one saved,
+ then first write out the saved one. */
+ d10v_cleanup ();
+
+ /* Assemble first instruction and save it. */
prev_insn = do_assemble (str, &prev_opcode);
- if (prev_insn == -1)
- as_fatal ("can't find opcode ");
+ prev_seg = now_seg;
+ prev_subseg = now_subseg;
+ if (prev_insn == (unsigned long) -1)
+ as_fatal (_("can't find opcode "));
fixups = fixups->next;
str = str2 + 2;
}
}
insn = do_assemble (str, &opcode);
- if (insn == -1)
+ if (insn == (unsigned long) -1)
{
- if (extype)
+ if (extype != PACK_UNSPEC)
{
etype = extype;
return;
}
- as_fatal ("can't find opcode ");
+ as_fatal (_("can't find opcode "));
}
- if (etype)
+ if (etype != PACK_UNSPEC)
{
extype = etype;
- etype = 0;
+ etype = PACK_UNSPEC;
}
- /* if this is a long instruction, write it and any previous short instruction */
- if (opcode->format & LONG_OPCODE)
+ /* If this is a long instruction, write it and any previous short
+ instruction. */
+ if (opcode->format & LONG_OPCODE)
{
- if (extype)
- as_fatal("Unable to mix instructions as specified");
- d10v_cleanup();
- write_long (opcode, insn, fixups);
+ if (extype != PACK_UNSPEC)
+ as_fatal (_("Unable to mix instructions as specified"));
+ d10v_cleanup ();
+ write_long (insn, fixups);
prev_opcode = NULL;
return;
}
-
- if (prev_opcode && prev_seg && ((prev_seg != now_seg) || (prev_subseg != now_subseg)))
- d10v_cleanup();
-
- if (prev_opcode && (write_2_short (prev_opcode, prev_insn, opcode, insn, extype, fixups) == 0))
+
+ if (prev_opcode
+ && prev_seg
+ && ((prev_seg != now_seg) || (prev_subseg != now_subseg)))
+ d10v_cleanup ();
+
+ if (prev_opcode
+ && (write_2_short (prev_opcode, prev_insn, opcode, insn, extype, fixups) == 0))
{
- /* no instructions saved */
+ /* No instructions saved. */
prev_opcode = NULL;
}
else
{
- if (extype)
- as_fatal("Unable to mix instructions as specified");
- /* save off last instruction so it may be packed on next pass */
+ if (extype != PACK_UNSPEC)
+ as_fatal (_("Unable to mix instructions as specified"));
+ /* Save last instruction so it may be packed on next pass. */
prev_opcode = opcode;
prev_insn = insn;
prev_seg = now_seg;
}
}
-
-/* do_assemble assembles a single instruction and returns an opcode */
-/* it returns -1 (an invalid opcode) on error */
+/* Assemble a single instruction.
+ Return an opcode, or -1 (an invalid opcode) on error. */
static unsigned long
-do_assemble (str, opcode)
+do_assemble (str, opcode)
char *str;
struct d10v_opcode **opcode;
{
expressionS myops[6];
unsigned long insn;
- /* Drop leading whitespace */
+ /* Drop leading whitespace. */
while (*str == ' ')
str++;
- /* find the opcode end */
+ /* Find the opcode end. */
for (op_start = op_end = (unsigned char *) (str);
*op_end
&& nlen < 20
&& !is_end_of_line[*op_end] && *op_end != ' ';
op_end++)
{
- name[nlen] = tolower(op_start[nlen]);
+ name[nlen] = TOLOWER (op_start[nlen]);
nlen++;
}
name[nlen] = 0;
if (nlen == 0)
- return (-1);
-
- /* find the first opcode with the proper name */
- *opcode = (struct d10v_opcode *)hash_find (d10v_hash, name);
+ return -1;
+
+ /* Find the first opcode with the proper name. */
+ *opcode = (struct d10v_opcode *) hash_find (d10v_hash, name);
if (*opcode == NULL)
- as_fatal ("unknown opcode: %s",name);
+ as_fatal (_("unknown opcode: %s"), name);
save = input_line_pointer;
input_line_pointer = op_end;
return -1;
input_line_pointer = save;
- insn = build_insn ((*opcode), myops, 0);
+ insn = build_insn ((*opcode), myops, 0);
return (insn);
}
-/* find_opcode() gets a pointer to an entry in the opcode table. */
-/* It must look at all opcodes with the same name and use the operands */
-/* to choose the correct opcode. */
+/* Find the symbol which has the same name as the register in EXP. */
+
+static symbolS *
+find_symbol_matching_register (exp)
+ expressionS *exp;
+{
+ int i;
+
+ if (exp->X_op != O_register)
+ return NULL;
+
+ /* Find the name of the register. */
+ for (i = d10v_reg_name_cnt (); i--;)
+ if (d10v_predefined_registers[i].value == exp->X_add_number)
+ break;
+
+ if (i < 0)
+ abort ();
+
+ /* Now see if a symbol has been defined with the same name. */
+ return symbol_find (d10v_predefined_registers[i].name);
+}
+
+/* Get a pointer to an entry in the opcode table.
+ The function must look at all opcodes with the same name and use
+ the operands to choose the correct opcode. */
static struct d10v_opcode *
find_opcode (opcode, myops)
struct d10v_opcode *opcode;
expressionS myops[];
{
- int i, match, done;
+ int i, match;
struct d10v_opcode *next_opcode;
- /* get all the operands and save them as expressions */
+ /* Get all the operands and save them as expressions. */
get_operands (myops);
- /* now see if the operand is a fake. If so, find the correct size */
- /* instruction, if possible */
+ /* Now see if the operand is a fake. If so, find the correct size
+ instruction, if possible. */
if (opcode->format == OPCODE_FAKE)
{
int opnum = opcode->operands[0];
int flags;
-
+
if (myops[opnum].X_op == O_register)
{
myops[opnum].X_op = O_symbol;
- myops[opnum].X_add_symbol = symbol_find_or_make ((char *)myops[opnum].X_op_symbol);
+ myops[opnum].X_add_symbol =
+ symbol_find_or_make ((char *) myops[opnum].X_op_symbol);
myops[opnum].X_add_number = 0;
myops[opnum].X_op_symbol = NULL;
}
- next_opcode=opcode+1;
+ next_opcode = opcode + 1;
/* If the first operand is supposed to be a register, make sure
we got a valid one. */
int num = myops[0].X_add_number;
if (X_op != O_register
- || (flags & OPERAND_ACC) != (num & OPERAND_ACC)
- || (flags & OPERAND_FFLAG) != (num & OPERAND_FFLAG)
- || (flags & OPERAND_CFLAG) != (num & OPERAND_CFLAG)
- || (flags & OPERAND_CONTROL) != (num & OPERAND_CONTROL))
+ || (num & ~flags
+ & (OPERAND_GPR | OPERAND_ACC0 | OPERAND_ACC1
+ | OPERAND_FFLAG | OPERAND_CFLAG | OPERAND_CONTROL)))
{
- as_bad ("bad opcode or operands");
+ as_bad (_("bad opcode or operands"));
return 0;
}
}
- if (myops[opnum].X_op == O_constant || (myops[opnum].X_op == O_symbol &&
- S_IS_DEFINED(myops[opnum].X_add_symbol) &&
- (S_GET_SEGMENT(myops[opnum].X_add_symbol) == now_seg)))
+ if (myops[opnum].X_op == O_constant
+ || (myops[opnum].X_op == O_symbol
+ && S_IS_DEFINED (myops[opnum].X_add_symbol)
+ && (S_GET_SEGMENT (myops[opnum].X_add_symbol) == now_seg)))
{
- for (i=0; opcode->operands[i+1]; i++)
+ for (i = 0; opcode->operands[i + 1]; i++)
{
int bits = d10v_operands[next_opcode->operands[opnum]].bits;
int flags = d10v_operands[next_opcode->operands[opnum]].flags;
if (flags & OPERAND_ADDR)
bits += 2;
+
if (myops[opnum].X_op == O_constant)
{
if (!check_range (myops[opnum].X_add_number, bits, flags))
}
else
{
+ fragS *sym_frag;
fragS *f;
- long value;
- /* calculate the current address by running through the previous frags */
- /* and adding our current offset */
- for (value = 0, f = frchain_now->frch_root; f; f = f->fr_next)
- value += f->fr_fix + f->fr_offset;
+ unsigned long current_position;
+ unsigned long symbol_position;
+ unsigned long value;
+ boolean found_symbol;
+
+ /* Calculate the address of the current instruction
+ and the address of the symbol. Do this by summing
+ the offsets of previous frags until we reach the
+ frag containing the symbol, and the current frag. */
+ sym_frag = symbol_get_frag (myops[opnum].X_add_symbol);
+ found_symbol = false;
+
+ current_position =
+ obstack_next_free (&frchain_now->frch_obstack)
+ - frag_now->fr_literal;
+ symbol_position = S_GET_VALUE (myops[opnum].X_add_symbol);
+
+ for (f = frchain_now->frch_root; f; f = f->fr_next)
+ {
+ current_position += f->fr_fix + f->fr_offset;
+
+ if (f == sym_frag)
+ found_symbol = true;
+
+ if (! found_symbol)
+ symbol_position += f->fr_fix + f->fr_offset;
+ }
+
+ value = symbol_position;
if (flags & OPERAND_ADDR)
- value = S_GET_VALUE(myops[opnum].X_add_symbol) - value -
- (obstack_next_free(&frchain_now->frch_obstack) - frag_now->fr_literal);
- else
- value = S_GET_VALUE(myops[opnum].X_add_symbol);
+ value -= current_position;
- if (myops[opnum].X_add_number == AT_WORD &&
- myops[opnum].X_op_symbol == (struct symbol *)-1)
+ if (AT_WORD_P (&myops[opnum]))
{
if (bits > 4)
{
}
next_opcode++;
}
- as_fatal ("value out of range");
+ as_fatal (_("value out of range"));
}
else
{
- /* not a constant, so use a long instruction */
- return opcode+2;
+ /* Not a constant, so use a long instruction. */
+ return opcode + 2;
}
}
else
{
match = 0;
- /* now search the opcode table table for one with operands */
- /* that matches what we've got */
+ /* Now search the opcode table table for one with operands
+ that matches what we've got. */
while (!match)
{
match = 1;
- for (i = 0; opcode->operands[i]; i++)
+ for (i = 0; opcode->operands[i]; i++)
{
int flags = d10v_operands[opcode->operands[i]].flags;
int X_op = myops[i].X_op;
int num = myops[i].X_add_number;
- if (X_op==0)
+ if (X_op == 0)
{
- match=0;
+ match = 0;
break;
}
-
+
if (flags & OPERAND_REG)
{
- if ((X_op != O_register) ||
- ((flags & OPERAND_ACC) != (num & OPERAND_ACC)) ||
- ((flags & OPERAND_FFLAG) != (num & OPERAND_FFLAG)) ||
- ((flags & OPERAND_CFLAG) != (num & OPERAND_CFLAG)) ||
- ((flags & OPERAND_CONTROL) != (num & OPERAND_CONTROL)))
+ if ((X_op != O_register)
+ || (num & ~flags
+ & (OPERAND_GPR | OPERAND_ACC0 | OPERAND_ACC1
+ | OPERAND_FFLAG | OPERAND_CFLAG
+ | OPERAND_CONTROL)))
{
- match=0;
+ match = 0;
break;
}
}
-
- if (((flags & OPERAND_MINUS) && ((X_op != O_absent) || (num != OPERAND_MINUS))) ||
- ((flags & OPERAND_PLUS) && ((X_op != O_absent) || (num != OPERAND_PLUS))) ||
+
+ if (((flags & OPERAND_MINUS) && ((X_op != O_absent) || (num != OPERAND_MINUS))) ||
+ ((flags & OPERAND_PLUS) && ((X_op != O_absent) || (num != OPERAND_PLUS))) ||
((flags & OPERAND_ATMINUS) && ((X_op != O_absent) || (num != OPERAND_ATMINUS))) ||
- ((flags & OPERAND_ATPAR) && ((X_op != O_absent) || (num != OPERAND_ATPAR))) ||
- ((flags & OPERAND_ATSIGN) && ((X_op != O_absent) || (num != OPERAND_ATSIGN))))
+ ((flags & OPERAND_ATPAR) && ((X_op != O_absent) || (num != OPERAND_ATPAR))) ||
+ ((flags & OPERAND_ATSIGN) && ((X_op != O_absent) || ((num != OPERAND_ATSIGN) && (num != OPERAND_ATPAR)))))
{
- match=0;
+ match = 0;
break;
- }
+ }
+
+ /* Unfortunatly, for the indirect operand in
+ instructions such as ``ldb r1, @(c,r14)'' this
+ function can be passed X_op == O_register (because
+ 'c' is a valid register name). However we cannot
+ just ignore the case when X_op == O_register but
+ flags & OPERAND_REG is null, so we check to see if a
+ symbol of the same name as the register exists. If
+ the symbol does exist, then the parser was unable to
+ distinguish the two cases and we fix things here.
+ (Ref: PR14826) */
+
+ if (!(flags & OPERAND_REG) && (X_op == O_register))
+ {
+ symbolS *sym = find_symbol_matching_register (&myops[i]);
+
+ if (sym != NULL)
+ {
+ myops[i].X_op = X_op = O_symbol;
+ myops[i].X_add_symbol = sym;
+ }
+ else
+ as_bad
+ (_("illegal operand - register name found where none expected"));
+ }
}
- /* we're only done if the operands matched so far AND there
- are no more to check */
- if (match && myops[i].X_op==0)
+
+ /* We're only done if the operands matched so far AND there
+ are no more to check. */
+ if (match && myops[i].X_op == 0)
break;
else
match = 0;
- next_opcode = opcode+1;
- if (next_opcode->opcode == 0)
+ next_opcode = opcode + 1;
+
+ if (next_opcode->opcode == 0)
break;
- if (strcmp(next_opcode->name, opcode->name))
+
+ if (strcmp (next_opcode->name, opcode->name))
break;
+
opcode = next_opcode;
}
}
- if (!match)
+ if (!match)
{
- as_bad ("bad opcode or operands");
+ as_bad (_("bad opcode or operands"));
return (0);
}
- /* Check that all registers that are required to be even are. */
- /* Also, if any operands were marked as registers, but were really symbols */
- /* fix that here. */
- for (i=0; opcode->operands[i]; i++)
+ /* Check that all registers that are required to be even are.
+ Also, if any operands were marked as registers, but were really symbols,
+ fix that here. */
+ for (i = 0; opcode->operands[i]; i++)
{
if ((d10v_operands[opcode->operands[i]].flags & OPERAND_EVEN) &&
- (myops[i].X_add_number & 1))
- as_fatal("Register number must be EVEN");
+ (myops[i].X_add_number & 1))
+ as_fatal (_("Register number must be EVEN"));
if (myops[i].X_op == O_register)
{
- if (!(d10v_operands[opcode->operands[i]].flags & OPERAND_REG))
+ if (!(d10v_operands[opcode->operands[i]].flags & OPERAND_REG))
{
myops[i].X_op = O_symbol;
- myops[i].X_add_symbol = symbol_find_or_make ((char *)myops[i].X_op_symbol);
+ myops[i].X_add_symbol =
+ symbol_find_or_make ((char *) myops[i].X_op_symbol);
myops[i].X_add_number = 0;
myops[i].X_op_symbol = NULL;
}
return opcode;
}
-/* if while processing a fixup, a reloc really needs to be created */
-/* then it is done here */
-
+/* 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;
+ asection *seg ATTRIBUTE_UNUSED;
fixS *fixp;
{
arelent *reloc;
reloc = (arelent *) xmalloc (sizeof (arelent));
- 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->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);
+ _("reloc %d not supported by object file format"),
+ (int) fixp->fx_r_type);
return NULL;
}
+
+ if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ reloc->address = fixp->fx_offset;
+
reloc->addend = fixp->fx_addnumber;
+
return reloc;
}
int
md_estimate_size_before_relax (fragp, seg)
- fragS *fragp;
- asection *seg;
+ fragS *fragp ATTRIBUTE_UNUSED;
+ asection *seg ATTRIBUTE_UNUSED;
{
abort ();
return 0;
-}
+}
long
md_pcrel_from_section (fixp, sec)
fixS *fixp;
segT sec;
{
- if (fixp->fx_addsy != (symbolS *)NULL && (!S_IS_DEFINED (fixp->fx_addsy) ||
- (S_GET_SEGMENT (fixp->fx_addsy) != sec)))
+ if (fixp->fx_addsy != (symbolS *) NULL
+ && (!S_IS_DEFINED (fixp->fx_addsy)
+ || (S_GET_SEGMENT (fixp->fx_addsy) != sec)))
return 0;
return fixp->fx_frag->fr_address + fixp->fx_where;
}
md_apply_fix3 (fixp, valuep, seg)
fixS *fixp;
valueT *valuep;
- segT seg;
+ segT seg ATTRIBUTE_UNUSED;
{
char *where;
unsigned long insn;
long value;
int op_type;
- int left=0;
+ int left = 0;
if (fixp->fx_addsy == (symbolS *) NULL)
{
else
{
/* We don't actually support subtracting a symbol. */
- as_bad_where (fixp->fx_file, fixp->fx_line,
- "expression too complex");
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("expression too complex"));
}
}
}
fixp->fx_r_type = BFD_RELOC_D10V_18;
}
else
- fixp->fx_r_type = get_reloc((struct d10v_operand *)&d10v_operands[op_type]);
+ fixp->fx_r_type =
+ get_reloc ((struct d10v_operand *) &d10v_operands[op_type]);
}
/* Fetch the instruction, insert the fully resolved operand
case BFD_RELOC_D10V_10_PCREL_R:
case BFD_RELOC_D10V_18_PCREL:
case BFD_RELOC_D10V_18:
- /* instruction addresses are always right-shifted by 2 */
- value >>= 2;
+ /* Instruction addresses are always right-shifted by 2. */
+ value >>= AT_WORD_RIGHT_SHIFT;
if (fixp->fx_size == 2)
bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
else
{
- insn = d10v_insert_operand (insn, op_type, (offsetT)value, left, fixp);
- bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
+ struct d10v_opcode *rep, *repi;
+
+ rep = (struct d10v_opcode *) hash_find (d10v_hash, "rep");
+ repi = (struct d10v_opcode *) hash_find (d10v_hash, "repi");
+ if ((insn & FM11) == FM11
+ && ( (repi != NULL && (insn & repi->mask) == (unsigned) repi->opcode)
+ || (rep != NULL && (insn & rep->mask) == (unsigned) rep->opcode))
+ && value < 4)
+ as_fatal
+ (_("line %d: rep or repi must include at least 4 instructions"),
+ fixp->fx_line);
+ insn =
+ d10v_insert_operand (insn, op_type, (offsetT) value, left, fixp);
+ bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
}
break;
case BFD_RELOC_32:
case BFD_RELOC_16:
bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
break;
+
+ case BFD_RELOC_VTABLE_INHERIT:
+ case BFD_RELOC_VTABLE_ENTRY:
+ fixp->fx_done = 0;
+ return 1;
+
default:
- as_fatal ("line %d: unknown relocation type: 0x%x",fixp->fx_line,fixp->fx_r_type);
+ as_fatal (_("line %d: unknown relocation type: 0x%x"),
+ fixp->fx_line, fixp->fx_r_type);
}
return 0;
}
-/* d10v_cleanup() is called after the assembler has finished parsing the input
- file or after a label is defined. Because the D10V assembler sometimes saves short
- instructions to see if it can package them with the next instruction, there may
- be a short instruction that still needs written. */
+/* d10v_cleanup() is called after the assembler has finished parsing
+ the input file, when a label is read from the input file, or when a
+ stab directive is output. Because the D10V assembler sometimes
+ saves short instructions to see if it can package them with the
+ next instruction, there may be a short instruction that still needs
+ to be written.
+
+ NOTE: accesses a global, etype.
+ NOTE: invoked by various macros such as md_cleanup: see. */
+
int
d10v_cleanup ()
{
segT seg;
subsegT subseg;
- if (prev_opcode)
+ /* If cleanup was invoked because the assembler encountered, e.g., a
+ user label, we write out the pending instruction, if any. If it
+ was invoked because the assembler is outputting a piece of line
+ debugging information, though, we write out the pending
+ instruction only if the --no-gstabs-packing command line switch
+ has been specified. */
+ if (prev_opcode
+ && etype == PACK_UNSPEC
+ && (! outputting_stabs_line_debug || ! flag_allow_gstabs_packing))
{
seg = now_seg;
subseg = now_subseg;
- subseg_set (prev_seg, prev_subseg);
+
+ if (prev_seg)
+ subseg_set (prev_seg, prev_subseg);
+
write_1_short (prev_opcode, prev_insn, fixups->next);
+
subseg_set (seg, subseg);
prev_opcode = NULL;
}
return 1;
}
-/* Like normal .word, except support @word */
-/* clobbers input_line_pointer, checks end-of-line. */
+/* Like normal .word, except support @word. */
+/* Clobbers input_line_pointer, checks end-of-line. */
+
static void
-d10v_dot_word (nbytes)
- register int nbytes; /* 1=.byte, 2=.word, 4=.long */
+d10v_dot_word (dummy)
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS exp;
- bfd_reloc_code_real_type reloc;
char *p;
- int offset;
if (is_it_end_of_statement ())
{
{
exp.X_add_number = 0;
input_line_pointer += 5;
-
+
p = frag_more (2);
- fix_new_exp (frag_now, p - frag_now->fr_literal, 2,
+ fix_new_exp (frag_now, p - frag_now->fr_literal, 2,
&exp, 0, BFD_RELOC_D10V_18);
}
else
}
while (*input_line_pointer++ == ',');
- input_line_pointer--; /* Put terminator back into stream. */
+ input_line_pointer--; /* Put terminator back into stream. */
demand_empty_rest_of_line ();
}
+/* Mitsubishi asked that we support some old syntax that apparently
+ had immediate operands starting with '#'. This is in some of their
+ sample code but is not documented (although it appears in some
+ examples in their assembler manual). For now, we'll solve this
+ compatibility problem by simply ignoring any '#' at the beginning
+ of an operand. */
-/* Mitsubishi asked that we support some old syntax that apparently */
-/* had immediate operands starting with '#'. This is in some of their */
-/* sample code but is not documented (although it appears in some */
-/* examples in their assembler manual). For now, we'll solve this */
-/* compatibility problem by simply ignoring any '#' at the beginning */
-/* of an operand. */
-
-/* operands that begin with '#' should fall through to here */
-/* from expr.c */
+/* Operands that begin with '#' should fall through to here. */
+/* From expr.c. */
-void
+void
md_operand (expressionP)
expressionS *expressionP;
{
- if (*input_line_pointer == '#')
+ if (*input_line_pointer == '#' && ! do_not_ignore_hash)
{
input_line_pointer++;
expression (expressionP);
}
}
+boolean
+d10v_fix_adjustable (fixP)
+ fixS *fixP;
+{
+ if (fixP->fx_addsy == NULL)
+ return 1;
+
+ /* Prevent all adjustments to global symbols. */
+ if (S_IS_EXTERN (fixP->fx_addsy))
+ return 0;
+ if (S_IS_WEAK (fixP->fx_addsy))
+ return 0;
+
+ /* We need the symbol name for the VTABLE entries. */
+ if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ return 0;
+
+ return 1;
+}
+
+int
+d10v_force_relocation (fixp)
+ fixS *fixp;
+{
+ if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ return 1;
+
+ return 0;
+}