This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [PATCH] Support VU0 on MIPS R5900
- From: Richard Sandiford <rdsandiford at googlemail dot com>
- To: JÃrgen Urban <JuergenUrban at gmx dot de>
- Cc: "binutils\ at sourceware dot org" <binutils at sourceware dot org>
- Date: Sat, 03 Aug 2013 12:33:00 +0100
- Subject: Re: [PATCH] Support VU0 on MIPS R5900
- References: <20130108234130 dot 27410 at gmx dot net> <87a9rrso6l dot fsf at talisman dot default> <trinity-c3dc44a3-27c5-482b-b113-ca0cae29d590-1375046137093 at 3capp-gmx-bs55> <87mwp39mfo dot fsf at talisman dot default> <76A90B6E-700D-4EE8-9BD4-D7EAB1B0D7D6 at gmx dot de>
JÃrgen Urban <JuergenUrban@gmx.de> writes:
> Am 31.07.2013 um 10:13 schrieb Richard Sandiford <rdsandiford@googlemail.com>:
>> "JÃrgen Urban" <JuergenUrban@gmx.de> writes:
>>> ragnarok2040 is busy and wasn't able to finish the work. So I took over
>>> the work. The binutils changed in the meantime. So the old patch doesn't
>>> apply and your questions are no longer applicable (the patch is
>>> completely changed). I couldn't find a way to work the old stuff in,
>>> because the new binutils are very different. So I decided to add it
>>> without special support for suffixes. All suffixes are listed instead in
>>> the mips opcode table, so the suffixes will work without special suffix
>>> support. I think this was the intented way that binutils was designed
>>> for.
>>
>> Well, I'm not sure there's really a precedent either way. These VU0
>> instructions are pretty idiosyncratic. Things like .ob vs. .qh for MDMX
>> and .s/.d/.ps for FP are similar, but there are different requirements
>> for when you can use those (no .qh for VR5400, no .ps until MIPS V, etc.)
>> In this case the suffix is really just an operand that happens to be part
>> of the mnemonic, so I preferred your original approach of dealing with the
>> suffixes programmatically. Certainly....
>>
>>> The result is that the patch adds 1527 instructions.
>>
>> ...this seems far too many :-)
>>
>> The easiest way of dealing with it would be to have a pinfo/pinfo2 bit
>> to say that the suffix is required. Unfortunately there are none left
>> that we can use.
>>
>> I'm close to finishing a series of patches to further rework the opcode
>> table and free up more bits. Those patches again interfere with yours,
>> sorry. Rather than ask you to make another wholesale change, I've locally
>> reworked your patch to apply on top of the other ones and to make it
>> use the pinfo2 approach.
>
> I would appreciate it. I am hoping that it gets finally in.
Here's the patch I'd like to apply. Does it look OK to you?
I've not posted the testsuite part because that's still the
same as your version.
As well as the other changes I mentioned before, I made "#-" and "#+"
stand for "--" and "++" since they are really single tokens.
>>> I did the same for register suffixes, so all combinations are part of
>>> the internal symbol table for registers, i.e. 1043 registers.
>>
>> Here too I think your original approach was better, sorry. Although the
>> syntax glues the suffix directly to the register name, I think it's
>> logically a separate token. The fact that the designers chose the syntax
>> "$vf0xyz" rather than "$vf0.xyz" (or "$vf0[xyz]", or whatever) isn't
>> particularly important. In the new parsing scheme that means the suffix
>> should be a separate OT_*.
>>
>> The same principle applies to the operands. The fields specified by the
>> suffixes are not contiguous with the register fields, so I think things
>> like "$vf0xyz" should be two separate mips_operands, one normal register
>> operand and one new type for just the suffix.
>
> You need to know that there are special cases for instructions with brackets:
>
> vlqd.xyz $vf0xyz, (--$vi3)xyz
> vlqi.xyz $vf1xyz, ($vi2++)xyz
> vsqd.x $vf3x, (--$vi4)x
> vsqi.y $vf7y, ($vi6++)y
> vilwr.w $vi7, ($vi8)w
> viswr.z $vi1, ($vi15)z
>
> The suffix is behind the closing bracket. My tests didn't test for the
> last suffix, because I wasn't able to handle this with my approach. I
> want that the disassembler prints the last suffix, but this means that
> the test fails and need to be updated.
OK, that should be fairly easy with the patch below. You could try
calling mips_parse_vu0_channels after we've added an OT_CHAR for ')'.
Then, if the channel mask is nonzero, add an OT_CHANNELS for it.
There should be no ambiguity because we don't allow expressions
immediately after a ')'.
Let's keep that as a separate patch though.
>> I've done this locally and it seems to be working well.
>>
>> BTW, out of interest, I notice the syntax allows "$0" instead of "$vf0"
>> or "$vi0", but not "$0xyz" instead of "$vf0xyz" or "$vi0xyz". Is that
>> historical? I've no problem with keeping it that way, I was just curious.
>
> I think "$0xyz" is confusing and it seems to be never used, so I decided
> to forbid it. Some source code uses "$0" because there are some old
> versions of binutils which don't have support for the real register
> name. I want to have support for "$0" because it makes it easier to port
> existing code to the new GCC and binutils.
Ah, OK, thanks.
Richard
include/opcode/
* mips.h: Document new VU0 operand characters.
(OP_VU0_SUFFIX, OP_VU0_MATCH_SUFFIX): New mips_operand_types.
(OP_REG_VF, OP_REG_VI, OP_REG_R5900_I, OP_REG_R5900_Q, OP_REG_R5900_R)
(OP_REG_R5900_ACC): New mips_reg_operand_types.
(INSN2_VU0_CHANNEL_SUFFIX): New macro.
(mips_vu0_channel_mask): Declare.
opcodes/
* mips-dis.c (print_reg): Handle OP_REG_VI, OP_REG_VF, OP_REG_R5900_I,
OP_REG_R5900_Q, OP_REG_R5900_R and OP_REG_R5900_ACC.
(print_vu0_channel): New function.
(print_insn_arg): Handle OP_VU0_SUFFIX and OP_VU0_MATCH_SUFFIX.
(print_insn_args): Handle '#'.
(print_insn_mips): Handle INSN2_VU0_CHANNEL_SUFFIX.
* mips-opc.c (mips_vu0_channel_mask): New constant.
(decode_mips_operand): Handle new VU0 operand types.
(VU0, VU0CH): New macros.
(mips_builtin_opcodes): Add VU0 opcodes. Use "+7" rather than "E"
for LQC2 and SQC2. Use "+9" rather than "G" for EE CFC2 and CTC2.
Use "+6" rather than "G" for QMFC2 and QMTC2.
gas/
* config/tc-mips.c (MAX_OPERANDS): Bump to 6.
(RWARN): Bump to 0x8000000.
(RTYPE_VI, RTYPE_VF, RTYPE_R5900_I, RTYPE_R5900_Q, RTYPE_R5900_R)
(RTYPE_R5900_ACC): New register types.
(RTYPE_MASK): Include them.
(R5900_I_NAMES, R5900_Q_NAMES, R5900_R_NAMES, R5900_ACC_NAMES): New
macros.
(reg_names): Include them.
(mips_parse_register_1): New function, split out from...
(mips_parse_register): ...here. Add a channels_ptr parameter.
Look for VU0 channel suffixes when nonnull.
(reg_lookup): Update the call to mips_parse_register.
(mips_parse_vu0_channels): New function.
(OT_CHANNELS, OT_DOUBLE_CHAR): New mips_operand_token_types.
(mips_operand_token): Add a "channels" field to the union.
Extend the comment above "ch" to OT_DOUBLE_CHAR.
(mips_parse_base_start): Match -- and ++. Handle channel suffixes.
(mips_parse_argument_token): Handle channel suffixes here too.
(validate_mips_insn): Handle INSN2_VU0_CHANNEL_SUFFIX.
Ignore OP_VU0_MATCH_SUFFIX when calculating the used bits.
Handle '#' formats.
(md_begin): Register $vfN and $vfI registers.
(operand_reg_mask): Handle OP_VU0_SUFFIX and OP_VU0_MATCH_SUFFIX.
(convert_reg_type): Handle OP_REG_VI, OP_REG_VF, OP_REG_R5900_I,
OP_REG_R5900_Q, OP_REG_R5900_R and OP_REG_R5900_ACC.
(match_vu0_suffix_operand): New function.
(match_operand): Handle OP_VU0_SUFFIX and OP_VU0_MATCH_SUFFIX.
(macro): Use "+7" rather than "E" for LDQ2 and STQ2.
(mips_lookup_insn): New function.
(mips_ip): Use it. Allow "+K" operands to be elided at the end
of an instruction. Handle '#' sequences.
gas/testsuite/
* gas/mips/r5900-vu0.d: Expect $vfN and $viN instead of numeric
coprocessor registers.
* gas/mips/r5900-all-vu0.s, gas/mips/r5900-all-vu0.d,
gas/mips/r5900-full-vu0.s, gas/mips/r5900-full-vu0.d,
gas/mips/r5900-error-vu0.s, gas/mips/r5900-error-vu0.l: New tests.
* gas/mips/mips.exp: Run them.
Index: include/opcode/mips.h
===================================================================
--- include/opcode/mips.h 2013-08-03 11:49:28.265647192 +0100
+++ include/opcode/mips.h 2013-08-03 12:14:12.614900958 +0100
@@ -401,7 +401,15 @@ enum mips_operand_type {
OP_REPEAT_PREV_REG,
/* $pc, which has no encoding in the architectural instruction. */
- OP_PC
+ OP_PC,
+
+ /* A 4-bit XYZW channel mask or 2-bit XYZW index; the size determines
+ which. */
+ OP_VU0_SUFFIX,
+
+ /* Like OP_VU0_SUFFIX, but used when the operand's value has already
+ been set. Any suffix used here must match the previous value. */
+ OP_VU0_MATCH_SUFFIX
};
/* Enumerates the types of MIPS register. */
@@ -430,7 +438,19 @@ enum mips_reg_operand_type {
/* Hardware registers $0-$31. Mnemonic names like hwr_cpunum can
also be used in some contexts. */
- OP_REG_HW
+ OP_REG_HW,
+
+ /* Floating-point registers $vf0-$vf31. */
+ OP_REG_VF,
+
+ /* Integer registers $vi0-$vi31. */
+ OP_REG_VI,
+
+ /* R5900 VU0 registers $I, $Q, $R and $ACC. */
+ OP_REG_R5900_I,
+ OP_REG_R5900_Q,
+ OP_REG_R5900_R,
+ OP_REG_R5900_ACC
};
/* Base class for all operands. */
@@ -781,6 +801,26 @@ struct mips_opcode
"Y" source register (OP_*_FS)
"Z" source register (OP_*_FT)
+ R5900 VU0 Macromode instructions:
+ "+5" 5 bit floating point register (FD)
+ "+6" 5 bit floating point register (FS)
+ "+7" 5 bit floating point register (FT)
+ "+8" 5 bit integer register (FD)
+ "+9" 5 bit integer register (FS)
+ "+0" 5 bit integer register (FT)
+ "+K" match an existing 4-bit channel mask starting at bit 21
+ "+L" 2-bit channel index starting at bit 21
+ "+M" 2-bit channel index starting at bit 23
+ "+N" match an existing 2-bit channel index starting at bit 0
+ "+f" 15 bit immediate for VCALLMS
+ "+g" 5 bit signed immediate for VIADDI
+ "+m" $ACC register (syntax only)
+ "+q" $Q register (syntax only)
+ "+r" $R register (syntax only)
+ "+y" $I register (syntax only)
+ "#+" "++" decorator in ($reg++) sequence
+ "#-" "--" decorator in (--$reg) sequence
+
DSP ASE usage:
"2" 2 bit unsigned immediate for byte align (OP_*_BP)
"3" 3 bit unsigned immediate (OP_*_SA3)
@@ -846,15 +886,15 @@ struct mips_opcode
Characters used so far, for quick reference when adding more:
"1234567890"
- "%[]<>(),+:'@!$*&\~"
+ "%[]<>(),+:'@!#$*&\~"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklopqrstuvwxz"
Extension character sequences used so far ("+" followed by the
following), for quick reference when adding more:
- "1234"
- "ABCEFGHIJPQSXZ"
- "abcijpstxz"
+ "1234567890"
+ "ABCEFGHIJKLMNPQSXZ"
+ "abcfgijmpqrstxyz"
*/
/* These are the bits which may be set in the pinfo field of an
@@ -960,6 +1000,8 @@ #define INSN2_UNCOND_BRANCH 0x000008
#define INSN2_COND_BRANCH 0x00001000
/* Reads from $16. This is true of the MIPS16 0x6500 nop. */
#define INSN2_READ_GPR_16 0x00002000
+/* Has an "\.x?y?z?w?" suffix based on mips_vu0_channel_mask. */
+#define INSN2_VU0_CHANNEL_SUFFIX 0x00004000
/* Masks used to mark instructions to indicate which MIPS ISA level
they were introduced in. INSN_ISA_MASK masks an enumeration that
@@ -1490,6 +1532,7 @@ enum
Many instructions are short hand for other instructions (i.e., The
jal <register> instruction is short for jalr <register>). */
+extern const struct mips_operand mips_vu0_channel_mask;
extern const struct mips_operand *decode_mips_operand (const char *);
extern const struct mips_opcode mips_builtin_opcodes[];
extern const int bfd_mips_num_builtin_opcodes;
Index: opcodes/mips-dis.c
===================================================================
--- opcodes/mips-dis.c 2013-08-03 11:37:24.448662401 +0100
+++ opcodes/mips-dis.c 2013-08-03 12:14:12.614900958 +0100
@@ -917,6 +917,30 @@ print_reg (struct disassemble_info *info
case OP_REG_HW:
info->fprintf_func (info->stream, "%s", mips_hwr_names[regno]);
break;
+
+ case OP_REG_VF:
+ info->fprintf_func (info->stream, "$vf%d", regno);
+ break;
+
+ case OP_REG_VI:
+ info->fprintf_func (info->stream, "$vi%d", regno);
+ break;
+
+ case OP_REG_R5900_I:
+ info->fprintf_func (info->stream, "$I");
+ break;
+
+ case OP_REG_R5900_Q:
+ info->fprintf_func (info->stream, "$Q");
+ break;
+
+ case OP_REG_R5900_R:
+ info->fprintf_func (info->stream, "$R");
+ break;
+
+ case OP_REG_R5900_ACC:
+ info->fprintf_func (info->stream, "$ACC");
+ break;
}
}
@@ -941,6 +965,25 @@ init_print_arg_state (struct mips_print_
memset (state, 0, sizeof (*state));
}
+/* Print OP_VU0_SUFFIX or OP_VU0_MATCH_SUFFIX operand OPERAND,
+ whose value is given by UVAL. */
+
+static void
+print_vu0_channel (struct disassemble_info *info,
+ const struct mips_operand *operand, unsigned int uval)
+{
+ if (operand->size == 4)
+ info->fprintf_func (info->stream, "%s%s%s%s",
+ uval & 8 ? "x" : "",
+ uval & 4 ? "y" : "",
+ uval & 2 ? "z" : "",
+ uval & 1 ? "w" : "");
+ else if (operand->size == 2)
+ info->fprintf_func (info->stream, "%c", "xyzw"[uval]);
+ else
+ abort ();
+}
+
/* Print operand OPERAND of OPCODE, using STATE to track inter-operand state.
UVAL is the encoding of the operand (shifted into bit 0) and BASE_PC is
the base address for OP_PCREL operands. */
@@ -1201,6 +1244,11 @@ print_insn_arg (struct disassemble_info
case OP_PC:
infprintf (is, "$pc");
break;
+
+ case OP_VU0_SUFFIX:
+ case OP_VU0_MATCH_SUFFIX:
+ print_vu0_channel (info, operand, uval);
+ break;
}
}
@@ -1231,6 +1279,11 @@ print_insn_args (struct disassemble_info
infprintf (is, "%c", *s);
break;
+ case '#':
+ ++s;
+ infprintf (is, "%c%c", *s, *s);
+ break;
+
default:
operand = decode_operand (s);
if (!operand)
@@ -1365,6 +1418,14 @@ #define GET_OP(insn, field) \
info->insn_type = dis_dref;
infprintf (is, "%s", op->name);
+ if (op->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX)
+ {
+ unsigned int uval;
+
+ infprintf (is, ".");
+ uval = mips_extract_operand (&mips_vu0_channel_mask, word);
+ print_vu0_channel (info, &mips_vu0_channel_mask, uval);
+ }
if (op->args[0])
{
Index: opcodes/mips-opc.c
===================================================================
--- opcodes/mips-opc.c 2013-08-03 11:37:24.448662401 +0100
+++ opcodes/mips-opc.c 2013-08-03 12:14:12.615900968 +0100
@@ -30,6 +30,9 @@
#include "opcode/mips.h"
#include "mips-formats.h"
+/* The 4-bit XYZW mask used in some VU0 instructions. */
+const struct mips_operand mips_vu0_channel_mask = { OP_VU0_SUFFIX, 4, 21 };
+
static unsigned char reg_0_map[] = { 0 };
/* Return the mips_operand structure for the operand at the beginning of P. */
@@ -46,6 +49,12 @@ decode_mips_operand (const char *p)
case '2': HINT (10, 6);
case '3': HINT (15, 6);
case '4': HINT (20, 6);
+ case '5': REG (5, 6, VF);
+ case '6': REG (5, 11, VF);
+ case '7': REG (5, 16, VF);
+ case '8': REG (5, 6, VI);
+ case '9': REG (5, 11, VI);
+ case '0': REG (5, 16, VI);
case 'A': BIT (5, 6, 0); /* (0 .. 31) */
case 'B': MSB (5, 11, 1, TRUE, 32); /* (1 .. 32), 32-bit op */
@@ -55,6 +64,10 @@ decode_mips_operand (const char *p)
case 'G': MSB (5, 11, 33, FALSE, 64); /* (33 .. 64), 64-bit op */
case 'H': MSB (5, 11, 1, FALSE, 64); /* (1 .. 32), 64-bit op */
case 'J': HINT (10, 11);
+ case 'K': SPECIAL (4, 21, VU0_MATCH_SUFFIX);
+ case 'L': SPECIAL (2, 21, VU0_SUFFIX);
+ case 'M': SPECIAL (2, 23, VU0_SUFFIX);
+ case 'N': SPECIAL (2, 0, VU0_MATCH_SUFFIX);
case 'P': BIT (5, 6, 32); /* (32 .. 63) */
case 'Q': SINT (10, 6);
case 'S': MSB (5, 11, 0, FALSE, 63); /* (0 .. 31), 64-bit op */
@@ -64,12 +77,18 @@ decode_mips_operand (const char *p)
case 'a': SINT (8, 6);
case 'b': SINT (8, 3);
case 'c': INT_ADJ (9, 6, 255, 4, FALSE); /* (-256 .. 255) << 4 */
+ case 'f': INT_ADJ (15, 6, 32767, 3, TRUE);
+ case 'g': SINT (5, 6);
case 'i': JALX (26, 0, 2);
case 'j': SINT (9, 7);
+ case 'm': REG (0, 0, R5900_ACC);
case 'p': BIT (5, 6, 0); /* (0 .. 31), 32-bit op */
+ case 'q': REG (0, 0, R5900_Q);
+ case 'r': REG (0, 0, R5900_R);
case 's': MSB (5, 11, 0, FALSE, 31); /* (0 .. 31) */
case 't': REG (5, 16, COPRO);
case 'x': BIT (5, 16, 0); /* (0 .. 31) */
+ case 'y': REG (0, 0, R5900_I);
case 'z': REG (5, 0, GP);
}
break;
@@ -267,6 +286,10 @@ #define MMI EE
/* 64 bit CPU with only 32 bit multiplication/division support. */
#define M32 EE
+/* Support for VU0 Coprocessor instructions */
+#define VU0 EE
+#define VU0CH INSN2_VU0_CHANNEL_SUFFIX
+
/* MIPS DSP ASE support.
NOTE:
1. MIPS DSP ASE includes 4 accumulators ($ac0 - $ac3). $ac0 is the pair
@@ -403,6 +426,136 @@ const struct mips_opcode mips_builtin_op
{"gslqc1", "+Z,T,+c(b)", 0xc8008020, 0xfc008020, WR_1|WR_2|RD_4|LDD, 0, IL3A, 0, 0 },
{"gssqc1", "+Z,T,+c(b)", 0xe8008020, 0xfc008020, RD_1|RD_2|RD_4|SM, 0, IL3A, 0, 0 },
+/* R5900 VU0 Macromode instructions. */
+{"vabs", "+7+K,+6+K", 0x4a0001fd, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vadd", "+5+K,+6+K,+7+K", 0x4a000028, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vaddi", "+5+K,+6+K,+y", 0x4a000022, 0xfe1f003f, CP, VU0CH, VU0, 0, 0 },
+{"vaddq", "+5+K,+6+K,+q", 0x4a000020, 0xfe1f003f, CP, VU0CH, VU0, 0, 0 },
+{"vaddw", "+5+K,+6+K,+7+N", 0x4a000003, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vaddx", "+5+K,+6+K,+7+N", 0x4a000000, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vaddy", "+5+K,+6+K,+7+N", 0x4a000001, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vaddz", "+5+K,+6+K,+7+N", 0x4a000002, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vadda", "+m+K,+7+K,+6+K", 0x4a0002bc, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vaddai", "+m+K,+6+K,+y", 0x4a00023e, 0xfe1f07ff, CP, VU0CH, VU0, 0, 0 },
+{"vaddaq", "+m+K,+6+K,+q", 0x4a00023c, 0xfe1f07ff, CP, VU0CH, VU0, 0, 0 },
+{"vaddaw", "+m+K,+6+K,+7+N", 0x4a00003f, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vaddax", "+m+K,+6+K,+7+N", 0x4a00003c, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vadday", "+m+K,+6+K,+7+N", 0x4a00003d, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vaddaz", "+m+K,+6+K,+7+N", 0x4a00003e, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vcallms", "+f", 0x4a000038, 0xffe0003f, CP, 0, VU0, 0, 0 },
+{"vcallmsr", "+9", 0x4a000039, 0xffff07ff, CP, 0, VU0, 0, 0 },
+{"vclipw.xyz", "+6+K,+7+N", 0x4bc001ff, 0xffe007ff, CP, 0, VU0, 0, 0 },
+{"vdiv", "+q,+6+L,+7+M", 0x4a0003bc, 0xfe0007ff, CP, 0, VU0, 0, 0 },
+{"vftoi0", "+7+K,+6+K", 0x4a00017c, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vftoi4", "+7+K,+6+K", 0x4a00017d, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vftoi12", "+7+K,+6+K", 0x4a00017e, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vftoi15", "+7+K,+6+K", 0x4a00017f, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"viadd", "+8,+9,+0", 0x4a000030, 0xffe0003f, CP, 0, VU0, 0, 0 },
+{"viaddi", "+0,+9,+g", 0x4a000032, 0xffe0003f, CP, 0, VU0, 0, 0 },
+{"viand", "+8,+9,+0", 0x4a000034, 0xffe0003f, CP, 0, VU0, 0, 0 },
+{"vilwr.w", "+0,(+9)", 0x4a2003fe, 0xffe007ff, CP, 0, VU0, 0, 0 },
+{"vilwr.x", "+0,(+9)", 0x4b0003fe, 0xffe007ff, CP, 0, VU0, 0, 0 },
+{"vilwr.y", "+0,(+9)", 0x4a8003fe, 0xffe007ff, CP, 0, VU0, 0, 0 },
+{"vilwr.z", "+0,(+9)", 0x4a4003fe, 0xffe007ff, CP, 0, VU0, 0, 0 },
+{"vior", "+8,+9,+0", 0x4a000035, 0xffe0003f, CP, 0, VU0, 0, 0 },
+{"viswr.w", "+0,(+9)", 0x4a2003ff, 0xffe007ff, CP, 0, VU0, 0, 0 },
+{"viswr.x", "+0,(+9)", 0x4b0003ff, 0xffe007ff, CP, 0, VU0, 0, 0 },
+{"viswr.y", "+0,(+9)", 0x4a8003ff, 0xffe007ff, CP, 0, VU0, 0, 0 },
+{"viswr.z", "+0,(+9)", 0x4a4003ff, 0xffe007ff, CP, 0, VU0, 0, 0 },
+{"visub", "+8,+9,+0", 0x4a000031, 0xffe0003f, CP, 0, VU0, 0, 0 },
+{"vitof0", "+7+K,+6+K", 0x4a00013c, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vitof4", "+7+K,+6+K", 0x4a00013d, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vitof12", "+7+K,+6+K", 0x4a00013e, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vitof15", "+7+K,+6+K", 0x4a00013f, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vlqd", "+7+K,(#-+9)", 0x4a00037e, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vlqi", "+7+K,(+9#+)", 0x4a00037c, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmadd", "+5+K,+6+K,+7+K", 0x4a000029, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmaddi", "+5+K,+6+K,+y", 0x4a000023, 0xfe1f003f, CP, VU0CH, VU0, 0, 0 },
+{"vmaddq", "+5+K,+6+K,+q", 0x4a000021, 0xfe1f003f, CP, VU0CH, VU0, 0, 0 },
+{"vmaddw", "+5+K,+6+K,+7+N", 0x4a00000b, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmaddx", "+5+K,+6+K,+7+N", 0x4a000008, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmaddy", "+5+K,+6+K,+7+N", 0x4a000009, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmaddz", "+5+K,+6+K,+7+N", 0x4a00000a, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmadda", "+m+K,+6+K,+7+K", 0x4a0002bd, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmaddai", "+m+K,+6+K,+y", 0x4a00023f, 0xfe1f07ff, CP, VU0CH, VU0, 0, 0 },
+{"vmaddaq", "+m+K,+6+K,+q", 0x4a00023d, 0xfe1f07ff, CP, VU0CH, VU0, 0, 0 },
+{"vmaddaw", "+m+K,+6+K,+7+N", 0x4a0000bf, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmaddax", "+m+K,+6+K,+7+N", 0x4a0000bc, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmadday", "+m+K,+6+K,+7+N", 0x4a0000bd, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmaddaz", "+m+K,+6+K,+7+N", 0x4a0000be, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmax", "+5+K,+6+K,+7+K", 0x4a00002b, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmaxi", "+5+K,+6+K,+y", 0x4a00001d, 0xfe1f003f, CP, VU0CH, VU0, 0, 0 },
+{"vmaxw", "+5+K,+6+K,+7+N", 0x4a000013, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmaxx", "+5+K,+6+K,+7+N", 0x4a000010, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmaxy", "+5+K,+6+K,+7+N", 0x4a000011, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmaxz", "+5+K,+6+K,+7+N", 0x4a000012, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmfir", "+7+K,+9", 0x4a0003fd, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmini", "+5+K,+6+K,+7+K", 0x4a00002f, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vminii", "+5+K,+6+K,+y", 0x4a00001f, 0xfe1f003f, CP, VU0CH, VU0, 0, 0 },
+{"vminiw", "+5+K,+6+K,+7+N", 0x4a000017, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vminix", "+5+K,+6+K,+7+N", 0x4a000014, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vminiy", "+5+K,+6+K,+7+N", 0x4a000015, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vminiz", "+5+K,+6+K,+7+N", 0x4a000016, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmove", "+7+K,+6+K", 0x4a00033c, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmr32", "+7+K,+6+K", 0x4a00033d, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmsub", "+5+K,+6+K,+7+K", 0x4a00002d, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmsubi", "+5+K,+6+K,+y", 0x4a000027, 0xfe1f003f, CP, VU0CH, VU0, 0, 0 },
+{"vmsubq", "+5+K,+6+K,+q", 0x4a000025, 0xfe1f003f, CP, VU0CH, VU0, 0, 0 },
+{"vmsubw", "+5+K,+6+K,+7+N", 0x4a00000f, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmsubx", "+5+K,+6+K,+7+N", 0x4a00000c, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmsuby", "+5+K,+6+K,+7+N", 0x4a00000d, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmsubz", "+5+K,+6+K,+7+N", 0x4a00000e, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmsuba", "+m+K,+7+K,+6+K", 0x4a0002fd, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmsubai", "+m+K,+6+K,+y", 0x4a00027f, 0xfe1f07ff, CP, VU0CH, VU0, 0, 0 },
+{"vmsubaq", "+m+K,+6+K,+q", 0x4a00027d, 0xfe1f07ff, CP, VU0CH, VU0, 0, 0 },
+{"vmsubaw", "+m+K,+6+K,+7+N", 0x4a0000ff, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmsubax", "+m+K,+6+K,+7+N", 0x4a0000fc, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmsubay", "+m+K,+6+K,+7+N", 0x4a0000fd, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmsubaz", "+m+K,+6+K,+7+N", 0x4a0000fe, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmtir", "+0,+6+L", 0x4a0003fc, 0xff8007ff, CP, 0, VU0, 0, 0 },
+{"vmul", "+5+K,+6+K,+7+K", 0x4a00002a, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmuli", "+5+K,+6+K,+y", 0x4a00001e, 0xfe1f003f, CP, VU0CH, VU0, 0, 0 },
+{"vmulq", "+5+K,+6+K,+q", 0x4a00001c, 0xfe1f003f, CP, VU0CH, VU0, 0, 0 },
+{"vmulw", "+5+K,+6+K,+7+N", 0x4a00001b, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmulx", "+5+K,+6+K,+7+N", 0x4a000018, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmuly", "+5+K,+6+K,+7+N", 0x4a000019, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmulz", "+5+K,+6+K,+7+N", 0x4a00001a, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vmula", "+m+K,+6+K,+7+K", 0x4a0002be, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmulai", "+m+K,+6+K,+y", 0x4a0001fe, 0xfe1f07ff, CP, VU0CH, VU0, 0, 0 },
+{"vmulaq", "+m+K,+6+K,+q", 0x4a0001fc, 0xfe1f07ff, CP, VU0CH, VU0, 0, 0 },
+{"vmulaw", "+m+K,+6+K,+7+N", 0x4a0001bf, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmulax", "+m+K,+6+K,+7+N", 0x4a0001bc, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmulay", "+m+K,+6+K,+7+N", 0x4a0001bd, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vmulaz", "+m+K,+6+K,+7+N", 0x4a0001be, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vnop", "", 0x4a0002ff, 0xffffffff, CP, 0, VU0, 0, 0 },
+{"vopmula.xyz", "+m+K,+6+K,+7+K", 0x4bc002fe, 0xffe007ff, CP, 0, VU0, 0, 0 },
+{"vopmula", "+m+K,+6+K,+7+K", 0x4bc002fe, 0xffe007ff, CP, 0, VU0, 0, 0 },
+{"vopmsub.xyz", "+5+K,+6+K,+7+K", 0x4bc0002e, 0xffe0003f, CP, 0, VU0, 0, 0 },
+{"vopmsub", "+5+K,+6+K,+7+K", 0x4bc0002e, 0xffe0003f, CP, 0, VU0, 0, 0 },
+{"vrget", "+7+K,+r", 0x4a00043d, 0xfe00ffff, CP, VU0CH, VU0, 0, 0 },
+{"vrinit", "+r,+6+L", 0x4a00043e, 0xff9f07ff, CP, 0, VU0, 0, 0 },
+{"vrnext", "+7+K,+r", 0x4a00043c, 0xfe00ffff, CP, VU0CH, VU0, 0, 0 },
+{"vrsqrt", "+q,+6+L,+7+M", 0x4a0003be, 0xfe0007ff, CP, 0, VU0, 0, 0 },
+{"vrxor", "+r,+6+L", 0x4a00043f, 0xff9f07ff, CP, 0, VU0, 0, 0 },
+{"vsqd", "+6+K,(#-+0)", 0x4a00037f, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vsqi", "+6+K,(+0#+)", 0x4a00037d, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vsqrt", "+q,+7+M", 0x4a2003bd, 0xfe60ffff, CP, 0, VU0, 0, 0 },
+{"vsub", "+5+K,+6+K,+7+K", 0x4a00002c, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vsubi", "+5+K,+6+K,+y", 0x4a000026, 0xfe1f003f, CP, VU0CH, VU0, 0, 0 },
+{"vsubq", "+5+K,+6+K,+q", 0x4a000024, 0xfe1f003f, CP, VU0CH, VU0, 0, 0 },
+{"vsubw", "+5+K,+6+K,+7+N", 0x4a000007, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vsubx", "+5+K,+6+K,+7+N", 0x4a000004, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vsuby", "+5+K,+6+K,+7+N", 0x4a000005, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vsubz", "+5+K,+6+K,+7+N", 0x4a000006, 0xfe00003f, CP, VU0CH, VU0, 0, 0 },
+{"vsuba", "+m+K,+6+K,+7+K", 0x4a0002fc, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vsubai", "+m+K,+6+K,+y", 0x4a00027e, 0xfe1f07ff, CP, VU0CH, VU0, 0, 0 },
+{"vsubaq", "+m+K,+6+K,+q", 0x4a00027c, 0xfe1f07ff, CP, VU0CH, VU0, 0, 0 },
+{"vsubaw", "+m+K,+6+K,+7+N", 0x4a00007f, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vsubax", "+m+K,+6+K,+7+N", 0x4a00007c, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vsubay", "+m+K,+6+K,+7+N", 0x4a00007d, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vsubaz", "+m+K,+6+K,+7+N", 0x4a00007e, 0xfe0007ff, CP, VU0CH, VU0, 0, 0 },
+{"vwaitq", "", 0x4a0003bf, 0xffffffff, CP, 0, VU0, 0, 0 },
+
{"abs", "d,v", 0, (int) M_ABS, INSN_MACRO, 0, I1, 0, 0 },
{"abs.s", "D,V", 0x46000005, 0xffff003f, WR_1|RD_2|FP_S, 0, I1, 0, 0 },
{"abs.d", "D,V", 0x46200005, 0xffff003f, WR_1|RD_2|FP_D, 0, I1, 0, SF },
@@ -1011,8 +1164,8 @@ const struct mips_opcode mips_builtin_op
{"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, 0, I3, 0, EE },
{"lq", "t,o(b)", 0x78000000, 0xfc000000, WR_1|RD_3, 0, MMI, 0, 0 },
{"lq", "t,A(b)", 0, (int) M_LQ_AB, INSN_MACRO, 0, MMI, 0, 0 },
-{"lqc2", "E,o(b)", 0xd8000000, 0xfc000000, RD_3|WR_C2, 0, EE, 0, 0 },
-{"lqc2", "E,A(b)", 0, (int) M_LQC2_AB, INSN_MACRO, 0, EE, 0, 0 },
+{"lqc2", "+7,o(b)", 0xd8000000, 0xfc000000, RD_3|WR_C2, 0, EE, 0, 0 },
+{"lqc2", "+7,A(b)", 0, (int) M_LQC2_AB, INSN_MACRO, 0, EE, 0, 0 },
{"lui", "t,u", 0x3c000000, 0xffe00000, WR_1, 0, I1, 0, 0 },
{"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, WR_1|RD_2|RD_3|LDD|FP_D, 0, I5_33|N55, 0, 0},
{"lw", "t,o(b)", 0x8c000000, 0xfc000000, WR_1|RD_3|LDD, 0, I1, 0, 0 },
@@ -1601,8 +1754,8 @@ const struct mips_opcode mips_builtin_op
{"snei", "t,r,+Q", 0x7000002f, 0xfc00003f, WR_1|RD_2, 0, IOCT, 0, 0 },
{"sq", "t,o(b)", 0x7c000000, 0xfc000000, RD_1|RD_3|SM, 0, MMI, 0, 0 },
{"sq", "t,A(b)", 0, (int) M_SQ_AB, INSN_MACRO, 0, MMI, 0, 0 },
-{"sqc2", "E,o(b)", 0xf8000000, 0xfc000000, RD_3|RD_C2|SM, 0, EE, 0, 0 },
-{"sqc2", "E,A(b)", 0, (int) M_SQC2_AB, INSN_MACRO, 0, EE, 0, 0 },
+{"sqc2", "+7,o(b)", 0xf8000000, 0xfc000000, RD_3|RD_C2|SM, 0, EE, 0, 0 },
+{"sqc2", "+7,A(b)", 0, (int) M_SQC2_AB, INSN_MACRO, 0, EE, 0, 0 },
{"sqrt.d", "D,S", 0x46200004, 0xffff003f, WR_1|RD_2|FP_D, 0, I2, 0, SF },
{"sqrt.s", "D,S", 0x46000004, 0xffff003f, WR_1|RD_2|FP_S, 0, I2, 0, 0 },
{"sqrt.ps", "D,S", 0x46c00004, 0xffff003f, WR_1|RD_2|FP_D, 0, SB1, 0, 0 },
@@ -1847,12 +2000,14 @@ const struct mips_opcode mips_builtin_op
{"bc2t", "N,p", 0x49010000, 0xffe30000, RD_CC|CBD, 0, I32, 0, IOCT|IOCTP|IOCT2 },
{"bc2tl", "p", 0x49030000, 0xffff0000, RD_CC|CBL, 0, I2|T3, 0, IOCT|IOCTP|IOCT2 },
{"bc2tl", "N,p", 0x49030000, 0xffe30000, RD_CC|CBL, 0, I32, 0, IOCT|IOCTP|IOCT2 },
-{"cfc2", "t,G", 0x48400000, 0xffe007ff, WR_1|RD_C2|LCD, 0, I1, 0, IOCT|IOCTP|IOCT2 },
-{"cfc2.i", "t,G", 0x48400001, 0xffe007ff, WR_1|RD_C2|LCD, 0, EE, 0, 0 },
-{"cfc2.ni", "t,G", 0x48400000, 0xffe007ff, WR_1|RD_C2|LCD, 0, EE, 0, 0 },
-{"ctc2", "t,G", 0x48c00000, 0xffe007ff, RD_1|WR_CC|COD, 0, I1, 0, IOCT|IOCTP|IOCT2 },
-{"ctc2.i", "t,G", 0x48c00001, 0xffe007ff, RD_1|WR_CC|COD, 0, EE, 0, 0 },
-{"ctc2.ni", "t,G", 0x48c00000, 0xffe007ff, RD_1|WR_CC|COD, 0, EE, 0, 0 },
+{"cfc2", "t,G", 0x48400000, 0xffe007ff, WR_1|RD_C2|LCD, 0, I1, 0, IOCT|IOCTP|IOCT2|EE },
+{"cfc2", "t,+9", 0x48400000, 0xffe007ff, WR_1|RD_C2|LCD, 0, EE, 0, 0 },
+{"cfc2.i", "t,+9", 0x48400001, 0xffe007ff, WR_1|RD_C2|LCD, 0, EE, 0, 0 },
+{"cfc2.ni", "t,+9", 0x48400000, 0xffe007ff, WR_1|RD_C2|LCD, 0, EE, 0, 0 },
+{"ctc2", "t,G", 0x48c00000, 0xffe007ff, RD_1|WR_CC|COD, 0, I1, 0, IOCT|IOCTP|IOCT2|EE },
+{"ctc2", "t,+9", 0x48c00000, 0xffe007ff, RD_1|WR_CC|COD, 0, EE, 0, 0 },
+{"ctc2.i", "t,+9", 0x48c00001, 0xffe007ff, RD_1|WR_CC|COD, 0, EE, 0, 0 },
+{"ctc2.ni", "t,+9", 0x48c00000, 0xffe007ff, RD_1|WR_CC|COD, 0, EE, 0, 0 },
{"dmfc2", "t,i", 0x48200000, 0xffe00000, WR_1|RD_C2|LCD, 0, IOCT, 0, 0 },
{"dmfc2", "t,G", 0x48200000, 0xffe007ff, WR_1|RD_C2|LCD, 0, I3, 0, IOCT|IOCTP|IOCT2|EE },
{"dmfc2", "t,G,H", 0x48200000, 0xffe007f8, WR_1|RD_C2|LCD, 0, I64, 0, IOCT|IOCTP|IOCT2 },
@@ -1869,12 +2024,12 @@ const struct mips_opcode mips_builtin_op
{"mthc2", "t,G", 0x48e00000, 0xffe007ff, RD_1|WR_C2|WR_CC|COD, 0, I33, 0, IOCT|IOCTP|IOCT2 },
{"mthc2", "t,G,H", 0x48e00000, 0xffe007f8, RD_1|WR_C2|WR_CC|COD, 0, I33, 0, IOCT|IOCTP|IOCT2 },
{"mthc2", "t,i", 0x48e00000, 0xffe00000, RD_1|WR_C2|WR_CC|COD, 0, I33, 0, IOCT|IOCTP|IOCT2 },
-{"qmfc2", "t,G", 0x48200000, 0xffe007ff, WR_1|RD_C2, 0, EE, 0, 0 },
-{"qmfc2.i", "t,G", 0x48200001, 0xffe007ff, WR_1|RD_C2, 0, EE, 0, 0 },
-{"qmfc2.ni", "t,G", 0x48200000, 0xffe007ff, WR_1|RD_C2, 0, EE, 0, 0 },
-{"qmtc2", "t,G", 0x48a00000, 0xffe007ff, RD_1|WR_C2, 0, EE, 0, 0 },
-{"qmtc2.i", "t,G", 0x48a00001, 0xffe007ff, RD_1|WR_C2, 0, EE, 0, 0 },
-{"qmtc2.ni", "t,G", 0x48a00000, 0xffe007ff, RD_1|WR_C2, 0, EE, 0, 0 },
+{"qmfc2", "t,+6", 0x48200000, 0xffe007ff, WR_1|RD_C2, 0, EE, 0, 0 },
+{"qmfc2.i", "t,+6", 0x48200001, 0xffe007ff, WR_1|RD_C2, 0, EE, 0, 0 },
+{"qmfc2.ni", "t,+6", 0x48200000, 0xffe007ff, WR_1|RD_C2, 0, EE, 0, 0 },
+{"qmtc2", "t,+6", 0x48a00000, 0xffe007ff, RD_1|WR_C2, 0, EE, 0, 0 },
+{"qmtc2.i", "t,+6", 0x48a00001, 0xffe007ff, RD_1|WR_C2, 0, EE, 0, 0 },
+{"qmtc2.ni", "t,+6", 0x48a00000, 0xffe007ff, RD_1|WR_C2, 0, EE, 0, 0 },
/* Coprocessor 3 move/branch operations overlap with MIPS IV COP1X
instructions, so they are here for the latters to take precedence. */
{"bc3f", "p", 0x4d000000, 0xffff0000, RD_CC|CBD, 0, I1, 0, IOCT|IOCTP|IOCT2|EE },
Index: gas/config/tc-mips.c
===================================================================
--- gas/config/tc-mips.c 2013-08-03 12:11:11.543172269 +0100
+++ gas/config/tc-mips.c 2013-08-03 12:28:19.695537792 +0100
@@ -690,7 +690,7 @@ #define MAX_NOPS 4
static struct mips_cl_insn history[1 + MAX_NOPS];
/* Arrays of operands for each instruction. */
-#define MAX_OPERANDS 5
+#define MAX_OPERANDS 6
struct mips_operand_array {
const struct mips_operand *operand[MAX_OPERANDS];
};
@@ -2206,18 +2206,24 @@ struct regname {
unsigned int num;
};
-#define RTYPE_MASK 0x1ff00
-#define RTYPE_NUM 0x00100
-#define RTYPE_FPU 0x00200
-#define RTYPE_FCC 0x00400
-#define RTYPE_VEC 0x00800
-#define RTYPE_GP 0x01000
-#define RTYPE_CP0 0x02000
-#define RTYPE_PC 0x04000
-#define RTYPE_ACC 0x08000
-#define RTYPE_CCC 0x10000
-#define RNUM_MASK 0x000ff
-#define RWARN 0x80000
+#define RNUM_MASK 0x00000ff
+#define RTYPE_MASK 0x0efff00
+#define RTYPE_NUM 0x0000100
+#define RTYPE_FPU 0x0000200
+#define RTYPE_FCC 0x0000400
+#define RTYPE_VEC 0x0000800
+#define RTYPE_GP 0x0001000
+#define RTYPE_CP0 0x0002000
+#define RTYPE_PC 0x0004000
+#define RTYPE_ACC 0x0008000
+#define RTYPE_CCC 0x0010000
+#define RTYPE_VI 0x0020000
+#define RTYPE_VF 0x0040000
+#define RTYPE_R5900_I 0x0080000
+#define RTYPE_R5900_Q 0x0100000
+#define RTYPE_R5900_R 0x0200000
+#define RTYPE_R5900_ACC 0x0400000
+#define RWARN 0x8000000
#define GENERIC_REGISTER_NUMBERS \
{"$0", RTYPE_NUM | 0}, \
@@ -2403,6 +2409,18 @@ #define MDMX_VECTOR_REGISTER_NAMES \
{"$v30", RTYPE_VEC | 30}, \
{"$v31", RTYPE_VEC | 31}
+#define R5900_I_NAMES \
+ {"$I", RTYPE_R5900_I | 0}
+
+#define R5900_Q_NAMES \
+ {"$Q", RTYPE_R5900_Q | 0}
+
+#define R5900_R_NAMES \
+ {"$R", RTYPE_R5900_R | 0}
+
+#define R5900_ACC_NAMES \
+ {"$ACC", RTYPE_R5900_ACC | 0 }
+
#define MIPS_DSP_ACCUMULATOR_NAMES \
{"$ac0", RTYPE_ACC | 0}, \
{"$ac1", RTYPE_ACC | 1}, \
@@ -2423,6 +2441,10 @@ static const struct regname reg_names[]
MIPS16_SPECIAL_REGISTER_NAMES,
MDMX_VECTOR_REGISTER_NAMES,
+ R5900_I_NAMES,
+ R5900_Q_NAMES,
+ R5900_R_NAMES,
+ R5900_ACC_NAMES,
MIPS_DSP_ACCUMULATOR_NAMES,
{0, 0}
};
@@ -2450,24 +2472,14 @@ mips_prefer_vec_regno (unsigned int symv
return symval;
}
-/* Return true if the string at *SPTR is a valid register name. If so,
- move *SPTR past the register and store the register's symbol value
- in *SYMVAL. This symbol value includes the register number
- (RNUM_MASK) and register type (RTYPE_MASK). */
+/* Return true if string [S, E) is a valid register name, storing its
+ symbol value in *SYMVAL_PTR if so. */
static bfd_boolean
-mips_parse_register (char **sptr, unsigned int *symval)
+mips_parse_register_1 (char *s, char *e, unsigned int *symval_ptr)
{
- symbolS *symbol;
- char *s, *e;
char save_c;
-
- /* Find end of name. */
- s = e = *sptr;
- if (is_name_beginner (*e))
- ++e;
- while (is_part_of_name (*e))
- ++e;
+ symbolS *symbol;
/* Terminate name. */
save_c = *e;
@@ -2480,8 +2492,63 @@ mips_parse_register (char **sptr, unsign
if (!symbol || S_GET_SEGMENT (symbol) != reg_section)
return FALSE;
+ *symval_ptr = S_GET_VALUE (symbol);
+ return TRUE;
+}
+
+/* Return true if the string at *SPTR is a valid register name. Allow it
+ to have a VU0-style channel suffix of the form x?y?z?w? if CHANNELS_PTR
+ is nonnull.
+
+ When returning true, move *SPTR past the register, store the
+ register's symbol value in *SYMVAL_PTR and the channel mask in
+ *CHANNELS_PTR (if nonnull). The symbol value includes the register
+ number (RNUM_MASK) and register type (RTYPE_MASK). The channel mask
+ is a 4-bit value of the form XYZW and is 0 if no suffix was given. */
+
+static bfd_boolean
+mips_parse_register (char **sptr, unsigned int *symval_ptr,
+ unsigned int *channels_ptr)
+{
+ char *s, *e, *m;
+ const char *q;
+ unsigned int channels, symval, bit;
+
+ /* Find end of name. */
+ s = e = *sptr;
+ if (is_name_beginner (*e))
+ ++e;
+ while (is_part_of_name (*e))
+ ++e;
+
+ channels = 0;
+ if (!mips_parse_register_1 (s, e, &symval))
+ {
+ if (!channels_ptr)
+ return FALSE;
+
+ /* Eat characters from the end of the string that are valid
+ channel suffixes. The preceding register must be $ACC or
+ end with a digit, so there is no ambiguity. */
+ bit = 1;
+ m = e;
+ for (q = "wzyx"; *q; q++, bit <<= 1)
+ if (m > s && m[-1] == *q)
+ {
+ --m;
+ channels |= bit;
+ }
+
+ if (channels == 0
+ || !mips_parse_register_1 (s, m, &symval)
+ || (symval & (RTYPE_VI | RTYPE_VF | RTYPE_R5900_ACC)) == 0)
+ return FALSE;
+ }
+
*sptr = e;
- *symval = S_GET_VALUE (symbol);
+ *symval_ptr = symval;
+ if (channels_ptr)
+ *channels_ptr = channels;
return TRUE;
}
@@ -2494,7 +2561,7 @@ reg_lookup (char **s, unsigned int types
{
unsigned int regno;
- if (mips_parse_register (s, ®no))
+ if (mips_parse_register (s, ®no, NULL))
{
if (types & RTYPE_VEC)
regno = mips_prefer_vec_regno (regno);
@@ -2514,11 +2581,32 @@ reg_lookup (char **s, unsigned int types
return regno <= RNUM_MASK;
}
+/* Parse a VU0 "x?y?z?w?" channel mask at S and store the associated
+ mask in *CHANNELS. Return a pointer to the first unconsumed character. */
+
+static char *
+mips_parse_vu0_channels (char *s, unsigned int *channels)
+{
+ unsigned int i;
+
+ *channels = 0;
+ for (i = 0; i < 4; i++)
+ if (*s == "xyzw"[i])
+ {
+ *channels |= 1 << (3 - i);
+ ++s;
+ }
+ return s;
+}
+
/* Token types for parsed operand lists. */
enum mips_operand_token_type {
/* A plain register, e.g. $f2. */
OT_REG,
+ /* A 4-bit XYZW channel mask. */
+ OT_CHANNELS,
+
/* An element of a vector, e.g. $v0[1]. */
OT_REG_ELEMENT,
@@ -2535,6 +2623,9 @@ enum mips_operand_token_type {
before OT_REGs. */
OT_CHAR,
+ /* A doubled character, either "--" or "++". */
+ OT_DOUBLE_CHAR,
+
/* The end of the operand list. */
OT_END
};
@@ -2549,6 +2640,9 @@ struct mips_operand_token
/* The register symbol value for an OT_REG. */
unsigned int regno;
+ /* The 4-bit channel mask for an OT_CHANNEL_SUFFIX. */
+ unsigned int channels;
+
/* The register symbol value and index for an OT_REG_ELEMENT. */
struct {
unsigned int regno;
@@ -2577,7 +2671,7 @@ struct mips_operand_token
int length;
} flt;
- /* The character represented by an OT_CHAR. */
+ /* The character represented by an OT_CHAR or OT_DOUBLE_CHAR. */
char ch;
} u;
};
@@ -2603,22 +2697,56 @@ mips_add_token (struct mips_operand_toke
mips_parse_base_start (char *s)
{
struct mips_operand_token token;
- unsigned int regno;
+ unsigned int regno, channels;
+ bfd_boolean decrement_p;
if (*s != '(')
return 0;
++s;
SKIP_SPACE_TABS (s);
- if (!mips_parse_register (&s, ®no))
+
+ /* Only match "--" as part of a base expression. In other contexts "--X"
+ is a double negative. */
+ decrement_p = (s[0] == '-' && s[1] == '-');
+ if (decrement_p)
+ {
+ s += 2;
+ SKIP_SPACE_TABS (s);
+ }
+
+ /* Allow a channel specifier because that leads to better error messages
+ than treating something like "$vf0x++" as an expression. */
+ if (!mips_parse_register (&s, ®no, &channels))
return 0;
token.u.ch = '(';
mips_add_token (&token, OT_CHAR);
+ if (decrement_p)
+ {
+ token.u.ch = '-';
+ mips_add_token (&token, OT_DOUBLE_CHAR);
+ }
+
token.u.regno = regno;
mips_add_token (&token, OT_REG);
+ if (channels)
+ {
+ token.u.channels = channels;
+ mips_add_token (&token, OT_CHANNELS);
+ }
+
+ /* For consistency, only match "++" as part of base expressions too. */
+ SKIP_SPACE_TABS (s);
+ if (s[0] == '+' && s[1] == '+')
+ {
+ s += 2;
+ token.u.ch = '+';
+ mips_add_token (&token, OT_DOUBLE_CHAR);
+ }
+
return s;
}
@@ -2631,7 +2759,7 @@ mips_parse_base_start (char *s)
mips_parse_argument_token (char *s, char float_format)
{
char *end, *save_in, *err;
- unsigned int regno1, regno2;
+ unsigned int regno1, regno2, channels;
struct mips_operand_token token;
/* First look for "($reg", since we want to treat that as an
@@ -2650,15 +2778,26 @@ mips_parse_argument_token (char *s, char
}
/* Handle tokens that start with a register. */
- if (mips_parse_register (&s, ®no1))
+ if (mips_parse_register (&s, ®no1, &channels))
{
+ if (channels)
+ {
+ /* A register and a VU0 channel suffix. */
+ token.u.regno = regno1;
+ mips_add_token (&token, OT_REG);
+
+ token.u.channels = channels;
+ mips_add_token (&token, OT_CHANNELS);
+ return s;
+ }
+
SKIP_SPACE_TABS (s);
if (*s == '-')
{
/* A register range. */
++s;
SKIP_SPACE_TABS (s);
- if (!mips_parse_register (&s, ®no2))
+ if (!mips_parse_register (&s, ®no2, NULL))
{
insn_error = _("Invalid register range");
return 0;
@@ -2897,6 +3036,8 @@ validate_mips_insn (const struct mips_op
}
used_bits = 0;
opno = 0;
+ if (opcode->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX)
+ used_bits = mips_insert_operand (&mips_vu0_channel_mask, used_bits, -1);
for (s = opcode->args; *s; ++s)
switch (*s)
{
@@ -2905,6 +3046,10 @@ validate_mips_insn (const struct mips_op
case ')':
break;
+ case '#':
+ s++;
+ break;
+
default:
if (!decode_operand)
operand = decode_mips16_operand (*s, FALSE);
@@ -2918,9 +3063,9 @@ validate_mips_insn (const struct mips_op
}
gas_assert (opno < MAX_OPERANDS);
operands->operand[opno] = operand;
- if (operand)
+ if (operand && operand->type != OP_VU0_MATCH_SUFFIX)
{
- used_bits |= ((1 << operand->size) - 1) << operand->lsb;
+ used_bits = mips_insert_operand (operand, used_bits, -1);
if (operand->type == OP_MDMX_IMM_REG)
/* Bit 5 is the format selector (OB vs QH). The opcode table
has separate entries for each format. */
@@ -3160,6 +3305,23 @@ md_begin (void)
reg_names_o32[i].num, /* & RNUM_MASK, */
&zero_address_frag));
+ for (i = 0; i < 32; i++)
+ {
+ char regname[7];
+
+ /* R5900 VU0 floating-point register. */
+ regname[sizeof (rename) - 1] = 0;
+ snprintf (regname, sizeof (regname) - 1, "$vf%d", i);
+ symbol_table_insert (symbol_new (regname, reg_section,
+ RTYPE_VF | i, &zero_address_frag));
+
+ /* R5900 VU0 integer register. */
+ snprintf (regname, sizeof (regname) - 1, "$vi%d", i);
+ symbol_table_insert (symbol_new (regname, reg_section,
+ RTYPE_VI | i, &zero_address_frag));
+
+ }
+
obstack_init (&mips_operand_tokens);
mips_no_prev_insn ();
@@ -3701,6 +3863,8 @@ operand_reg_mask (const struct mips_cl_i
case OP_REPEAT_DEST_REG:
case OP_REPEAT_PREV_REG:
case OP_PC:
+ case OP_VU0_SUFFIX:
+ case OP_VU0_MATCH_SUFFIX:
abort ();
case OP_REG:
@@ -4113,6 +4277,24 @@ convert_reg_type (const struct mips_opco
case OP_REG_HW:
return RTYPE_NUM;
+
+ case OP_REG_VI:
+ return RTYPE_NUM | RTYPE_VI;
+
+ case OP_REG_VF:
+ return RTYPE_NUM | RTYPE_VF;
+
+ case OP_REG_R5900_I:
+ return RTYPE_R5900_I;
+
+ case OP_REG_R5900_Q:
+ return RTYPE_R5900_Q;
+
+ case OP_REG_R5900_R:
+ return RTYPE_R5900_R;
+
+ case OP_REG_R5900_ACC:
+ return RTYPE_R5900_ACC;
}
abort ();
}
@@ -5046,6 +5228,42 @@ match_float_constant (struct mips_arg_in
return TRUE;
}
+/* OP_VU0_SUFFIX and OP_VU0_MATCH_SUFFIX matcher; MATCH_P selects between
+ them. */
+
+static bfd_boolean
+match_vu0_suffix_operand (struct mips_arg_info *arg,
+ const struct mips_operand *operand,
+ bfd_boolean match_p)
+{
+ unsigned int uval;
+
+ /* The operand can be an XYZW mask or a single 2-bit channel index
+ (with X being 0). */
+ gas_assert (operand->size == 2 || operand->size == 4);
+
+ /* The suffix can be omitted when matching a previous 4-bit mask. */
+ if (arg->token->type != OT_CHANNELS)
+ return operand->size == 4 && match_p;
+
+ uval = arg->token->u.channels;
+ if (operand->size == 2)
+ {
+ /* Check that a single bit is set and convert it into a 2-bit index. */
+ if ((uval & -uval) != uval)
+ return FALSE;
+ uval = 4 - ffs (uval);
+ }
+
+ if (match_p && insn_extract_operand (arg->insn, operand) != uval)
+ return FALSE;
+
+ ++arg->token;
+ if (!match_p)
+ insn_insert_operand (arg->insn, operand, uval);
+ return TRUE;
+}
+
/* S is the text seen for ARG. Match it against OPERAND. Return the end
of the argument text if the match is successful, otherwise return null. */
@@ -5102,6 +5320,12 @@ match_operand (struct mips_arg_info *arg
case OP_PC:
return match_pc_operand (arg);
+
+ case OP_VU0_SUFFIX:
+ return match_vu0_suffix_operand (arg, operand, FALSE);
+
+ case OP_VU0_MATCH_SUFFIX:
+ return match_vu0_suffix_operand (arg, operand, TRUE);
}
abort ();
}
@@ -9913,7 +10137,7 @@ macro (struct mips_cl_insn *ip, char *st
goto ld_st;
case M_LQC2_AB:
s = "lqc2";
- fmt = "E,o(b)";
+ fmt = "+7,o(b)";
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
@@ -10077,7 +10301,7 @@ macro (struct mips_cl_insn *ip, char *st
goto ld_st;
case M_SQC2_AB:
s = "sqc2";
- fmt = "E,o(b)";
+ fmt = "+7,o(b)";
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
@@ -12078,6 +12302,74 @@ mips16_macro (struct mips_cl_insn *ip)
}
}
+/* Look up instruction [START, START + LENGTH) in HASH. Record any extra
+ opcode bits in *OPCODE_EXTRA. */
+
+static struct mips_opcode *
+mips_lookup_insn (struct hash_control *hash, const char *start,
+ unsigned int length, unsigned int *opcode_extra)
+{
+ char *name, *dot, *p;
+ unsigned int mask, suffix;
+ size_t opend;
+ struct mips_opcode *insn;
+
+ /* Make a copy of the instruction so that we can fiddle with it. */
+ name = alloca (length + 1);
+ memcpy (name, start, length);
+ name[length] = '\0';
+
+ /* Look up the instruction as-is. */
+ insn = (struct mips_opcode *) hash_find (hash, name);
+ if (insn && (insn->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX) == 0)
+ return insn;
+
+ dot = strchr (name, '.');
+ if (dot && dot[1])
+ {
+ /* Try to interpret the text after the dot as a VU0 channel suffix. */
+ p = mips_parse_vu0_channels (dot + 1, &mask);
+ if (*p == 0 && mask != 0)
+ {
+ *dot = 0;
+ insn = (struct mips_opcode *) hash_find (hash, name);
+ *dot = '.';
+ if (insn && (insn->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX) != 0)
+ {
+ *opcode_extra |= mask << mips_vu0_channel_mask.lsb;
+ return insn;
+ }
+ }
+ }
+
+ if (mips_opts.micromips)
+ {
+ /* See if there's an instruction size override suffix,
+ either `16' or `32', at the end of the mnemonic proper,
+ that defines the operation, i.e. before the first `.'
+ character if any. Strip it and retry. */
+ opend = dot != NULL ? dot - name : length;
+ if (opend >= 3 && name[opend - 2] == '1' && name[opend - 1] == '6')
+ suffix = 2;
+ else if (name[opend - 2] == '3' && name[opend - 1] == '2')
+ suffix = 4;
+ else
+ suffix = 0;
+ if (suffix)
+ {
+ memcpy (name + opend - 2, name + opend, length - opend + 1);
+ insn = (struct mips_opcode *) hash_find (hash, name);
+ if (insn && (insn->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX) == 0)
+ {
+ forced_insn_length = suffix;
+ return insn;
+ }
+ }
+ }
+
+ return NULL;
+}
+
/* Assemble an instruction into its binary format. If the instruction
is a macro, set imm_expr, imm2_expr and offset_expr to the values
associated with "I", "+I" and "A" operands respectively. Otherwise
@@ -12095,16 +12387,14 @@ mips_ip (char *str, struct mips_cl_insn
struct hash_control *hash;
const char *args;
char c = 0;
- struct mips_opcode *insn;
- long opend;
- char *name;
- char *dot;
+ struct mips_opcode *first, *insn;
char format;
- long end;
+ size_t end;
const struct mips_operand *operand;
struct mips_arg_info arg;
struct mips_operand_token *tokens;
bfd_boolean optional_reg;
+ unsigned int opcode_extra;
insn_error = NULL;
@@ -12120,50 +12410,22 @@ mips_ip (char *str, struct mips_cl_insn
}
forced_insn_length = 0;
insn = NULL;
+ opcode_extra = 0;
/* We first try to match an instruction up to a space or to the end. */
for (end = 0; str[end] != '\0' && !ISSPACE (str[end]); end++)
continue;
- /* Make a copy of the instruction so that we can fiddle with it. */
- name = alloca (end + 1);
- memcpy (name, str, end);
- name[end] = '\0';
-
- for (;;)
- {
- insn = (struct mips_opcode *) hash_find (hash, name);
-
- if (insn != NULL || !mips_opts.micromips)
- break;
- if (forced_insn_length)
- break;
-
- /* See if there's an instruction size override suffix,
- either `16' or `32', at the end of the mnemonic proper,
- that defines the operation, i.e. before the first `.'
- character if any. Strip it and retry. */
- dot = strchr (name, '.');
- opend = dot != NULL ? dot - name : end;
- if (opend < 3)
- break;
- if (name[opend - 2] == '1' && name[opend - 1] == '6')
- forced_insn_length = 2;
- else if (name[opend - 2] == '3' && name[opend - 1] == '2')
- forced_insn_length = 4;
- else
- break;
- memcpy (name + opend - 2, name + opend, end - opend + 1);
- }
+ first = insn = mips_lookup_insn (hash, str, end, &opcode_extra);
if (insn == NULL)
{
insn_error = _("Unrecognized opcode");
return;
}
- if (strcmp (name, "li.s") == 0)
+ if (strcmp (insn->name, "li.s") == 0)
format = 'f';
- else if (strcmp (name, "li.d") == 0)
+ else if (strcmp (insn->name, "li.d") == 0)
format = 'd';
else
format = 0;
@@ -12184,7 +12446,7 @@ mips_ip (char *str, struct mips_cl_insn
bfd_boolean ok;
bfd_boolean more_alts;
- gas_assert (strcmp (insn->name, name) == 0);
+ gas_assert (strcmp (insn->name, first->name) == 0);
ok = is_opcode_valid (insn);
size_ok = is_size_valid (insn);
@@ -12240,6 +12502,7 @@ mips_ip (char *str, struct mips_cl_insn
offset_reloc[2] = BFD_RELOC_UNUSED;
create_insn (ip, insn);
+ ip->insn_opcode |= opcode_extra;
insn_error = NULL;
memset (&arg, 0, sizeof (arg));
arg.insn = ip;
@@ -12272,6 +12535,9 @@ mips_ip (char *str, struct mips_cl_insn
if (strcmp (args, "(b)") == 0)
args += 3;
+ if (args[0] == '+' && args[1] == 'K')
+ args += 2;
+
/* Fail the match if there were too few operands. */
if (*args)
break;
@@ -12301,6 +12567,17 @@ mips_ip (char *str, struct mips_cl_insn
continue;
break;
}
+ if (*args == '#')
+ {
+ ++args;
+ if (arg.token->type == OT_DOUBLE_CHAR
+ && arg.token->u.ch == *args)
+ {
+ ++arg.token;
+ continue;
+ }
+ break;
+ }
/* Handle special macro operands. Work out the properties of
other operands. */