/* tc-d30v.c -- Assembler code for the Mitsubishi D30V
-
- Copyright (C) 1997, 1998 Free Software Foundation.
+ Copyright (C) 1997, 1998, 1999 Free Software Foundation.
This file is part of GAS, the GNU Assembler.
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dD";
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
#define NOP_MULTIPLY 1
#define NOP_ALL 2
static int warn_nops = 0;
{
expressionP->X_op = O_register;
/* temporarily store a pointer to the string here */
- expressionP->X_op_symbol = (struct symbol *)input_line_pointer;
+ expressionP->X_op_symbol = (symbolS *)input_line_pointer;
expressionP->X_add_number = reg_number;
input_line_pointer = p;
return 1;
int retval=0;
/* don't bother checking 32-bit values */
- if (bits == 32)
+ if (bits == 32 && sizeof(unsigned long) * CHAR_BIT == 32)
return 0;
+ /* Sign extend signed values to unsigned long */
+ if ((flags & OPERAND_SIGNED) && (num & ((unsigned long)1 << (bits - 1))))
+ num |= ((long)-1 << (bits - 1));
+
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);
+ num = (unsigned long) ( (long) num >= 0)
+ ? ( ((long) num) >> 3 )
+ : ( (num >> 3) | ((unsigned long)-1 << (32 - 3)) );
else
num >>= 3;
}
if (flags & OPERAND_SIGNED)
{
- max = (1 << (bits - 1))-1;
- min = - (1 << (bits - 1));
+ max = ((unsigned long)1 << (bits - 1)) - 1;
+ min = - ((unsigned long)1 << (bits - 1));
if (((long)num > max) || ((long)num < min))
retval = 1;
}
else
{
- max = (1 << bits) - 1;
+ max = ((unsigned long)1 << bits) - 1;
min = 0;
if ((num > max) || (num < min))
retval = 1;
fx = fx->next;
}
}
- else if (opcode1->op->flags_used & (FLAG_JMP | FLAG_JSR)
- && ((opcode1->op->flags_used & FLAG_DELAY) == 0)
- && ((opcode1->ecc == ECC_AL) || ! Optimizing))
+ else if ((opcode1->op->flags_used & (FLAG_JMP | FLAG_JSR)
+ && ((opcode1->op->flags_used & FLAG_DELAY) == 0)
+ && ((opcode1->ecc == ECC_AL) || ! Optimizing))
+ || opcode1->op->flags_used & FLAG_RP)
{
/* We must emit (non-delayed) branch type instructions
on their own with nothing in the right container. */
+ /* We must treat repeat instructions likewise, since the
+ following instruction has to be separate from the repeat
+ in order to be repeated. */
+ write_1_short (opcode1, insn1, fx->next, false);
+ return 1;
+ }
+ else if (prev_left_kills_right_p)
+ {
+ /* The left instruction kils the right slot, so we
+ must leave it empty. */
write_1_short (opcode1, insn1, fx->next, false);
return 1;
}
}
flag_reg[j] = 0;
mod_reg[j][0] = mod_reg[j][1] = 0;
- mod_reg[j][2] = (op->flags_set & FLAG_ALL);
used_reg[j][0] = used_reg[j][1] = 0;
- used_reg[j][2] = (op->flags_used & FLAG_ALL);
+ if (flag_explicitly_parallel)
+ {
+ /* For human specified parallel instructions we have been asked
+ to ignore the possibility that both instructions could modify
+ bits in the PSW, so we initialise the mod & used arrays to 0.
+ We have been asked, however, to refuse to allow parallel
+ instructions which explicitly set the same flag register,
+ eg "cmpne f0,r1,0x10 || cmpeq f0, r5, 0x2", so further on we test
+ for the use of a flag register and set a bit in the mod or used
+ array appropriately. */
+
+ mod_reg[j][2] = 0;
+ used_reg[j][2] = 0;
+ }
+ else
+ {
+ mod_reg[j][2] = (op->flags_set & FLAG_ALL);
+ used_reg[j][2] = (op->flags_used & FLAG_ALL);
+ }
+
/* BSR/JSR always sets R62 */
if (op->flags_used & FLAG_JSR)
mod_reg[j][1] = (1L << (62-32));
prev_insn = do_assemble (str, &prev_opcode, 1, 0);
if (prev_insn == -1)
as_bad (_("Cannot assemble instruction"));
- if (prev_opcode.form->form >= LONG)
+ if (prev_opcode.form != NULL && prev_opcode.form->form >= LONG)
as_bad (_("First opcode is long. Unable to mix instructions as specified."));
fixups = fixups->next;
str = str2 + 2;
if (insn == -1)
{
if (extype != EXEC_UNKNOWN)
- {
- etype = extype;
- return;
- }
+ etype = extype;
as_bad (_("Cannot assemble instruction"));
+ return;
}
if (etype != EXEC_UNKNOWN)
/* do_assemble assembles a single instruction and returns an opcode */
/* it returns -1 (an invalid opcode) on error */
+#define NAME_BUF_LEN 20
+
static long long
do_assemble (str, opcode, shortp, is_parallel)
char *str;
int shortp;
int is_parallel;
{
- unsigned char *op_start, *save;
- unsigned char *op_end;
- char name[20];
- int cmp_hack, nlen = 0, fsize = (shortp ? FORCE_SHORT : 0);
- expressionS myops[6];
- long long insn;
+ unsigned char * op_start;
+ unsigned char * save;
+ unsigned char * op_end;
+ char name [NAME_BUF_LEN];
+ int cmp_hack;
+ int nlen = 0;
+ int fsize = (shortp ? FORCE_SHORT : 0);
+ expressionS myops [6];
+ long long insn;
/* Drop leading whitespace */
- while (*str == ' ')
- str++;
+ while (* str == ' ')
+ str ++;
/* find the opcode end */
for (op_start = op_end = (unsigned char *) (str);
- *op_end
- && nlen < 20
- && *op_end != '/'
+ * op_end
+ && nlen < (NAME_BUF_LEN - 1)
+ && * op_end != '/'
&& !is_end_of_line[*op_end] && *op_end != ' ';
op_end++)
{
/* find the first opcode with the proper name */
opcode->op = (struct d30v_opcode *)hash_find (d30v_hash, name);
if (opcode->op == NULL)
- as_bad (_("unknown opcode: %s"),name);
+ {
+ as_bad (_("unknown opcode: %s"),name);
+ return -1;
+ }
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_bad (_("operands for opcode `%s' do not match any valid format"), name);
+ if (opcode->op->name == NULL || strcmp (opcode->op->name, name))
+ {
+ as_bad (_("operands for opcode `%s' do not match any valid format"), name);
+ return -1;
+ }
}
input_line_pointer = save;
cur_left_kills_right_p = 0;
}
-
return insn;
}
int numops, match, index, i=0, j, k;
struct d30v_format *fm;
+ if (opcode == NULL)
+ return NULL;
+
/* Get all the operands and save them as expressions. */
numops = get_operands (myops, cmp_hack);
{
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)
switch (fixp->fx_r_type)
{
- case BFD_RELOC_8: /* Caused by a bad .byte directive. */
- /* Drop trhough. */
+ case BFD_RELOC_8: /* Check for a bad .byte directive. */
+ if (fixp->fx_addsy != NULL)
+ as_bad (_("line %d: unable to place address of symbol '%s' into a byte"),
+ fixp->fx_line, S_GET_NAME (fixp->fx_addsy));
+ else if (((unsigned)value) > 0xff)
+ as_bad (_("line %d: unable to place value %x into a byte"),
+ fixp->fx_line, value);
+ else
+ * (unsigned char *) where = value;
+ break;
- case BFD_RELOC_16: /* Caused by a bad .short directive. */
- /* Drop through. */
+ case BFD_RELOC_16: /* Check for a bad .short directive. */
+ if (fixp->fx_addsy != NULL)
+ as_bad (_("line %d: unable to place address of symbol '%s' into a short"),
+ fixp->fx_line, S_GET_NAME (fixp->fx_addsy));
+ else if (((unsigned)value) > 0xffff)
+ as_bad (_("line %d: unable to place value %x into a short"),
+ fixp->fx_line, value);
+ else
+ bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
+ break;
- 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_64: /* Check for a bad .quad directive. */
+ if (fixp->fx_addsy != NULL)
+ as_bad (_("line %d: unable to place address of symbol '%s' into a quad"),
+ fixp->fx_line, S_GET_NAME (fixp->fx_addsy));
+ else
+ {
+ bfd_putb32 ((bfd_vma) value, (unsigned char *) where);
+ bfd_putb32 (0, ((unsigned char *) where) + 4);
+ }
+ break;
case BFD_RELOC_D30V_6:
check_size (value, 6, fixp->fx_file, fixp->fx_line);
d30v_cleanup (false);
/* Update the label's address with the current output pointer. */
- lab->sy_frag = frag_now;
+ symbol_set_frag (lab, frag_now);
S_SET_VALUE (lab, (valueT) frag_now_fix ());
/* Record this label for future adjustment after we find out what
assert (S_GET_SEGMENT (label) == now_seg);
- old_frag = label->sy_frag;
+ old_frag = symbol_get_frag (label);
old_value = S_GET_VALUE (label);
new_value = (valueT) frag_now_fix ();
in the target fragment. Note, this search is guaranteed to
find at least one match when sym == label, so no special case
code is necessary. */
- for (sym = symbol_lastP; sym != NULL; sym = sym->sy_previous)
+ for (sym = symbol_lastP; sym != NULL; sym = symbol_previous (sym))
{
- if (sym->sy_frag == old_frag && S_GET_VALUE (sym) == old_value)
+ if (symbol_get_frag (sym) == old_frag
+ && S_GET_VALUE (sym) == old_value)
{
label_seen = true;
- sym->sy_frag = frag_now;
+ symbol_set_frag (sym, frag_now);
S_SET_VALUE (sym, new_value);
}
- else if (label_seen && sym->sy_frag != old_frag)
+ else if (label_seen && symbol_get_frag (sym) != old_frag)
break;
}
}