* config/tc-dvp.c: Include stdarg.h/varargs.h.

(md_pseudo_table): Add .word.
	(assemble_dma): Set alignment to 16 bytes.  Enable code that records
	fixups.
	(assemble_one_insn): Handle DVP_OPERAND_DMA_{ADDR,AUTOCOUNT}.
	(md_apply_fix3): Handle DVP_OPERAND_DMA_ADDR.
	(parse_dma_addr_autocount): Renamed from parse_dma_ptr_autocount.
	Rewrite.
	(eval_expr): New function.
	(create_label,create_colon_label): New function.
	(s_enddmadata): Rewrite.
This commit is contained in:
Doug Evans
1998-02-19 10:24:15 +00:00
parent c9320f0675
commit 1ece1d561b

View File

@ -20,6 +20,7 @@
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
#include "sysdep.h" #include "sysdep.h"
#include "as.h" #include "as.h"
#include "subsegs.h" #include "subsegs.h"
@ -28,10 +29,21 @@
#include "opcode/dvp.h" #include "opcode/dvp.h"
#include "elf/mips.h" #include "elf/mips.h"
static long parse_float PARAMS ((char **, const char **)); #ifdef USE_STDARG
#include <stdarg.h>
#else
#include <varargs.h>
#endif
/* Compute DMA operand index number of OP. */
#define DMA_OPERAND_INDEX(op) ((op) - dma_operands)
static long parse_float PARAMS ((char **, const char **));
static struct symbol * create_label PARAMS ((const char *, const char *));
static struct symbol * create_colon_label PARAMS ((const char *, const char *));
static long eval_expr PARAMS ((int, int, const char *, ...));
static long parse_dma_ild_autocount (); static long parse_dma_ild_autocount ();
static long parse_dma_ptr_autocount (); static long parse_dma_addr_autocount ();
static void insert_operand static void insert_operand
PARAMS ((dvp_cpu, const dvp_opcode *, const dvp_operand *, int, PARAMS ((dvp_cpu, const dvp_opcode *, const dvp_operand *, int,
@ -139,16 +151,17 @@ static void s_state PARAMS ((int));
/* The target specific pseudo-ops which we support. */ /* The target specific pseudo-ops which we support. */
const pseudo_typeS md_pseudo_table[] = const pseudo_typeS md_pseudo_table[] =
{ {
{ "dmadata", s_dmadata, 0 }, { "word", cons, 4 },
{ "dmapackvif", s_dmapackvif, 0 }, { "dmadata", s_dmadata, 0 },
{ "enddirect", s_enddirect, 0 }, { "dmapackvif", s_dmapackvif, 0 },
{ "enddmadata", s_enddmadata, 0 }, { "enddirect", s_enddirect, 0 },
{ "endgif", s_endgif, 0 }, { "enddmadata", s_enddmadata, 0 },
{ "endmpg", s_endmpg, 0 }, { "endgif", s_endgif, 0 },
{ "endunpack", s_endunpack, 0 }, { "endmpg", s_endmpg, 0 },
/* .vu added to simplify debugging and creation of input files */ { "endunpack", s_endunpack, 0 },
{ "vu", s_state, ASM_VU }, /* .vu added to simplify debugging and creation of input files */
{ NULL, NULL, 0 } { "vu", s_state, ASM_VU },
{ NULL, NULL, 0 }
}; };
void void
@ -225,7 +238,7 @@ md_assemble (str)
{ {
if (strncasecmp (str, "dma", 3) == 0) if (strncasecmp (str, "dma", 3) == 0)
assemble_dma (str); assemble_dma (str);
if (strncasecmp (str, "gif", 3) == 0) else if (strncasecmp (str, "gif", 3) == 0)
assemble_gif (str); assemble_gif (str);
else else
assemble_vif (str); assemble_vif (str);
@ -243,62 +256,64 @@ static void
assemble_dma (str) assemble_dma (str)
char *str; char *str;
{ {
DVP_INSN insn_buf[4]; DVP_INSN insn_buf[4];
int len; /* Insn's length, in 32 bit words. */ /* Insn's length, in 32 bit words. */
char *f; /* Pointer to allocated frag. */ int len;
int i; /* Pointer to allocated frag. */
const dvp_opcode *opcode; char *f;
int i;
const dvp_opcode *opcode;
/* /* Fill the first two words with VIF NOPs.
Fill the first two words with VIF NOPs. They may be over-written later if DmaPackPke is on.
They may be over-written later if DmaPackPke is on. initialize the remainder with zeros. */
initialize the remainder with zeros. insn_buf[0] = 0;
*/ insn_buf[1] = 0;
insn_buf[ 0] = 0; insn_buf[2] = 0;
insn_buf[ 1] = 0; insn_buf[3] = 0;
insn_buf[ 2] = 0;
insn_buf[ 3] = 0;
opcode = assemble_one_insn (DVP_DMA, opcode = assemble_one_insn (DVP_DMA,
dma_opcode_lookup_asm (str), dma_operands, dma_opcode_lookup_asm (str), dma_operands,
&str, insn_buf); &str, insn_buf);
if( opcode == NULL) return; if (opcode == NULL)
if( !output_dma) return; return;
if (!output_dma)
return;
len = 4; /* Do an implicit alignment to a 16 byte boundary. */
f = frag_more( len * 4); frag_align (4, 0, 0);
record_alignment (now_seg, 4);
/* Write out the VIF / DMA instructions. */ len = 4;
for( i = 0; i < len; ++i) f = frag_more (len * 4);
md_number_to_chars( f + i * 4, insn_buf[i], 4);
/* Create any fixups. */ /* Write out the DMA instruction. */
/* FIXME: It might eventually be possible to combine all the various for (i = 0; i < len; ++i)
copies of this bit of code. */ md_number_to_chars (f + i * 4, insn_buf[i], 4);
for( i = 0; i < fixup_count; ++i)
/* Create any fixups. */
/* FIXME: It might eventually be possible to combine all the various
copies of this bit of code. */
for (i = 0; i < fixup_count; ++i)
{ {
int op_type, reloc_type, offset; int op_type, reloc_type, offset;
const dvp_operand *operand; const dvp_operand *operand;
#if 0 /* Create a fixup for this operand.
/* At this point we do not use a bfd_reloc_code_real_type for
Create a fixup for this operand. operands residing in the insn, but instead just use the
At this point we do not use a bfd_reloc_code_real_type for operand index. This lets us easily handle fixups for any
operands residing in the insn, but instead just use the operand type, although that is admittedly not a very exciting
operand index. This lets us easily handle fixups for any feature. We pick a BFD reloc type in md_apply_fix. */
operand type, although that is admittedly not a very exciting
feature. We pick a BFD reloc type in md_apply_fix.
*/
op_type = fixups[i].opindex; op_type = fixups[i].opindex;
offset = fixups[i].offset; offset = fixups[i].offset;
reloc_type = encode_fixup_reloc_type (DVP_VIF, op_type); reloc_type = encode_fixup_reloc_type (DVP_DMA, op_type);
operand = &vif_operands[op_type]; operand = &dma_operands[op_type];
fix_new_exp (frag_now, f + offset - frag_now->fr_literal, 4, fix_new_exp (frag_now, f + offset - frag_now->fr_literal, 4,
&fixups[i].exp, &fixups[i].exp,
(operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0, (operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0,
(bfd_reloc_code_real_type) reloc_type); (bfd_reloc_code_real_type) reloc_type);
#endif
} }
} }
@ -715,11 +730,12 @@ assemble_one_insn (cpu, opcode, operand_table, pstr, insn_buf)
if (errmsg) if (errmsg)
break; break;
} }
else if (operand->flags & DVP_OPERAND_DMA_PTR_AUTOCOUNT) else if ((operand->flags & (DVP_OPERAND_DMA_ADDR | DVP_OPERAND_DMA_AUTOCOUNT))
== (DVP_OPERAND_DMA_ADDR | DVP_OPERAND_DMA_AUTOCOUNT))
{ {
errmsg = 0; errmsg = 0;
value = parse_dma_ptr_autocount (opcode, operand, mods, value = parse_dma_addr_autocount (opcode, operand, mods,
insn_buf, &str, &errmsg); insn_buf, &str, &errmsg);
if (errmsg) if (errmsg)
break; break;
} }
@ -753,7 +769,15 @@ assemble_one_insn (cpu, opcode, operand_table, pstr, insn_buf)
as_fatal ("too many fixups"); as_fatal ("too many fixups");
fixups[fixup_count].exp = exp; fixups[fixup_count].exp = exp;
fixups[fixup_count].opindex = index; fixups[fixup_count].opindex = index;
fixups[fixup_count].offset = (operand->shift / 32) * 4; /* FIXME: Revisit. Do we really need operand->word?
The endianness of a 128 bit DMAtag is rather
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. */
if (operand->word != 0)
fixups[fixup_count].offset = operand->word * 4;
else
fixups[fixup_count].offset = (operand->shift / 32) * 4;
++fixup_count; ++fixup_count;
value = 0; value = 0;
} }
@ -957,7 +981,7 @@ md_apply_fix3 (fixP, valueP, seg)
} }
} }
/* Check for dvp operand's. These are indicated with a reloc value /* Check for dvp operands. These are indicated with a reloc value
>= BFD_RELOC_UNUSED. */ >= BFD_RELOC_UNUSED. */
if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
@ -970,7 +994,9 @@ md_apply_fix3 (fixP, valueP, seg)
& cpu, & operand); & cpu, & operand);
/* Fetch the instruction, insert the fully resolved operand /* Fetch the instruction, insert the fully resolved operand
value, and stuff the instruction back again. */ value, and stuff the instruction back again. The fixup is recorded
at the appropriate word so pass DVP_MOD_THIS_WORD so any offset
specified in the tables is ignored. */
insn = bfd_getl32 ((unsigned char *) where); insn = bfd_getl32 ((unsigned char *) where);
insert_operand_final (cpu, operand, DVP_MOD_THIS_WORD, &insn, insert_operand_final (cpu, operand, DVP_MOD_THIS_WORD, &insn,
(offsetT) value, fixP->fx_file, fixP->fx_line); (offsetT) value, fixP->fx_file, fixP->fx_line);
@ -987,11 +1013,16 @@ md_apply_fix3 (fixP, valueP, seg)
/* FIXME: This test is a hack. */ /* FIXME: This test is a hack. */
if ((operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0) if ((operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0)
{ {
assert ((operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0 assert (operand->bits == 11
&& operand->bits == 11
&& operand->shift == 0); && operand->shift == 0);
fixP->fx_r_type = BFD_RELOC_MIPS_DVP_11_PCREL; fixP->fx_r_type = BFD_RELOC_MIPS_DVP_11_PCREL;
} }
else if ((operand->flags & DVP_OPERAND_DMA_ADDR) != 0)
{
assert (operand->bits == 27
&& operand->shift == 4);
fixP->fx_r_type = BFD_RELOC_MIPS_DVP_27_S4;
}
else else
{ {
as_bad_where (fixP->fx_file, fixP->fx_line, as_bad_where (fixP->fx_file, fixP->fx_line,
@ -1154,7 +1185,7 @@ parse_float (pstr, errmsg)
/* Compute the auto-count value for a DMA tag with inline data. */ /* Compute the auto-count value for a DMA tag with inline data. */
static long static long
parse_dma_ild_autocount( opcode, operand, mods, insn_buf, pstr, errmsg) parse_dma_ild_autocount (opcode, operand, mods, insn_buf, pstr, errmsg)
const dvp_opcode *opcode; const dvp_opcode *opcode;
const dvp_operand *operand; const dvp_operand *operand;
int mods; int mods;
@ -1180,18 +1211,18 @@ parse_dma_ild_autocount( opcode, operand, mods, insn_buf, pstr, errmsg)
/* Scan a symbol and return a pointer to one past the end. */ /* Scan a symbol and return a pointer to one past the end. */
#define issymchar(ch) (isalnum(ch) || ch == '_') #define issymchar(ch) (isalnum(ch) || ch == '_')
static char * static char *
scan_symbol( sym) scan_symbol (sym)
char *sym; char *sym;
{ {
while( *sym && issymchar( *sym)) while (*sym && issymchar (*sym))
++sym; ++sym;
return sym; return sym;
} }
/* Compute the auto-count value for a DMA tag with out-of-line data. */ /* Compute the auto-count value for a DMA tag with out-of-line data. */
static long static long
parse_dma_ptr_autocount( opcode, operand, mods, insn_buf, pstr, errmsg) parse_dma_addr_autocount (opcode, operand, mods, insn_buf, pstr, errmsg)
const dvp_opcode *opcode; const dvp_opcode *opcode;
const dvp_operand *operand; const dvp_operand *operand;
int mods; int mods;
@ -1199,58 +1230,132 @@ parse_dma_ptr_autocount( opcode, operand, mods, insn_buf, pstr, errmsg)
char **pstr; char **pstr;
const char **errmsg; const char **errmsg;
{ {
char *start = *pstr; char *start = *pstr;
char *end = start; char *end = start;
long retval; long retval;
/* Data reference must be a .DmaData label. */
struct symbol *label, *label2, *endlabel;
const char *name;
char *name2;
int len;
long count;
char c;
/* Data reference must be a .DmaData label. */ label = label2 = 0;
struct symbol *label, *label2; if (! is_name_beginner (*start))
const char *name;
char *name2;
int len;
long count;
label = label2 = 0;
if( is_name_beginner( *start) )
{ {
char c; *errmsg = "invalid .DmaData label";
return 0;
end = scan_symbol( start);
c = *end;
*end = 0;
label = symbol_find( start);
*end = c;
}
if( label )
{
name = S_GET_NAME( label);
len = strlen( name) + 1;
name2 = xmalloc( len + 2);
name2[ 0] = '_';
name2[ 1] = '$';
memcpy( name2+2, name, len); /* copy original name & \0 */
label2 = symbol_find( name2);
free( name2);
}
if( label == 0 || label2 == 0 )
{
*errmsg = "2nd operand must be a .DmaData label";
return 0;
} }
/* The second operand's value is the value of "symbol". */ name = start;
retval = S_GET_VALUE( label); end = scan_symbol (name);
c = *end;
*end = 0;
label = symbol_find_or_make (name);
*end = c;
/* The computed count value is val(symbol2) - val(symbol). */ label2 = create_label ("_$", name);
count = S_GET_VALUE( label2) - retval; /* FIXME: revisit .L. */
endlabel = create_label (".L.end.", name);
/* Store the count field. */ retval = eval_expr (dma_operand_addr, operand->word * 4, name);
count &= 0x0000ffff; count = eval_expr (dma_operand_count, (operand->word + 1) * 4,
insn_buf[ 4] &= 0xffff0000; ".L.end.%s - %s", name, name);
insn_buf[ 4] |= count & 0x0000ffff; /* count is in quadwords */
count /= 16;
*pstr = end; /* Store the count field. */
return retval; insn_buf[3] &= 0xffff0000;
insn_buf[3] |= count & 0x0000ffff;
*pstr = end;
return retval;
}
/* Evaluate an expression.
The result is the value of the expression if it can be evaluated,
or 0 if it cannot (say because some symbols haven't been defined yet)
in which case a fixup is queued. */
static long
#ifdef USE_STDARG
eval_expr (int opindex, int offset, const char *fmt, ...)
#else
eval_expr (opindex, offset, fmt, va_alist)
int opindex,offset;
const char *fmt;
va_dcl
#endif
{
long value;
va_list ap;
char *str,*save_input;
expressionS exp;
#ifdef USE_STDARG
va_start (ap, fmt);
#else
va_start (ap);
#endif
vasprintf (&str, fmt, ap);
va_end (ap);
save_input = input_line_pointer;
input_line_pointer = str;
expression (&exp);
input_line_pointer = save_input;
free (str);
if (exp.X_op == O_constant)
value = exp.X_add_number;
else
{
fixups[fixup_count].exp = exp;
fixups[fixup_count].opindex = opindex;
fixups[fixup_count].offset = offset;
++fixup_count;
value = 0;
}
return value;
}
/* Create a label named by concatenating PREFIX to NAME. */
static struct symbol *
create_label (prefix, name)
const char *prefix, *name;
{
int namelen = strlen (name);
int prefixlen = strlen (prefix);
char *fullname;
struct symbol *result;
fullname = xmalloc (prefixlen + namelen + 1);
strcpy (fullname, prefix);
strcat (fullname, name);
result = symbol_find_or_make (fullname);
free (fullname);
return result;
}
/* Create a label named by concatenating PREFIX to NAME,
and define it as `.'. */
static struct symbol *
create_colon_label (prefix, name)
const char *prefix, *name;
{
int namelen = strlen (name);
int prefixlen = strlen (prefix);
char *fullname;
struct symbol *result;
fullname = xmalloc (prefixlen + namelen + 1);
strcpy (fullname, prefix);
strcat (fullname, name);
result = colon (fullname);
free (fullname);
return result;
} }
/* Return length in bytes of the variable length VIF insn /* Return length in bytes of the variable length VIF insn
@ -1383,11 +1488,12 @@ insert_operand (cpu, opcode, operand, mods, insn_buf, val, errmsg)
} }
else else
{ {
#if 0 /* FIXME: revisit */
/* We currently assume a field does not cross a word boundary. */ /* We currently assume a field does not cross a word boundary. */
int shift = ((mods & DVP_MOD_THIS_WORD) int shift = ((mods & DVP_MOD_THIS_WORD)
? (operand->shift & 31) ? (operand->shift & 31)
: operand->shift); : operand->shift);
int word = (mods & DVP_MOD_THIS_WORD) ? 0 : operand->word;
#if 0 /* FIXME: revisit */
DVP_INSN *p = insn_buf + (shift / 32); DVP_INSN *p = insn_buf + (shift / 32);
if (operand->bits == 32) if (operand->bits == 32)
*p = val; *p = val;
@ -1397,13 +1503,12 @@ insert_operand (cpu, opcode, operand, mods, insn_buf, val, errmsg)
*p |= ((long) val & ((1 << operand->bits) - 1)) << shift; *p |= ((long) val & ((1 << operand->bits) - 1)) << shift;
} }
#else #else
/* We currently assume a field does not cross a word boundary. */
if (operand->bits == 32) if (operand->bits == 32)
insn_buf[ operand->word] = val; insn_buf[word] = val;
else else
{ {
long temp = (long) val & ((1 << operand->bits) - 1); long temp = (long) val & ((1 << operand->bits) - 1);
insn_buf[ operand->word] |= temp << operand->shift; insn_buf[word] |= temp << operand->shift;
} }
} }
#endif #endif
@ -1486,104 +1591,97 @@ static const char *dmadata_name;
static int implied_dmadata_p = 0; static int implied_dmadata_p = 0;
static void static void
s_dmadata_implied( ignore) s_dmadata_implied (ignore)
int ignore; int ignore;
{ {
if( dmadata_state != 0 ) if (dmadata_state != 0 )
{ {
as_bad( "DmaData blocks cannot be nested."); as_bad ("DmaData blocks cannot be nested.");
} }
dmadata_state = 1; dmadata_state = 1;
dmadata_name = 0; dmadata_name = 0;
} }
static void static void
s_dmadata( ignore) s_dmadata (ignore)
int ignore; int ignore;
{ {
char *name, c; char *name, c;
dmadata_name = 0; dmadata_name = 0;
if( dmadata_state != 0 ) if (dmadata_state != 0)
{ {
as_bad( "DmaData blocks cannot be nested."); as_bad ("DmaData blocks cannot be nested.");
ignore_rest_of_line(); ignore_rest_of_line ();
return; return;
} }
dmadata_state = 1; dmadata_state = 1;
SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */ SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */
name = input_line_pointer; name = input_line_pointer;
if( !is_name_beginner( *name) ) if (!is_name_beginner (*name))
{ {
as_bad( "invalid identifier for \".DmaData\""); as_bad ("invalid identifier for \".DmaData\"");
obstack_1grow( &cond_obstack, 0); /*FIXME what is this for?*/ ignore_rest_of_line ();
ignore_rest_of_line(); return;
return;
} }
c = get_symbol_end(); c = get_symbol_end ();
line_label = colon( name); /* user-defined label */ line_label = colon (name); /* user-defined label */
dmadata_name = line_label->bsym->name; dmadata_name = S_GET_NAME (line_label);
*input_line_pointer = c; *input_line_pointer = c;
demand_empty_rest_of_line(); demand_empty_rest_of_line ();
} }
static void static void
s_enddmadata( ignore) s_enddmadata (ignore)
int ignore; int ignore;
{ {
if( dmadata_state != 1) if (dmadata_state != 1)
{ {
as_warn( ".EndDmaData encountered outside a DmaData block -- ignored."); as_warn (".EndDmaData encountered outside a DmaData block -- ignored.");
ignore_rest_of_line(); ignore_rest_of_line ();
dmadata_name = 0; dmadata_name = 0;
} }
dmadata_state = 0; dmadata_state = 0;
demand_empty_rest_of_line(); demand_empty_rest_of_line ();
/* /* "label" points to beginning of block.
* "label" points to beginning of block Create a name for the final label like _$<name>. */
* Create a name for the final label like _$<name> if (dmadata_name)
*/ {
if( dmadata_name) { /* Fill the data out to a multiple of 16 bytes. */
int temp; /* FIXME: Does the fill contents matter? */
char *name; frag_align (4, 0, 0);
create_colon_label (".L.end.", dmadata_name);
temp = strlen( dmadata_name) + 1;
name = xmalloc( temp + 2);
name[ 0] = '_';
name[ 1] = '$';
memcpy( name+2, dmadata_name, temp); /* copy original name & \0 */
colon( name);
free( name);
} }
} }
static void static void
s_dmapackvif( ignore) s_dmapackvif (ignore)
int ignore; int ignore;
{ {
/* Syntax: .dmapackvif 0|1 */ /* Syntax: .dmapackvif 0|1 */
struct symbol *label; /* Points to symbol */ struct symbol *label; /* Points to symbol */
char *name; /* points to name of symbol */ char *name; /* points to name of symbol */
SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */ /* Leading whitespace is part of operand. */
switch( *input_line_pointer++ ) SKIP_WHITESPACE ();
switch (*input_line_pointer++)
{ {
case '0': case '0':
dma_pack_vif_p = 0; dma_pack_vif_p = 0;
break; break;
case '1': case '1':
dma_pack_vif_p = 1; dma_pack_vif_p = 1;
break; break;
default: default:
as_bad( "illegal argument to `.DmaPackPke'"); as_bad ("illegal argument to `.DmaPackPke'");
} }
demand_empty_rest_of_line(); demand_empty_rest_of_line ();
} }
static void static void
@ -1690,57 +1788,57 @@ s_endgif (ignore)
/* Parse a DMA data spec which can be either of '*' or a quad word count. */ /* Parse a DMA data spec which can be either of '*' or a quad word count. */
static int static int
parse_dma_count( pstr, errmsg) parse_dma_count (pstr, errmsg)
char **pstr; char **pstr;
const char **errmsg; const char **errmsg;
{ {
char *str = *pstr; char *str = *pstr;
long count, value; long count, value;
expressionS exp; expressionS exp;
if( *str == '*' ) if (*str == '*')
{ {
++*pstr; ++*pstr;
/* -1 is a special marker to caller to tell it the count is to be /* -1 is a special marker to caller to tell it the count is to be
computed from the data. */ computed from the data. */
return -1; return -1;
} }
expression( &exp); expression (&exp);
if( exp.X_op == O_illegal if (exp.X_op == O_illegal
|| exp.X_op == O_absent ) || exp.X_op == O_absent)
; ;
else if( exp.X_op == O_constant ) else if (exp.X_op == O_constant)
value = exp.X_add_number; value = exp.X_add_number;
else if( exp.X_op == O_register ) else if (exp.X_op == O_register)
as_fatal( "got O_register"); as_fatal ("got O_register");
else else
{ {
/* We need to generate a fixup for this expression. */ /* We need to generate a fixup for this expression. */
if( fixup_count >= MAX_FIXUPS ) if (fixup_count >= MAX_FIXUPS )
as_fatal( "too many fixups"); as_fatal ("too many fixups");
fixups[fixup_count].exp = exp; fixups[fixup_count].exp = exp;
fixups[fixup_count].opindex = 0 /*FIXME*/; fixups[fixup_count].opindex = 0 /*FIXME*/;
fixups[fixup_count].offset = 0 /*FIXME*/; fixups[fixup_count].offset = 0 /*FIXME*/;
++fixup_count; ++fixup_count;
value = 0; value = 0;
} }
if( isdigit( *str) ) /* ????????needs to accept an expression*/ if (isdigit( *str)) /* ????????needs to accept an expression*/
{ {
char *start = str; char *start = str;
while( *str && *str != ',' ) while (*str && *str != ',')
++str; ++str;
if( *str != ',' ) if (*str != ',')
{ {
*errmsg = "invalid dma count"; *errmsg = "invalid dma count";
return 0; return 0;
} }
count = atoi (start); count = atoi (start);
*pstr = str; *pstr = str;
return(count); return (count);
} }
*errmsg = "invalid dma count"; *errmsg = "invalid dma count";
return 0; return 0;
} }