Tue Sep 24 12:22:18 1996 Martin M. Hunt <hunt@pizza.cygnus.com>

* tc-d10v.c (md_operand): Created.  Allows operands to
	start with '#'.
	* tc-d10v.h (md_operand): Undefined.
This commit is contained in:
Martin Hunt 1996-09-24 19:24:38 +00:00
parent 8626a9d58a
commit 3547832c08

View file

@ -26,7 +26,7 @@
#include "opcode/d10v.h"
#include "elf/ppc.h"
const char comment_chars[] = "#;";
const char comment_chars[] = ";";
const char line_comment_chars[] = "#";
const char line_separator_chars[] = "";
const char *md_shortopts = "O";
@ -35,6 +35,8 @@ const char FLT_CHARS[] = "dD";
int Optimizing = 0;
#define AT_WORD (-1)
/* fixups */
#define MAX_INSN_FIXUPS (5)
struct d10v_fixup
@ -42,6 +44,8 @@ struct d10v_fixup
expressionS exp;
int operand;
int pcrel;
int size;
bfd_reloc_code_real_type reloc;
};
typedef struct _fixups
@ -79,9 +83,12 @@ struct option md_longopts[] = {
};
size_t md_longopts_size = sizeof(md_longopts);
static void d10v_dot_word PARAMS ((int));
/* The target specific pseudo-ops which we support. */
const pseudo_typeS md_pseudo_table[] =
{
{ "word", d10v_dot_word, 2 },
{ NULL, NULL, 0 }
};
@ -362,6 +369,7 @@ get_reloc (op)
return (BFD_RELOC_16);
}
/* get_operands parses a string of operands and returns
an array of expressions */
@ -412,7 +420,6 @@ get_operands (exp)
input_line_pointer = p;
/* check to see if it might be a register name */
if (!register_name (&exp[numops]))
{
@ -420,6 +427,20 @@ get_operands (exp)
expression (&exp[numops]);
}
if (!strncasecmp (input_line_pointer, "@word", 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 */
exp[numops].X_op = O_symbol;
exp[numops].X_add_symbol = symbol_find_or_make ((char *)exp[numops].X_op_symbol);
exp[numops].X_op_symbol = NULL;
}
exp[numops].X_add_number = AT_WORD;
input_line_pointer += 5;
}
if (exp[numops].X_op == O_illegal)
as_bad ("illegal operand");
else if (exp[numops].X_op == O_absent)
@ -519,6 +540,21 @@ build_insn (opcode, opers, insn)
if (fixups->fc >= MAX_INSN_FIXUPS)
as_fatal ("too many fixups");
if (opers[i].X_op == O_symbol && number == AT_WORD)
{
number = opers[i].X_add_number = 0;
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]]);
if (fixups->fix[fixups->fc].reloc == BFD_RELOC_16 ||
fixups->fix[fixups->fc].reloc == BFD_RELOC_D10V_18)
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;
@ -548,7 +584,7 @@ write_long (opcode, insn, fx)
unsigned long insn;
Fixups *fx;
{
int i;
int i, where;
char *f = frag_more(4);
insn |= FM11;
@ -557,17 +593,23 @@ write_long (opcode, insn, fx)
for (i=0; i < fx->fc; i++)
{
if (get_reloc((struct d10v_operand *)&d10v_operands[fx->fix[i].operand]))
if (fx->fix[i].reloc)
{
where = f - frag_now->fr_literal;
if (fx->fix[i].size == 2)
where += 2;
/*
printf("fix_new_exp: where:%x size:4\n ",f - frag_now->fr_literal);
printf("fix_new_exp: where:%x size:%d\n ",where,fx->fix[i].size);
print_expr_1(stdout,&(fx->fix[i].exp));
printf("\n");
*/
if (fx->fix[i].reloc == BFD_RELOC_D10V_18)
fx->fix[i].operand |= 4096;
fix_new_exp (frag_now,
f - frag_now->fr_literal,
4,
where,
fx->fix[i].size,
&(fx->fix[i].exp),
fx->fix[i].pcrel,
fx->fix[i].operand|2048);
@ -585,7 +627,7 @@ write_1_short (opcode, insn, fx)
Fixups *fx;
{
char *f = frag_more(4);
int i;
int i, where;
if (opcode->exec_type & PARONLY)
as_fatal ("Instruction must be executed in parallel with another instruction.");
@ -602,23 +644,28 @@ write_1_short (opcode, insn, fx)
number_to_chars_bigendian (f, insn, 4);
for (i=0; i < fx->fc; i++)
{
bfd_reloc_code_real_type reloc;
reloc = get_reloc((struct d10v_operand *)&d10v_operands[fx->fix[i].operand]);
if (reloc)
if (fx->fix[i].reloc)
{
where = f - frag_now->fr_literal;
if (fx->fix[i].size == 2)
where += 2;
/*
printf("fix_new_exp: where:%x size:4\n ",f - frag_now->fr_literal);
printf("fix_new_exp: where:%x size:%d\n ",where, fx->fix[i].size);
print_expr_1(stdout,&(fx->fix[i].exp));
printf("\n");
*/
if (fx->fix[i].reloc == BFD_RELOC_D10V_18)
fx->fix[i].operand |= 4096;
/* if it's an R reloc, we may have to switch it to L */
if ( (reloc == BFD_RELOC_D10V_10_PCREL_R) && (opcode->unit != IU) )
if ( (fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R) && (opcode->unit != IU) )
fx->fix[i].operand |= 1024;
fix_new_exp (frag_now,
f - frag_now->fr_literal,
4,
where,
fx->fix[i].size,
&(fx->fix[i].exp),
fx->fix[i].pcrel,
fx->fix[i].operand|2048);
@ -638,7 +685,7 @@ write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)
{
unsigned long insn;
char *f;
int i,j;
int i,j, where;
if ( (exec_type != 1) && ((opcode1->exec_type & PARONLY)
|| (opcode2->exec_type & PARONLY)))
@ -729,23 +776,29 @@ write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)
for (j=0; j<2; j++)
{
bfd_reloc_code_real_type reloc;
for (i=0; i < fx->fc; i++)
{
reloc = get_reloc((struct d10v_operand *)&d10v_operands[fx->fix[i].operand]);
if (reloc)
if (fx->fix[i].reloc)
{
if ( (reloc == BFD_RELOC_D10V_10_PCREL_R) && (j == 0) )
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) )
fx->fix[i].operand |= 1024;
if (fx->fix[i].reloc == BFD_RELOC_D10V_18)
fx->fix[i].operand |= 4096;
/*
printf("fix_new_exp: where:%x reloc:%d\n ",f - frag_now->fr_literal,fx->fix[i].operand);
printf("fix_new_exp: where:%x reloc:%d\n ",where,fx->fix[i].operand);
print_expr_1(stdout,&(fx->fix[i].exp));
printf("\n");
*/
fix_new_exp (frag_now,
f - frag_now->fr_literal,
4,
where,
fx->fix[i].size,
&(fx->fix[i].exp),
fx->fix[i].pcrel,
fx->fix[i].operand|2048);
@ -1013,7 +1066,7 @@ do_assemble (str, opcode)
input_line_pointer = save;
insn = build_insn ((*opcode), myops, 0);
/* printf("sub-insn = %lx\n",insn); */
/* printf("sub-insn = %lx\n",insn); */
return (insn);
}
@ -1037,7 +1090,7 @@ find_opcode (opcode, myops)
if (opcode->format == OPCODE_FAKE)
{
int opnum = opcode->operands[0];
if (myops[opnum].X_op == O_register)
{
myops[opnum].X_op = O_symbol;
@ -1064,9 +1117,29 @@ find_opcode (opcode, myops)
}
else
{
int value = obstack_next_free(&frchain_now->frch_obstack) - frag_now->fr_literal -
S_GET_VALUE(myops[opnum].X_add_symbol);
if (!check_range (value, bits, flags))
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;
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);
if (myops[opnum].X_add_number == AT_WORD)
{
if (bits > 4)
{
bits += 2;
if (!check_range (value, bits, flags))
return next_opcode;
}
}
else if (!check_range (value, bits, flags))
return next_opcode;
}
next_opcode++;
@ -1092,7 +1165,7 @@ find_opcode (opcode, myops)
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)
{
match=0;
@ -1121,12 +1194,13 @@ find_opcode (opcode, myops)
break;
}
}
/* 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)
break;
@ -1237,14 +1311,14 @@ md_apply_fix3 (fixp, valuep, seg)
else
{
/* We don't actually support subtracting a symbol. */
as_bad_where (fixp->fx_file, fixp->fx_line,
as_bad_where (fixp->fx_file, fixp->fx_line,
"expression too complex");
}
}
}
/* printf("md_apply_fix: value=0x%x type=0x%x where=0x%x size=%d line=%d\n", value, fixp->fx_r_type,fixp->fx_where,fixp->fx_size, fixp->fx_line); */
op_type = fixp->fx_r_type;
if (op_type & 2048)
{
@ -1255,6 +1329,11 @@ md_apply_fix3 (fixp, valuep, seg)
fixp->fx_r_type = BFD_RELOC_D10V_10_PCREL_L;
left = 1;
}
else if (op_type & 4096)
{
op_type -= 4096;
fixp->fx_r_type = BFD_RELOC_D10V_18;
}
else
fixp->fx_r_type = get_reloc((struct d10v_operand *)&d10v_operands[op_type]);
}
@ -1269,33 +1348,29 @@ md_apply_fix3 (fixp, valuep, seg)
case BFD_RELOC_D10V_10_PCREL_L:
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;
if (fixp->fx_size == 2)
bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
else
{
/* printf(" insn=%x value=%x where=%x pcrel=%x\n",insn,value,fixp->fx_where,fixp->fx_pcrel); */
insn = d10v_insert_operand (insn, op_type, (offsetT)value, left, fixp);
/* printf(" new insn=%x\n",insn); */
bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
}
break;
case BFD_RELOC_32:
bfd_putb32 ((bfd_vma) value, (unsigned char *) where);
return 1;
case BFD_RELOC_16:
if (fixp->fx_size == 2)
{
bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
return 1;
}
default:
break;
case BFD_RELOC_16:
bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
break;
default:
as_fatal ("line %d: unknown relocation type: 0x%x",fixp->fx_line,fixp->fx_r_type);
}
/* printf(" insn=%x value=%x where=%x pcrel=%x\n",insn,value,fixp->fx_where,fixp->fx_pcrel); */
insn = d10v_insert_operand (insn, op_type, (offsetT)value, left, fixp);
/* printf(" new insn=%x\n",insn); */
bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
if (fixp->fx_done)
return 1;
fixp->fx_addnumber = value;
return 1;
return 0;
}
@ -1321,3 +1396,64 @@ d10v_cleanup (done)
}
return 1;
}
/* 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 */
{
expressionS exp;
bfd_reloc_code_real_type reloc;
char *p;
int offset;
if (is_it_end_of_statement ())
{
demand_empty_rest_of_line ();
return;
}
do
{
expression (&exp);
if (!strncasecmp (input_line_pointer, "@word", 5))
{
exp.X_add_number = 0;
input_line_pointer += 5;
p = frag_more (2);
fix_new_exp (frag_now, p - frag_now->fr_literal, 2,
&exp, 0, BFD_RELOC_D10V_18);
}
else
emit_expr (&exp, 2);
}
while (*input_line_pointer++ == ',');
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. */
/* operands that begin with '#' should fall through to here */
/* from expr.c */
void
md_operand (expressionP)
expressionS *expressionP;
{
if (*input_line_pointer == '#')
{
input_line_pointer++;
expression (expressionP);
}
}