const char comment_chars[] = ";";
const char line_comment_chars[] = "#";
const char line_separator_chars[] = "";
-const char *md_shortopts = "OnN";
+const char *md_shortopts = "OnNcC";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dD";
#define NOP_ALL 2
static int warn_nops = 0;
static int Optimizing = 0;
+static int warn_register_name_conflicts = 1;
#define FORCE_SHORT 1
#define FORCE_LONG 2
static Fixups FixUps[2];
static Fixups *fixups;
-/* Whether current and previous instruction is a word multiply. */
+/* Whether current and previous instruction are word multiply insns. */
static int cur_mul32_p = 0;
static int prev_mul32_p = 0;
static int flag_explicitly_parallel = 0;
static int flag_xp_state = 0;
+/* Whether current and previous left sub-instruction disables
+ execution of right sub-instruction. */
+static int cur_left_kills_right_p = 0;
+static int prev_left_kills_right_p = 0;
+
/* The known current alignment of the current section. */
static int d30v_current_align;
static segT d30v_current_align_seg;
static symbolS *d30v_last_label;
/* Two nops */
-#define NOP_LEFT ((long long)NOP << 32)
-#define NOP_RIGHT ((long long)NOP)
+#define NOP_LEFT ((long long) NOP << 32)
+#define NOP_RIGHT ((long long) NOP)
#define NOP2 (FM00 | NOP_LEFT | NOP_RIGHT)
/* local functions */
expressionS ops[],int fsize, int cmp_hack));
static long long build_insn PARAMS ((struct d30v_insn *opcode, expressionS *opers));
static void write_long PARAMS ((struct d30v_insn *opcode, long long insn, Fixups *fx));
-static void write_1_short PARAMS ((struct d30v_insn *opcode, long long insn, Fixups *fx));
+static void write_1_short PARAMS ((struct d30v_insn *opcode, long long insn,
+ Fixups *fx, int use_sequential));
static int write_2_short PARAMS ((struct d30v_insn *opcode1, long long insn1,
struct d30v_insn *opcode2, long long insn2, exec_type_enum exec_type, Fixups *fx));
static long long do_assemble PARAMS ((char *str, struct d30v_insn *opcode,
- int shortp));
+ int shortp, int is_parallel));
static int parallel_ok PARAMS ((struct d30v_insn *opcode1, unsigned long insn1,
struct d30v_insn *opcode2, unsigned long insn2,
exec_type_enum exec_type));
int cmp;
low = 0;
- high = reg_name_cnt() - 1;
+ high = reg_name_cnt () - 1;
do
{
high = middle - 1;
else if (cmp > 0)
low = middle + 1;
- else
+ else
+ {
+ if (symbol_find (name) != NULL)
+ {
+ if (warn_register_name_conflicts)
+ as_warn (_("Register name %s conflicts with symbol of the same name"),
+ name);
+ }
+
return pre_defined_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 */
+ to see if it is a valid register name. */
static int
register_name (expressionP)
if (bits == 32)
return 0;
+ if (flags & OPERAND_SHIFT)
+ {
+ /* We know that all shifts are right by three bits.... */
+
+ if (flags & OPERAND_SIGNED)
+ num = (unsigned long) (((/*signed*/ long) num) >> 3);
+ else
+ num >>= 3;
+ }
+
if (flags & OPERAND_SIGNED)
{
max = (1 << (bits - 1))-1;
if ((num > max) || (num < min))
retval = 1;
}
+
return retval;
}
md_show_usage (stream)
FILE *stream;
{
- fprintf(stream, _("\nD30V options:\n\
+ fprintf (stream, _("\nD30V options:\n\
-O Make adjacent short instructions parallel if possible.\n\
-n Warn about all NOPs inserted by the assembler.\n\
--N Warn about NOPs inserted after word multiplies.\n"));
-}
+-N Warn about NOPs inserted after word multiplies.\n\
+-c Warn about symbols whoes names match register names.\n\
+-C Opposite of -C. -c is the default.\n"));
+}
int
md_parse_option (c, arg)
warn_nops = NOP_MULTIPLY;
break;
+ case 'c':
+ warn_register_name_conflicts = 1;
+ break;
+
+ case 'C':
+ warn_register_name_conflicts = 0;
+ break;
+
default:
return 0;
}
void
md_begin ()
{
- struct d30v_opcode *opcode;
- d30v_hash = hash_new();
+ struct d30v_opcode * opcode;
+ d30v_hash = hash_new ();
/* Insert opcode names into a hash table. */
for (opcode = (struct d30v_opcode *)d30v_opcode_table; opcode->name; opcode++)
break;
case 12:
if (!(op->flags & OPERAND_SHIFT))
- as_warn(_("unexpected 12-bit reloc type"));
+ as_warn (_("unexpected 12-bit reloc type"));
if (rel_flag == RELOC_PCREL)
return BFD_RELOC_D30V_15_PCREL;
else
return BFD_RELOC_D30V_15;
case 18:
if (!(op->flags & OPERAND_SHIFT))
- as_warn(_("unexpected 18-bit reloc type"));
+ as_warn (_("unexpected 18-bit reloc type"));
if (rel_flag == RELOC_PCREL)
return BFD_RELOC_D30V_21_PCREL;
else
as_fatal (_("too many fixups"));
fixups->fix[fixups->fc].reloc =
- get_reloc((struct d30v_operand *)&d30v_operand_table[form->operands[i]], op->reloc_flag);
+ get_reloc ((struct d30v_operand *)&d30v_operand_table[form->operands[i]], op->reloc_flag);
fixups->fix[fixups->fc].size = 4;
fixups->fix[fixups->fc].exp = opers[i];
fixups->fix[fixups->fc].operand = form->operands[i];
/* 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);
if (bits < 31)
number &= 0x7FFFFFFF >> (31 - bits);
if (flags & OPERAND_SHIFT)
Fixups *fx;
{
int i, where;
- char *f = frag_more(8);
+ char *f = frag_more (8);
insn |= FM11;
d30v_number_to_chars (f, insn, 8);
}
-/* 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, use_sequential)
struct d30v_insn *opcode;
long long insn;
Fixups *fx;
+ int use_sequential;
{
- char *f = frag_more(8);
+ char *f = frag_more (8);
int i, where;
if (warn_nops == NOP_ALL)
- as_warn (_("NOP inserted"));
+ as_warn (_("%s NOP inserted"), use_sequential ?
+ _("sequential") : _("parallel"));
- /* 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->op->unit == IU)
- insn |= FM00 | NOP_LEFT; /* right container */
+ /* The other container needs to be NOP. */
+ if (use_sequential)
+ {
+ /* Use a sequential NOP rather than a parallel one,
+ as the current instruction is a FLAG_MUL32 type one
+ and the next instruction is a load. */
+
+ /* According to 4.3.1: for FM=01, sub-instructions performed
+ only by IU cannot be encoded in L-container. */
+
+ if (opcode->op->unit == IU)
+ insn |= FM10 | NOP_LEFT; /* right then left */
+ else
+ insn = FM01 | (insn << 32) | NOP_RIGHT; /* left then right */
+ }
else
- insn = FM00 | (insn << 32) | NOP_RIGHT; /* left container */
+ {
+ /* According to 4.3.1: for FM=00, sub-instructions performed
+ only by IU cannot be encoded in L-container. */
+
+ if (opcode->op->unit == IU)
+ insn |= FM00 | NOP_LEFT; /* right container */
+ else
+ insn = FM00 | (insn << 32) | NOP_RIGHT; /* left container */
+ }
d30v_number_to_chars (f, insn, 8);
fx->fc = 0;
}
-/* write out a short form instruction if possible */
-/* return number of instructions not written out */
+/* Write out a short form instruction if possible.
+ Return number of instructions not written out. */
static int
write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)
struct d30v_insn *opcode1, *opcode2;
char *f;
int i,j, where;
- if(exec_type != EXEC_PARALLEL &&
- ((opcode1->op->flags_used & (FLAG_JSR | FLAG_DELAY)) == FLAG_JSR))
+ if (exec_type == EXEC_SEQ
+ && (opcode1->op->flags_used & (FLAG_JMP | FLAG_JSR))
+ && ((opcode1->op->flags_used & FLAG_DELAY) == 0)
+ && ((opcode1->ecc == ECC_AL) || ! Optimizing))
{
- /* subroutines must be called from 32-bit boundaries */
- /* so the return address will be correct */
- write_1_short (opcode1, insn1, fx->next);
- return (1);
+ /* Unconditional, non-delayed branches kill instructions in
+ the right bin. Conditional branches don't always but if
+ we are not optimizing, then we have been asked to produce
+ an error about such constructs. For the purposes of this
+ test, subroutine calls are considered to be branches. */
+ write_1_short (opcode1, insn1, fx->next, false);
+ return 1;
}
-
+
+ /* Note: we do not have to worry about subroutine calls occuring
+ in the right hand container. The return address is always
+ aligned to the next 64 bit boundary, be that 64 or 32 bit away. */
+
switch (exec_type)
{
- case EXEC_UNKNOWN: /* order not specified */
- if (Optimizing && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type))
+ case EXEC_UNKNOWN: /* Order not specified. */
+ if (Optimizing
+ && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type)
+ && ! ( (opcode1->op->unit == EITHER_BUT_PREFER_MU
+ || opcode1->op->unit == MU)
+ &&
+ ( opcode2->op->unit == EITHER_BUT_PREFER_MU
+ || opcode2->op->unit == MU)))
{
/* parallel */
exec_type = EXEC_PARALLEL;
- if (opcode1->op->unit == IU)
- insn = FM00 | (insn2 << 32) | insn1;
- else if (opcode2->op->unit == MU)
+
+ if (opcode1->op->unit == IU
+ || opcode2->op->unit == MU
+ || opcode2->op->unit == EITHER_BUT_PREFER_MU)
insn = FM00 | (insn2 << 32) | insn1;
else
{
fx = fx->next;
}
}
- else if (opcode1->op->unit == IU)
+ else if (opcode1->op->flags_used & (FLAG_JMP | FLAG_JSR)
+ && ((opcode1->op->flags_used & FLAG_DELAY) == 0)
+ && ((opcode1->ecc == ECC_AL) || ! Optimizing))
+ {
+ /* We must emit (non-delayed) branch type instructions
+ on their own with nothing in the right container. */
+ write_1_short (opcode1, insn1, fx->next, false);
+ return 1;
+ }
+ else if (opcode1->op->unit == IU
+ || (opcode1->op->unit == EITHER
+ && opcode2->op->unit == EITHER_BUT_PREFER_MU))
{
/* reverse sequential */
insn = FM10 | (insn2 << 32) | insn1;
case EXEC_PARALLEL: /* parallel */
flag_explicitly_parallel = flag_xp_state;
if (! parallel_ok (opcode1, insn1, opcode2, insn2, exec_type))
- as_fatal (_("Instructions may not be executed in parallel"));
+ as_bad (_("Instructions may not be executed in parallel"));
else if (opcode1->op->unit == IU)
{
if (opcode2->op->unit == IU)
- as_fatal (_("Two IU instructions may not be executed in parallel"));
+ as_bad (_("Two IU instructions may not be executed in parallel"));
as_warn (_("Swapping instruction order"));
insn = FM00 | (insn2 << 32) | insn1;
}
else if (opcode2->op->unit == MU)
{
if (opcode1->op->unit == MU)
- as_fatal (_("Two MU instructions may not be executed in parallel"));
+ as_bad (_("Two MU instructions may not be executed in parallel"));
+ else if (opcode1->op->unit == EITHER_BUT_PREFER_MU)
+ as_warn (_("Executing %s in IU may not work"), opcode1->op->name);
as_warn (_("Swapping instruction order"));
insn = FM00 | (insn2 << 32) | insn1;
}
else
{
+ if (opcode2->op->unit == EITHER_BUT_PREFER_MU)
+ as_warn (_("Executing %s in IU may not work"), opcode2->op->name);
+
insn = FM00 | (insn1 << 32) | insn2;
fx = fx->next;
}
case EXEC_SEQ: /* sequential */
if (opcode1->op->unit == IU)
- as_fatal (_("IU instruction may not be in the left container"));
+ as_bad (_("IU instruction may not be in the left container"));
+ if (prev_left_kills_right_p)
+ as_bad (_("special left instruction `%s' kills instruction "
+ "`%s' in right container"),
+ opcode1->op->name, opcode2->op->name);
+ if (opcode2->op->unit == EITHER_BUT_PREFER_MU)
+ as_warn (_("Executing %s in IU may not work"), opcode2->op->name);
insn = FM01 | (insn1 << 32) | insn2;
fx = fx->next;
break;
case EXEC_REVSEQ: /* reverse sequential */
if (opcode2->op->unit == MU)
- as_fatal (_("MU instruction may not be in the right container"));
+ as_bad (_("MU instruction may not be in the right container"));
+ if (opcode2->op->unit == EITHER_BUT_PREFER_MU)
+ as_warn (_("Executing %s in IU may not work"), opcode2->op->name);
insn = FM10 | (insn1 << 32) | insn2;
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()"));
}
- /* printf("writing out %llx\n",insn); */
- f = frag_more(8);
+ /* printf ("writing out %llx\n",insn); */
+ f = frag_more (8);
d30v_number_to_chars (f, insn, 8);
/* If the previous instruction was a 32-bit multiply but it is put into a
fx->fix[i].reloc);
}
}
+
fx->fc = 0;
fx = fx->next;
}
- return (0);
+
+ return 0;
}
}
}
}
-
+
flags_set1 = op1->op->flags_set;
flags_set2 = op2->op->flags_set;
flags_used1 = op1->op->flags_used;
mod_reg[0][2] = mod_reg[1][2] = 0;
}
- for(j = 0; j < 3; j++)
+ for (j = 0; j < 3; j++)
{
/* If the second instruction depends on the first, we obviously
cannot parallelize. Note, the mod flag implies use, so
don't trust the human if both instructions modify the same
register but we do trust the human if they modify the same
flags. */
+ /* We have now been requested not to trust the human if the
+ instructions modify the same flag registers either. */
if (flag_explicitly_parallel)
{
- if ((j < 2) && (mod_reg[0][j] & mod_reg[1][j]) != 0)
+ if ((mod_reg[0][j] & mod_reg[1][j]) != 0)
return 0;
}
else
}
-
/* 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 D30V, it mostly handles the special VLIW parsing and packing
if ((prev_insn != -1) && prev_seg
&& ((prev_seg != now_seg) || (prev_subseg != now_subseg)))
- d30v_cleanup();
+ d30v_cleanup (false);
if (d30v_current_align < 3)
d30v_align (3, NULL, d30v_last_label);
/* if two instructions are present and we already have one saved
then first write it out */
- d30v_cleanup();
+ d30v_cleanup (false);
- /* assemble first instruction and save it */
- prev_insn = do_assemble (str, &prev_opcode, 1);
+ /* Assemble first instruction and save it. */
+ prev_insn = do_assemble (str, &prev_opcode, 1, 0);
if (prev_insn == -1)
- as_fatal (_("Cannot assemble instruction"));
+ as_bad (_("Cannot assemble instruction"));
if (prev_opcode.form->form >= LONG)
- as_fatal (_("First opcode is long. Unable to mix instructions as specified."));
+ as_bad (_("First opcode is long. Unable to mix instructions as specified."));
fixups = fixups->next;
str = str2 + 2;
prev_seg = now_seg;
}
insn = do_assemble (str, &opcode,
- (extype != EXEC_UNKNOWN || etype != EXEC_UNKNOWN));
+ (extype != EXEC_UNKNOWN || etype != EXEC_UNKNOWN),
+ extype == EXEC_PARALLEL);
if (insn == -1)
{
if (extype != EXEC_UNKNOWN)
etype = extype;
return;
}
- as_fatal (_("Cannot assemble instruction"));
+ as_bad (_("Cannot assemble instruction"));
}
if (etype != EXEC_UNKNOWN)
/* Word multiply instructions must not be followed by either a load or a
16-bit multiply instruction in the next cycle. */
- if (prev_mul32_p && (opcode.op->flags_used & (FLAG_MEM | FLAG_MUL16)))
+ if ( (extype != EXEC_REVSEQ)
+ && prev_mul32_p
+ && (opcode.op->flags_used & (FLAG_MEM | FLAG_MUL16)))
{
/* However, load and multiply should able to be combined in a parallel
operation, so check for that first. */
-
if (prev_insn != -1
&& (opcode.op->flags_used & FLAG_MEM)
&& opcode.form->form < LONG
prev_insn = -1;
return;
}
-
- /* Can't parallelize, flush current instruction and emit a word of NOPS */
else
{
- char *f;
- d30v_cleanup();
+ /* Can't parallelize, flush previous instruction and emit a word of NOPS,
+ unless the previous instruction is a NOP, in which case just flush it,
+ as this will generate a word of NOPs for us. */
- f = frag_more(8);
- d30v_number_to_chars (f, NOP2, 8);
- if (warn_nops == NOP_ALL || warn_nops == NOP_MULTIPLY)
+ if (prev_insn != -1 && (strcmp (prev_opcode.op->name, "nop") == 0))
+ d30v_cleanup (false);
+ else
{
- if (opcode.op->flags_used & FLAG_MEM)
- as_warn (_("word of NOPs added between word multiply and load"));
+ char * f;
+
+ if (prev_insn != -1)
+ d30v_cleanup (true);
else
- as_warn (_("word of NOPs added between word multiply and 16-bit multiply"));
+ {
+ f = frag_more (8);
+ d30v_number_to_chars (f, NOP2, 8);
+
+ if (warn_nops == NOP_ALL || warn_nops == NOP_MULTIPLY)
+ {
+ if (opcode.op->flags_used & FLAG_MEM)
+ as_warn (_("word of NOPs added between word multiply and load"));
+ else
+ as_warn (_("word of NOPs added between word multiply and 16-bit multiply"));
+ }
+ }
}
+
extype = EXEC_UNKNOWN;
}
}
+ else if ( (extype == EXEC_REVSEQ)
+ && cur_mul32_p
+ && (prev_opcode.op->flags_used & (FLAG_MEM | FLAG_MUL16)))
+ {
+ /* Can't parallelize, flush current instruction and add a sequential NOP. */
+ write_1_short (& opcode, (long) insn, fixups->next->next, true);
+
+ /* Make the previous instruction the current one. */
+ extype = EXEC_UNKNOWN;
+ insn = prev_insn;
+ now_seg = prev_seg;
+ now_subseg = prev_subseg;
+ prev_insn = -1;
+ cur_mul32_p = prev_mul32_p;
+ prev_mul32_p = 0;
+ memcpy (&opcode, &prev_opcode, sizeof (prev_opcode));
+ }
- /* if this is a long instruction, write it and any previous short instruction */
+ /* If this is a long instruction, write it and any previous short instruction. */
if (opcode.form->form >= LONG)
{
- if (extype)
- as_fatal(_("Unable to mix instructions as specified"));
- d30v_cleanup();
- write_long (&opcode, insn, fixups);
+ if (extype != EXEC_UNKNOWN)
+ as_bad (_("Instruction uses long version, so it cannot be mixed as specified"));
+ d30v_cleanup (false);
+ write_long (& opcode, insn, fixups);
prev_insn = -1;
- return;
}
-
- if ((prev_insn != -1) &&
- (write_2_short (&prev_opcode, (long)prev_insn, &opcode, (long)insn, extype, fixups) == 0))
+ else if ((prev_insn != -1)
+ && (write_2_short
+ (& prev_opcode, (long) prev_insn, & opcode,
+ (long) insn, extype, fixups) == 0))
{
- /* no instructions saved */
+ /* No instructions saved. */
prev_insn = -1;
}
-
else
{
- if (extype)
- as_fatal(_("Unable to mix instructions as specified"));
- /* save off last instruction so it may be packed on next pass */
- memcpy(&prev_opcode, &opcode, sizeof(prev_opcode));
+ if (extype != EXEC_UNKNOWN)
+ as_bad (_("Unable to mix instructions as specified"));
+
+ /* Save off last instruction so it may be packed on next pass. */
+ memcpy (&prev_opcode, &opcode, sizeof (prev_opcode));
prev_insn = insn;
prev_seg = now_seg;
prev_subseg = now_subseg;
fixups = fixups->next;
+ prev_mul32_p = cur_mul32_p;
}
}
/* it returns -1 (an invalid opcode) on error */
static long long
-do_assemble (str, opcode, shortp)
+do_assemble (str, opcode, shortp, is_parallel)
char *str;
struct d30v_insn *opcode;
int shortp;
+ int is_parallel;
{
unsigned char *op_start, *save;
unsigned char *op_end;
&& !is_end_of_line[*op_end] && *op_end != ' ';
op_end++)
{
- name[nlen] = tolower(op_start[nlen]);
+ name[nlen] = tolower (op_start[nlen]);
nlen++;
}
if (nlen == 0)
- return (-1);
+ return -1;
name[nlen] = 0;
if (*op_end == '/')
{
int i = 0;
- while ( (i < ECC_MAX) && strncasecmp(d30v_ecc_names[i],op_end+1,2))
+ while ( (i < ECC_MAX) && strncasecmp (d30v_ecc_names[i], op_end + 1, 2))
i++;
if (i == ECC_MAX)
{
char tmp[4];
- strncpy(tmp,op_end+1,2);
+ strncpy (tmp, op_end + 1, 2);
tmp[2] = 0;
- as_fatal (_("unknown condition code: %s"),tmp);
+ as_bad (_("unknown condition code: %s"),tmp);
return -1;
}
- /* printf("condition code=%d\n",i); */
+ /* printf ("condition code=%d\n",i); */
opcode->ecc = i;
op_end += 3;
}
/* CMP and CMPU change their name based on condition codes */
- if (!strncmp(name,"cmp",3))
+ if (!strncmp (name, "cmp", 3))
{
int p,i;
char **str = (char **)d30v_cc_names;
else
p = 3;
- for(i=1; *str && strncmp(*str,&name[p],2); i++, str++)
+ for (i=1; *str && strncmp (*str, & name[p], 2); i++, str++)
;
/* cmpu only supports some condition codes */
if (i < 3 || i > 6)
{
name[p+2]=0;
- as_fatal (_("cmpu doesn't support condition code %s"),&name[p]);
+ as_bad (_("cmpu doesn't support condition code %s"),&name[p]);
}
}
if (!*str)
{
name[p+2]=0;
- as_fatal (_("unknown condition code: %s"),&name[p]);
+ as_bad (_("unknown condition code: %s"),&name[p]);
}
cmp_hack = i;
/* find the first opcode with the proper name */
opcode->op = (struct d30v_opcode *)hash_find (d30v_hash, name);
if (opcode->op == NULL)
- as_fatal (_("unknown opcode: %s"),name);
+ as_bad (_("unknown opcode: %s"),name);
save = input_line_pointer;
input_line_pointer = op_end;
while (!(opcode->form = find_format (opcode->op, myops, fsize, cmp_hack)))
{
opcode->op++;
- if (strcmp(opcode->op->name,name))
- as_fatal (_("operands for opcode `%s' do not match any valid format"), name);
+ if (strcmp (opcode->op->name, name))
+ as_bad (_("operands for opcode `%s' do not match any valid format"), name);
}
input_line_pointer = save;
/* Propigate multiply status */
if (insn != -1)
{
- prev_mul32_p = cur_mul32_p;
- cur_mul32_p = (opcode->op->flags_used & FLAG_MUL32) != 0;
+ if (is_parallel && prev_mul32_p)
+ cur_mul32_p = 1;
+ else
+ {
+ prev_mul32_p = cur_mul32_p;
+ cur_mul32_p = (opcode->op->flags_used & FLAG_MUL32) != 0;
+ }
+ }
+
+ /* Propagate left_kills_right status */
+ if (insn != -1)
+ {
+ prev_left_kills_right_p = cur_left_kills_right_p;
+
+ if (opcode->op->flags_set & FLAG_LKR)
+ {
+ cur_left_kills_right_p = 1;
+
+ if (strcmp (opcode->op->name, "mvtsys") == 0)
+ {
+ /* Left kills right for only mvtsys only for PSW/PSWH/PSWL/flags target. */
+ if ((myops[0].X_op == O_register) &&
+ ((myops[0].X_add_number == OPERAND_CONTROL) || /* psw */
+ (myops[0].X_add_number == OPERAND_CONTROL+MAX_CONTROL_REG+2) || /* pswh */
+ (myops[0].X_add_number == OPERAND_CONTROL+MAX_CONTROL_REG+1) || /* pswl */
+ (myops[0].X_add_number == OPERAND_FLAG+0) || /* f0 */
+ (myops[0].X_add_number == OPERAND_FLAG+1) || /* f1 */
+ (myops[0].X_add_number == OPERAND_FLAG+2) || /* f2 */
+ (myops[0].X_add_number == OPERAND_FLAG+3) || /* f3 */
+ (myops[0].X_add_number == OPERAND_FLAG+4) || /* f4 */
+ (myops[0].X_add_number == OPERAND_FLAG+5) || /* f5 */
+ (myops[0].X_add_number == OPERAND_FLAG+6) || /* f6 */
+ (myops[0].X_add_number == OPERAND_FLAG+7))) /* f7 */
+ {
+ cur_left_kills_right_p = 1;
+ }
+ else
+ {
+ /* Other mvtsys target registers don't kill right instruction. */
+ cur_left_kills_right_p = 0;
+ }
+ } /* mvtsys */
+ }
+ else
+ cur_left_kills_right_p = 0;
}
- return (insn);
+
+ return insn;
}
{
if (X_op != O_register
|| ((flags & OPERAND_ACC) && !(num & OPERAND_ACC))
+ || (!(flags & OPERAND_ACC) && (num & OPERAND_ACC))
|| ((flags & OPERAND_FLAG) && !(num & OPERAND_FLAG))
+ || (!(flags & (OPERAND_FLAG | OPERAND_CONTROL)) && (num & OPERAND_FLAG))
|| ((flags & OPERAND_CONTROL)
&& !(num & (OPERAND_CONTROL | OPERAND_FLAG))))
{
{
/* A number can be a constant or symbol expression. */
+ /* If we have found a register name, but that name also
+ matches a symbol, then re-parse the name as an expression. */
+ if (X_op == O_register
+ && symbol_find ((char *) myops[j].X_op_symbol))
+ {
+ input_line_pointer = (char *) myops[j].X_op_symbol;
+ expression (& myops[j]);
+ }
+
/* Turn an expression into a symbol for later resolution. */
if (X_op != O_absent && X_op != O_constant
&& X_op != O_symbol && X_op != O_register
match = 0;
}
else if (X_op == O_symbol
- && S_IS_DEFINED(myops[j].X_add_symbol)
- && S_GET_SEGMENT(myops[j].X_add_symbol) == now_seg
+ && S_IS_DEFINED (myops[j].X_add_symbol)
+ && S_GET_SEGMENT (myops[j].X_add_symbol) == now_seg
&& opcode->reloc_flag == RELOC_PCREL)
{
/* If the symbol is defined, see if the value will fit
value = 0;
for (f = frchain_now->frch_root; f; f = f->fr_next)
value += f->fr_fix + f->fr_offset;
- value = (S_GET_VALUE(myops[j].X_add_symbol) - value
- - (obstack_next_free(&frchain_now->frch_obstack)
+ value = (S_GET_VALUE (myops[j].X_add_symbol) - value
+ - (obstack_next_free (&frchain_now->frch_obstack)
- frag_now->fr_literal));
if (check_range (value, bits, flags))
match = 0;
/* printf("through the loop: match=%d\n",match); */
/* We're only done if the operands matched so far AND there
are no more to check. */
- if (match && myops[j].X_op == 0)
- return fm;
+ if (match && myops[j].X_op == 0)
+ {
+ /* Final check - issue a warning if an odd numbered register
+ is used as the first register in an instruction that reads
+ or writes 2 registers. */
+
+ for (j = 0; fm->operands[j]; j++)
+ if (myops[j].X_op == O_register
+ && (myops[j].X_add_number & 1)
+ && (d30v_operand_table[fm->operands[j]].flags & OPERAND_2REG))
+ as_warn (\
+_("Odd numbered register used as target of multi-register instruction"));
+
+ return fm;
+ }
fm = (struct d30v_format *)&d30v_format_table[++k];
}
/* printf("trying another format: i=%d\n",i); */
int
md_apply_fix3 (fixp, valuep, seg)
- fixS *fixp;
- valueT *valuep;
+ fixS * fixp;
+ valueT * valuep;
segT seg;
{
- char *where;
+ char * where;
unsigned long insn, insn2;
long value;
-
+
if (fixp->fx_addsy == (symbolS *) NULL)
{
- value = *valuep;
+ value = * valuep;
fixp->fx_done = 1;
}
else if (fixp->fx_pcrel)
- {
- value = *valuep;
- }
+ value = * valuep;
else
{
value = fixp->fx_offset;
+
if (fixp->fx_subsy != (symbolS *) NULL)
{
if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
switch (fixp->fx_r_type)
{
+ case BFD_RELOC_8: /* Caused by a bad .byte directive. */
+ /* Drop trhough. */
+
+ case BFD_RELOC_16: /* Caused by a bad .short directive. */
+ /* Drop through. */
+
+ case BFD_RELOC_64: /* Caused by a bad .quad directive. */
+ {
+ char * size;
+
+ size = (fixp->fx_r_type == BFD_RELOC_8) ? _("byte")
+ : (fixp->fx_r_type == BFD_RELOC_16) ? _("short")
+ : _("quad");
+
+ if (fixp->fx_addsy == NULL)
+ as_bad (_("line %d: unable to place address into a %s"),
+ fixp->fx_line, size);
+ else
+ as_bad (_("line %d: unable to place address of symbol '%s' into a %s"),
+ fixp->fx_line,
+ S_GET_NAME (fixp->fx_addsy),
+ size);
+ break;
+ }
+
case BFD_RELOC_D30V_6:
check_size (value, 6, fixp->fx_file, fixp->fx_line);
insn |= value & 0x3F;
break;
default:
- as_fatal (_("line %d: unknown relocation type: 0x%x"),fixp->fx_line,fixp->fx_r_type);
+ as_bad (_("line %d: unknown relocation type: 0x%x"),
+ fixp->fx_line,fixp->fx_r_type);
}
+
return 0;
}
instructions to see if it can package them with the next instruction, there may
be a short instruction that still needs written. */
int
-d30v_cleanup ()
+d30v_cleanup (use_sequential)
+ int use_sequential;
{
segT seg;
subsegT subseg;
seg = now_seg;
subseg = now_subseg;
subseg_set (prev_seg, prev_subseg);
- write_1_short (&prev_opcode, (long)prev_insn, fixups->next);
+ write_1_short (&prev_opcode, (long)prev_insn, fixups->next, use_sequential);
subseg_set (seg, subseg);
prev_insn = -1;
+ if (use_sequential)
+ prev_mul32_p = false;
}
return 1;
}
/* then write out any unwritten instructions */
void
-d30v_start_line()
+d30v_start_line ()
{
char *c = input_line_pointer;
- while(isspace(*c))
+ while (isspace (*c))
c++;
- if (*c == '.')
- d30v_cleanup();
+ if (*c == '.')
+ d30v_cleanup (false);
}
static void
symbolS *lab;
{
/* Emit any pending instructions. */
- d30v_cleanup();
+ d30v_cleanup (false);
/* Update the label's address with the current output pointer. */
lab->sy_frag = frag_now;
temporarily when -g is in effect. */
int switched_seg_p = (d30v_current_align_seg != now_seg);
- if (d30v_current_align >= n && !switched_seg_p)
- return;
-
- d30v_cleanup();
+ /* Do not assume that if 'd30v_current_align >= n' and
+ '! switched_seg_p' that it is safe to avoid performing
+ this alignement request. The alignment of the current frag
+ can be changed under our feet, for example by a .ascii
+ directive in the source code. cf testsuite/gas/d30v/reloc.s */
+
+ d30v_cleanup (false);
if (pfill == NULL)
{
old_frag = label->sy_frag;
old_value = S_GET_VALUE (label);
- new_value = (valueT) frag_now_fix();
+ new_value = (valueT) frag_now_fix ();
/* It is possible to have more than one label at a particular
address, especially if debugging is enabled, so we must
}
}
- record_alignment(now_seg, n);
+ record_alignment (now_seg, n);
}
/* Handle the .align pseudo-op. This aligns to a power of two. We