From: Doug Evans Date: Mon, 5 Jan 1998 14:56:04 +0000 (+0000) Subject: * config/tc-txvu.c: #include dis-asm.h, opcode/txvu.h, elf/txvu.h. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f6428b86cccb6a2aa2fc3b9d659fedc5200b1047;p=binutils-gdb.git * config/tc-txvu.c: #include dis-asm.h, opcode/txvu.h, elf/txvu.h. (md_begin): Call txvu_opcode_init_tables. (assemble_insn): New function. (md_assemble): Beginnings of implementation. --- diff --git a/gas/ChangeLog b/gas/ChangeLog index 953a98a150e..e76d12aa2c0 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,12 @@ +start-sanitize-sky +Mon Jan 5 14:54:09 1998 Doug Evans + + * config/tc-txvu.c: #include dis-asm.h, opcode/txvu.h, elf/txvu.h. + (md_begin): Call txvu_opcode_init_tables. + (assemble_insn): New function. + (md_assemble): Beginnings of implementation. + +end-sanitize-sky Fri Jan 2 16:08:54 1998 Ian Lance Taylor * config/tc-i386.c (i386_operand): Give an error if there are diff --git a/gas/config/tc-txvu.c b/gas/config/tc-txvu.c index 6c30a8cdb77..fbc7344f13a 100644 --- a/gas/config/tc-txvu.c +++ b/gas/config/tc-txvu.c @@ -21,7 +21,11 @@ #include #include #include "as.h" -#include "subsegs.h" +#include "subsegs.h" +/* Needed by opcode/txvu.h. */ +#include "dis-asm.h" +#include "opcode/txvu.h" +#include "elf/txvu.h" const char comment_chars[] = ";"; const char line_comment_chars[] = "#"; @@ -80,12 +84,335 @@ md_begin () subseg = now_subseg; subseg_set (seg, subseg); + + /* Initialize the opcode tables. + This involves computing the hash chains. */ + txvu_opcode_init_tables (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 void assemble_insn PARAMS ((char *, int)); + void md_assemble (str) char *str; { + char *p = strchr (str, '|'); + + if (p == NULL) + { + as_bad ("lower slot missing in `%s'", str); + return; + } + + *p = 0; + assemble_insn (str, 0); + *p = '|'; + assemble_insn (p + 1, 1); +} + +/* Assemble one instruction. + LOWER_P is non-zero if assembling in the lower insn slot. */ + +static void +assemble_insn (str, lower_p) + char *str; + int lower_p; +{ + const struct txvu_opcode *opcode; + char *start; + TXVU_INSN insn_buf[2]; + TXVU_INSN insn; + + /* Skip leading white space. */ + while (isspace (*str)) + str++; + + /* The instructions are stored in lists hashed by the first letter (though + we needn't care how they're hashed). Get the first in the list. */ + + if (lower_p) + opcode = txvu_lower_opcode_lookup_asm (str); + else + opcode = txvu_upper_opcode_lookup_asm (str); + + /* Keep looking until we find a match. */ + + start = str; + for ( ; opcode != NULL; opcode = TXVU_OPCODE_NEXT_ASM (opcode)) + { + int past_opcode_p, fc, num_suffixes, num_operands; + const unsigned char *syn; + struct txvu_fixup fixups[MAX_FIXUPS]; + + /* 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; + if (isalpha (*str)) + continue; + + /* Scan the syntax string. If it doesn't match, try the next one. */ + + txvu_opcode_init_parse (); + insn = opcode->value; + fc = 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 struct txvu_operand *operand; + const char *errmsg; + + /* Non operand chars must match exactly. */ + if (*syn < 128) + { + if (*str == *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 (txvu_operands[index].flags)) + { + mods |= txvu_operands[index].flags & TXVU_MOD_BITS; + ++syn; + index = TXVU_OPERAND_INDEX (*syn); + } + operand = txvu_operands + index; + + if (operand->flags & TXVU_OPERAND_FAKE) + { + if (operand->insert) + { + insn = (*operand->insert) (insn, operand, mods, 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. */ + for (t = *s == '.' ? s + 1 : s; *t && isalpha (*t); ++t) + continue; + c = *t; + *t = '\0'; + suf_value = (*operand->parse) (&s, &errmsg); + *t = c; + if (errmsg) + { + /* This can happen 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) + insn = (*operand->insert) (insn, operand, + mods, suf_value, NULL); + else + insn |= 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 this is not the first, there must be a comma. */ + if (num_operands > 0) + { + if (*str != ',') + break; + ++str; + } + + /* 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. */ + if (*str == '\0') + break; + + /* Parse the operand. */ + if (operand->parse) + { + value = (*operand->parse) (&str, &errmsg); + } + 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) + as_bad ("illegal operand"); + else if (exp.X_op == O_absent) + as_bad ("missing operand"); + 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 (fc >= MAX_FIXUPS) + as_fatal ("too many fixups"); + fixups[fc].exp = exp; + fixups[fc].opindex = index; + ++fc; + value = 0; + } + } + + /* Insert the register or expression into the instruction. */ + if (operand->insert) + { + const char *errmsg = NULL; + insn = (*operand->insert) (insn, operand, mods, + value, &errmsg); +#if 0 + if (errmsg != (const char *) NULL) + as_warn (errmsg); +#endif + /* FIXME: We want to try shimm insns for limm ones. But if + the constant won't fit, we must go on to try the next + possibility. Where do we issue warnings for constants + that are too big then? At present, we'll flag the insn + as unrecognizable! Maybe have the "bad instruction" + error message include our `errmsg'? */ + if (errmsg != (const char *) NULL) + break; + } + else + insn |= (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; + char *f; + + /* 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') + as_bad ("junk at end of line: `%s'", str); + + /* Write out the instruction. + It is important to fetch enough space in one call to `frag_more'. + We use (f - frag_now->fr_literal) to compute where we are and we + don't want frag_now to change between calls. */ + f = frag_more (4); + md_number_to_chars (f, insn, 4); + + /* Create any fixups. */ + for (i = 0; i < fc; ++i) + { + int op_type, reloc_type; + const struct 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 = op_type + (int) BFD_RELOC_UNUSED; + operand = &txvu_operands[op_type]; + fix_new_exp (frag_now, + ((f - frag_now->fr_literal) + + (operand->flags & TXVU_OPERAND_LIMM ? 4 : 0)), 4, + &fixups[i].exp, + (operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) != 0, + (bfd_reloc_code_real_type) reloc_type); + } + + /* All done. */ + return; + } + + /* Try the next entry. */ + } + + as_bad ("bad instruction `%s'", start); } void