From 1ece1d561b79a77d751b25fb4bc786ce201795dd Mon Sep 17 00:00:00 2001 From: Doug Evans Date: Thu, 19 Feb 1998 10:24:15 +0000 Subject: [PATCH] * 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. --- gas/config/tc-dvp.c | 544 ++++++++++++++++++++++++++------------------ 1 file changed, 321 insertions(+), 223 deletions(-) diff --git a/gas/config/tc-dvp.c b/gas/config/tc-dvp.c index 38580ffb7dd..0d3f19381ab 100644 --- a/gas/config/tc-dvp.c +++ b/gas/config/tc-dvp.c @@ -20,6 +20,7 @@ #include #include + #include "sysdep.h" #include "as.h" #include "subsegs.h" @@ -28,10 +29,21 @@ #include "opcode/dvp.h" #include "elf/mips.h" -static long parse_float PARAMS ((char **, const char **)); +#ifdef USE_STDARG +#include +#else +#include +#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_ptr_autocount (); +static long parse_dma_addr_autocount (); static void insert_operand 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. */ const pseudo_typeS md_pseudo_table[] = { - { "dmadata", s_dmadata, 0 }, - { "dmapackvif", s_dmapackvif, 0 }, - { "enddirect", s_enddirect, 0 }, - { "enddmadata", s_enddmadata, 0 }, - { "endgif", s_endgif, 0 }, - { "endmpg", s_endmpg, 0 }, - { "endunpack", s_endunpack, 0 }, - /* .vu added to simplify debugging and creation of input files */ - { "vu", s_state, ASM_VU }, - { NULL, NULL, 0 } + { "word", cons, 4 }, + { "dmadata", s_dmadata, 0 }, + { "dmapackvif", s_dmapackvif, 0 }, + { "enddirect", s_enddirect, 0 }, + { "enddmadata", s_enddmadata, 0 }, + { "endgif", s_endgif, 0 }, + { "endmpg", s_endmpg, 0 }, + { "endunpack", s_endunpack, 0 }, + /* .vu added to simplify debugging and creation of input files */ + { "vu", s_state, ASM_VU }, + { NULL, NULL, 0 } }; void @@ -225,7 +238,7 @@ md_assemble (str) { if (strncasecmp (str, "dma", 3) == 0) assemble_dma (str); - if (strncasecmp (str, "gif", 3) == 0) + else if (strncasecmp (str, "gif", 3) == 0) assemble_gif (str); else assemble_vif (str); @@ -243,62 +256,64 @@ static void assemble_dma (str) char *str; { - DVP_INSN insn_buf[4]; - int len; /* Insn's length, in 32 bit words. */ - char *f; /* Pointer to allocated frag. */ - int i; - const dvp_opcode *opcode; + DVP_INSN insn_buf[4]; + /* Insn's length, in 32 bit words. */ + int len; + /* Pointer to allocated frag. */ + char *f; + int i; + const dvp_opcode *opcode; - /* - Fill the first two words with VIF NOPs. - They may be over-written later if DmaPackPke is on. - initialize the remainder with zeros. - */ - insn_buf[ 0] = 0; - insn_buf[ 1] = 0; - insn_buf[ 2] = 0; - insn_buf[ 3] = 0; + /* Fill the first two words with VIF NOPs. + They may be over-written later if DmaPackPke is on. + initialize the remainder with zeros. */ + insn_buf[0] = 0; + insn_buf[1] = 0; + insn_buf[2] = 0; + insn_buf[3] = 0; - opcode = assemble_one_insn (DVP_DMA, - dma_opcode_lookup_asm (str), dma_operands, - &str, insn_buf); - if( opcode == NULL) return; - if( !output_dma) return; + opcode = assemble_one_insn (DVP_DMA, + dma_opcode_lookup_asm (str), dma_operands, + &str, insn_buf); + if (opcode == NULL) + return; + if (!output_dma) + return; - len = 4; - f = frag_more( len * 4); + /* Do an implicit alignment to a 16 byte boundary. */ + frag_align (4, 0, 0); + record_alignment (now_seg, 4); - /* Write out the VIF / DMA instructions. */ - for( i = 0; i < len; ++i) - md_number_to_chars( f + i * 4, insn_buf[i], 4); + len = 4; + f = frag_more (len * 4); - /* 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) + /* Write out the DMA instruction. */ + for (i = 0; i < len; ++i) + md_number_to_chars (f + i * 4, insn_buf[i], 4); + + /* 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; - const dvp_operand *operand; + int op_type, reloc_type, offset; + 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 - operands residing in the insn, but instead just use the - operand index. This lets us easily handle fixups for any - operand type, although that is admittedly not a very exciting - feature. We pick a BFD reloc type in md_apply_fix. - */ + /* Create a fixup for this operand. + At this point we do not use a bfd_reloc_code_real_type for + operands residing in the insn, but instead just use the + operand index. This lets us easily handle fixups for any + 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; - offset = fixups[i].offset; - reloc_type = encode_fixup_reloc_type (DVP_VIF, op_type); - operand = &vif_operands[op_type]; - fix_new_exp (frag_now, f + offset - frag_now->fr_literal, 4, - &fixups[i].exp, - (operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0, - (bfd_reloc_code_real_type) reloc_type); -#endif + op_type = fixups[i].opindex; + offset = fixups[i].offset; + reloc_type = encode_fixup_reloc_type (DVP_DMA, op_type); + operand = &dma_operands[op_type]; + fix_new_exp (frag_now, f + offset - frag_now->fr_literal, 4, + &fixups[i].exp, + (operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0, + (bfd_reloc_code_real_type) reloc_type); } } @@ -715,11 +730,12 @@ assemble_one_insn (cpu, opcode, operand_table, pstr, insn_buf) if (errmsg) 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; - value = parse_dma_ptr_autocount (opcode, operand, mods, - insn_buf, &str, &errmsg); + value = parse_dma_addr_autocount (opcode, operand, mods, + insn_buf, &str, &errmsg); if (errmsg) break; } @@ -753,7 +769,15 @@ assemble_one_insn (cpu, opcode, operand_table, pstr, insn_buf) as_fatal ("too many fixups"); fixups[fixup_count].exp = exp; 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; 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. */ if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) @@ -970,7 +994,9 @@ md_apply_fix3 (fixP, valueP, seg) & cpu, & 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); insert_operand_final (cpu, operand, DVP_MOD_THIS_WORD, &insn, (offsetT) value, fixP->fx_file, fixP->fx_line); @@ -987,11 +1013,16 @@ md_apply_fix3 (fixP, valueP, seg) /* FIXME: This test is a hack. */ if ((operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0) { - assert ((operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0 - && operand->bits == 11 + assert (operand->bits == 11 && operand->shift == 0); 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 { 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. */ 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_operand *operand; 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. */ #define issymchar(ch) (isalnum(ch) || ch == '_') static char * -scan_symbol( sym) +scan_symbol (sym) char *sym; { - while( *sym && issymchar( *sym)) - ++sym; - return sym; + while (*sym && issymchar (*sym)) + ++sym; + return sym; } /* Compute the auto-count value for a DMA tag with out-of-line data. */ 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_operand *operand; int mods; @@ -1199,58 +1230,132 @@ parse_dma_ptr_autocount( opcode, operand, mods, insn_buf, pstr, errmsg) char **pstr; const char **errmsg; { - char *start = *pstr; - char *end = start; - long retval; + char *start = *pstr; + char *end = start; + 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. */ - struct symbol *label, *label2; - const char *name; - char *name2; - int len; - long count; - - label = label2 = 0; - if( is_name_beginner( *start) ) + label = label2 = 0; + if (! is_name_beginner (*start)) { - char c; - - 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; + *errmsg = "invalid .DmaData label"; + return 0; } - /* The second operand's value is the value of "symbol". */ - retval = S_GET_VALUE( label); + name = start; + 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). */ - count = S_GET_VALUE( label2) - retval; + label2 = create_label ("_$", name); + /* FIXME: revisit .L. */ + endlabel = create_label (".L.end.", name); - /* Store the count field. */ - count &= 0x0000ffff; - insn_buf[ 4] &= 0xffff0000; - insn_buf[ 4] |= count & 0x0000ffff; + retval = eval_expr (dma_operand_addr, operand->word * 4, name); + count = eval_expr (dma_operand_count, (operand->word + 1) * 4, + ".L.end.%s - %s", name, name); + /* count is in quadwords */ + count /= 16; - *pstr = end; - return retval; + /* Store the count field. */ + 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 @@ -1383,11 +1488,12 @@ insert_operand (cpu, opcode, operand, mods, insn_buf, val, errmsg) } else { -#if 0 /* FIXME: revisit */ /* We currently assume a field does not cross a word boundary. */ int shift = ((mods & DVP_MOD_THIS_WORD) ? (operand->shift & 31) : operand->shift); + int word = (mods & DVP_MOD_THIS_WORD) ? 0 : operand->word; +#if 0 /* FIXME: revisit */ DVP_INSN *p = insn_buf + (shift / 32); if (operand->bits == 32) *p = val; @@ -1397,13 +1503,12 @@ insert_operand (cpu, opcode, operand, mods, insn_buf, val, errmsg) *p |= ((long) val & ((1 << operand->bits) - 1)) << shift; } #else - /* We currently assume a field does not cross a word boundary. */ if (operand->bits == 32) - insn_buf[ operand->word] = val; + insn_buf[word] = val; else { long temp = (long) val & ((1 << operand->bits) - 1); - insn_buf[ operand->word] |= temp << operand->shift; + insn_buf[word] |= temp << operand->shift; } } #endif @@ -1486,104 +1591,97 @@ static const char *dmadata_name; static int implied_dmadata_p = 0; static void -s_dmadata_implied( ignore) +s_dmadata_implied (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_name = 0; + dmadata_state = 1; + dmadata_name = 0; } static void -s_dmadata( ignore) +s_dmadata (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."); - ignore_rest_of_line(); - return; + as_bad ("DmaData blocks cannot be nested."); + ignore_rest_of_line (); + return; } - dmadata_state = 1; + dmadata_state = 1; - SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */ - name = input_line_pointer; + SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */ + name = input_line_pointer; - if( !is_name_beginner( *name) ) + if (!is_name_beginner (*name)) { - as_bad( "invalid identifier for \".DmaData\""); - obstack_1grow( &cond_obstack, 0); /*FIXME what is this for?*/ - ignore_rest_of_line(); - return; + as_bad ("invalid identifier for \".DmaData\""); + ignore_rest_of_line (); + return; } - c = get_symbol_end(); - line_label = colon( name); /* user-defined label */ - dmadata_name = line_label->bsym->name; - *input_line_pointer = c; + c = get_symbol_end (); + line_label = colon (name); /* user-defined label */ + dmadata_name = S_GET_NAME (line_label); + *input_line_pointer = c; - demand_empty_rest_of_line(); + demand_empty_rest_of_line (); } static void -s_enddmadata( ignore) +s_enddmadata (ignore) int ignore; { - if( dmadata_state != 1) + if (dmadata_state != 1) { - as_warn( ".EndDmaData encountered outside a DmaData block -- ignored."); - ignore_rest_of_line(); - dmadata_name = 0; + as_warn (".EndDmaData encountered outside a DmaData block -- ignored."); + ignore_rest_of_line (); + dmadata_name = 0; } - dmadata_state = 0; - demand_empty_rest_of_line(); + dmadata_state = 0; + demand_empty_rest_of_line (); - /* - * "label" points to beginning of block - * Create a name for the final label like _$ - */ - if( dmadata_name) { - int temp; - char *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); + /* "label" points to beginning of block. + Create a name for the final label like _$. */ + if (dmadata_name) + { + /* Fill the data out to a multiple of 16 bytes. */ + /* FIXME: Does the fill contents matter? */ + frag_align (4, 0, 0); + create_colon_label (".L.end.", dmadata_name); } } static void -s_dmapackvif( ignore) +s_dmapackvif (ignore) int ignore; { - /* Syntax: .dmapackvif 0|1 */ - struct symbol *label; /* Points to symbol */ - char *name; /* points to name of symbol */ + /* Syntax: .dmapackvif 0|1 */ + struct symbol *label; /* Points to symbol */ + char *name; /* points to name of symbol */ - SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */ - switch( *input_line_pointer++ ) + /* Leading whitespace is part of operand. */ + SKIP_WHITESPACE (); + switch (*input_line_pointer++) { case '0': - dma_pack_vif_p = 0; - break; + dma_pack_vif_p = 0; + break; case '1': - dma_pack_vif_p = 1; - break; + dma_pack_vif_p = 1; + break; 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 @@ -1690,57 +1788,57 @@ s_endgif (ignore) /* Parse a DMA data spec which can be either of '*' or a quad word count. */ static int -parse_dma_count( pstr, errmsg) - char **pstr; - const char **errmsg; +parse_dma_count (pstr, errmsg) + char **pstr; + const char **errmsg; { - char *str = *pstr; - long count, value; - expressionS exp; + char *str = *pstr; + long count, value; + expressionS exp; - if( *str == '*' ) + if (*str == '*') { - ++*pstr; - /* -1 is a special marker to caller to tell it the count is to be - computed from the data. */ - return -1; + ++*pstr; + /* -1 is a special marker to caller to tell it the count is to be + computed from the data. */ + return -1; } - expression( &exp); - if( exp.X_op == O_illegal - || exp.X_op == O_absent ) - ; - else if( exp.X_op == O_constant ) - value = exp.X_add_number; - else if( exp.X_op == O_register ) - as_fatal( "got O_register"); - else + expression (&exp); + if (exp.X_op == O_illegal + || exp.X_op == O_absent) + ; + else if (exp.X_op == O_constant) + value = exp.X_add_number; + else if (exp.X_op == O_register) + as_fatal ("got O_register"); + else { - /* We need to generate a fixup for this expression. */ - if( fixup_count >= MAX_FIXUPS ) - as_fatal( "too many fixups"); - fixups[fixup_count].exp = exp; - fixups[fixup_count].opindex = 0 /*FIXME*/; - fixups[fixup_count].offset = 0 /*FIXME*/; - ++fixup_count; - value = 0; + /* We need to generate a fixup for this expression. */ + if (fixup_count >= MAX_FIXUPS ) + as_fatal ("too many fixups"); + fixups[fixup_count].exp = exp; + fixups[fixup_count].opindex = 0 /*FIXME*/; + fixups[fixup_count].offset = 0 /*FIXME*/; + ++fixup_count; + value = 0; } - if( isdigit( *str) ) /* ????????needs to accept an expression*/ + if (isdigit( *str)) /* ????????needs to accept an expression*/ { - char *start = str; - while( *str && *str != ',' ) - ++str; - if( *str != ',' ) + char *start = str; + while (*str && *str != ',') + ++str; + if (*str != ',') { - *errmsg = "invalid dma count"; - return 0; + *errmsg = "invalid dma count"; + return 0; } - count = atoi (start); - *pstr = str; - return(count); + count = atoi (start); + *pstr = str; + return (count); } - *errmsg = "invalid dma count"; - return 0; + *errmsg = "invalid dma count"; + return 0; }