From: Doug Evans Date: Wed, 28 Jan 1998 10:15:09 +0000 (+0000) Subject: txvu renamed to dvp X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=276dd6efe97ff5537291b3f7fdf76d1ed7b01d31;p=binutils-gdb.git txvu renamed to dvp --- diff --git a/gas/config/.Sanitize b/gas/config/.Sanitize index 9c57e0c15ad..6be825169f2 100644 --- a/gas/config/.Sanitize +++ b/gas/config/.Sanitize @@ -35,7 +35,7 @@ else lose_these_too="${tic80_files} ${lose_these_too}" fi -sky_files="tc-txvu.c tc-txvu.h" +sky_files="tc-dvp.c tc-dvp.h" if ( echo $* | grep keep\-sky > /dev/null ) ; then keep_these_too="${sky_files} ${keep_these_too}" diff --git a/gas/config/tc-dvp.c b/gas/config/tc-dvp.c new file mode 100644 index 00000000000..2e1fddad2cd --- /dev/null +++ b/gas/config/tc-dvp.c @@ -0,0 +1,1219 @@ +/* tc-dvp.c -- Assembler for the DVP + Copyright (C) 1997, 1998 Free Software Foundation. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include "as.h" +#include "subsegs.h" +/* Needed by opcode/dvp.h. */ +#include "dis-asm.h" +#include "opcode/dvp.h" +#include "elf/dvp.h" + +enum cputype { CPU_DMA, CPU_PKE, CPU_GPUIF, CPU_VUUP, CPU_VULO }; + +static DVP_INSN dvp_insert_operand + PARAMS ((DVP_INSN, enum cputype, const dvp_operand *, + int, offsetT, char *, unsigned int)); + +const char comment_chars[] = ";"; +const char line_comment_chars[] = "#"; +const char line_separator_chars[] = "!"; +const char EXP_CHARS[] = "eE"; +const char FLT_CHARS[] = "dD"; + +/* Non-zero if in vu-mode. */ +static int vu_mode_p; + +/* Non-zero if packing pke instructions in dma tags. */ +static int dma_pack_pke_p; + +const char *md_shortopts = ""; + +struct option md_longopts[] = +{ + /* insert options here */ + + {NULL, no_argument, NULL, 0} +}; +size_t md_longopts_size = sizeof(md_longopts); + +int +md_parse_option (c, arg) + int c; + char *arg; +{ + return 0; +} + +void +md_show_usage (stream) + FILE *stream; +{ +#if 0 + fprintf (stream, "TX VU options:\n"); +#endif +} + +/* 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_dmapackpke PARAMS ((int)); +static void s_enddirect PARAMS ((int)); +static void s_endgpuif PARAMS ((int)); +static void s_endmpg PARAMS ((int)); +static void s_endunpack PARAMS ((int)); +static void s_vu PARAMS ((int)); + +/* 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,.endvu added to simplify debugging */ + { "vu", s_vu, 1 }, + { "endvu", s_vu, 0 }, + { NULL, NULL, 0 } +}; + +void +md_begin () +{ + flagword applicable; + segT seg; + subsegT subseg; + + /* Save the current subseg so we can restore it [it's the default one and + we don't want the initial section to be .sbss. */ + seg = now_seg; + subseg = now_subseg; + + subseg_set (seg, subseg); + + /* Initialize the opcode tables. + This involves computing the hash chains. */ + dvp_opcode_init_tables (0); + + vu_mode_p = 0; + dma_pack_pke_p = 0; +} + +/* We need to keep a list of fixups. We can't simply generate them as + we go, because that would require us to first create the frag, and + that would screw up references to ``.''. */ + +struct dvp_fixup +{ + /* index into `dvp_operands' */ + int opindex; + expressionS exp; +}; + +#define MAX_FIXUPS 5 + +static int fixup_count; +static struct dvp_fixup fixups[MAX_FIXUPS]; + +/* Given a cpu type and operand number, return a temporary reloc type + for use in generating the fixup that encodes the cpu type and operand. */ +static int encode_fixup_reloc_type PARAMS ((enum cputype, int)); +/* Given an encoded fixup reloc type, decode it into cpu and operand. */ +static void decode_fixup_reloc_type PARAMS ((int, enum cputype *, + const dvp_operand **)); + +static void assemble_dma PARAMS ((char *)); +static void assemble_gpuif PARAMS ((char *)); +static void assemble_pke PARAMS ((char *)); +static void assemble_vu PARAMS ((char *)); +static char * assemble_vu_insn PARAMS ((enum cputype, + const dvp_opcode *, + const dvp_operand *, + char *, char *)); +static char * assemble_one_insn PARAMS ((enum cputype, + const dvp_opcode *, + const dvp_operand *, + char *, DVP_INSN *)); + +void +md_assemble (str) + char *str; +{ + /* Skip leading white space. */ + while (isspace (*str)) + str++; + + if (! vu_mode_p) + { + if (strncasecmp (str, "dma", 3) == 0) + assemble_dma (str); + else if (strncasecmp (str, "gpuif", 5) == 0) + assemble_gpuif (str); + else + assemble_pke (str); + } + else + assemble_vu (str); +} + +/* Subroutine of md_assemble to assemble DMA instructions. */ + +static void +assemble_dma (str) + char *str; +{ + DVP_INSN insn_buf[4]; + + str = assemble_one_insn (CPU_DMA, + dma_opcode_lookup_asm (str), dma_operands, + str, insn_buf); + if (str == NULL) + return; +} + +/* Subroutine of md_assemble to assemble PKE instructions. */ + +static void +assemble_pke (str) + char *str; +{ + /* Space for the instruction. + The variable length insns can require much more space than this. + It is allocated later, when we know we have such an insn. */ + DVP_INSN insn_buf[5]; + /* Insn's length, in 32 bit words. */ + int len; + /* Non-zero if this is a variable length insn. */ + int varlen_p; + /* Pointer to allocated frag. */ + char *f; + int i; + + str = assemble_one_insn (CPU_PKE, + pke_opcode_lookup_asm (str), pke_operands, + str, insn_buf); + if (str == NULL) + return; + + /* Call back into the parser's state to get the insn's length. + This is just the length of the insn, not of any following data. + The result 0 if the length is unknown. */ + varlen_p = pke_varlen_p (); + len = pke_len (); + + if (varlen_p) + { + /* FIXME: not done yet */ + } + else + { + f = frag_more (len * 4); + } + + /* Write out the instruction. + 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. */ + 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; + const dvp_operand *operand; + + /* 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; + reloc_type = encode_fixup_reloc_type (CPU_PKE, op_type); + operand = &pke_operands[op_type]; + fix_new_exp (frag_now, f - frag_now->fr_literal, 4, + &fixups[i].exp, + (operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0, + (bfd_reloc_code_real_type) reloc_type); + } +} + +/* Subroutine of md_assemble to assemble GPUIF instructions. */ + +static void +assemble_gpuif (str) + char *str; +{ + DVP_INSN insn_buf[4]; + + str = assemble_one_insn (CPU_GPUIF, + gpuif_opcode_lookup_asm (str), gpuif_operands, + str, insn_buf); + if (str == NULL) + return; +} + +/* Subroutine of md_assemble to assemble VU instructions. */ + +static void +assemble_vu (str) + char *str; +{ + /* The lower instruction has the lower address. + Handle this by grabbing 8 bytes now, and then filling each word + as appropriate. */ + char *f = frag_more (8); + +#ifdef VERTICAL_BAR_SEPARATOR + char *p = strchr (str, '|'); + + if (p == NULL) + { + as_bad ("lower slot missing in `%s'", str); + return; + } + + *p = 0; + assemble_vu_insn (CPU_VUUP, + vu_upper_opcode_lookup_asm (str), vu_operands, + str, f + 4); + *p = '|'; + assemble_vu_insn (CPU_VULO, + vu_lower_opcode_lookup_asm (str), vu_operands, + p + 1, f); +#else + str = assemble_vu_insn (CPU_VUUP, + vu_upper_opcode_lookup_asm (str), vu_operands, + str, f + 4); + /* Don't assemble next one if we couldn't assemble the first. */ + if (str) + assemble_vu_insn (CPU_VULO, + vu_lower_opcode_lookup_asm (str), vu_operands, + str, f); +#endif +} + +static char * +assemble_vu_insn (cpu, opcode, operand_table, str, buf) + enum cputype cpu; + const dvp_opcode *opcode; + const dvp_operand *operand_table; + char *str; + char *buf; +{ + int i; + DVP_INSN insn; + + str = assemble_one_insn (cpu, opcode, operand_table, str, &insn); + if (str == NULL) + return NULL; + + /* Write out the instruction. + 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); + + /* Create any fixups. */ + for (i = 0; i < fixup_count; ++i) + { + int op_type, reloc_type; + const dvp_operand *operand; + + /* 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; + 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, + &fixups[i].exp, + (operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0, + (bfd_reloc_code_real_type) reloc_type); + } + + /* All done. */ + return str; +} + +/* Assemble one instruction. + CPU indicates what component we're assembling for. + The assembled instruction is stored in INSN_BUF. + + The result is a pointer to beyond the end of the scanned insn + or NULL if an error occured. This is to handle the VU where two + instructions appear on one line. If this is the upper insn, the caller + can pass back to result to us parse the lower insn. */ + +static char * +assemble_one_insn (cpu, opcode, operand_table, str, insn_buf) + enum cputype cpu; + const dvp_opcode *opcode; + const dvp_operand *operand_table; + char *str; + DVP_INSN *insn_buf; +{ + char *start; + + /* Keep looking until we find a match. */ + + start = str; + for ( ; opcode != NULL; opcode = DVP_OPCODE_NEXT_ASM (opcode)) + { + int past_opcode_p, num_suffixes, num_operands; + const unsigned char *syn; + + /* Ensure the mnemonic part matches. */ + for (str = start, syn = opcode->mnemonic; *syn != '\0'; ++str, ++syn) + if (tolower (*str) != tolower (*syn)) + break; + if (*syn != '\0') + continue; + + /* Scan the syntax string. If it doesn't match, try the next one. */ + + dvp_opcode_init_parse (); + *insn_buf = opcode->value; + fixup_count = 0; + past_opcode_p = 0; + num_suffixes = 0; + num_operands = 0; + + /* We don't check for (*str != '\0') here because we want to parse + any trailing fake arguments in the syntax string. */ + for (/*str = start, */ syn = opcode->syntax; *syn != '\0'; ) + { + int mods,index; + const dvp_operand *operand; + const char *errmsg; + + /* Non operand chars must match exactly. + Operand chars that are letters are not part of symbols + and are case insensitive. */ + if (*syn < 128) + { + if (tolower (*str) == tolower (*syn)) + { + if (*syn == ' ') + past_opcode_p = 1; + ++syn; + ++str; + } + else + break; + continue; + } + + /* We have a suffix or an operand. Pick out any modifiers. */ + mods = 0; + index = DVP_OPERAND_INDEX (*syn); + while (DVP_MOD_P (operand_table[index].flags)) + { + mods |= operand_table[index].flags & DVP_MOD_BITS; + ++syn; + index = DVP_OPERAND_INDEX (*syn); + } + operand = operand_table + index; + + if (operand->flags & DVP_OPERAND_FAKE) + { + if (operand->insert) + { + errmsg = NULL; + (*operand->insert) (opcode, operand, mods, insn_buf, 0, + &errmsg); + /* If we get an error, go on to try the next insn. */ + if (errmsg) + break; + } + ++syn; + } + /* Are we finished with suffixes? */ + else if (!past_opcode_p) + { + int found; + char c; + char *s,*t; + long suf_value; + + if (!(operand->flags & DVP_OPERAND_SUFFIX)) + as_fatal ("bad opcode table, missing suffix flag"); + + /* If we're at a space in the input string, we want to skip the + remaining suffixes. There may be some fake ones though, so + just go on to try the next one. */ + if (*str == ' ') + { + ++syn; + continue; + } + + s = str; + + /* Pick the suffix out and parse it. */ + /* ??? Hmmm ... there may not be any need to nul-terminate the + string, and it may in fact complicate things. */ + for (t = (*s == '.' || *s == '/') ? s + 1 : s; + *t && (isalnum (*t) || *t == '[' || *t == ']'); + ++t) + continue; + c = *t; + *t = '\0'; + errmsg = NULL; + suf_value = (*operand->parse) (opcode, operand, mods, &s, + &errmsg); + *t = c; + if (errmsg) + { + /* This can happen, for example, in ARC's in "blle foo" and + we're currently using the template "b%q%.n %j". The "bl" + insn occurs later in the table so "lle" isn't an illegal + suffix. */ + break; + } + /* Insert the suffix's value into the insn. */ + if (operand->insert) + (*operand->insert) (opcode, operand, mods, + insn_buf, suf_value, NULL); + else + *insn_buf |= suf_value << operand->shift; + + str = t; + ++syn; + } + else + /* This is an operand, either a register or an expression of + some kind. */ + { + char c; + char *hold; + long value = 0; + expressionS exp; + + if (operand->flags & DVP_OPERAND_SUFFIX) + as_fatal ("bad opcode table, suffix wrong"); + +#if 0 /* commas are in the syntax string now */ + /* If this is not the first, there must be a comma. */ + if (num_operands > 0) + { + if (*str != ',') + break; + ++str; + } +#endif + + /* Is there anything left to parse? + We don't check for this at the top because we want to parse + any trailing fake arguments in the syntax string. */ + /* ??? This doesn't allow operands with a legal value of "". */ + if (*str == '\0') + break; + + /* Is this the special DMA count operand? */ + if( operand->flags & DVP_OPERAND_DMA_COUNT) + dvp_dma_operand_count( 0); + if( (operand->flags & DVP_OPERAND_DMA_COUNT) && *str == '*') + { + /* Yes, it is! + Remember that we must compute the length later + when the dma-block label (second operand) is known. */ + ++*pstr; + dvp_dma_operand_count( 1); + } + + /* Parse the operand. */ + else if (operand->parse) + { + errmsg = NULL; + value = (*operand->parse) (opcode, operand, mods, + &str, &errmsg); + if (errmsg) + break; + } + else + { + hold = input_line_pointer; + input_line_pointer = str; + expression (&exp); + str = input_line_pointer; + input_line_pointer = hold; + + if (exp.X_op == O_illegal + || exp.X_op == O_absent) + break; + 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 = index; + ++fixup_count; + value = 0; + } + } + + /* Insert the register or expression into the instruction. */ + if (operand->insert) + { + const char *errmsg = NULL; + (*operand->insert) (opcode, operand, mods, + insn_buf, value, &errmsg); + if (errmsg != (const char *) NULL) + break; + } + else + *insn_buf |= (value & ((1 << operand->bits) - 1)) << operand->shift; + + ++syn; + ++num_operands; + } + } + + /* If we're at the end of the syntax string, we're done. */ + /* FIXME: try to move this to a separate function. */ + if (*syn == '\0') + { + int i; + + /* For the moment we assume a valid `str' can only contain blanks + now. IE: We needn't try again with a longer version of the + insn and it is assumed that longer versions of insns appear + before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */ + + while (isspace (*str)) + ++str; + + if (*str != '\0' +#ifndef VERTICAL_BAR_SEPARATOR + && cpu != CPU_VUUP +#endif + ) + as_bad ("junk at end of line: `%s'", str); + + /* It's now up to the caller to emit the instruction and any + relocations. */ + return str; + } + + /* Try the next entry. */ + } + + as_bad ("bad instruction `%s'", start); + return 0; +} + +void +md_operand (expressionP) + expressionS *expressionP; +{ +} + +valueT +md_section_align (segment, size) + segT segment; + valueT size; +{ + int align = bfd_get_section_alignment (stdoutput, segment); + return ((size + (1 << align) - 1) & (-1 << align)); +} + +symbolS * +md_undefined_symbol (name) + char *name; +{ + return 0; +} + +/* Functions concerning relocs. */ + +/* Spacing between each cpu type's operand numbers. + Should be at least as bit as any operand table. */ +#define RELOC_SPACING 256 + +/* Given a cpu type and operand number, return a temporary reloc type + for use in generating the fixup that encodes the cpu type and operand + number. */ + +static int +encode_fixup_reloc_type (cpu, opnum) + enum cputype cpu; + int opnum; +{ + return (int) BFD_RELOC_UNUSED + ((int) cpu * RELOC_SPACING) + opnum; +} + +/* Given a fixup reloc type, decode it into cpu type and operand. */ + +static void +decode_fixup_reloc_type (fixup_reloc, cpuP, operandP) + int fixup_reloc; + enum cputype *cpuP; + const dvp_operand **operandP; +{ + enum cputype cpu = (fixup_reloc - (int) BFD_RELOC_UNUSED) / RELOC_SPACING; + int opnum = (fixup_reloc - (int) BFD_RELOC_UNUSED) % RELOC_SPACING; + + *cpuP = cpu; + switch (cpu) + { + case CPU_VUUP : *operandP = &vu_operands[opnum]; break; + case CPU_VULO : *operandP = &vu_operands[opnum]; break; + case CPU_DMA : *operandP = &dma_operands[opnum]; break; + case CPU_PKE : *operandP = &pke_operands[opnum]; break; + case CPU_GPUIF : *operandP = &gpuif_operands[opnum]; break; + default : as_fatal ("bad fixup encoding"); + } +} + +/* 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. */ + +long +md_pcrel_from_section (fixP, sec) + fixS *fixP; + segT sec; +{ + if (fixP->fx_addsy != (symbolS *) NULL + && (! S_IS_DEFINED (fixP->fx_addsy) + || S_GET_SEGMENT (fixP->fx_addsy) != sec)) + { + /* The symbol is undefined (or is defined but not in this section). + Let the linker figure it out. */ + return 0; + } + + /* FIXME: `& -16L'? */ + return (fixP->fx_frag->fr_address + fixP->fx_where) & -8L; +} + +/* Apply a fixup to the object code. This is called for all the + fixups we generated by calls to fix_new_exp. At this point all symbol + values should be fully resolved, and we attempt to completely resolve the + reloc. If we can not do that, we determine the correct reloc code and put + it back in the fixup. */ + +int +md_apply_fix3 (fixP, valueP, seg) + fixS *fixP; + valueT *valueP; + segT seg; +{ + char *where = fixP->fx_frag->fr_literal + fixP->fx_where; + valueT value; + + /* FIXME FIXME FIXME: The value we are passed in *valueP includes + the symbol values. Since we are using BFD_ASSEMBLER, if we are + doing this relocation the code in write.c is going to call + bfd_perform_relocation, which is also going to use the symbol + value. That means that if the reloc is fully resolved we want to + use *valueP since bfd_perform_relocation is not being used. + However, if the reloc is not fully resolved we do not want to use + *valueP, and must use fx_offset instead. However, if the reloc + is PC relative, we do want to use *valueP since it includes the + result of md_pcrel_from. This is confusing. */ + + if (fixP->fx_addsy == (symbolS *) NULL) + { + value = *valueP; + fixP->fx_done = 1; + } + else if (fixP->fx_pcrel) + { + value = *valueP; + } + else + { + value = fixP->fx_offset; + if (fixP->fx_subsy != (symbolS *) NULL) + { + if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section) + value -= S_GET_VALUE (fixP->fx_subsy); + else + { + /* We can't actually support subtracting a symbol. */ + as_bad_where (fixP->fx_file, fixP->fx_line, + "expression too complex"); + } + } + } + + /* Check for dvp operand's. These are indicated with a reloc value + >= BFD_RELOC_UNUSED. */ + + if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) + { + enum cputype cpu; + const dvp_operand *operand; + DVP_INSN insn; + + decode_fixup_reloc_type ((int) fixP->fx_r_type, + & cpu, & operand); + + /* Fetch the instruction, insert the fully resolved operand + value, and stuff the instruction back again. */ + insn = bfd_getl32 ((unsigned char *) where); + insn = dvp_insert_operand (insn, cpu, operand, -1, (offsetT) value, + fixP->fx_file, fixP->fx_line); + bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); + + if (fixP->fx_done) + { + /* Nothing else to do here. */ + return 1; + } + + /* 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->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0 + && operand->bits == 11 + && operand->shift == 0); + fixP->fx_r_type = BFD_RELOC_DVP_11_PCREL; + } + else + { + as_bad_where (fixP->fx_file, fixP->fx_line, + "unresolved expression that must be resolved"); + fixP->fx_done = 1; + return 1; + } + } + else + { + switch (fixP->fx_r_type) + { + case BFD_RELOC_8: + md_number_to_chars (where, value, 1); + break; + case BFD_RELOC_16: + md_number_to_chars (where, value, 2); + break; + case BFD_RELOC_32: + md_number_to_chars (where, value, 4); + break; + default: + abort (); + } + } + + fixP->fx_addnumber = value; + + return 1; +} + +/* Translate internal representation of relocation info to BFD target + format. */ + +arelent * +tc_gen_reloc (section, fixP) + asection *section; + fixS *fixP; +{ + arelent *reloc; + + reloc = (arelent *) xmalloc (sizeof (arelent)); + + reloc->sym_ptr_ptr = &fixP->fx_addsy->bsym; + reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; + reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); + if (reloc->howto == (reloc_howto_type *) NULL) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + "internal error: can't export reloc type %d (`%s')", + fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type)); + return NULL; + } + + assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); + + reloc->addend = fixP->fx_addnumber; + + return reloc; +} + +/* Write a value out to the object file, using the appropriate endianness. */ + +void +md_number_to_chars (buf, val, n) + char *buf; + valueT val; + int n; +{ + if (target_big_endian) + number_to_chars_bigendian (buf, val, n); + else + number_to_chars_littleendian (buf, val, n); +} + +/* Turn a string in input_line_pointer into a floating point constant of type + type, and store the appropriate bytes in *litP. The number of LITTLENUMS + emitted is stored in *sizeP . An error message is returned, or NULL on OK. +*/ + +/* Equal to MAX_PRECISION in atof-ieee.c */ +#define MAX_LITTLENUMS 6 + +char * +md_atof (type, litP, sizeP) + char type; + char *litP; + int *sizeP; +{ + int i,prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + char *atof_ieee (); + + switch (type) + { + case 'f': + case 'F': + case 's': + case 'S': + prec = 2; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + prec = 4; + break; + + /* FIXME: Some targets allow other format chars for bigger sizes here. */ + + default: + *sizeP = 0; + return "Bad call to md_atof()"; + } + + t = atof_ieee (input_line_pointer, type, words); + if (t) + input_line_pointer = t; + *sizeP = prec * sizeof (LITTLENUM_TYPE); + + if (target_big_endian) + { + for (i = 0; i < prec; i++) + { + md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE)); + litP += sizeof (LITTLENUM_TYPE); + } + } + else + { + for (i = prec - 1; i >= 0; i--) + { + md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE)); + litP += sizeof (LITTLENUM_TYPE); + } + } + + return 0; +} + +/* Insert an operand value into an instruction. */ + +static DVP_INSN +dvp_insert_operand (insn, cpu, operand, mods, val, file, line) + DVP_INSN insn; + enum cputype cpu; + const dvp_operand *operand; + int mods; + offsetT val; + char *file; + unsigned int line; +{ + if (operand->bits != 32) + { + long min, max; + offsetT test; + + if ((operand->flags & DVP_OPERAND_RELATIVE_BRANCH) != 0) + { + if ((val & 7) != 0) + { + if (file == (char *) NULL) + as_warn ("branch to misaligned address"); + else + as_warn_where (file, line, "branch to misaligned address"); + } + val >>= 3; + } + + if ((operand->flags & DVP_OPERAND_SIGNED) != 0) + { + if ((operand->flags & DVP_OPERAND_SIGNOPT) != 0) + max = (1 << operand->bits) - 1; + else + max = (1 << (operand->bits - 1)) - 1; + min = - (1 << (operand->bits - 1)); + } + else + { + max = (1 << operand->bits) - 1; + min = 0; + } + + if ((operand->flags & DVP_OPERAND_NEGATIVE) != 0) + test = - val; + else + test = val; + + if (test < (offsetT) min || test > (offsetT) max) + { + const char *err = + "operand out of range (%s not between %ld and %ld)"; + char buf[100]; + + sprint_value (buf, test); + if (file == (char *) NULL) + as_warn (err, buf, min, max); + else + as_warn_where (file, line, err, buf, min, max); + } + } + + if (operand->insert) + { + const char *errmsg = NULL; + (*operand->insert) (NULL, operand, mods, &insn, (long) val, &errmsg); + if (errmsg != (const char *) NULL) + as_warn (errmsg); + } + else + insn |= (((long) val & ((1 << operand->bits) - 1)) + << operand->shift); + + return insn; +} + +static void + s_dmadata( type) + int type; +{ + static short state = 0; + static symbolS *label; /* Points to symbol */ + char *name; + const char *prevName; + int temp; + + switch( type ) + { + case 1: /* .DmaData */ + if( state != 0 ) + { + as_bad( "DmaData blocks cannot be nested."); + ignore_rest_of_line(); + state = 1; + break; + } + state = 1; + + SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */ + name = input_line_pointer; + + if( !is_name_beginner( *name) ) + { + as_bad( "invalid identifier for \".DmaData\""); + obstack_1grow( &cond_obstack, 0); + ignore_rest_of_line(); + break; + } + else + { + char c; + + c = get_symbol_end(); + line_label = label = colon( name); /* user-defined label */ + *input_line_pointer = c; + + demand_empty_rest_of_line(); + } /* if a valid identifyer name */ + break; + + case 0: /* .EndDmaData */ + if( state != 1 ) + { + as_warn( ".EndDmaData encountered outside a DmaData block -- ignored."); + ignore_rest_of_line(); + state = 0; + break; + } + state = 0; + demand_empty_rest_of_line(); + + /* + *"label" points to beginning of block + * Create a name for the final label like _$ + */ + prevName = label->bsym->name; + temp = strlen( prevName) + 1; + name = malloc( temp + 2); + name[ 0] = '_'; + name[ 1] = '$'; + memcpy( name+2, prevName, temp); /* copy original name & \0 */ + colon( name); + free( name); + break; + + default: + as_assert( __FILE__, __LINE__, 0); + } +} + +static void +s_dmapackpke( ignore) + int ignore; +{ + /* Syntax: .dmapackpke 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++ ) + { + case 0: + dma_pack_pke_p = 0; + break; + case 1: + dma_pack_pke_p = 1; + break; + default: + as_bad( "illegal argument to `.DmaPackPke'"); + } + demand_empty_rest_of_line(); +} + +static void +s_enddirect (ignore) + int ignore; +{ +} + +static void +s_endgpuif (ignore) + int ignore; +{ +} + +static void +s_endmpg (ignore) + int ignore; +{ + vu_mode_p = 0; +} + +static void +s_endunpack (ignore) + int ignore; +{ + vu_mode_p = 0; +} + +static void +s_vu (enable_p) + int enable_p; +{ + vu_mode_p = enable_p; +} + +/* Parse a DMA data spec which can be either of '*' or a quad word count. */ + +static void +parse_dma_count( pstr, errmsg) + char **pstr; + const char **errmsg; +{ + char *str = *pstr; + long count; + + if( *str == '*' ) + { + ++*pstr; + /* -1 is a special marker to caller to tell it the count is to be + computed from the data. */ + return -1; + } + + expressionS exp; + expression( &exp); + if( exp.X_op == O_illegal + || exp.X_op == O_absent ) + break; + 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 = index; + ++fixup_count; + value = 0; + } + + if( isdigit( *str) ) ????????needs to accept an expression + { + char *start = str; + while( *str && *str != ',' ) + ++str; + if( *str != ',' ) + { + *errmsg = "invalid dma count"; + return 0; + } + count = atoi (start); + *pstr = str; + return(count); + } + + *errmsg = "invalid dma count"; + return 0; +} + diff --git a/gas/config/tc-dvp.h b/gas/config/tc-dvp.h new file mode 100644 index 00000000000..9e0f6f2b307 --- /dev/null +++ b/gas/config/tc-dvp.h @@ -0,0 +1,54 @@ +/* tc-dvp.h -- Header file for tc-dvp.c. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#define TC_DVP + +#ifndef BFD_ASSEMBLER +/* leading space so will compile with cc */ + #error DVP support requires BFD_ASSEMBLER +#endif + +#define LISTING_HEADER "DVP GAS " + +/* The target BFD architecture. */ +#define TARGET_ARCH bfd_arch_mips + +#define TARGET_FORMAT "elf32-littlemips" + +#define TARGET_BYTES_BIG_ENDIAN 0 + +/* call md_pcrel_from_section, not md_pcrel_from */ +#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from_section(FIXP, SEC) + +/* Permit temporary numeric labels. */ +#define LOCAL_LABELS_FB 1 + +#define DIFF_EXPR_OK /* .-foo gets turned into PC relative relocs */ + +/* We don't need to handle .word strangely. */ +#define WORKING_DOT_WORD + +#define md_convert_frag(b,s,f) {as_fatal ("dvp convert_frag\n");} +#define md_estimate_size_before_relax(f,s) \ + (as_fatal("estimate_size_before_relax called"),1) + +#define MD_APPLY_FIX3 + +#define TC_HANDLES_FX_DONE diff --git a/gas/config/tc-txvu.c b/gas/config/tc-txvu.c deleted file mode 100644 index a6b18dedded..00000000000 --- a/gas/config/tc-txvu.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* tc-txvu.c -- Assembler for the TX VU. - Copyright (C) 1997, 1998 Free Software Foundation. - - This file is part of GAS, the GNU Assembler. - - GAS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - GAS is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GAS; see the file COPYING. If not, write to - the Free Software Foundation, 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#include -#include -#include "as.h" -#include "subsegs.h" -/* Needed by opcode/txvu.h. */ -#include "dis-asm.h" -#include "opcode/txvu.h" -#include "elf/txvu.h" - -enum cputype { CPU_VUUP, CPU_VULO, CPU_DMA, CPU_PKE, CPU_GPUIF }; - -static TXVU_INSN txvu_insert_operand - PARAMS ((TXVU_INSN, enum cputype, const txvu_operand *, - int, offsetT, char *, unsigned int)); - -const char comment_chars[] = ";"; -const char line_comment_chars[] = "#"; -const char line_separator_chars[] = "!"; -const char EXP_CHARS[] = "eE"; -const char FLT_CHARS[] = "dD"; - -/* Non-zero if in vu-mode. */ -static int vu_mode_p; - -/* Non-zero if packing pke instructions in dma tags. */ -static int dma_pack_pke_p; - -const char *md_shortopts = ""; - -struct option md_longopts[] = -{ - /* insert options here */ - - {NULL, no_argument, NULL, 0} -}; -size_t md_longopts_size = sizeof(md_longopts); - -int -md_parse_option (c, arg) - int c; - char *arg; -{ - return 0; -} - -void -md_show_usage (stream) - FILE *stream; -{ -#if 0 - fprintf (stream, "TX VU options:\n"); -#endif -} - -/* Set by md_assemble for use by txvu_fill_insn. */ -static subsegT prev_subseg; -static segT prev_seg; - -static void s_dmadata PARAMS ((int)); -static void s_dmapackpke PARAMS ((int)); -static void s_enddirect PARAMS ((int)); -static void s_endgpuif PARAMS ((int)); -static void s_endmpg PARAMS ((int)); -static void s_endunpack PARAMS ((int)); -static void s_vu PARAMS ((int)); - -/* 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,.endvu added to simplify debugging */ - { "vu", s_vu, 1 }, - { "endvu", s_vu, 0 }, - { NULL, NULL, 0 } -}; - -void -md_begin () -{ - flagword applicable; - segT seg; - subsegT subseg; - - /* Save the current subseg so we can restore it [it's the default one and - we don't want the initial section to be .sbss. */ - seg = now_seg; - subseg = now_subseg; - - subseg_set (seg, subseg); - - /* Initialize the opcode tables. - This involves computing the hash chains. */ - txvu_opcode_init_tables (0); - - vu_mode_p = 0; - dma_pack_pke_p = 0; -} - -/* We need to keep a list of fixups. We can't simply generate them as - we go, because that would require us to first create the frag, and - that would screw up references to ``.''. */ - -struct txvu_fixup -{ - /* index into `txvu_operands' */ - int opindex; - expressionS exp; -}; - -#define MAX_FIXUPS 5 - -static int fixup_count; -static struct txvu_fixup fixups[MAX_FIXUPS]; - -/* Given a cpu type and operand number, return a temporary reloc type - for use in generating the fixup that encodes the cpu type and operand. */ -static int encode_fixup_reloc_type PARAMS ((enum cputype, int)); -/* Given an encoded fixup reloc type, decode it into cpu and operand. */ -static void decode_fixup_reloc_type PARAMS ((int, enum cputype *, - const txvu_operand **)); - -static void assemble_dma PARAMS ((char *)); -static void assemble_gpuif PARAMS ((char *)); -static void assemble_pke PARAMS ((char *)); -static void assemble_vu PARAMS ((char *)); -static char * assemble_vu_insn PARAMS ((enum cputype, - const txvu_opcode *, - const txvu_operand *, - char *, char *)); -static char * assemble_one_insn PARAMS ((enum cputype, - const txvu_opcode *, - const txvu_operand *, - char *, TXVU_INSN *)); - -void -md_assemble (str) - char *str; -{ - /* Skip leading white space. */ - while (isspace (*str)) - str++; - - if (! vu_mode_p) - { - if (strncasecmp (str, "dma", 3) == 0) - assemble_dma (str); - else if (strncasecmp (str, "gpuif", 5) == 0) - assemble_gpuif (str); - else - assemble_pke (str); - } - else - assemble_vu (str); -} - -/* Subroutine of md_assemble to assemble DMA instructions. */ - -static void -assemble_dma (str) - char *str; -{ - TXVU_INSN insn_buf[4]; - - str = assemble_one_insn (CPU_DMA, - dma_opcode_lookup_asm (str), dma_operands, - str, insn_buf); - if (str == NULL) - return; -} - -/* Subroutine of md_assemble to assemble PKE instructions. */ - -static void -assemble_pke (str) - char *str; -{ - /* Space for the instruction. - The variable length insns can require much more space than this. - It is allocated later, when we know we have such an insn. */ - TXVU_INSN insn_buf[5]; - /* Insn's length, in 32 bit words. */ - int len; - /* Non-zero if this is a variable length insn. */ - int varlen_p; - /* Pointer to allocated frag. */ - char *f; - int i; - - str = assemble_one_insn (CPU_PKE, - pke_opcode_lookup_asm (str), pke_operands, - str, insn_buf); - if (str == NULL) - return; - - /* Call back into the parser's state to get the insn's length. - This is just the length of the insn, not of any following data. - The result 0 if the length is unknown. */ - varlen_p = pke_varlen_p (); - len = pke_len (); - - if (varlen_p) - { - /* FIXME: not done yet */ - } - else - { - f = frag_more (len * 4); - } - - /* Write out the instruction. - 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. */ - 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; - const txvu_operand *operand; - - /* 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; - reloc_type = encode_fixup_reloc_type (CPU_PKE, op_type); - operand = &pke_operands[op_type]; - fix_new_exp (frag_now, f - frag_now->fr_literal, 4, - &fixups[i].exp, - (operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) != 0, - (bfd_reloc_code_real_type) reloc_type); - } -} - -/* Subroutine of md_assemble to assemble GPUIF instructions. */ - -static void -assemble_gpuif (str) - char *str; -{ - TXVU_INSN insn_buf[4]; - - str = assemble_one_insn (CPU_GPUIF, - gpuif_opcode_lookup_asm (str), gpuif_operands, - str, insn_buf); - if (str == NULL) - return; -} - -/* Subroutine of md_assemble to assemble VU instructions. */ - -static void -assemble_vu (str) - char *str; -{ - /* The lower instruction has the lower address. - Handle this by grabbing 8 bytes now, and then filling each word - as appropriate. */ - char *f = frag_more (8); - -#ifdef VERTICAL_BAR_SEPARATOR - char *p = strchr (str, '|'); - - if (p == NULL) - { - as_bad ("lower slot missing in `%s'", str); - return; - } - - *p = 0; - assemble_vu_insn (CPU_VUUP, - txvu_upper_opcode_lookup_asm (str), txvu_operands, - str, f + 4); - *p = '|'; - assemble_vu_insn (CPU_VULO, - txvu_lower_opcode_lookup_asm (str), txvu_operands, - p + 1, f); -#else - str = assemble_vu_insn (CPU_VUUP, - txvu_upper_opcode_lookup_asm (str), txvu_operands, - str, f + 4); - /* Don't assemble next one if we couldn't assemble the first. */ - if (str) - assemble_vu_insn (CPU_VULO, - txvu_lower_opcode_lookup_asm (str), txvu_operands, - str, f); -#endif -} - -static char * -assemble_vu_insn (cpu, opcode, operand_table, str, buf) - enum cputype cpu; - const txvu_opcode *opcode; - const txvu_operand *operand_table; - char *str; - char *buf; -{ - int i; - TXVU_INSN insn; - - str = assemble_one_insn (cpu, opcode, operand_table, str, &insn); - if (str == NULL) - return NULL; - - /* Write out the instruction. - 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); - - /* Create any fixups. */ - for (i = 0; i < fixup_count; ++i) - { - int op_type, reloc_type; - const txvu_operand *operand; - - /* 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; - reloc_type = encode_fixup_reloc_type (cpu, op_type); - operand = &txvu_operands[op_type]; - fix_new_exp (frag_now, buf - frag_now->fr_literal, 4, - &fixups[i].exp, - (operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) != 0, - (bfd_reloc_code_real_type) reloc_type); - } - - /* All done. */ - return str; -} - -/* Assemble one instruction. - CPU indicates what component we're assembling for. - The assembled instruction is stored in INSN_BUF. - - The result is a pointer to beyond the end of the scanned insn - or NULL if an error occured. This is to handle the VU where two - instructions appear on one line. If this is the upper insn, the caller - can pass back to result to us parse the lower insn. */ - -static char * -assemble_one_insn (cpu, opcode, operand_table, str, insn_buf) - enum cputype cpu; - const txvu_opcode *opcode; - const txvu_operand *operand_table; - char *str; - TXVU_INSN *insn_buf; -{ - char *start; - - /* Keep looking until we find a match. */ - - start = str; - for ( ; opcode != NULL; opcode = TXVU_OPCODE_NEXT_ASM (opcode)) - { - int past_opcode_p, num_suffixes, num_operands; - const unsigned char *syn; - - /* Ensure the mnemonic part matches. */ - for (str = start, syn = opcode->mnemonic; *syn != '\0'; ++str, ++syn) - if (tolower (*str) != tolower (*syn)) - break; - if (*syn != '\0') - continue; - - /* Scan the syntax string. If it doesn't match, try the next one. */ - - txvu_opcode_init_parse (); - *insn_buf = opcode->value; - fixup_count = 0; - past_opcode_p = 0; - num_suffixes = 0; - num_operands = 0; - - /* We don't check for (*str != '\0') here because we want to parse - any trailing fake arguments in the syntax string. */ - for (/*str = start, */ syn = opcode->syntax; *syn != '\0'; ) - { - int mods,index; - const txvu_operand *operand; - const char *errmsg; - - /* Non operand chars must match exactly. - Operand chars that are letters are not part of symbols - and are case insensitive. */ - if (*syn < 128) - { - if (tolower (*str) == tolower (*syn)) - { - if (*syn == ' ') - past_opcode_p = 1; - ++syn; - ++str; - } - else - break; - continue; - } - - /* We have a suffix or an operand. Pick out any modifiers. */ - mods = 0; - index = TXVU_OPERAND_INDEX (*syn); - while (TXVU_MOD_P (operand_table[index].flags)) - { - mods |= operand_table[index].flags & TXVU_MOD_BITS; - ++syn; - index = TXVU_OPERAND_INDEX (*syn); - } - operand = operand_table + index; - - if (operand->flags & TXVU_OPERAND_FAKE) - { - if (operand->insert) - { - errmsg = NULL; - (*operand->insert) (opcode, operand, mods, insn_buf, 0, - &errmsg); - /* If we get an error, go on to try the next insn. */ - if (errmsg) - break; - } - ++syn; - } - /* Are we finished with suffixes? */ - else if (!past_opcode_p) - { - int found; - char c; - char *s,*t; - long suf_value; - - if (!(operand->flags & TXVU_OPERAND_SUFFIX)) - as_fatal ("bad opcode table, missing suffix flag"); - - /* If we're at a space in the input string, we want to skip the - remaining suffixes. There may be some fake ones though, so - just go on to try the next one. */ - if (*str == ' ') - { - ++syn; - continue; - } - - s = str; - - /* Pick the suffix out and parse it. */ - /* ??? Hmmm ... there may not be any need to nul-terminate the - string, and it may in fact complicate things. */ - for (t = (*s == '.' || *s == '/') ? s + 1 : s; - *t && (isalnum (*t) || *t == '[' || *t == ']'); - ++t) - continue; - c = *t; - *t = '\0'; - errmsg = NULL; - suf_value = (*operand->parse) (opcode, operand, mods, &s, - &errmsg); - *t = c; - if (errmsg) - { - /* This can happen, for example, in ARC's in "blle foo" and - we're currently using the template "b%q%.n %j". The "bl" - insn occurs later in the table so "lle" isn't an illegal - suffix. */ - break; - } - /* Insert the suffix's value into the insn. */ - if (operand->insert) - (*operand->insert) (opcode, operand, mods, - insn_buf, suf_value, NULL); - else - *insn_buf |= suf_value << operand->shift; - - str = t; - ++syn; - } - else - /* This is an operand, either a register or an expression of - some kind. */ - { - char c; - char *hold; - long value = 0; - expressionS exp; - - if (operand->flags & TXVU_OPERAND_SUFFIX) - as_fatal ("bad opcode table, suffix wrong"); - -#if 0 /* commas are in the syntax string now */ - /* If this is not the first, there must be a comma. */ - if (num_operands > 0) - { - if (*str != ',') - break; - ++str; - } -#endif - - /* Is there anything left to parse? - We don't check for this at the top because we want to parse - any trailing fake arguments in the syntax string. */ - /* ??? This doesn't allow operands with a legal value of "". */ - if (*str == '\0') - break; - - /* Is this the special DMA count operand? */ - if( operand->flags & TXVU_OPERAND_DMA_COUNT) - txvu_dma_operand_count( 0); - if( (operand->flags & TXVU_OPERAND_DMA_COUNT) && *str == '*') - { - /* Yes, it is! - Remember that we must compute the length later - when the dma-block label (second operand) is known. */ - ++*pstr; - txvu_dma_operand_count( 1); - } - - /* Parse the operand. */ - else if (operand->parse) - { - errmsg = NULL; - value = (*operand->parse) (opcode, operand, mods, - &str, &errmsg); - if (errmsg) - break; - } - else - { - hold = input_line_pointer; - input_line_pointer = str; - expression (&exp); - str = input_line_pointer; - input_line_pointer = hold; - - if (exp.X_op == O_illegal - || exp.X_op == O_absent) - break; - 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 = index; - ++fixup_count; - value = 0; - } - } - - /* Insert the register or expression into the instruction. */ - if (operand->insert) - { - const char *errmsg = NULL; - (*operand->insert) (opcode, operand, mods, - insn_buf, value, &errmsg); - if (errmsg != (const char *) NULL) - break; - } - else - *insn_buf |= (value & ((1 << operand->bits) - 1)) << operand->shift; - - ++syn; - ++num_operands; - } - } - - /* If we're at the end of the syntax string, we're done. */ - /* FIXME: try to move this to a separate function. */ - if (*syn == '\0') - { - int i; - - /* For the moment we assume a valid `str' can only contain blanks - now. IE: We needn't try again with a longer version of the - insn and it is assumed that longer versions of insns appear - before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */ - - while (isspace (*str)) - ++str; - - if (*str != '\0' -#ifndef VERTICAL_BAR_SEPARATOR - && cpu != CPU_VUUP -#endif - ) - as_bad ("junk at end of line: `%s'", str); - - /* It's now up to the caller to emit the instruction and any - relocations. */ - return str; - } - - /* Try the next entry. */ - } - - as_bad ("bad instruction `%s'", start); - return 0; -} - -void -md_operand (expressionP) - expressionS *expressionP; -{ -} - -valueT -md_section_align (segment, size) - segT segment; - valueT size; -{ - int align = bfd_get_section_alignment (stdoutput, segment); - return ((size + (1 << align) - 1) & (-1 << align)); -} - -symbolS * -md_undefined_symbol (name) - char *name; -{ - return 0; -} - -/* Functions concerning relocs. */ - -/* Spacing between each cpu type's operand numbers. - Should be at least as bit as any operand table. */ -#define RELOC_SPACING 256 - -/* Given a cpu type and operand number, return a temporary reloc type - for use in generating the fixup that encodes the cpu type and operand - number. */ - -static int -encode_fixup_reloc_type (cpu, opnum) - enum cputype cpu; - int opnum; -{ - return (int) BFD_RELOC_UNUSED + ((int) cpu * RELOC_SPACING) + opnum; -} - -/* Given a fixup reloc type, decode it into cpu type and operand. */ - -static void -decode_fixup_reloc_type (fixup_reloc, cpuP, operandP) - int fixup_reloc; - enum cputype *cpuP; - const txvu_operand **operandP; -{ - enum cputype cpu = (fixup_reloc - (int) BFD_RELOC_UNUSED) / RELOC_SPACING; - int opnum = (fixup_reloc - (int) BFD_RELOC_UNUSED) % RELOC_SPACING; - - *cpuP = cpu; - switch (cpu) - { - case CPU_VUUP : *operandP = &txvu_operands[opnum]; break; - case CPU_VULO : *operandP = &txvu_operands[opnum]; break; - case CPU_DMA : *operandP = &dma_operands[opnum]; break; - case CPU_PKE : *operandP = &pke_operands[opnum]; break; - case CPU_GPUIF : *operandP = &gpuif_operands[opnum]; break; - default : as_fatal ("bad fixup encoding"); - } -} - -/* 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. */ - -long -md_pcrel_from_section (fixP, sec) - fixS *fixP; - segT sec; -{ - if (fixP->fx_addsy != (symbolS *) NULL - && (! S_IS_DEFINED (fixP->fx_addsy) - || S_GET_SEGMENT (fixP->fx_addsy) != sec)) - { - /* The symbol is undefined (or is defined but not in this section). - Let the linker figure it out. */ - return 0; - } - - /* FIXME: `& -16L'? */ - return (fixP->fx_frag->fr_address + fixP->fx_where) & -8L; -} - -/* Apply a fixup to the object code. This is called for all the - fixups we generated by calls to fix_new_exp. At this point all symbol - values should be fully resolved, and we attempt to completely resolve the - reloc. If we can not do that, we determine the correct reloc code and put - it back in the fixup. */ - -int -md_apply_fix3 (fixP, valueP, seg) - fixS *fixP; - valueT *valueP; - segT seg; -{ - char *where = fixP->fx_frag->fr_literal + fixP->fx_where; - valueT value; - - /* FIXME FIXME FIXME: The value we are passed in *valueP includes - the symbol values. Since we are using BFD_ASSEMBLER, if we are - doing this relocation the code in write.c is going to call - bfd_perform_relocation, which is also going to use the symbol - value. That means that if the reloc is fully resolved we want to - use *valueP since bfd_perform_relocation is not being used. - However, if the reloc is not fully resolved we do not want to use - *valueP, and must use fx_offset instead. However, if the reloc - is PC relative, we do want to use *valueP since it includes the - result of md_pcrel_from. This is confusing. */ - - if (fixP->fx_addsy == (symbolS *) NULL) - { - value = *valueP; - fixP->fx_done = 1; - } - else if (fixP->fx_pcrel) - { - value = *valueP; - } - else - { - value = fixP->fx_offset; - if (fixP->fx_subsy != (symbolS *) NULL) - { - if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section) - value -= S_GET_VALUE (fixP->fx_subsy); - else - { - /* We can't actually support subtracting a symbol. */ - as_bad_where (fixP->fx_file, fixP->fx_line, - "expression too complex"); - } - } - } - - /* Check for dvp operand's. These are indicated with a reloc value - >= BFD_RELOC_UNUSED. */ - - if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) - { - enum cputype cpu; - const txvu_operand *operand; - TXVU_INSN insn; - - decode_fixup_reloc_type ((int) fixP->fx_r_type, - & cpu, & operand); - - /* Fetch the instruction, insert the fully resolved operand - value, and stuff the instruction back again. */ - insn = bfd_getl32 ((unsigned char *) where); - insn = txvu_insert_operand (insn, cpu, operand, -1, (offsetT) value, - fixP->fx_file, fixP->fx_line); - bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); - - if (fixP->fx_done) - { - /* Nothing else to do here. */ - return 1; - } - - /* 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 & TXVU_OPERAND_RELATIVE_BRANCH) != 0) - { - assert ((operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) != 0 - && operand->bits == 11 - && operand->shift == 0); - fixP->fx_r_type = BFD_RELOC_TXVU_11_PCREL; - } - else - { - as_bad_where (fixP->fx_file, fixP->fx_line, - "unresolved expression that must be resolved"); - fixP->fx_done = 1; - return 1; - } - } - else - { - switch (fixP->fx_r_type) - { - case BFD_RELOC_8: - md_number_to_chars (where, value, 1); - break; - case BFD_RELOC_16: - md_number_to_chars (where, value, 2); - break; - case BFD_RELOC_32: - md_number_to_chars (where, value, 4); - break; - default: - abort (); - } - } - - fixP->fx_addnumber = value; - - return 1; -} - -/* Translate internal representation of relocation info to BFD target - format. */ - -arelent * -tc_gen_reloc (section, fixP) - asection *section; - fixS *fixP; -{ - arelent *reloc; - - reloc = (arelent *) xmalloc (sizeof (arelent)); - - reloc->sym_ptr_ptr = &fixP->fx_addsy->bsym; - reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; - reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); - if (reloc->howto == (reloc_howto_type *) NULL) - { - as_bad_where (fixP->fx_file, fixP->fx_line, - "internal error: can't export reloc type %d (`%s')", - fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type)); - return NULL; - } - - assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); - - reloc->addend = fixP->fx_addnumber; - - return reloc; -} - -/* Write a value out to the object file, using the appropriate endianness. */ - -void -md_number_to_chars (buf, val, n) - char *buf; - valueT val; - int n; -{ - if (target_big_endian) - number_to_chars_bigendian (buf, val, n); - else - number_to_chars_littleendian (buf, val, n); -} - -/* Turn a string in input_line_pointer into a floating point constant of type - type, and store the appropriate bytes in *litP. The number of LITTLENUMS - emitted is stored in *sizeP . An error message is returned, or NULL on OK. -*/ - -/* Equal to MAX_PRECISION in atof-ieee.c */ -#define MAX_LITTLENUMS 6 - -char * -md_atof (type, litP, sizeP) - char type; - char *litP; - int *sizeP; -{ - int i,prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - LITTLENUM_TYPE *wordP; - char *t; - char *atof_ieee (); - - switch (type) - { - case 'f': - case 'F': - case 's': - case 'S': - prec = 2; - break; - - case 'd': - case 'D': - case 'r': - case 'R': - prec = 4; - break; - - /* FIXME: Some targets allow other format chars for bigger sizes here. */ - - default: - *sizeP = 0; - return "Bad call to md_atof()"; - } - - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - *sizeP = prec * sizeof (LITTLENUM_TYPE); - - if (target_big_endian) - { - for (i = 0; i < prec; i++) - { - md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - } - else - { - for (i = prec - 1; i >= 0; i--) - { - md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - } - - return 0; -} - -/* Insert an operand value into an instruction. */ - -static TXVU_INSN -txvu_insert_operand (insn, cpu, operand, mods, val, file, line) - TXVU_INSN insn; - enum cputype cpu; - const txvu_operand *operand; - int mods; - offsetT val; - char *file; - unsigned int line; -{ - if (operand->bits != 32) - { - long min, max; - offsetT test; - - if ((operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) != 0) - { - if ((val & 7) != 0) - { - if (file == (char *) NULL) - as_warn ("branch to misaligned address"); - else - as_warn_where (file, line, "branch to misaligned address"); - } - val >>= 3; - } - - if ((operand->flags & TXVU_OPERAND_SIGNED) != 0) - { - if ((operand->flags & TXVU_OPERAND_SIGNOPT) != 0) - max = (1 << operand->bits) - 1; - else - max = (1 << (operand->bits - 1)) - 1; - min = - (1 << (operand->bits - 1)); - } - else - { - max = (1 << operand->bits) - 1; - min = 0; - } - - if ((operand->flags & TXVU_OPERAND_NEGATIVE) != 0) - test = - val; - else - test = val; - - if (test < (offsetT) min || test > (offsetT) max) - { - const char *err = - "operand out of range (%s not between %ld and %ld)"; - char buf[100]; - - sprint_value (buf, test); - if (file == (char *) NULL) - as_warn (err, buf, min, max); - else - as_warn_where (file, line, err, buf, min, max); - } - } - - if (operand->insert) - { - const char *errmsg = NULL; - (*operand->insert) (NULL, operand, mods, &insn, (long) val, &errmsg); - if (errmsg != (const char *) NULL) - as_warn (errmsg); - } - else - insn |= (((long) val & ((1 << operand->bits) - 1)) - << operand->shift); - - return insn; -} - -static void - s_dmadata( type) - int type; -{ - static short state = 0; - static symbolS *label; /* Points to symbol */ - char *name; - const char *prevName; - int temp; - - switch( type ) - { - case 1: /* .DmaData */ - if( state != 0 ) - { - as_bad( "DmaData blocks cannot be nested."); - ignore_rest_of_line(); - state = 1; - break; - } - state = 1; - - SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */ - name = input_line_pointer; - - if( !is_name_beginner( *name) ) - { - as_bad( "invalid identifier for \".DmaData\""); - obstack_1grow( &cond_obstack, 0); - ignore_rest_of_line(); - break; - } - else - { - char c; - - c = get_symbol_end(); - line_label = label = colon( name); /* user-defined label */ - *input_line_pointer = c; - - demand_empty_rest_of_line(); - } /* if a valid identifyer name */ - break; - - case 0: /* .EndDmaData */ - if( state != 1 ) - { - as_warn( ".EndDmaData encountered outside a DmaData block -- ignored."); - ignore_rest_of_line(); - state = 0; - break; - } - state = 0; - demand_empty_rest_of_line(); - - /* - *"label" points to beginning of block - * Create a name for the final label like _$ - */ - prevName = label->bsym->name; - temp = strlen( prevName) + 1; - name = malloc( temp + 2); - name[ 0] = '_'; - name[ 1] = '$'; - memcpy( name+2, prevName, temp); /* copy original name & \0 */ - colon( name); - free( name); - break; - - default: - as_assert( __FILE__, __LINE__, 0); - } -} - -static void -s_dmapackpke( ignore) - int ignore; -{ - /* Syntax: .dmapackpke 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++ ) - { - case 0: - dma_pack_pke_p = 0; - break; - case 1: - dma_pack_pke_p = 1; - break; - default: - as_bad( "illegal argument to `.DmaPackPke'"); - } - demand_empty_rest_of_line(); -} - -static void -s_enddirect (ignore) - int ignore; -{ -} - -static void -s_endgpuif (ignore) - int ignore; -{ -} - -static void -s_endmpg (ignore) - int ignore; -{ - vu_mode_p = 0; -} - -static void -s_endunpack (ignore) - int ignore; -{ - vu_mode_p = 0; -} - -static void -s_vu (enable_p) - int enable_p; -{ - vu_mode_p = enable_p; -} - -/* Parse a DMA data spec which can be either of '*' or a quad word count. */ - -static void -parse_dma_count( pstr, errmsg) - char **pstr; - const char **errmsg; -{ - char *str = *pstr; - long count; - - if( *str == '*' ) - { - ++*pstr; - /* -1 is a special marker to caller to tell it the count is to be - computed from the data. */ - return -1; - } - - expressionS exp; - expression( &exp); - if( exp.X_op == O_illegal - || exp.X_op == O_absent ) - break; - 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 = index; - ++fixup_count; - value = 0; - } - - if( isdigit( *str) ) ????????needs to accept an expression - { - char *start = str; - while( *str && *str != ',' ) - ++str; - if( *str != ',' ) - { - *errmsg = "invalid dma count"; - return 0; - } - count = atoi (start); - *pstr = str; - return(count); - } - - *errmsg = "invalid dma count"; - return 0; -} - diff --git a/gas/config/tc-txvu.h b/gas/config/tc-txvu.h deleted file mode 100644 index cdde90cec58..00000000000 --- a/gas/config/tc-txvu.h +++ /dev/null @@ -1,54 +0,0 @@ -/* tc-txvu.h -- Header file for tc-txvu.c. - Copyright (C) 1997 Free Software Foundation, Inc. - - This file is part of GAS, the GNU Assembler. - - GAS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - GAS is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GAS; see the file COPYING. If not, write to - the Free Software Foundation, 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#define TC_TXVU - -#ifndef BFD_ASSEMBLER -/* leading space so will compile with cc */ - #error TXVU support requires BFD_ASSEMBLER -#endif - -#define LISTING_HEADER "TXVU GAS " - -/* The target BFD architecture. */ -#define TARGET_ARCH bfd_arch_txvu - -#define TARGET_FORMAT "elf32-txvu" - -#define TARGET_BYTES_BIG_ENDIAN 0 - -/* call md_pcrel_from_section, not md_pcrel_from */ -#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from_section(FIXP, SEC) - -/* Permit temporary numeric labels. */ -#define LOCAL_LABELS_FB 1 - -#define DIFF_EXPR_OK /* .-foo gets turned into PC relative relocs */ - -/* We don't need to handle .word strangely. */ -#define WORKING_DOT_WORD - -#define md_convert_frag(b,s,f) {as_fatal ("txvu convert_frag\n");} -#define md_estimate_size_before_relax(f,s) \ - (as_fatal("estimate_size_before_relax called"),1) - -#define MD_APPLY_FIX3 - -#define TC_HANDLES_FX_DONE