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}"
--- /dev/null
+/* 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 <stdio.h>
+#include <ctype.h>
+#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;
+\f
+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 }
+};
+\f
+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;
+}
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+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 _$<name>
+ */
+ 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;
+}
+
--- /dev/null
+/* 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
+++ /dev/null
-/* 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 <stdio.h>
-#include <ctype.h>
-#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;
-\f
-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 }
-};
-\f
-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;
-}
-\f
-/* 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;
-}
-\f
-/* 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;
-}
-\f
-/* 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;
-}
-\f
-/* 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;
-}
-\f
-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 _$<name>
- */
- 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;
-}
-
+++ /dev/null
-/* 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