Handle EV5 (21164/66/68) PALcode support.

* config/tc-alpha.c (machine): New variable.
(load_insn): New macro.
(load_insn_table): New function.
(md_begin): Call load_insn_table, once for basic instructions and
once for appropriate PAL instruction table.
(md_parse_option): Set `machine' based on -m##### arguments.

* config/alpha-opcode.h (alpha_pal21064_opcodes): Split out from alpha_opcodes.
(alpha_pal21164_opcodes): New table.
(NUM21064OPCODES, NUM21164OPCODES): New macros.
This commit is contained in:
Ken Raeburn
1994-06-02 16:06:43 +00:00
parent 4b9f440949
commit 0952861cab
2 changed files with 544 additions and 113 deletions

View File

@ -86,7 +86,7 @@ Kinds of operands:
e fa floating point register.
f fb floating point register.
g fc floating point register.
I 26 bit immediate
I 26 bit immediate (PALcode function #)
l 16 low bits of immediate
h 16 high(er) bits of immediate [Never used. KR]
L 22 bit PC relative immediate.
@ -173,6 +173,33 @@ static const struct alpha_opcode alpha_opcodes[] =
{ "stq_c", 0xbc000000, 0, "1,l(2)" },
{ "stq_c", 0xbc000000, 0, "1,P" }, /* regbase macro */
{ "ldb", 0, 0, "1,l(2)Bd" },
{ "ldb", 0, 0, "1,PBd" },
{ "ldbu", 0, 0, "1,l(2)Bd" },
{ "ldbu", 0, 0, "1,PBd" },
{ "ldw", 0, 0, "1,l(2)Bd" },
{ "ldw", 0, 0, "1,PBd" },
{ "ldwu", 0, 0, "1,l(2)Bd" },
{ "ldwu", 0, 0, "1,PBd" },
{ "stb", 0, 0, "1,l(2)Bd" },
{ "stb", 0, 0, "1,PBd" },
{ "stw", 0, 0, "1,l(2)Bd" },
{ "stw", 0, 0, "1,PBd" },
{ "ustw", 0, 0, "1,l(2)Bd" },
{ "ustw", 0, 0, "1,PBd" },
{ "ustl", 0, 0, "1,l(2)Bd" },
{ "ustl", 0, 0, "1,PBd" },
{ "ustq", 0, 0, "1,l(2)Bd" },
{ "ustq", 0, 0, "1,PBd" },
{ "uldw", 0, 0, "1,l(2)Bd" },
{ "uldw", 0, 0, "1,PBd" },
{ "uldwu", 0, 0, "1,l(2)Bd" },
{ "uldwu", 0, 0, "1,PBd" },
{ "uldl", 0, 0, "1,l(2)Bd" },
{ "uldl", 0, 0, "1,PBd" },
{ "uldq", 0, 0, "1,l(2)Bd" },
{ "uldq", 0, 0, "1,PBd" },
{ "beq", 0xe4000000, 0, "1,L" }, /* 6o+5a+21d */
{ "bne", 0xf4000000, 0, "1,L" },
{ "blt", 0xe8000000, 0, "1,L" },
@ -723,7 +750,7 @@ static const struct alpha_opcode alpha_opcodes[] =
{ "mult/suid", 0x5800fc40, 1, "e,f,g" },
/*
* Miscellaneous
* Miscellaneous, including standard PAL instructions.
*/
{ "pal", 0x00000000, 0, "I" }, /* 6o+26f */
{ "call_pal", 0x00000000, 0, "I" }, /* alias */
@ -741,8 +768,19 @@ static const struct alpha_opcode alpha_opcodes[] =
{ "rs", 0x6000f000, 0, "1" },
/*
* PAL instructions
* More macros
*/
{ "nop", 0x47ff041f, 0, "" }, /* or zero,zero,zero */
{ "mov", 0x47e00400, 0, "2,3" }, /* or zero,r2,r3 */
};
#define NUMOPCODES ((sizeof alpha_opcodes)/(sizeof alpha_opcodes[0]))
/*
* PAL instructions for 21064 (and 21066/68)
*/
static const struct alpha_opcode alpha_pal21064_opcodes[] =
{
{ "hw_ld", 0x6c000000, 0, "1,t(2)" },
{ "hw_ld/p", 0x6c008000, 0, "1,t(2)" },
{ "hw_ld/a", 0x6c004000, 0, "1,t(2)" },
@ -814,11 +852,42 @@ static const struct alpha_opcode alpha_opcodes[] =
{ "hw_mtpr", 0x74000000, 0, "R,8" },
{ "hw_rei", 0x7bff8000, 0, "" },
/*
* More macros
*/
{ "nop", 0x47ff041f, 0, "" }, /* or zero,zero,zero */
{ "mov", 0x47e00400, 0, "2,3" }, /* or zero,r2,r3 */
};
#define NUMOPCODES ((sizeof alpha_opcodes)/(sizeof alpha_opcodes[0]))
#define NUM21064OPCODES ((sizeof alpha_pal21064_opcodes)/(sizeof alpha_pal21064_opcodes[0]))
/*
* 21164 (and 21166/68) specific PAL instructions.
*/
static const struct alpha_opcode alpha_pal21164_opcodes[] =
{
{ "hw_ld", 0x6c000000, 0, "1,l(2)" }, /* RA, 16 bit displacement (RB) */
{ "hw_st", 0x7c000000, 0, "1,l(2)" }, /* RA, 16 bit displacement (RB) */
{ "hw_ldl/a", 0x6c004000, 0, "1,t(2)" }, /* RA, 12 bit displacement (RB) */
{ "hw_ldq/a", 0x6c005000, 0, "1,t(2)" }, /* RA, 12 bit displacement (RB) */
{ "hw_stl/a", 0x7c004000, 0, "1,t(2)" }, /* RA, 12 bit displacement (RB) */
{ "hw_stq/a", 0x7c005000, 0, "1,t(2)" }, /* RA, 12 bit displacement (RB) */
{ "hw_ldl/p", 0x6c008000, 0, "1,t(2)" }, /* RA, 12 bit displacement (RB) */
{ "hw_ldq/p", 0x6c009000, 0, "1,t(2)" }, /* RA, 12 bit displacement (RB) */
{ "hw_stl/p", 0x7c008000, 0, "1,t(2)" }, /* RA, 12 bit displacement (RB) */
{ "hw_stq/p", 0x7c009000, 0, "1,t(2)" }, /* RA, 12 bit displacement (RB) */
{ "hw_ldq/v", 0x6c001800, 0, "1,t(2)" }, /* RA, 12 bit displacement (RB) */
{ "hw_ldl/l", 0x6c000400, 0, "1,t(2)" }, /* RA, 12 bit displacement (RB) */
{ "hw_ldq/l", 0x6c001400, 0, "1,t(2)" }, /* RA, 12 bit displacement (RB) */
{ "hw_stl/c", 0x7c000400, 0, "1,t(2)" }, /* RA, 12 bit displacement (RB) */
{ "hw_stq/c", 0x7c001400, 0, "1,t(2)" }, /* RA, 12 bit displacement (RB) */
{ "hw_mfpr", 0x64000000, 0, "R,l" }, /* RA,RB,16 bits displacement */
{ "hw_mtpr", 0x74000000, 0, "R,l" }, /* RA,RB,16 bits displacement */
{ "hw_rei", 0x7bff8000, 0, "" },
{ "hw_rei_stall", 0x7bffc000, 0, "" },
};
#define NUM21164OPCODES ((sizeof alpha_pal21164_opcodes)/(sizeof alpha_pal21164_opcodes[0]))

View File

@ -61,6 +61,10 @@
/* @@ Will a simple 0x8000 work here? If not, why not? */
#define GP_ADJUSTMENT (0x8000 - 0x10)
/* Which machine type is this? Currently stores an integer for the
model, one of: 21064, 21066, 21164. */
static unsigned long machine;
/* These are exported to relaxing code, even though we don't do any
relaxing on this processor currently. */
const relax_typeS md_relax_table[1];
@ -148,7 +152,8 @@ const pseudo_typeS md_pseudo_table[] =
#define T9 23
#define T10 24
#define T11 25
#define RA 26
#define T12 26
#define RA 26 /* note: same as T12 */
#define PV 27
#define AT 28
#define GP 29
@ -188,6 +193,7 @@ const char line_separator_chars[1];
/* Chars that mean this number is a floating point constant, as in
"0f12.456" or "0d1.2345e12". */
/* @@ Do all of these really get used on the alpha?? */
char FLT_CHARS[] = "rRsSfFdDxXpP";
/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
@ -482,8 +488,74 @@ get_lit4_offset (val)
return retval;
}
#define load_insn(NAME, OP) (hash_insert (op_hash, (NAME), (PTR) (OP)))
static void
load_insn_table (ops, size)
struct alpha_opcode *ops;
int size;
{
struct alpha_opcode *end = ops + size;
struct alpha_opcode *op;
const char *name;
for (op = ops; op < end; )
{
const char *retval;
name = op->name;
retval = load_insn (op->name, op);
if (retval)
as_fatal ("internal error: can't hash opcode `%s': %s",
op->name, retval);
do
op++;
while (op < end
&& (op->name == name
|| !strcmp (op->name, name)));
}
/* Some opcodes include modifiers of various sorts with a "/mod"
syntax, like the architecture documentation suggests. However,
for use with gcc at least, we also need to access those same
opcodes without the "/". */
for (op = ops; op < end; )
{
name = op->name;
if (strchr (name, '/'))
{
const char *name2, *p, *q;
name2 = xmalloc (strlen (name));
p = name2;
q = name;
while (*q)
if (*q == '/')
q++;
else
*p++ = *q++;
*p = 0;
/* Ignore failures -- the opcode table does duplicate some
variants in different forms, like "hw_stq" and "hw_st/q".
Maybe the variants can be eliminated, and this error checking
restored. */
load_insn (name2, op);
}
do
op++;
while (op < end
&& (op->name == name
|| !strcmp (op->name, name)));
}
}
/* This function is called once, at assembler startup time. It should
set up all the tables, etc. that the MD part of the assembler will need. */
set up all the tables, etc. that the MD part of the assembler will
need, that can be determined before arguments are parsed. */
void
md_begin ()
{
@ -492,64 +564,24 @@ md_begin ()
unsigned int i = 0;
op_hash = hash_new ();
load_insn_table (alpha_opcodes, NUMOPCODES);
for (i = 0; i < NUMOPCODES; )
/* Default to 21064 PAL instructions. */
if (machine == 0)
machine = 21064;
switch (machine)
{
const char *name = alpha_opcodes[i].name;
retval = hash_insert (op_hash, name, (PTR) & alpha_opcodes[i]);
if (retval)
{
as_bad ("internal error: can't hash opcode `%s': %s",
alpha_opcodes[i].name, retval);
lose = 1;
}
do
++i;
while (i < NUMOPCODES
&& (alpha_opcodes[i].name == name
|| !strcmp (alpha_opcodes[i].name, name)));
case 21064:
case 21066:
load_insn_table (alpha_pal21064_opcodes, NUM21064OPCODES);
break;
case 21164:
load_insn_table (alpha_pal21164_opcodes, NUM21164OPCODES);
break;
default:
as_fatal ("palcode set unknown (internal error)");
}
/* Some opcodes include modifiers of various sorts with a "/mod"
syntax, like the architecture documentation suggests. However,
for use with gcc at least, we also need to access those same
opcodes without the "/". */
for (i = 0; i < NUMOPCODES; )
{
const char *name = alpha_opcodes[i].name;
if (strchr (name, '/'))
{
char *p = xmalloc (strlen (name));
const char *q = name;
char *q2 = p;
for (; *q; q++)
if (*q != '/')
*q2++ = *q;
*q2++ = 0;
retval = hash_insert (op_hash, p, (PTR) & alpha_opcodes[i]);
if (retval)
{
/* Ignore failures -- the opcode table does duplicate
some variants in different forms, like "hw_st/q" and
"hw_stq". */
#if 0
as_bad ("internal error: can't hash opcode variant `%s': %s",
p, retval);
lose = 1;
#endif
}
}
do
++i;
while (i < NUMOPCODES
&& (alpha_opcodes[i].name == name
|| !strcmp (alpha_opcodes[i].name, name)));
}
if (lose)
as_fatal ("Broken assembler. No assembly attempted.");
lituse_basereg.X_op = O_constant;
lituse_basereg.X_add_number = 1;
@ -569,12 +601,48 @@ md_begin ()
int optnum = 1;
static void
emit_insn (insn)
struct alpha_it *insn;
{
char *toP;
int j;
toP = frag_more (4);
/* put out the opcode */
md_number_to_chars (toP, insn->opcode, 4);
/* put out the symbol-dependent stuff */
for (j = 0; j < MAX_RELOCS; j++)
{
struct reloc_data *r = &insn->reloc[j];
fixS *f;
if (r->code != BFD_RELOC_NONE)
{
if (r->exp.X_op == O_constant)
{
r->exp.X_add_symbol = section_symbol (absolute_section);
r->exp.X_op = O_symbol;
}
f = fix_new_exp (frag_now, (toP - frag_now->fr_literal), 4,
&r->exp, r->pcrel, r->code);
}
if (r->code == BFD_RELOC_ALPHA_GPDISP_LO16)
{
static bit_fixS cookie;
/* @@ This'll make the range checking in write.c shut up. */
f->fx_bit_fixP = &cookie;
}
}
}
void
md_assemble (str)
char *str;
{
char *toP;
int i, j, count;
int i, count;
#define MAX_INSNS 5
struct alpha_it insns[MAX_INSNS];
@ -583,36 +651,7 @@ md_assemble (str)
return;
for (i = 0; i < count; i++)
{
toP = frag_more (4);
/* put out the opcode */
md_number_to_chars (toP, insns[i].opcode, 4);
/* put out the symbol-dependent stuff */
for (j = 0; j < MAX_RELOCS; j++)
{
struct reloc_data *r = &insns[i].reloc[j];
fixS *f;
if (r->code != BFD_RELOC_NONE)
{
if (r->exp.X_op == O_constant)
{
r->exp.X_add_symbol = section_symbol (absolute_section);
r->exp.X_op = O_symbol;
}
f = fix_new_exp (frag_now, (toP - frag_now->fr_literal), 4,
&r->exp, r->pcrel, r->code);
}
if (r->code == BFD_RELOC_ALPHA_GPDISP_LO16)
{
static bit_fixS cookie;
/* This'll make the range checking in write.c shut up. */
f->fx_bit_fixP = &cookie;
}
}
}
emit_insn (&insns[i]);
}
static inline void
@ -672,6 +711,7 @@ alpha_force_relocation (f)
case BFD_RELOC_8:
case BFD_RELOC_23_PCREL_S2:
case BFD_RELOC_14:
case BFD_RELOC_26:
return 0;
default:
abort ();
@ -712,13 +752,11 @@ md_section_align (seg, size)
}
/* Add this thing to the .lita section and produce a LITERAL reloc referring
to it.
to it. */
TODO:
Remove duplicates.
Set GP value properly, and have values in LITERAL references set
accordingly.
*/
/* Are we currently eligible to emit a LITUSE reloc for the literal
references just generated? */
static int lituse_pending;
static void
load_symbol_address (reg, insn)
@ -749,6 +787,7 @@ load_symbol_address (reg, insn)
insn->reloc[0].exp.X_add_symbol = lita_sym;
insn->reloc[0].exp.X_add_number = retval;
insn->reloc[0].code = BFD_RELOC_ALPHA_LITERAL;
lituse_pending = 1;
if (retval == 0x8000)
/* Overflow? */
@ -815,6 +854,7 @@ load_expression (reg, insn)
| (addend & 0xffff));
insn[1].reloc[0].code = BFD_RELOC_ALPHA_LITUSE;
insn[1].reloc[0].exp = lituse_basereg;
lituse_pending = 0;
}
return num_insns;
}
@ -878,6 +918,80 @@ getExpression (str, this_insn)
input_line_pointer = save_in;
}
/* All of these should soon be changed to just emit words to the
output frag... */
static void
emit_unaligned_io (dir, addr_reg, addr_offset, reg)
char *dir;
int addr_reg, reg;
valueT addr_offset;
{
char buf[90];
sprintf (buf, "%sq_u $%d,%ld($%d)", dir, reg, (long) addr_offset, addr_reg);
md_assemble (buf);
}
static void
emit_load_unal (addr_reg, addr_offset, reg)
int addr_reg, reg;
valueT addr_offset;
{
emit_unaligned_io ("ld", addr_reg, addr_offset, reg);
}
static void
emit_store_unal (addr_reg, addr_offset, reg)
int addr_reg, reg;
valueT addr_offset;
{
emit_unaligned_io ("st", addr_reg, addr_offset, reg);
}
static void
emit_byte_manip_r (op, in, mask, out, mode, which)
char *op;
{
char buf[90];
sprintf (buf, "%s%c%c $%d,$%d,$%d", op, mode, which, in, mask, out);
md_assemble (buf);
}
static void
emit_extract_r (in, mask, out, mode, which)
{
emit_byte_manip_r ("ext", in, mask, out, mode, which);
}
static void
emit_insert_r (in, mask, out, mode, which)
{
emit_byte_manip_r ("ins", in, mask, out, mode, which);
}
static void
emit_mask_r (in, mask, out, mode, which)
{
emit_byte_manip_r ("msk", in, mask, out, mode, which);
}
static void
emit_sign_extend (reg, size)
{
char buf[90];
sprintf (buf, "sll $%d,0x%x,$%d", reg, 64 - size, reg);
md_assemble (buf);
sprintf (buf, "sra $%d,0x%x,$%d", reg, 64 - size, reg);
md_assemble (buf);
}
static void
emit_bis_r (in1, in2, out)
{
char buf[90];
sprintf (buf, "bis $%d,$%d,$%d", in1, in2, out);
md_assemble (buf);
}
/* Note that for now, this function is called recursively (by way of
calling md_assemble again). Some of the macros defined as part of
the assembly language are currently rewritten as sequences of
@ -1141,6 +1255,10 @@ alpha_ip (str, insns)
insns[0].reloc[0].code = BFD_RELOC_8;
goto immediate;
case 'I': /* 26 bit immediate, for PALcode */
insns[0].reloc[0].code = BFD_RELOC_26;
goto immediate;
#if 0
case 't': /* 12 bit 0...11 */
insns[0].reloc = RELOC_0_12;
@ -1155,7 +1273,6 @@ alpha_ip (str, insns)
#else
case 't':
case '8':
case 'I':
abort ();
#endif
/*FALLTHROUGH*/
@ -1257,8 +1374,12 @@ alpha_ip (str, insns)
insns[0].reloc[0].exp.X_op = O_symbol;
offset &= 0xffff;
num_gen = load_expression (AT, &insns[0]);
insns[num_gen].reloc[0].code = BFD_RELOC_ALPHA_LITUSE;
insns[num_gen].reloc[0].exp = lituse_basereg;
if (lituse_pending)
{
insns[num_gen].reloc[0].code = BFD_RELOC_ALPHA_LITUSE;
insns[num_gen].reloc[0].exp = lituse_basereg;
lituse_pending = 0;
}
insns[num_gen++].opcode = opcode | (AT << SB) | offset;
opcode = insns[0].opcode;
s = input_line_pointer;
@ -1342,15 +1463,23 @@ alpha_ip (str, insns)
tmp_reg = AT;
num_gen = load_expression (tmp_reg, insns);
opcode = insns[0].opcode;
/* lda is opcode 8, 0x20000000 */
if (OPCODE (old_opcode) != 0x08)
/* lda is opcode 8, 0x20000000, and the macros that use
this code have an opcode field of 0. The latter
require further processing, and we don't have the
true opcode here. */
if (OPCODE (old_opcode) != 0
&& OPCODE (old_opcode) != 0x08)
{
struct alpha_it *i;
i = &insns[num_gen++];
i->opcode = old_opcode | (tmp_reg << SB);
i->reloc[0].code = BFD_RELOC_ALPHA_LITUSE;
i->reloc[0].exp = lituse_basereg;
if (lituse_pending)
{
i->reloc[0].code = BFD_RELOC_ALPHA_LITUSE;
i->reloc[0].exp = lituse_basereg;
lituse_pending = 0;
}
}
}
else
@ -1422,7 +1551,8 @@ alpha_ip (str, insns)
insns[1].opcode |= addend & 0xffff;
insns[0].opcode |= ((addend >> 16)
+ (addend & 0x8000 ? 1 : 0));
ecoff_set_gp_prolog_size (0);
if (r2 == PV)
ecoff_set_gp_prolog_size (0);
}
break;
default:
@ -1468,12 +1598,13 @@ alpha_ip (str, insns)
| (mask << SA)
| (PV << SB)
| 0);
if (num_gen == 2)
if (lituse_pending)
{
/* LITUSE wasn't emitted yet */
jsr->reloc[0].code = BFD_RELOC_ALPHA_LITUSE;
jsr->reloc[0].exp = lituse_jsr;
r = &jsr->reloc[1];
lituse_pending = 0;
}
else
r = &jsr->reloc[0];
@ -1484,6 +1615,187 @@ alpha_ip (str, insns)
}
continue;
case 'd':
/* Sub-word loads and stores. We load the address into
$at, which might involve using the `P' parameter
processing too, then emit a sequence to get the job
done, using unaligned memory accesses and byte
manipulation, with t9 and t10 as temporaries. */
{
/* Characteristics of access. */
int is_load, is_unsigned = 0, is_unaligned = 0;
int mode_size, mode;
/* Register operand. */
int reg;
/* Addend for loads and stores. */
valueT addend;
/* Which register do we use for the address? */
int addr;
{
/* Pick apart name and set flags. */
char *s = pattern->name;
if (*s == 'u')
{
is_unaligned = 1;
s++;
}
if (s[0] == 'l' && s[1] == 'd')
is_load = 1;
else if (s[0] == 's' && s[1] == 't')
is_load = 0;
else
as_fatal ("unrecognized sub-word access insn `%s'",
str);
s += 2;
mode = *s++;
if (mode == 'b') mode_size = 1;
else if (mode == 'w') mode_size = 2;
else if (mode == 'l') mode_size = 4;
else if (mode == 'q') mode_size = 8;
else abort ();
if (*s == 'u')
{
is_unsigned = 1;
s++;
}
assert (*s == 0);
/* Longwords are always kept sign-extended. */
if (mode == 'l' && is_unsigned)
abort ();
/* There's no special unaligned byte handling. */
if (mode == 'b' && is_unaligned)
abort ();
/* Stores don't care about signedness. */
if (!is_load && is_unsigned)
abort ();
}
if (args[-2] == 'P')
{
addr = AT;
addend = 0;
}
else
{
/* foo r1,num(r2)
r2 -> mask
r1 -> (opcode >> SA) & 31
num -> insns->reloc[0].*
We want to emit "lda at,num(r2)", since these
operations require the use of a single register
with the starting address of the memory operand
we want to access.
We could probably get away without doing this
(and use r2 below, with the addend for the
actual reads and writes) in cases where the
addend is known to be a multiple of 8. */
int r2 = mask;
int r1 = (opcode >> SA) & 31;
if (insns[0].reloc[0].code == BFD_RELOC_NONE)
addend = 0;
else if (insns[0].reloc[0].code == BFD_RELOC_16)
{
if (insns[0].reloc[0].exp.X_op != O_constant)
abort ();
addend = insns[0].reloc[0].exp.X_add_number;
}
else
abort ();
if (addend + mode_size - 1 < 0x7fff
&& (addend % 8) == 0
&& (r2 < T9 || r2 > T12))
{
addr = r2;
num_gen = 0;
}
else
{
/* Let later relocation processing deal
with the addend field. */
insns[num_gen-1].opcode = (0x20000000 /* lda */
| (AT << SA)
| (r2 << SB));
addr = AT;
addend = 0;
}
reg = r1;
}
/* Because the emit_* routines append directly to
the current frag, we now need to flush any
pending insns. */
{
int i;
for (i = 0; i < num_gen; i++)
emit_insn (&insns[i]);
num_gen = 0;
}
if (is_load)
{
int reg2, reg3;
if (is_unaligned)
reg2 = T9, reg3 = T10;
else
reg2 = reg;
emit_load_unal (addr, addend, T9);
if (is_unaligned)
emit_load_unal (addr, addend + mode_size - 1, T10);
emit_extract_r (T9, addr, reg2, mode, 'l');
if (is_unaligned)
{
emit_extract_r (T10, addr, reg3, mode, 'h');
emit_bis_r (T9, T10, reg);
}
if (!is_unsigned)
emit_sign_extend (reg, mode_size * 8);
}
else
{
/* The second word gets processed first
because if the address does turn out to be
aligned, the processing for the second word
will be pushing around all-zeros, and the
entire value will be handled as the `first'
word. So we want to store the `first' word
last. */
/* Pair these up so that the memory loads get
separated from each other, as well as being
well in advance of the uses of the values
loaded. */
if (is_unaligned)
{
emit_load_unal (addr, addend + mode_size - 1, T11);
emit_insert_r (reg, addr, T12, mode, 'h');
}
emit_load_unal (addr, addend, T9);
emit_insert_r (reg, addr, T10, mode, 'l');
if (is_unaligned)
emit_mask_r (T12, addr, T12, mode, 'h');
emit_mask_r (T10, addr, T10, mode, 'l');
if (is_unaligned)
emit_bis_r (T11, T12, T11);
emit_bis_r (T9, T10, T9);
if (is_unaligned)
emit_store_unal (addr, addend + mode_size - 1, T11);
emit_store_unal (addr, addend, T9);
}
}
return 0;
/* DIVISION and MODULUS. Yech.
Convert OP x,y,result
to mov x,t10
@ -1731,6 +2043,34 @@ md_parse_option (argP, cntP, vecP)
if (!strcmp (*argP, "nocpp"))
{
*argP += 5;
return 1;
}
if (**argP == 'm')
{
unsigned long mach;
(*argP)++;
if (!strcmp (*argP, "21064"))
mach = 21064;
else if (!strcmp (*argP, "21066"))
mach = 21066;
else if (!strcmp (*argP, "21164"))
mach = 21164;
else
{
mach = 0;
(*argP)--;
return 0;
}
(*argP) += 5;
if (machine != 0 && machine != mach)
{
as_warn ("machine type %lu already chosen, overriding with %lu",
machine, mach);
}
machine = mach;
return 1;
}
return 0;
@ -1921,6 +2261,28 @@ md_apply_fix (fixP, valueP)
}
break;
case BFD_RELOC_26:
if (fixP->fx_addsy != 0
&& fixP->fx_addsy->bsym->section != absolute_section)
as_bad_where (fixP->fx_file, fixP->fx_line,
"PALcode instructions require immediate constant function code");
else if (value >> 26 != 0)
as_bad_where (fixP->fx_file, fixP->fx_line,
"overflow in 26-bit PALcode function field");
*p++ = value & 0xff;
value >>= 8;
*p++ = value & 0xff;
value >>= 8;
*p++ = value & 0xff;
value >>= 8;
{
char x = *p;
x &= ~3;
x |= (value & 3);
*p++ = x;
}
goto done;
case BFD_RELOC_14:
if (fixP->fx_addsy != 0
&& fixP->fx_addsy->bsym->section != absolute_section)