* config/tc-dvp.c (VU_LABEL_PREFIX): New macro.
(compute_mpgloc): New function. (eval_expr): New arg `cpu'. All callers updated. (non_vu_insn_seen_p): New static global. (RELAX_{MPG,DIRECT,VU,ENCODE,GROWTH,DONE_}): New macros. (struct dvp_fixup): New member `cpu'. (assemble_one_insn): New args init_fixup_count, fixup_offset. All callers updated. (md_assemble): Set non_vu_insn_seen_p as appropriate. (assemble_vif): Set `cpu' field of fixup. Clean up calls to frag_var. Recorded mpgloc is now in bytes. (assemble_vu_insn): Delete, contents moved into ... (assemble_vu): ... here. Don't record fixups until after parsing both upper and lower insns. If branch insn inside mpg, properly compute target address. (dvp_frob_label): Create copies of vu labels inside mpg's. (dvp_relax_frag): Clean up. (md_convert_frag): Ditto. (md_apply_fix3): Signal error if mpg embedded vu code has branch to undefined label (not currently supported). (eval_expr): New arg `cpu'. All callers updated. (insert_operand_final): Convert mpgloc from bytes to dwords. (s_endmpg): Use compute_mpgloc to update $.mpgloc. (s_state): If switching to vu state, initialize $.mpgloc.
This commit is contained in:
parent
cf93a3aa81
commit
07b2042891
@ -4,6 +4,32 @@ Thu Apr 9 10:29:42 1998 Doug Evans <devans@canuck.cygnus.com>
|
||||
(print_symbol_value_1): Use it.
|
||||
* expr.h (expr_build_dot): Declare.
|
||||
* expr.c (expr_build_dot): New function.
|
||||
start-sanitize-sky
|
||||
* config/tc-dvp.c (VU_LABEL_PREFIX): New macro.
|
||||
(compute_mpgloc): New function.
|
||||
(eval_expr): New arg `cpu'. All callers updated.
|
||||
(non_vu_insn_seen_p): New static global.
|
||||
(RELAX_{MPG,DIRECT,VU,ENCODE,GROWTH,DONE_}): New macros.
|
||||
(struct dvp_fixup): New member `cpu'.
|
||||
(assemble_one_insn): New args init_fixup_count, fixup_offset.
|
||||
All callers updated.
|
||||
(md_assemble): Set non_vu_insn_seen_p as appropriate.
|
||||
(assemble_vif): Set `cpu' field of fixup.
|
||||
Clean up calls to frag_var. Recorded mpgloc is now in bytes.
|
||||
(assemble_vu_insn): Delete, contents moved into ...
|
||||
(assemble_vu): ... here. Don't record fixups until after parsing
|
||||
both upper and lower insns. If branch insn inside mpg, properly
|
||||
compute target address.
|
||||
(dvp_frob_label): Create copies of vu labels inside mpg's.
|
||||
(dvp_relax_frag): Clean up.
|
||||
(md_convert_frag): Ditto.
|
||||
(md_apply_fix3): Signal error if mpg embedded vu code has branch
|
||||
to undefined label (not currently supported).
|
||||
(eval_expr): New arg `cpu'. All callers updated.
|
||||
(insert_operand_final): Convert mpgloc from bytes to dwords.
|
||||
(s_endmpg): Use compute_mpgloc to update $.mpgloc.
|
||||
(s_state): If switching to vu state, initialize $.mpgloc.
|
||||
end-sanitize-sky
|
||||
|
||||
Wed Apr 8 16:16:11 1998 Doug Evans <devans@canuck.cygnus.com>
|
||||
|
||||
|
@ -49,15 +49,20 @@
|
||||
#define END_LABEL_PREFIX ".L.end."
|
||||
/* Label to use for unique labels. */
|
||||
#define UNIQUE_LABEL_PREFIX ".L.dvptmp."
|
||||
/* Prefix for mips version of labels defined in vu code.
|
||||
Note that symbols that begin with '$' are local symbols
|
||||
on mips targets, so we can't begin it with '$'. */
|
||||
#define VU_LABEL_PREFIX "._."
|
||||
|
||||
static long parse_float PARAMS ((char **, const char **));
|
||||
static symbolS * create_label PARAMS ((const char *, const char *));
|
||||
static symbolS * create_colon_label PARAMS ((int, const char *, const char *));
|
||||
static char * unique_name PARAMS ((const char *));
|
||||
static symbolS * compute_mpgloc PARAMS ((symbolS *, symbolS *, symbolS *));
|
||||
static int compute_nloop PARAMS ((gif_type, int, int));
|
||||
static void check_nloop PARAMS ((gif_type, int, int, int,
|
||||
char *, unsigned int));
|
||||
static long eval_expr PARAMS ((int, int, const char *, ...));
|
||||
static long eval_expr PARAMS ((dvp_cpu, int, int, const char *, ...));
|
||||
static long parse_dma_addr_autocount ();
|
||||
static void inline_dma_data PARAMS ((int, DVP_INSN *));
|
||||
static void setup_dma_autocount PARAMS ((const char *, DVP_INSN *, int));
|
||||
@ -114,6 +119,10 @@ static int cur_state_index;
|
||||
static void push_asm_state PARAMS ((asm_state));
|
||||
static void pop_asm_state PARAMS ((int));
|
||||
static void set_asm_state PARAMS ((asm_state));
|
||||
|
||||
/* Set to non-zero if any non-vu insn seen.
|
||||
Used to control type of relocations emitted. */
|
||||
static int non_vu_insn_seen_p = 0;
|
||||
|
||||
/* Current cpu (machine variant) type state.
|
||||
We copy the mips16 way of recording what the current machine type is in
|
||||
@ -139,7 +148,7 @@ static symbolS *vif_data_start;
|
||||
/* Label at end of insn's data. */
|
||||
static symbolS *vif_data_end;
|
||||
|
||||
/* Special symbol $.mpgloc. */
|
||||
/* Special symbol $.mpgloc. The value is in bytes. */
|
||||
static symbolS *mpgloc_sym;
|
||||
/* Special symbol $.unpackloc. */
|
||||
static symbolS *unpackloc_sym;
|
||||
@ -175,6 +184,17 @@ static const dvp_operand *cur_operand;
|
||||
|
||||
/* Options for the `caller' argument to s_endmpg. */
|
||||
typedef enum { ENDMPG_USER, ENDMPG_INTERNAL, ENDMPG_MIDDLE } endmpg_caller;
|
||||
|
||||
/* Relaxation support. */
|
||||
#define RELAX_MPG 1
|
||||
#define RELAX_DIRECT 2
|
||||
/* vu insns aren't relaxed, but they use machine dependent frags so we
|
||||
must handle them during relaxation */
|
||||
#define RELAX_VU 3
|
||||
#define RELAX_ENCODE(type, growth) (10 + (growth))
|
||||
#define RELAX_GROWTH(state) ((state) - 10)
|
||||
/* Return non-zero if STATE represents a relaxed state. */
|
||||
#define RELAX_DONE_P(state) ((state) >= 10)
|
||||
|
||||
const char *md_shortopts = "";
|
||||
|
||||
@ -220,10 +240,6 @@ DVP options:\n\
|
||||
");
|
||||
}
|
||||
|
||||
/* Set by md_assemble for use by dvp_fill_insn. */
|
||||
static subsegT prev_subseg;
|
||||
static segT prev_seg;
|
||||
|
||||
static void s_dmadata PARAMS ((int));
|
||||
static void s_enddmadata PARAMS ((int));
|
||||
static void s_dmapackvif PARAMS ((int));
|
||||
@ -280,6 +296,8 @@ md_begin ()
|
||||
|
||||
struct dvp_fixup
|
||||
{
|
||||
/* the cpu this fixup is associated with */
|
||||
dvp_cpu cpu;
|
||||
/* index into `dvp_operands' */
|
||||
int opindex;
|
||||
/* byte offset from beginning of instruction */
|
||||
@ -315,6 +333,7 @@ static const dvp_opcode * assemble_vu_insn PARAMS ((dvp_cpu,
|
||||
static const dvp_opcode * assemble_one_insn PARAMS ((dvp_cpu,
|
||||
const dvp_opcode *,
|
||||
const dvp_operand *,
|
||||
int, int,
|
||||
char **, DVP_INSN *));
|
||||
|
||||
/* Main entry point for assembling an instruction. */
|
||||
@ -356,9 +375,13 @@ md_assemble (str)
|
||||
assemble_gif (str);
|
||||
else
|
||||
assemble_vif (str);
|
||||
non_vu_insn_seen_p = 1;
|
||||
}
|
||||
else if (CUR_ASM_STATE == ASM_DIRECT)
|
||||
assemble_gif (str);
|
||||
{
|
||||
assemble_gif (str);
|
||||
non_vu_insn_seen_p = 1;
|
||||
}
|
||||
else if (CUR_ASM_STATE == ASM_VU
|
||||
|| CUR_ASM_STATE == ASM_MPG)
|
||||
assemble_vu (str);
|
||||
@ -398,7 +421,7 @@ assemble_dma (str)
|
||||
|
||||
opcode = assemble_one_insn (DVP_DMA,
|
||||
dma_opcode_lookup_asm (str), dma_operands,
|
||||
&str, insn_buf);
|
||||
0, 0, &str, insn_buf);
|
||||
if (opcode == NULL)
|
||||
return;
|
||||
if (!output_dma)
|
||||
@ -499,7 +522,7 @@ assemble_vif (str)
|
||||
|
||||
opcode = assemble_one_insn (DVP_VIF,
|
||||
vif_opcode_lookup_asm (str), vif_operands,
|
||||
&str, insn_buf);
|
||||
0, 0, &str, insn_buf);
|
||||
if (opcode == NULL)
|
||||
return;
|
||||
|
||||
@ -539,6 +562,7 @@ assemble_vif (str)
|
||||
unique_name ("varlen"));
|
||||
vif_data_end = symbol_new (name, now_seg, 0, 0);
|
||||
symbol_table_insert (vif_data_end);
|
||||
fixups[fixup_count].cpu = DVP_VIF;
|
||||
fixups[fixup_count].exp.X_op = O_symbol;
|
||||
fixups[fixup_count].exp.X_add_symbol = vif_data_end;
|
||||
fixups[fixup_count].exp.X_add_number = 0;
|
||||
@ -574,8 +598,14 @@ assemble_vif (str)
|
||||
frag_wane (frag_now);
|
||||
frag_new (0);
|
||||
|
||||
/* This dance with frag_grow is to ensure the variable part and
|
||||
fixed part are in the same fragment. */
|
||||
/* One could combine the previous two lines with the following.
|
||||
They're not for clarity: keep separate the actions being
|
||||
performed. */
|
||||
|
||||
/* This dance with frag_grow is so we can record frag_now in
|
||||
insn_frag. frag_var always changes frag_now. We must allocate
|
||||
the maximal amount of space we need so there's room to move
|
||||
the insn in the frag during relaxation. */
|
||||
frag_grow (8);
|
||||
/* Allocate space for the fixed part. */
|
||||
f = frag_more (4);
|
||||
@ -583,8 +613,8 @@ assemble_vif (str)
|
||||
|
||||
frag_var (rs_machine_dependent,
|
||||
4, /* max chars */
|
||||
0, /* variable part already allocated */
|
||||
1, /* subtype */
|
||||
0, /* variable part is empty at present */
|
||||
RELAX_MPG, /* subtype */
|
||||
NULL, /* no symbol */
|
||||
0, /* offset */
|
||||
f); /* opcode */
|
||||
@ -599,13 +629,15 @@ assemble_vif (str)
|
||||
unique_name ("mpg"));
|
||||
insn_frag->fr_symbol = vif_data_start;
|
||||
|
||||
/* Get the value of mpgloc. If it wasn't '*' update $.mpgloc. */
|
||||
/* Get the value of mpgloc. If it wasn't '*'
|
||||
then update $.mpgloc. */
|
||||
{
|
||||
int mpgloc = vif_get_mpgloc ();
|
||||
if (mpgloc != -1)
|
||||
{
|
||||
mpgloc_sym->sy_value.X_op = O_constant;
|
||||
mpgloc_sym->sy_value.X_add_number = mpgloc;
|
||||
/* The value is recorded in bytes. */
|
||||
mpgloc_sym->sy_value.X_add_number = mpgloc * 8;
|
||||
mpgloc_sym->sy_value.X_unsigned = 1;
|
||||
}
|
||||
}
|
||||
@ -624,8 +656,14 @@ assemble_vif (str)
|
||||
frag_wane (frag_now);
|
||||
frag_new (0);
|
||||
|
||||
/* This dance with frag_grow is to ensure the variable part and
|
||||
fixed part are in the same fragment. */
|
||||
/* One could combine the previous two lines with the following.
|
||||
They're not for clarity: keep separate the actions being
|
||||
performed. */
|
||||
|
||||
/* This dance with frag_grow is so we can record frag_now in
|
||||
insn_frag. frag_var always changes frag_now. We must allocate
|
||||
the maximal amount of space we need so there's room to move
|
||||
the insn in the frag during relaxation. */
|
||||
frag_grow (16);
|
||||
/* Allocate space for the fixed part. */
|
||||
f = frag_more (4);
|
||||
@ -633,8 +671,8 @@ assemble_vif (str)
|
||||
|
||||
frag_var (rs_machine_dependent,
|
||||
12, /* max chars */
|
||||
0, /* variable part already allocated */
|
||||
2, /* subtype */
|
||||
0, /* variable part is empty at present */
|
||||
RELAX_DIRECT, /* subtype */
|
||||
NULL, /* no symbol */
|
||||
0, /* offset */
|
||||
f); /* opcode */
|
||||
@ -797,7 +835,7 @@ assemble_gif (str)
|
||||
|
||||
opcode = assemble_one_insn (DVP_GIF,
|
||||
gif_opcode_lookup_asm (str), gif_operands,
|
||||
&str, insn_buf);
|
||||
0, 0, &str, insn_buf);
|
||||
if (opcode == NULL)
|
||||
return;
|
||||
|
||||
@ -840,8 +878,13 @@ static void
|
||||
assemble_vu (str)
|
||||
char *str;
|
||||
{
|
||||
int i;
|
||||
char *f;
|
||||
const dvp_opcode *opcode;
|
||||
/* The lower instruction has the lower address so insns[0] = lower insn,
|
||||
insns[1] = upper insn. */
|
||||
DVP_INSN insns[2];
|
||||
fragS * insn_frag;
|
||||
|
||||
/* Handle automatic mpg insertion if enabled. */
|
||||
if (CUR_ASM_STATE == ASM_MPG
|
||||
@ -854,11 +897,6 @@ assemble_vu (str)
|
||||
|
||||
record_mach (DVP_VUUP, 0);
|
||||
|
||||
/* The lower instruction has the lower address.
|
||||
Handle this by grabbing 8 bytes now, and then filling each word
|
||||
as appropriate. */
|
||||
f = frag_more (8);
|
||||
|
||||
#ifdef VERTICAL_BAR_SEPARATOR
|
||||
char *p = strchr (str, '|');
|
||||
|
||||
@ -869,61 +907,78 @@ assemble_vu (str)
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
opcode = assemble_vu_insn (DVP_VUUP,
|
||||
vu_upper_opcode_lookup_asm (str), vu_operands,
|
||||
&str, f + 4);
|
||||
opcode = assemble_one_insn (DVP_VUUP,
|
||||
vu_upper_opcode_lookup_asm (str), vu_operands,
|
||||
0, 4, &str, &insns[1]);
|
||||
*p = '|';
|
||||
str = p + 1;
|
||||
#else
|
||||
opcode = assemble_vu_insn (DVP_VUUP,
|
||||
opcode = assemble_one_insn (DVP_VUUP,
|
||||
vu_upper_opcode_lookup_asm (str), vu_operands,
|
||||
&str, f + 4);
|
||||
0, 4, &str, &insns[1]);
|
||||
#endif
|
||||
|
||||
/* Don't assemble next one if we couldn't assemble the first. */
|
||||
if (opcode == NULL)
|
||||
return;
|
||||
opcode = assemble_vu_insn (DVP_VULO,
|
||||
vu_lower_opcode_lookup_asm (str), vu_operands,
|
||||
&str, f);
|
||||
/* If this was the "loi" pseudo-insn, we need to set the `i' bit. */
|
||||
if (opcode != NULL)
|
||||
{
|
||||
if (strcmp (opcode->mnemonic, "loi") == 0)
|
||||
f[7] |= 0x80;
|
||||
}
|
||||
|
||||
/* Increment the vu insn counter.
|
||||
If get reach 256 we need to insert an `mpg'. */
|
||||
++vu_count;
|
||||
}
|
||||
|
||||
static const dvp_opcode *
|
||||
assemble_vu_insn (cpu, opcode, operand_table, pstr, buf)
|
||||
dvp_cpu cpu;
|
||||
const dvp_opcode *opcode;
|
||||
const dvp_operand *operand_table;
|
||||
char **pstr;
|
||||
char *buf;
|
||||
{
|
||||
int i;
|
||||
DVP_INSN insn;
|
||||
|
||||
opcode = assemble_one_insn (cpu, opcode, operand_table, pstr, &insn);
|
||||
/* Assemble the lower insn.
|
||||
Pass `fixup_count' for `init_fixup_count' so that we don't clobber
|
||||
any fixups the upper insn had. */
|
||||
opcode = assemble_one_insn (DVP_VULO,
|
||||
vu_lower_opcode_lookup_asm (str), vu_operands,
|
||||
fixup_count, 0, &str, &insns[0]);
|
||||
if (opcode == NULL)
|
||||
return NULL;
|
||||
return;
|
||||
|
||||
/* Write out the instruction.
|
||||
/* If there were fixups and we're inside mpg, create a machine dependent
|
||||
fragment so that we can record the current value of $.mpgloc in fr_symbol.
|
||||
Reminder: it is important to fetch enough space in one call to
|
||||
`frag_more'. We use (f - frag_now->fr_literal) to compute where
|
||||
we are and we don't want frag_now to change between calls. */
|
||||
md_number_to_chars (buf, insn, 4);
|
||||
if (fixup_count != 0
|
||||
&& CUR_ASM_STATE == ASM_MPG)
|
||||
{
|
||||
symbolS * cur_mpgloc;
|
||||
|
||||
/* Ensure we get a new frag. */
|
||||
frag_wane (frag_now);
|
||||
frag_new (0);
|
||||
|
||||
/* Compute the current $.mpgloc. */
|
||||
cur_mpgloc = compute_mpgloc (mpgloc_sym, vif_data_start,
|
||||
expr_build_dot ());
|
||||
|
||||
/* We need to use frag_now afterwards, so we can't just call frag_var.
|
||||
Instead we use frag_more and save the value of frag_now in
|
||||
insn_frag. */
|
||||
f = frag_more (8);
|
||||
insn_frag = frag_now;
|
||||
/* Turn the frag into a machine dependent frag. */
|
||||
frag_variant (rs_machine_dependent,
|
||||
0, /* max chars */
|
||||
0, /* no variable part */
|
||||
RELAX_VU, /* subtype */
|
||||
cur_mpgloc, /* $.mpgloc */
|
||||
0, /* offset */
|
||||
NULL); /* opcode */
|
||||
}
|
||||
else
|
||||
{
|
||||
f = frag_more (8);
|
||||
insn_frag = frag_now;
|
||||
}
|
||||
|
||||
/* Write out the instructions. */
|
||||
md_number_to_chars (f, insns[0], 4);
|
||||
md_number_to_chars (f + 4, insns[1], 4);
|
||||
|
||||
/* Create any fixups. */
|
||||
for (i = 0; i < fixup_count; ++i)
|
||||
{
|
||||
int op_type, reloc_type;
|
||||
const dvp_operand *operand;
|
||||
dvp_cpu cpu;
|
||||
|
||||
/* Create a fixup for this operand.
|
||||
At this point we do not use a bfd_reloc_code_real_type for
|
||||
@ -932,24 +987,53 @@ assemble_vu_insn (cpu, opcode, operand_table, pstr, buf)
|
||||
operand type, although that is admittedly not a very exciting
|
||||
feature. We pick a BFD reloc type in md_apply_fix. */
|
||||
|
||||
cpu = fixups[i].cpu;
|
||||
op_type = fixups[i].opindex;
|
||||
reloc_type = encode_fixup_reloc_type (cpu, op_type);
|
||||
operand = &vu_operands[op_type];
|
||||
fix_new_exp (frag_now, buf - frag_now->fr_literal, 4,
|
||||
|
||||
/* Branch operands inside mpg have to be handled specially.
|
||||
We want a pc relative relocation in a section different from our own.
|
||||
See the br-2.s dejagnu testcase for a good example. */
|
||||
if (CUR_ASM_STATE == ASM_MPG
|
||||
&& (operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0)
|
||||
{
|
||||
symbolS *e1,*e2,*diff_expr;
|
||||
|
||||
/* For "br foo" we want "foo - (. + 8)". */
|
||||
e1 = expr_build_binary (O_add, insn_frag->fr_symbol,
|
||||
expr_build_uconstant (8));
|
||||
e2 = make_expr_symbol (&fixups[i].exp);
|
||||
diff_expr = expr_build_binary (O_subtract, e2, e1);
|
||||
fixups[i].exp.X_op = O_symbol;
|
||||
fixups[i].exp.X_add_symbol = diff_expr;
|
||||
fixups[i].exp.X_add_number = 0;
|
||||
}
|
||||
|
||||
fix_new_exp (insn_frag, f + fixups[i].offset - insn_frag->fr_literal, 4,
|
||||
&fixups[i].exp,
|
||||
(operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0,
|
||||
CUR_ASM_STATE == ASM_MPG /* pcrel */
|
||||
? 0
|
||||
: (operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0,
|
||||
(bfd_reloc_code_real_type) reloc_type);
|
||||
}
|
||||
|
||||
/* All done. */
|
||||
return opcode;
|
||||
/* If this was the "loi" pseudo-insn, we need to set the `i' bit. */
|
||||
if (strcmp (opcode->mnemonic, "loi") == 0)
|
||||
f[7] |= 0x80;
|
||||
|
||||
/* Increment the vu insn counter.
|
||||
If get reach 256 we need to insert an `mpg'. */
|
||||
++vu_count;
|
||||
}
|
||||
|
||||
/* Assemble one instruction at *PSTR.
|
||||
CPU indicates what component we're assembling for.
|
||||
The assembled instruction is stored in INSN_BUF.
|
||||
OPCODE is a pointer to the head of the hash chain.
|
||||
|
||||
INIT_FIXUP_COUNT is the initial value for `fixup_count'.
|
||||
It exists to allow the fixups for multiple calls to this insn to be
|
||||
queued up before actually emitting them.
|
||||
*PSTR is updated to point passed the parsed instruction.
|
||||
|
||||
If the insn is successfully parsed the result is a pointer to the opcode
|
||||
@ -959,10 +1043,13 @@ assemble_vu_insn (cpu, opcode, operand_table, pstr, buf)
|
||||
the error occured). */
|
||||
|
||||
static const dvp_opcode *
|
||||
assemble_one_insn (cpu, opcode, operand_table, pstr, insn_buf)
|
||||
assemble_one_insn (cpu, opcode, operand_table, init_fixup_count, fixup_offset,
|
||||
pstr, insn_buf)
|
||||
dvp_cpu cpu;
|
||||
const dvp_opcode *opcode;
|
||||
const dvp_operand *operand_table;
|
||||
int init_fixup_count;
|
||||
int fixup_offset;
|
||||
char **pstr;
|
||||
DVP_INSN *insn_buf;
|
||||
{
|
||||
@ -987,7 +1074,7 @@ assemble_one_insn (cpu, opcode, operand_table, pstr, insn_buf)
|
||||
|
||||
dvp_opcode_init_parse ();
|
||||
insn_buf[opcode->opcode_word] = opcode->value;
|
||||
fixup_count = 0;
|
||||
fixup_count = init_fixup_count;
|
||||
past_opcode_p = 0;
|
||||
num_suffixes = 0;
|
||||
|
||||
@ -1174,6 +1261,7 @@ assemble_one_insn (cpu, opcode, operand_table, pstr, insn_buf)
|
||||
/* We need to generate a fixup for this expression. */
|
||||
if (fixup_count >= MAX_FIXUPS)
|
||||
as_fatal ("internal error: too many fixups");
|
||||
fixups[fixup_count].cpu = cpu;
|
||||
fixups[fixup_count].exp = exp;
|
||||
fixups[fixup_count].opindex = index;
|
||||
/* FIXME: Revisit. Do we really need operand->word?
|
||||
@ -1181,10 +1269,11 @@ assemble_one_insn (cpu, opcode, operand_table, pstr, insn_buf)
|
||||
twisted. How about defining word 0 as the word with
|
||||
the lowest address and basing operand-shift off that.
|
||||
operand->word could then be deleted. */
|
||||
fixups[fixup_count].offset = fixup_offset;
|
||||
if (operand->word != 0)
|
||||
fixups[fixup_count].offset = operand->word * 4;
|
||||
fixups[fixup_count].offset += operand->word * 4;
|
||||
else
|
||||
fixups[fixup_count].offset = (operand->shift / 32) * 4;
|
||||
fixups[fixup_count].offset += (operand->shift / 32) * 4;
|
||||
++fixup_count;
|
||||
value = 0;
|
||||
}
|
||||
@ -1400,18 +1489,41 @@ dvp_after_pass_hook ()
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Called when a label is defined via tc_frob_label. */
|
||||
/* Called via tc_frob_label when a label is defined. */
|
||||
|
||||
void
|
||||
dvp_frob_label (sym)
|
||||
symbolS *sym;
|
||||
{
|
||||
const char * name = S_GET_NAME (sym);
|
||||
|
||||
/* All labels in vu code must be specially marked for the disassembler.
|
||||
The disassembler ignores all previous information at each new label
|
||||
(that has a higher address than the last one). */
|
||||
if (CUR_ASM_STATE == ASM_MPG
|
||||
|| CUR_ASM_STATE == ASM_VU)
|
||||
S_SET_OTHER (sym, STO_DVP_VU);
|
||||
|
||||
/* If inside an mpg, move vu space labels to their own section and create
|
||||
the corresponding ._. version in normal space. */
|
||||
|
||||
if (CUR_ASM_STATE == ASM_MPG
|
||||
/* Only do this special processing for user specified symbols.
|
||||
Not sure how we can distinguish them other than by some prefix. */
|
||||
&& *name != '.'
|
||||
/* Check for recursive invocation creating the ._.name. */
|
||||
&& strncmp (name, VU_LABEL_PREFIX, sizeof (VU_LABEL_PREFIX) - 1) != 0)
|
||||
{
|
||||
/* Move this symbol to vu space. */
|
||||
symbolS * cur_mpgloc = compute_mpgloc (mpgloc_sym, vif_data_start,
|
||||
expr_build_dot ());
|
||||
S_SET_SEGMENT (sym, expr_section);
|
||||
sym->sy_value = cur_mpgloc->sy_value;
|
||||
sym->sy_frag = &zero_address_frag;
|
||||
|
||||
/* Create the ._. symbol in normal space. */
|
||||
create_colon_label (STO_DVP_VU, VU_LABEL_PREFIX, name);
|
||||
}
|
||||
}
|
||||
|
||||
/* mpg/direct alignment is handled via relaxation */
|
||||
@ -1438,7 +1550,9 @@ md_estimate_size_before_relax (fragP, segment)
|
||||
|
||||
/* Perform the relaxation.
|
||||
All we have to do is figure out how many bytes we need to insert to
|
||||
get to the recorded symbol (which is at the required alignment). */
|
||||
get to the recorded symbol (which is at the required alignment).
|
||||
This function is also called for machine dependent vu insn frags.
|
||||
In this case the growth is always 0. */
|
||||
|
||||
long
|
||||
dvp_relax_frag (fragP, stretch)
|
||||
@ -1450,30 +1564,37 @@ dvp_relax_frag (fragP, stretch)
|
||||
/* Symbol marking start of data. */
|
||||
symbolS * symbolP = fragP->fr_symbol;
|
||||
/* Address of the symbol. */
|
||||
long target = S_GET_VALUE (symbolP) + symbolP->sy_frag->fr_address;
|
||||
long target;
|
||||
long growth;
|
||||
|
||||
/* subtype >= 10 means "done" */
|
||||
if (fragP->fr_subtype >= 10)
|
||||
if (RELAX_DONE_P (fragP->fr_subtype))
|
||||
return 0;
|
||||
|
||||
/* subtype 1 = mpg */
|
||||
if (fragP->fr_subtype == 1)
|
||||
/* vu insn? */
|
||||
if (fragP->fr_subtype == RELAX_VU)
|
||||
{
|
||||
fragP->fr_subtype = RELAX_ENCODE (RELAX_VU, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
target = S_GET_VALUE (symbolP) + symbolP->sy_frag->fr_address;
|
||||
|
||||
if (fragP->fr_subtype == RELAX_MPG)
|
||||
{
|
||||
growth = target - address;
|
||||
if (growth < 0)
|
||||
as_fatal ("internal error: bad mpg alignment handling");
|
||||
fragP->fr_subtype = 10 + growth;
|
||||
fragP->fr_subtype = RELAX_ENCODE (RELAX_MPG, growth);
|
||||
return growth;
|
||||
}
|
||||
|
||||
/* subtype 2 = direct */
|
||||
if (fragP->fr_subtype == 2)
|
||||
if (fragP->fr_subtype == RELAX_DIRECT)
|
||||
{
|
||||
growth = target - address;
|
||||
if (growth < 0)
|
||||
as_fatal ("internal error: bad direct alignment handling");
|
||||
fragP->fr_subtype = 10 + growth;
|
||||
fragP->fr_subtype = RELAX_ENCODE (RELAX_DIRECT, growth);
|
||||
return growth;
|
||||
}
|
||||
|
||||
@ -1493,7 +1614,7 @@ md_convert_frag (abfd, sec, fragP)
|
||||
segT sec;
|
||||
fragS * fragP;
|
||||
{
|
||||
int growth = fragP->fr_subtype - 10;
|
||||
int growth = RELAX_GROWTH (fragP->fr_subtype);
|
||||
|
||||
fragP->fr_fix += growth;
|
||||
|
||||
@ -1555,8 +1676,6 @@ decode_fixup_reloc_type (fixup_reloc, cpuP, operandP)
|
||||
}
|
||||
}
|
||||
|
||||
/* Given a fixup reloc type, return a pointer to the operand
|
||||
|
||||
/* The location from which a PC relative jump should be calculated,
|
||||
given a PC relative reloc. */
|
||||
|
||||
@ -1733,12 +1852,36 @@ md_apply_fix3 (fixP, valueP, seg)
|
||||
|
||||
/* Determine a BFD reloc value based on the operand information.
|
||||
We are only prepared to turn a few of the operands into relocs. */
|
||||
/* FIXME: This test is a hack. */
|
||||
if ((operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0)
|
||||
{
|
||||
assert (operand->bits == 11
|
||||
&& operand->shift == 0);
|
||||
fixP->fx_r_type = BFD_RELOC_MIPS_DVP_11_PCREL;
|
||||
|
||||
/* The fixup isn't recorded as a pc relative branch to some label.
|
||||
Instead a complicated expression is used to compute the desired
|
||||
value. Well, that didn't work and we have to emit a reloc.
|
||||
Things are tricky because the result we want is the difference
|
||||
of two addresses in a section potentially different from the one
|
||||
the reloc is in. Ugh.
|
||||
The solution is to emit two relocs, one that adds the target
|
||||
address and one that subtracts the source address + 8 (the
|
||||
linker will perform the byte->dword conversion).
|
||||
This is rather complicated and rather than risk breaking
|
||||
existing code we fall back on the old way if the file only
|
||||
contains vu code. In this case the file is intended to
|
||||
be fully linked with other vu code and thus we have a normal
|
||||
situation where the relocation directly corresponds to the
|
||||
branch insn. */
|
||||
|
||||
if (non_vu_insn_seen_p)
|
||||
{
|
||||
as_bad_where (fixP->fx_file, fixP->fx_line,
|
||||
"can't handle mpg loaded vu code with branch relocations");
|
||||
}
|
||||
else
|
||||
{
|
||||
fixP->fx_r_type = BFD_RELOC_MIPS_DVP_11_PCREL;
|
||||
}
|
||||
}
|
||||
else if ((operand->flags & DVP_OPERAND_DMA_ADDR) != 0
|
||||
|| (operand->flags & DVP_OPERAND_DMA_NEXT) != 0)
|
||||
@ -1929,9 +2072,10 @@ scan_symbol (sym)
|
||||
|
||||
static long
|
||||
#ifdef USE_STDARG
|
||||
eval_expr (int opindex, int offset, const char *fmt, ...)
|
||||
eval_expr (dvp_cpu cpu, int opindex, int offset, const char *fmt, ...)
|
||||
#else
|
||||
eval_expr (opindex, offset, fmt, va_alist)
|
||||
eval_expr (cpu, opindex, offset, fmt, va_alist)
|
||||
dvp_cpu cpu;
|
||||
int opindex,offset;
|
||||
const char *fmt;
|
||||
va_dcl
|
||||
@ -1961,6 +2105,7 @@ eval_expr (opindex, offset, fmt, va_alist)
|
||||
{
|
||||
if (opindex != 0)
|
||||
{
|
||||
fixups[fixup_count].cpu = cpu;
|
||||
fixups[fixup_count].exp = exp;
|
||||
fixups[fixup_count].opindex = opindex;
|
||||
fixups[fixup_count].offset = offset;
|
||||
@ -2037,6 +2182,23 @@ unique_name (prefix)
|
||||
++counter;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Compute a value for $.mpgloc given a symbol at the start of a chunk
|
||||
of code, the $.mpgloc value for the start, and a symbol at the end
|
||||
of the chunk of code. */
|
||||
|
||||
static symbolS *
|
||||
compute_mpgloc (startloc, startsym, endsym)
|
||||
symbolS * startloc;
|
||||
symbolS * startsym;
|
||||
symbolS * endsym;
|
||||
{
|
||||
symbolS *s;
|
||||
|
||||
s = expr_build_binary (O_subtract, endsym, startsym);
|
||||
s = expr_build_binary (O_add, startloc, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Compute a value for nloop. */
|
||||
|
||||
@ -2099,14 +2261,14 @@ setup_dma_autocount (name, insn_buf, inline_p)
|
||||
{
|
||||
/* -1: The count is the number of following quadwords, so skip the one
|
||||
containing the dma tag. */
|
||||
count = eval_expr (dma_operand_count, 0,
|
||||
count = eval_expr (DVP_DMA, dma_operand_count, 0,
|
||||
"((%s%s - %s) >> 4) - 1", END_LABEL_PREFIX, name, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We don't want to subtract 1 here as the begin and end labels
|
||||
properly surround the data we want to compute the length of. */
|
||||
count = eval_expr (dma_operand_count, 0,
|
||||
count = eval_expr (DVP_DMA, dma_operand_count, 0,
|
||||
"(%s%s - %s) >> 4", END_LABEL_PREFIX, name, name);
|
||||
}
|
||||
|
||||
@ -2175,7 +2337,7 @@ parse_dma_addr_autocount (opcode, operand, mods, insn_buf, pstr, errmsg)
|
||||
label2 = create_label ("_$", name);
|
||||
endlabel = create_label (END_LABEL_PREFIX, name);
|
||||
|
||||
retval = eval_expr (dma_operand_addr, 4, name);
|
||||
retval = eval_expr (DVP_DMA, dma_operand_addr, 4, name);
|
||||
|
||||
setup_dma_autocount (name, insn_buf, 0);
|
||||
|
||||
@ -2422,6 +2584,7 @@ insert_operand_final (cpu, operand, mods, insn_buf, val, file, line)
|
||||
{
|
||||
offsetT min, max, test;
|
||||
|
||||
/* ??? This test belongs more properly in the insert handler. */
|
||||
if ((operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0)
|
||||
{
|
||||
if ((val & 7) != 0)
|
||||
@ -2433,6 +2596,18 @@ insert_operand_final (cpu, operand, mods, insn_buf, val, file, line)
|
||||
}
|
||||
val >>= 3;
|
||||
}
|
||||
/* ??? This test belongs more properly in the insert handler. */
|
||||
else if ((operand->flags & DVP_OPERAND_VU_ADDRESS) != 0)
|
||||
{
|
||||
if ((val & 7) != 0)
|
||||
{
|
||||
if (file == (char *) NULL)
|
||||
as_warn ("misaligned vu address");
|
||||
else
|
||||
as_warn_where (file, line, "misaligned vu address");
|
||||
}
|
||||
val >>= 3;
|
||||
}
|
||||
|
||||
if ((operand->flags & DVP_OPERAND_SIGNED) != 0)
|
||||
{
|
||||
@ -2618,14 +2793,10 @@ s_endmpg (caller)
|
||||
|
||||
/* Update $.mpgloc.
|
||||
We have to leave the old value alone as it may be used in fixups
|
||||
already recorded. The new value is the old value plus the number of
|
||||
already recorded. Since compute_mpgloc allocates a new symbol for the
|
||||
result we're ok. The new value is the old value plus the number of
|
||||
double words in this chunk. */
|
||||
{
|
||||
symbolS *s;
|
||||
s = expr_build_binary (O_subtract, vif_data_end, vif_data_start);
|
||||
s = expr_build_binary (O_divide, s, expr_build_uconstant (8));
|
||||
mpgloc_sym = expr_build_binary (O_add, mpgloc_sym, s);
|
||||
}
|
||||
mpgloc_sym = compute_mpgloc (mpgloc_sym, vif_data_start, vif_data_end);
|
||||
|
||||
set_asm_state (ASM_INIT);
|
||||
|
||||
@ -2720,7 +2891,7 @@ s_endgif (ignore)
|
||||
when they're in different fragments but the difference is constant.
|
||||
Not sure how much of a slowdown that will introduce though. */
|
||||
fixup_count = 0;
|
||||
bytes = eval_expr (gif_operand_nloop, 0, ". - %s - 16", gif_data_name);
|
||||
bytes = eval_expr (DVP_GIF, gif_operand_nloop, 0, ". - %s - 16", gif_data_name);
|
||||
|
||||
/* Compute a value for nloop if we can. */
|
||||
|
||||
@ -2787,10 +2958,23 @@ s_state (state)
|
||||
{
|
||||
/* If in MPG state and the user requests to change to VU state,
|
||||
leave the state as MPG. This happens when we see an mpg followed
|
||||
by a .include that has .vu. */
|
||||
by a .include that has .vu. Note that no attempt is made to support
|
||||
an include depth > 1 for this case. */
|
||||
if (CUR_ASM_STATE == ASM_MPG && state == ASM_VU)
|
||||
return;
|
||||
|
||||
/* If changing to the VU state, we need to set up things for $.mpgloc
|
||||
calculations. */
|
||||
if (state == ASM_VU)
|
||||
{
|
||||
/* FIXME: May need to check that we're not clobbering currently
|
||||
in use versions of these. Also need to worry about which section
|
||||
the .vu is issued in. On the other hand, ".vu" isn't intended
|
||||
to be supported everywhere. */
|
||||
mpgloc_sym = expr_build_uconstant (0);
|
||||
vif_data_start = expr_build_dot ();
|
||||
}
|
||||
|
||||
set_asm_state (state);
|
||||
|
||||
demand_empty_rest_of_line ();
|
||||
|
Loading…
x
Reference in New Issue
Block a user