static int insert_file PARAMS ((const char *));
+static int cur_pke_insn_length PARAMS ((void));
static void install_pke_length PARAMS ((char *, int));
const char comment_chars[] = ";";
/* Current assembler state.
Instructions like mpg and direct are followed by a restricted set of
instructions until an end marker (e.g. mpg is followed by vu insns). */
-typedef enum { ASM_INIT, ASM_MPG, ASM_GPUIF, ASM_VU } asm_state;
+typedef enum {
+ ASM_INIT, ASM_MPG, ASM_DIRECT, ASM_UNPACK, ASM_GPUIF, ASM_VU
+} asm_state;
static asm_state cur_asm_state = ASM_INIT;
-/* Pointer to pke insn currently being assembled or NULL if none. */
-static char *cur_pke_insn;
+/* For variable length instructions, pointer to the initial frag
+ and pointer into that frag. These only hold valid values if
+ cur_asm_state is one of ASM_MPG, ASM_DIRECT, ASM_UNPACK. */
+static fragS *cur_varlen_frag;
+static char *cur_varlen_insn;
/* Non-zero if packing pke instructions in dma tags. */
static int dma_pack_pke_p;
FILE *stream;
{
#if 0
- fprintf (stream, "TX VU options:\n");
+ fprintf (stream, "DVP options:\n");
#endif
}
/* The target specific pseudo-ops which we support. */
const pseudo_typeS md_pseudo_table[] =
{
- { "dmadata", s_dmadata, 1 },
- { "dmapackpke", s_dmapackpke, 0 },
- { "enddirect", s_enddirect, 0 },
- { "enddmadata", s_dmadata, 0 },
- { "endgpuif", s_endgpuif, 0 },
- { "endmpg", s_endmpg, 0 },
- { "endunpack", s_endunpack, 0 },
- /* .vu,.gpuif added to simplify debugging */
- { "vu", s_state, ASM_VU },
- { "gpuif", s_state, ASM_GPUIF },
- { NULL, NULL, 0 }
+ { "dmadata", s_dmadata, 1 },
+ { "dmapackpke", s_dmapackpke, 0 },
+ { "enddirect", s_enddirect, 0 },
+ { "enddmadata", s_dmadata, 0 },
+ { "endgpuif", s_endgpuif, 0 },
+ { "endmpg", s_endmpg, 0 },
+ { "endunpack", s_endunpack, 0 },
+ /* .vu,.gpuif added to simplify debugging */
+ { "vu", s_state, ASM_VU },
+ { "gpuif", s_state, ASM_GPUIF },
+ { NULL, NULL, 0 }
};
\f
void
else
len = 1;
- f = frag_more (len * 4);
-
- /* Write out the instruction.
- Reminder: it is important to fetch enough space in one call to
+ /* 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. */
+ f = frag_more (len * 4);
+
+ /* Write out the instruction. */
for (i = 0; i < len; ++i)
md_number_to_chars (f + i * 4, insn_buf[i], 4);
(bfd_reloc_code_real_type) reloc_type);
}
+ /* Handle variable length insns. */
+
if (opcode->flags & PKE_OPCODE_LENVAR)
{
/* Name of file to read data from. */
char *file;
- /* In 32 bit words. */
+ /* Length in 32 bit words. */
int data_len;
- cur_pke_insn = NULL;
file = NULL;
data_len = 0;
pke_get_var_data (&file, &data_len);
if (data_len == 0 || data_len < -2)
as_bad ("invalid data length");
else if (data_len == -1)
- cur_pke_insn = f;
+ {
+ cur_varlen_frag = frag_now;
+ cur_varlen_insn = f;
+ if (opcode->flags & PKE_OPCODE_MPG)
+ cur_asm_state = ASM_MPG;
+ }
else
- install_pke_length (f, data_len * 4);
- if (opcode->flags & PKE_OPCODE_MPG)
- cur_asm_state = ASM_VU;
+ {
+ install_pke_length (f, data_len * 4);
+ /* Switch to VU state. We don't use MPG state as that is
+ used to indicate we're expecting to see a .endmpg. */
+ if (opcode->flags & PKE_OPCODE_MPG)
+ cur_asm_state = ASM_VU;
+ /* FIXME: We assume there is exactly the right amount of
+ data. */
+ }
}
}
}
{
return 0;
}
+
+/* Called after parsing the file via md_after_pass_hook. */
+
+void
+dvp_parse_done ()
+{
+ /* Check for missing .EndMpg, and supply one if necessary. */
+ if (cur_asm_state == ASM_MPG)
+ s_endmpg (0);
+ else if (cur_asm_state == ASM_DIRECT)
+ s_enddirect (0);
+ else if (cur_asm_state == ASM_UNPACK)
+ s_endunpack (0);
+}
\f
/* Functions concerning relocs. */
return 0;
}
- /* FIXME: `& -16L'? */
- return (fixP->fx_frag->fr_address + fixP->fx_where) & -8L;
+ /* We assume this is a vu branch.
+ Offsets are calculated based on the address of the next insn. */
+ return ((fixP->fx_frag->fr_address + fixP->fx_where) & -8L) + 8;
}
/* Apply a fixup to the object code. This is called for all the
/* Data reference must be a .DmaData label. */
struct symbol *label, *label2;
- char *name, *name2;
+ const char *name;
+ char *name2;
int len;
long count;
return retval;
}
\f
+/* Return length in bytes of the variable length PKE insn
+ currently being assembled. */
+
+static int
+cur_pke_insn_length ()
+{
+ int byte_len;
+ fragS *f;
+
+ if (cur_varlen_frag == frag_now)
+ byte_len = frag_more (0) - cur_varlen_insn - 4; /* -4 for mpg itself */
+ else
+ {
+ byte_len = (cur_varlen_frag->fr_fix + cur_varlen_frag->fr_offset -
+ (cur_varlen_insn - cur_varlen_frag->fr_literal)) - 4;
+ for (f = cur_varlen_frag->fr_next; f != frag_now; f = f->fr_next)
+ byte_len += f->fr_fix + f->fr_offset;
+ byte_len += frag_now_fix ();
+ }
+
+ return byte_len;
+}
+
/* Install length LEN, in bytes, in the pke insn at BUF.
The bytes in BUF are in target order. */
s_enddirect (ignore)
int ignore;
{
-}
+ int byte_len;
-static void
-s_endgpuif (ignore)
- int ignore;
-{
+ if (cur_asm_state != ASM_DIRECT)
+ {
+ as_bad ("`.enddirect' has no matching `direct' instruction");
+ return;
+ }
+
+ byte_len = cur_pke_insn_length ();
+ install_pke_length (cur_varlen_insn, byte_len);
+
+ cur_asm_state = ASM_INIT;
+ cur_varlen_frag = NULL;
+ cur_varlen_insn = NULL;
}
static void
s_endmpg (ignore)
int ignore;
{
- if (cur_asm_state != ASM_MPG || cur_pke_insn == NULL)
- as_bad ("`.endmpg' has no matching `mpg' instruction");
- else
- {
- /* Compute the length and install it in the instruction. */
- /*FIXME*/
+ int byte_len;
- cur_asm_state = ASM_INIT;
- cur_pke_insn = NULL;
+ if (cur_asm_state != ASM_MPG)
+ {
+ as_bad ("`.endmpg' has no matching `mpg' instruction");
+ return;
}
+
+ byte_len = cur_pke_insn_length ();
+ install_pke_length (cur_varlen_insn, byte_len);
+
+ cur_asm_state = ASM_INIT;
+ cur_varlen_frag = NULL;
+ cur_varlen_insn = NULL;
+
+ /* Update $.MpgLoc. */
+ pke_set_mpgloc (pke_get_mpgloc () + byte_len);
}
static void
s_endunpack (ignore)
int ignore;
{
+ int byte_len;
+
+ if (cur_asm_state != ASM_UNPACK)
+ {
+ as_bad ("`.endunpack' has no matching `unpack' instruction");
+ return;
+ }
+
+ byte_len = cur_pke_insn_length ();
+ install_pke_length (cur_varlen_insn, byte_len);
+
cur_asm_state = ASM_INIT;
+ cur_varlen_frag = NULL;
+ cur_varlen_insn = NULL;
+
+ /* Update $.UnpackLoc. */
+ pke_set_unpackloc (pke_get_unpackloc () + byte_len);
}
static void
cur_asm_state = state;
}
+static void
+s_endgpuif (ignore)
+ int ignore;
+{
+}
+\f
/* Parse a DMA data spec which can be either of '*' or a quad word count. */
static int