diff options
author | Ken Raeburn <raeburn@cygnus> | 1997-10-31 23:21:44 +0000 |
---|---|---|
committer | Ken Raeburn <raeburn@cygnus> | 1997-10-31 23:21:44 +0000 |
commit | aa2e0460a0f84d07ae15e12f6cdcb255ae76ff1a (patch) | |
tree | ca90a3a9f8bea97976a9374c9db954d7410e0fa2 /gas/config | |
parent | fcc86d82f7864c9609d2a02acb1a25074e9902ed (diff) | |
download | gdb-aa2e0460a0f84d07ae15e12f6cdcb255ae76ff1a.zip gdb-aa2e0460a0f84d07ae15e12f6cdcb255ae76ff1a.tar.gz gdb-aa2e0460a0f84d07ae15e12f6cdcb255ae76ff1a.tar.bz2 |
* config/tc-mips.c (mips_5400): New variable.
(md_begin, md_parse_option): Handle 5400 options/names.
(macro_build, mips_ip): Check for 5400-specific instructions.
(md_longopts, OPTION_M5400, OPTION_NO_M5400): More command-line support for
5400.
* config/tc-mips.c (validate_mips_insn): New function, checks match versus mask
bits, and also verifies that all bits to be output are actually specified
somewhere.
(md_begin): Call it for 32-bit instructions, instead of doing match/mask check
here. In case of failure, print a message, but check the rest of the opcode
table before exiting.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/.Sanitize | 28 | ||||
-rw-r--r-- | gas/config/tc-mips.c | 184 |
2 files changed, 201 insertions, 11 deletions
diff --git a/gas/config/.Sanitize b/gas/config/.Sanitize index 7335e9c..e864da1 100644 --- a/gas/config/.Sanitize +++ b/gas/config/.Sanitize @@ -201,6 +201,34 @@ else done fi +vr5400_files="tc-mips.c" +if ( echo $* | grep keep\-vr5400 > /dev/null ) ; then + for i in $vr5400_files ; do + if test ! -d $i && (grep sanitize-vr5400 $i > /dev/null) ; then + if [ -n "${verbose}" ] ; then + echo Keeping vr5400 stuff in $i + fi + fi + done +else + for i in * ; do + if test ! -d $i && (grep sanitize-vr5400 $i > /dev/null) ; then + if [ -n "${verbose}" ] ; then + echo Removing traces of \"vr5400\" from $i... + fi + cp $i new + sed '/start\-sanitize\-vr5400/,/end\-sanitize\-vr5400/d' < $i > new + if [ -n "${safe}" -a ! -f .Recover/$i ] ; then + if [ -n "${verbose}" ] ; then + echo Caching $i in .Recover... + fi + mv $i .Recover + fi + mv new $i + fi + done +fi + tx19_files="tc-mips.c" if ( echo $* | grep keep\-tx19 > /dev/null ) ; then diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 314d568..535a7f5 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -203,11 +203,16 @@ static int mips_4010 = -1; /* Whether the 4100 MADD16 and DMADD16 are permitted. */ static int mips_4100 = -1; +/* start-sanitize-vr5400 */ +/* Whether NEC vr5400 instructions are permitted. */ +static int mips_5400 = -1; + +/* end-sanitize-vr5400 */ /* start-sanitize-r5900 */ /* Whether Toshiba r5900 instructions are permitted. */ static int mips_5900 = -1; -/* end-sanitize-r5900 */ +/* end-sanitize-r5900 */ /* Whether Toshiba r3900 instructions are permitted. */ static int mips_3900 = -1; @@ -642,6 +647,8 @@ static void s_mipsend PARAMS ((int)); static void s_file PARAMS ((int)); static void s_mips_stab PARAMS ((int)); static int mips16_extended_frag PARAMS ((fragS *, asection *, long)); + +static int validate_mips_insn PARAMS ((const struct mips_opcode *)); /* Pseudo-op table. @@ -788,6 +795,7 @@ md_begin () boolean ok = false; register const char *retval = NULL; register unsigned int i = 0; + int broken = 0; if (mips_opts.isa == -1) { @@ -896,6 +904,18 @@ md_begin () if (mips_cpu == -1) mips_cpu = 5000; } + /* start-sanitize-vr5400 */ + else if (strcmp (cpu, "r5400") == 0 + || strcmp (cpu, "mips64r5400") == 0 + || strcmp (cpu, "mips64r5400el") == 0) + { + mips_opts.isa = 4; + if (mips_cpu == -1) + mips_cpu = 5400; + if (mips_5400 == -1) + mips_5400 = 1; + } + /* end-sanitize-vr5400 */ /* start-sanitize-r5900 */ else if (strcmp (cpu, "r5900") == 0 || strcmp (cpu, "mips64r5900") == 0 @@ -955,11 +975,16 @@ md_begin () if (mips_4100 < 0) mips_4100 = 0; + /* start-sanitize-vr5400 */ + if (mips_5400 < 0) + mips_5400 = 0; + + /* end-sanitize-vr5400 */ /* start-sanitize-r5900 */ if (mips_5900 < 0) mips_5900 = 0; - /* end-sanitize-r5900 */ + /* end-sanitize-r5900 */ if (mips_3900 < 0) mips_3900 = 0; @@ -997,17 +1022,15 @@ md_begin () { fprintf (stderr, "internal error: can't hash `%s': %s\n", mips_opcodes[i].name, retval); + /* Probably a memory allocation problem? Give up now. */ as_fatal ("Broken assembler. No assembly attempted."); } do { - if (mips_opcodes[i].pinfo != INSN_MACRO - && ((mips_opcodes[i].match & mips_opcodes[i].mask) - != mips_opcodes[i].match)) + if (mips_opcodes[i].pinfo != INSN_MACRO) { - fprintf (stderr, "internal error: bad opcode: `%s' \"%s\"\n", - mips_opcodes[i].name, mips_opcodes[i].args); - as_fatal ("Broken assembler. No assembly attempted."); + if (!validate_mips_insn (&mips_opcodes[i])) + broken = 1; } ++i; } @@ -1023,21 +1046,27 @@ md_begin () retval = hash_insert (mips16_op_hash, name, (PTR) &mips16_opcodes[i]); if (retval != NULL) - as_fatal ("internal error: can't hash `%s': %s\n", + as_fatal ("internal: can't hash `%s': %s", mips16_opcodes[i].name, retval); do { if (mips16_opcodes[i].pinfo != INSN_MACRO && ((mips16_opcodes[i].match & mips16_opcodes[i].mask) != mips16_opcodes[i].match)) - as_fatal ("internal error: bad opcode: `%s' \"%s\"\n", - mips16_opcodes[i].name, mips16_opcodes[i].args); + { + fprintf (stderr, "internal error: bad mips16 opcode: %s %s\n", + mips16_opcodes[i].name, mips16_opcodes[i].args); + broken = 1; + } ++i; } while (i < bfd_mips16_num_opcodes && strcmp (mips16_opcodes[i].name, name) == 0); } + if (broken) + as_fatal ("Broken assembler. No assembly attempted."); + /* We add all the general register names to the symbol table. This helps us detect invalid uses of them. */ for (i = 0; i < 32; i++) @@ -2392,6 +2421,10 @@ macro_build (place, counter, ep, name, fmt, va_alist) || (mips_5900 && (insn.insn_mo->membership & INSN_5900) != 0) /* end-sanitize-r5900 */ + /* start-sanitize-vr5400 */ + || (mips_5400 + && (insn.insn_mo->membership & INSN_5400) != 0) + /* end-sanitize-vr5400 */ || (mips_3900 && (insn.insn_mo->membership & INSN_3900) != 0)) /* start-sanitize-r5900 */ @@ -6568,6 +6601,107 @@ mips16_macro (ip) } } +/* For consistency checking, verify that all bits are specified either + by the match/mask part of the instruction definition, or by the + operand list. */ +static int +validate_mips_insn (opc) + const struct mips_opcode *opc; +{ + const char *p = opc->args; + char c; + unsigned long used_bits = opc->mask; + + if ((used_bits & opc->match) != opc->match) + { + as_bad ("internal: bad mips opcode (mask error): %s %s", + opc->name, opc->args); + return 0; + } +#define USE_BITS(mask,shift) (used_bits |= ((mask) << (shift))) + while (*p) + switch (c = *p++) + { + case ',': break; + case '(': break; + case ')': break; + case '<': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break; + case '>': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break; + case 'A': break; + case 'B': USE_BITS (OP_MASK_SYSCALL, OP_SH_SYSCALL); break; + case 'C': USE_BITS (OP_MASK_COPZ, OP_SH_COPZ); break; + case 'D': USE_BITS (OP_MASK_FD, OP_SH_FD); break; + case 'E': USE_BITS (OP_MASK_RT, OP_SH_RT); break; + case 'F': break; + case 'G': USE_BITS (OP_MASK_RD, OP_SH_RD); break; + case 'I': break; + case 'L': break; + case 'M': USE_BITS (OP_MASK_CCC, OP_SH_CCC); break; + case 'N': USE_BITS (OP_MASK_BCC, OP_SH_BCC); break; + case 'R': USE_BITS (OP_MASK_FR, OP_SH_FR); break; + case 'S': USE_BITS (OP_MASK_FS, OP_SH_FS); break; + case 'T': USE_BITS (OP_MASK_FT, OP_SH_FT); break; + case 'V': USE_BITS (OP_MASK_FS, OP_SH_FS); break; + case 'W': USE_BITS (OP_MASK_FT, OP_SH_FT); break; + case 'a': USE_BITS (OP_MASK_TARGET, OP_SH_TARGET); break; + case 'b': USE_BITS (OP_MASK_RS, OP_SH_RS); break; + case 'c': USE_BITS (OP_MASK_CODE, OP_SH_CODE); break; + case 'd': USE_BITS (OP_MASK_RD, OP_SH_RD); break; + case 'f': break; + case 'h': USE_BITS (OP_MASK_PREFX, OP_SH_PREFX); break; + case 'i': USE_BITS (OP_MASK_IMMEDIATE, OP_SH_IMMEDIATE); break; + case 'j': USE_BITS (OP_MASK_DELTA, OP_SH_DELTA); break; + case 'k': USE_BITS (OP_MASK_CACHE, OP_SH_CACHE); break; + case 'l': break; + case 'o': USE_BITS (OP_MASK_DELTA, OP_SH_DELTA); break; + case 'p': USE_BITS (OP_MASK_DELTA, OP_SH_DELTA); break; + case 'r': USE_BITS (OP_MASK_RS, OP_SH_RS); break; + case 's': USE_BITS (OP_MASK_RS, OP_SH_RS); break; + case 't': USE_BITS (OP_MASK_RT, OP_SH_RT); break; + case 'u': USE_BITS (OP_MASK_IMMEDIATE, OP_SH_IMMEDIATE); break; + case 'v': USE_BITS (OP_MASK_RS, OP_SH_RS); break; + case 'w': USE_BITS (OP_MASK_RT, OP_SH_RT); break; + case 'x': break; + case 'z': break; + /* start-sanitize-vr5400 */ + case 'P': USE_BITS (OP_MASK_PERFREG, OP_SH_PERFREG); break; + case 'e': USE_BITS (OP_MASK_VECBYTE, OP_SH_VECBYTE); break; + case '%': USE_BITS (OP_MASK_VECALIGN, OP_SH_VECALIGN); break; + case '[': break; + case ']': break; + /* end-sanitize-vr5400 */ + default: + as_bad ("internal: bad mips opcode (unknown operand type `%c'): %s %s", + c, opc->name, opc->args); + return 0; + } +#undef USE_BITS + /* Some of the trapping instructions (break, t*, sdbbp) have "code" + fields that cannot currently be set by assembly code. Ignore them + for now. */ + if (opc->pinfo & INSN_TRAP) + { + static const char *const trap_insns[] = { + "break", "sdbbp", + "teq", "tge", "tgeu", "tlt", "tltu", "tne", + }; + int i; + for (i = sizeof(trap_insns)/sizeof(trap_insns[0]) - 1; i >= 0; i--) + if (!strcmp (trap_insns[i], opc->name)) + { + used_bits |= 0xffc0; + break; + } + } + if (used_bits != 0xffffffff) + { + as_bad ("internal: bad mips opcode (bits 0x%lx undefined): %s %s", + ~used_bits & 0xffffffff, opc->name, opc->args); + return 0; + } + return 1; +} + /* This routine assembles an instruction into its binary format. As a side effect, it sets one of the global variables imm_reloc or offset_reloc to the type of relocation to do if one of the operands @@ -6630,6 +6764,9 @@ mips_ip (str, ip) /* start-sanitize-r5900 */ || (mips_5900 && (insn->membership & INSN_5900) != 0) /* end-sanitize-r5900 */ + /* start-sanitize-vr5400 */ + || (mips_5400 && (insn->membership & INSN_5400) != 0) + /* end-sanitize-vr5400 */ || (mips_3900 && (insn->membership & INSN_3900) != 0)) { ok = true; @@ -6710,6 +6847,10 @@ mips_ip (str, ip) return; case ')': /* these must match exactly */ + /* start-sanitize-vr5400 */ + case '[': + case ']': + /* end-sanitize-vr5400 */ if (*s++ == *args) continue; break; @@ -8393,6 +8534,13 @@ struct option md_longopts[] = { {"no-m1900", no_argument, NULL, OPTION_NO_M3900}, /* end-sanitize-tx19 */ + /* start-sanitize-vr5400 */ +#define OPTION_M5400 (OPTION_MD_BASE + 28) + {"m5400", no_argument, NULL, OPTION_M5400}, +#define OPTION_NO_M5400 (OPTION_MD_BASE + 29) + {"no-m5400", no_argument, NULL, OPTION_NO_M5400}, + + /* end-sanitize-vr5400 */ #define OPTION_CALL_SHARED (OPTION_MD_BASE + 7) #define OPTION_NON_SHARED (OPTION_MD_BASE + 8) #define OPTION_XGOT (OPTION_MD_BASE + 19) @@ -8571,6 +8719,10 @@ md_parse_option (c, arg) || strcmp (p, "5k") == 0 || strcmp (p, "5K") == 0) mips_cpu = 5000; + /* start-sanitize-vr5400 */ + else if (strcmp (p, "5400") == 0) + mips_cpu = 5400; + /* end-sanitize-vr5400 */ /* start-sanitize-r5900 */ else if (strcmp (p, "5900") == 0) mips_cpu = 5900; @@ -8646,6 +8798,16 @@ md_parse_option (c, arg) break; /* end-sanitize-r5900 */ + /* start-sanitize-vr5400 */ + case OPTION_M5400: + mips_5400 = 1; + break; + + case OPTION_NO_M5400: + mips_5400 = 0; + break; + + /* end-sanitize-vr5400 */ case OPTION_M3900: mips_3900 = 1; break; |