[PATCH v2 2/9] Add MIPS Allegrex VFPU register names and some vector instructions
David Guillen Fandos
david@davidgf.net
Tue Jan 20 23:37:18 GMT 2026
Vector registers are named differently depending on their size (1, 2, 3
or 4 elements). They can also be grouped as rows or columns (R vs C).
Register suffixes are optional and help indicating the register size.
Signed-off-by: David Guillen Fandos <david@davidgf.net>
---
gas/config/tc-mips.c | 191 ++++++++++++++++++++++++-
gas/testsuite/gas/mips/allegrex-vfpu.d | 51 +++++++
gas/testsuite/gas/mips/allegrex-vfpu.s | 52 +++++++
include/opcode/mips.h | 28 ++++
opcodes/mips-dis.c | 57 ++++++++
opcodes/mips-formats.h | 11 ++
opcodes/mips-opc.c | 60 ++++++++
7 files changed, 445 insertions(+), 5 deletions(-)
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 4440fb7cafb..f46d81ecfa2 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -3116,6 +3116,16 @@ struct regname {
{"$ac2", RTYPE_ACC | 2}, \
{"$ac3", RTYPE_ACC | 3}
+/* Register shapes for VFPU registers. */
+enum mips_vfpu_reg_shape {
+ /* A vector register, number of elements from 1 to 4. */
+ VFPU_REG_SHAPE_VECTOR_1,
+ VFPU_REG_SHAPE_VECTOR_2,
+ VFPU_REG_SHAPE_VECTOR_3,
+ VFPU_REG_SHAPE_VECTOR_4,
+ VFPU_REG_SHAPE_VECTOR_UNKNOWN
+};
+
static const struct regname reg_names[] = {
GENERIC_REGISTER_NUMBERS,
FPU_REGISTER_NAMES,
@@ -3314,6 +3324,108 @@ mips_parse_vu0_channels (char *s, unsigned int *channels)
return s;
}
+/* Try to parse a VFPU register and fill its shape (if specified). */
+static bool
+mips_vfpu_parse_register (char **sptr, unsigned int *regval,
+ enum mips_vfpu_reg_shape *regshape)
+{
+ char *s = *sptr;
+ char regtype = TOLOWER(*s++);
+ unsigned int suffix = 0;
+ unsigned int m, c, r;
+
+ static const enum mips_vfpu_reg_shape vecsz[] = {
+ VFPU_REG_SHAPE_VECTOR_UNKNOWN,
+ VFPU_REG_SHAPE_VECTOR_1, VFPU_REG_SHAPE_VECTOR_2,
+ VFPU_REG_SHAPE_VECTOR_3, VFPU_REG_SHAPE_VECTOR_4
+ };
+
+ if (s[0] < '0' || s[0] > '7' ||
+ s[1] < '0' || s[1] > '3' ||
+ s[2] < '0' || s[2] > '3')
+ return false;
+
+ m = *s++ - '0';
+ c = *s++ - '0';
+ r = *s++ - '0';
+
+ /* Try to parse suffix (.s/.p/.t/.q). */
+ if (*s == '.') {
+ s++;
+ switch (*s++) {
+ case 's': suffix = 1; break;
+ case 'p': suffix = 2; break;
+ case 't': suffix = 3; break;
+ case 'q': suffix = 4; break;
+ default:
+ return false;
+ };
+ }
+
+ if ((regtype == 's' && suffix > 1) ||
+ (regtype != 's' && suffix == 1))
+ return false;
+
+ switch (regtype) {
+ case 's':
+ *regval = c + m * 4 + r * 32;
+ *regshape = VFPU_REG_SHAPE_VECTOR_1;
+ break;
+
+ case 'c':
+ switch (r) {
+ case 0:
+ *regval = c + m * 4;
+ *regshape = vecsz[suffix];
+ break;
+ case 1:
+ if (suffix && suffix != 3)
+ return false;
+ *regval = c + m * 4 + 64;
+ *regshape = VFPU_REG_SHAPE_VECTOR_3;
+ break;
+ case 2:
+ if (suffix && suffix != 2)
+ return false;
+ *regval = c + m * 4 + 64;
+ *regshape = VFPU_REG_SHAPE_VECTOR_2;
+ break;
+ default:
+ return false;
+ };
+ break;
+
+ case 'r':
+ switch (c) {
+ case 0:
+ *regval = r + m * 4 + 32;
+ *regshape = vecsz[suffix];
+ break;
+ case 1:
+ if (suffix && suffix != 3)
+ return false;
+ *regval = r + m * 4 + 96;
+ *regshape = VFPU_REG_SHAPE_VECTOR_3;
+ break;
+ case 2:
+ if (suffix && suffix != 2)
+ return false;
+ *regval = r + m * 4 + 96;
+ *regshape = VFPU_REG_SHAPE_VECTOR_2;
+ break;
+ default:
+ return false;
+ };
+ break;
+
+ default:
+ return false;
+ };
+
+ *sptr = s;
+ return true;
+}
+
/* Token types for parsed operand lists. */
enum mips_operand_token_type {
/* A plain register, e.g. $f2. */
@@ -3331,6 +3443,9 @@ enum mips_operand_token_type {
/* A continuous range of registers, e.g. $s0-$s4. */
OT_REG_RANGE,
+ /* A VFPU register, eg. S000.s. */
+ OT_REG_VFPU,
+
/* A (possibly relocated) expression. */
OT_INTEGER,
@@ -3370,6 +3485,12 @@ struct mips_operand_token
unsigned int regno2;
} reg_range;
+ /* The register symbol value for an OT_REG_VFPU and its shape. */
+ struct {
+ unsigned int regno;
+ enum mips_vfpu_reg_shape shape;
+ } reg_vfpu;
+
/* The value of an OT_INTEGER. The value is represented as an
expression and the relocation operators that were applied to
that expression. The reloc entries are BFD_RELOC_UNUSED if no
@@ -3471,7 +3592,8 @@ mips_parse_base_start (char *s)
mips_parse_arguments. */
static char *
-mips_parse_argument_token (char *s, char float_format)
+mips_parse_argument_token (char *s, char float_format,
+ const struct mips_opcode *mo)
{
char *end, *save_in;
const char *err;
@@ -3493,6 +3615,15 @@ mips_parse_argument_token (char *s, char float_format)
return s;
}
+ /* Handle VFPU registers. */
+ if ((mo->membership & INSN_ALLEGREX)
+ && mips_vfpu_parse_register (&s, ®no1, &token.u.reg_vfpu.shape))
+ {
+ token.u.reg_vfpu.regno = regno1;
+ mips_add_token (&token, OT_REG_VFPU);
+ return s;
+ }
+
/* Handle tokens that start with a register. */
if (mips_parse_register (&s, ®no1, &channels))
{
@@ -3601,14 +3732,14 @@ mips_parse_argument_token (char *s, char float_format)
must obstack_free the list after use. */
static struct mips_operand_token *
-mips_parse_arguments (char *s, char float_format)
+mips_parse_arguments (char *s, char float_format, const struct mips_opcode *mo)
{
struct mips_operand_token token;
SKIP_SPACE_TABS (s);
while (*s)
{
- s = mips_parse_argument_token (s, float_format);
+ s = mips_parse_argument_token (s, float_format, mo);
if (!s)
{
obstack_free (&mips_operand_tokens,
@@ -3830,6 +3961,9 @@ validate_mips_insn (const struct mips_opcode *opcode,
/* Skip prefix characters. */
if (decode_operand && (*s == '+' || *s == 'm' || *s == '-'))
++s;
+ if (decode_operand && (*s == '?'))
+ s += 2;
+
opno += 1;
break;
}
@@ -4964,6 +5098,7 @@ operand_reg_mask (const struct mips_cl_insn *insn,
case OP_PC:
case OP_VU0_SUFFIX:
case OP_VU0_MATCH_SUFFIX:
+ case OP_VFPU_REG:
case OP_IMM_INDEX:
abort ();
@@ -6548,6 +6683,47 @@ match_vu0_suffix_operand (struct mips_arg_info *arg,
return true;
}
+/* Matches VFPU register operands. */
+static bfd_boolean
+match_vfpu_reg_operand (struct mips_arg_info *arg,
+ const struct mips_operand *operand)
+{
+ const struct mips_vfpu_reg_operand *regvfpuop;
+ enum mips_vfpu_reg_shape rshape;
+ unsigned int uval = arg->token->u.reg_vfpu.regno;
+
+ /* Validate register type, to ensure we use the right register prefix */
+ static const struct {
+ enum mips_vfpu_reg_shape gen, spc;
+ const char *errmsg;
+ } val_shap[] = {
+ { VFPU_REG_SHAPE_VECTOR_1, VFPU_REG_SHAPE_VECTOR_1, "single" },
+ { VFPU_REG_SHAPE_VECTOR_UNKNOWN, VFPU_REG_SHAPE_VECTOR_2, "pair" },
+ { VFPU_REG_SHAPE_VECTOR_UNKNOWN, VFPU_REG_SHAPE_VECTOR_3, "triple" },
+ { VFPU_REG_SHAPE_VECTOR_UNKNOWN, VFPU_REG_SHAPE_VECTOR_4, "quad" },
+ };
+
+ if (arg->token->type != OT_REG_VFPU || uval >= 128)
+ return false;
+
+ rshape = arg->token->u.reg_vfpu.shape;
+ regvfpuop = (struct mips_vfpu_reg_operand*)operand;
+
+ if (rshape != val_shap[regvfpuop->rsize].gen &&
+ rshape != val_shap[regvfpuop->rsize].spc)
+ {
+ set_insn_error_ss(arg->argnum,
+ "Invalid VFPU register size: a %s %s is required",
+ val_shap[regvfpuop->rsize].errmsg, "register");
+ return false;
+ }
+
+ insn_insert_operand (arg->insn, operand, uval);
+
+ ++arg->token;
+ return true;
+}
+
/* Try to match a token from ARG against OPERAND. Consume the token
and return true on success, otherwise return false. */
@@ -6615,6 +6791,9 @@ match_operand (struct mips_arg_info *arg,
case OP_VU0_MATCH_SUFFIX:
return match_vu0_suffix_operand (arg, operand, true);
+ case OP_VFPU_REG:
+ return match_vfpu_reg_operand (arg, operand);
+
case OP_IMM_INDEX:
return match_imm_index_operand (arg, operand);
@@ -8775,6 +8954,8 @@ match_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
/* Skip prefixes. */
if (*args == '+' || *args == 'm' || *args == '-')
args++;
+ if (*args == '?')
+ args += 2;
if (mips_optional_operand_p (operand)
&& args[1] == ','
@@ -14665,7 +14846,7 @@ mips_ip (char *str, struct mips_cl_insn *insn)
format = 'd';
else
format = 0;
- tokens = mips_parse_arguments (str + end, format);
+ tokens = mips_parse_arguments (str + end, format, first);
if (!tokens)
return;
@@ -14727,7 +14908,7 @@ mips16_ip (char *str, struct mips_cl_insn *insn)
return;
}
- tokens = mips_parse_arguments (s, 0);
+ tokens = mips_parse_arguments (s, 0, first);
if (!tokens)
return;
diff --git a/gas/testsuite/gas/mips/allegrex-vfpu.d b/gas/testsuite/gas/mips/allegrex-vfpu.d
index be6554c825e..e5fb8e13595 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu.d
+++ b/gas/testsuite/gas/mips/allegrex-vfpu.d
@@ -12,4 +12,55 @@ Disassembly of section .text:
0x0000000c ffff007b vsync 0x7b
0x00000010 ffff0320 vsync
0x00000014 ffff040d vflush
+0x00000018 606b3f00 vadd.s S000.s,S731.s,S233.s
+0x0000001c 605858f8 vadd.p R620.p,C602.p,C602.p
+0x00000020 6058d878 vadd.t R610.t,C601.t,C601.t
+0x00000024 600484a0 vadd.q R000.q,C100.q,C100.q
+0x00000028 d0474c8e vavg.p S320.s,C302.p
+0x0000002c d047cc0d vavg.t S310.s,C301.t
+0x00000030 d0478480 vavg.q S000.s,C100.q
+0x00000034 64a808ab vdot.p S231.s,C200.p,R200.p
+0x00000038 64a88869 vdot.t S213.s,C200.t,R200.t
+0x0000003c 64a888eb vdot.q S233.s,C200.q,R200.q
+0x00000040 d04660ff vfad.p S733.s,R020.p
+0x00000044 d046e07e vfad.t S723.s,R010.t
+0x00000048 d046a0df vfad.q S732.s,R000.q
+0x0000004c d00300e4 vidt.p R120.p
+0x00000050 d0038084 vidt.q C100.q
+0x00000054 6da10120 vmax.s S001.s,S010.s,S011.s
+0x00000058 6df5758e vmax.p C320.p,R521.p,R521.p
+0x0000005c 6df5b50d vmax.t C310.t,R501.t,R511.t
+0x00000060 6db5b58d vmax.q C310.q,R501.q,R501.q
+0x00000064 6d210120 vmin.s S001.s,S010.s,S011.s
+0x00000068 6d697986 vmin.p C120.p,R621.p,R221.p
+0x0000006c 6d69b905 vmin.t C110.t,R601.t,R211.t
+0x00000070 6d29b985 vmin.q C110.q,R601.q,R201.q
+0x00000074 d0002401 vmov.s S010.s,S101.s
+0x00000078 d00025c1 vmov.p C012.p,R101.p
+0x0000007c d000a541 vmov.t C011.t,R101.t
+0x00000080 d000a581 vmov.q C010.q,R101.q
+0x00000084 644a0240 vmul.s S002.s,S020.s,S222.s
+0x00000088 642408a8 vmul.p R200.p,C200.p,R100.p
+0x0000008c 64248828 vmul.t R200.t,C200.t,R100.t
+0x00000090 642488a8 vmul.q R200.q,C200.q,R100.q
+0x00000094 6f424002 vsge.s S020.s,S002.s,S022.s
+0x00000098 6f252581 vsge.p C010.p,R101.p,R101.p
+0x0000009c 6f25a501 vsge.t C010.t,R101.t,R101.t
+0x000000a0 6f25a581 vsge.q C010.q,R101.q,R101.q
+0x000000a4 d04a4002 vsgn.s S020.s,S002.s
+0x000000a8 d04a2581 vsgn.p C010.p,R101.p
+0x000000ac d04aa501 vsgn.t C010.t,R101.t
+0x000000b0 d04aa581 vsgn.q C010.q,R101.q
+0x000000b4 6fc24002 vslt.s S020.s,S002.s,S022.s
+0x000000b8 6fa52581 vslt.p C010.p,R101.p,R101.p
+0x000000bc 6fa5a501 vslt.t C010.t,R101.t,R101.t
+0x000000c0 6fa5a581 vslt.q C010.q,R101.q,R101.q
+0x000000c4 60e73f00 vsub.s S000.s,S731.s,S133.s
+0x000000c8 60c458f8 vsub.p R620.p,C602.p,C102.p
+0x000000cc 60ccd878 vsub.t R610.t,C601.t,C301.t
+0x000000d0 608884a0 vsub.q R000.q,C100.q,C200.q
+0x000000d4 d006006f vzero.s S333.s
+0x000000d8 d00600e4 vzero.p R120.p
+0x000000dc d0068028 vzero.t R200.t
+0x000000e0 d00680a8 vzero.q R200.q
\.\.\.
diff --git a/gas/testsuite/gas/mips/allegrex-vfpu.s b/gas/testsuite/gas/mips/allegrex-vfpu.s
index ca01c2b3a47..7bbe5db61b9 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu.s
+++ b/gas/testsuite/gas/mips/allegrex-vfpu.s
@@ -8,6 +8,58 @@
vsync 800
vsync 1037
+ vadd.s S000, S731, S233
+ vadd.p R620, C602, C602
+ vadd.t R610, C601, C601
+ vadd.q R000, C100, C100
+ vavg.p S320, C302
+ vavg.t S310, C301
+ vavg.q S000, C100
+ vdot.p S231, C200, R200
+ vdot.t S213, C200, R200
+ vdot.q S233, C200, R200
+ vfad.p S733, R020
+ vfad.t S723, R010
+ vfad.q S732, R000
+ vidt.p R120.p
+ vidt.q C100.q
+ vmax.s S001, S010, S011
+ vmax.p C320, R521, R521
+ vmax.t C310, R501, R511
+ vmax.q C310, R501, R501
+ vmin.s S001, S010, S011
+ vmin.p C120, R621, R221
+ vmin.t C110, R601, R211
+ vmin.q C110, R601, R201
+ vmov.s S010, S101
+ vmov.p C012, R101
+ vmov.t C011, R101
+ vmov.q C010, R101
+ vmul.s S002, S020, S222
+ vmul.p R200, C200, R100
+ vmul.t R200, C200, R100
+ vmul.q R200, C200, R100
+ vsge.s S020, S002, S022
+ vsge.p C010, R101, R101
+ vsge.t C010, R101, R101
+ vsge.q C010, R101, R101
+ vsgn.s S020, S002
+ vsgn.p C010, R101
+ vsgn.t C010, R101
+ vsgn.q C010, R101
+ vslt.s S020, S002, S022
+ vslt.p C010, R101, R101
+ vslt.t C010, R101, R101
+ vslt.q C010, R101, R101
+ vsub.s S000, S731, S133
+ vsub.p R620, C602, C102
+ vsub.t R610, C601, C301
+ vsub.q R000, C100, C200
+ vzero.s S333
+ vzero.p R120
+ vzero.t R200
+ vzero.q R200
+
# Force some (non-delay-slot) zero bytes, to make 'objdump' print ...
.align 4, 0
.space 16
diff --git a/include/opcode/mips.h b/include/opcode/mips.h
index 1edacd88499..7c177f6a283 100644
--- a/include/opcode/mips.h
+++ b/include/opcode/mips.h
@@ -168,6 +168,9 @@ enum mips_operand_type {
been set. Any suffix used here must match the previous value. */
OP_VU0_MATCH_SUFFIX,
+ /* A VFPU register. */
+ OP_VFPU_REG,
+
/* An index selected by an integer, e.g. [1]. */
OP_IMM_INDEX,
@@ -236,6 +239,17 @@ enum mips_reg_operand_type {
OP_REG_MSA_CTRL
};
+/* Enumerates the types of VFPU register. */
+enum mips_vfpu_reg_type {
+ /* Source registers. */
+ OP_VFPU_REG_S,
+ OP_VFPU_REG_T,
+
+ /* Destination registers. */
+ OP_VFPU_REG_D
+};
+
+
/* Base class for all operands. */
struct mips_operand
{
@@ -369,6 +383,20 @@ struct mips_pcrel_operand
unsigned int flip_isa_bit : 1;
};
+/* Describes a VFPU register, containing information on the addressed
+ register size as well as type. */
+struct mips_vfpu_reg_operand
+{
+ /* Encodes the offset. */
+ struct mips_operand root;
+
+ /* Register (sub)type. */
+ enum mips_vfpu_reg_type regtype;
+
+ /* Register access size. */
+ unsigned int rsize;
+};
+
/* Return true if the assembly syntax allows OPERAND to be omitted. */
static inline bool
diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c
index c0e3509a1ba..7ed84a952a4 100644
--- a/opcodes/mips-dis.c
+++ b/opcodes/mips-dis.c
@@ -1334,6 +1334,54 @@ print_vu0_channel (struct disassemble_info *info,
abort ();
}
+/* Print OP_VFPU_REG operand OPERAND, whose value is given by UVAL. */
+static void
+print_vfpu_reg (struct disassemble_info *info,
+ const struct mips_operand *operand, unsigned int uval)
+{
+ const fprintf_styled_ftype infprintf = info->fprintf_styled_func;
+ void *is = info->stream;
+ const struct mips_vfpu_reg_operand *vfpureg_op;
+
+ unsigned int rmtx = (uval >> 2) & 7; /* Matrix number. */
+ unsigned int ridx = (uval >> 0) & 3; /* Register index. */
+ unsigned int rffl = (uval >> 5) & 3; /* Register full field. */
+ unsigned int rfsl = (uval >> 6) & 1; /* Register field. */
+ unsigned int rrxc = (uval >> 5) & 1; /* Register direction. */
+
+ vfpureg_op = (const struct mips_vfpu_reg_operand *) operand;
+
+ switch (vfpureg_op->rsize) {
+ case 0:
+ infprintf (is, dis_style_register, "S%u%u%u.s", rmtx, ridx, rffl);
+ break;
+ case 1:
+ if (rrxc)
+ infprintf (is, dis_style_register, "R%d%d%d.p", rmtx, rfsl << 1, ridx);
+ else
+ infprintf (is, dis_style_register, "C%d%d%d.p", rmtx, ridx, rfsl << 1);
+ break;
+ case 2:
+ if (rrxc)
+ infprintf (is, dis_style_register, "R%d%d%d.t", rmtx, rfsl, ridx);
+ else
+ infprintf (is, dis_style_register, "C%d%d%d.t", rmtx, ridx, rfsl);
+ break;
+ case 3:
+ if (uval >= 64)
+ infprintf (is, dis_style_register, "????.q");
+ else
+ {
+ if (rrxc)
+ infprintf (is, dis_style_register, "R%d%d%d.q", rmtx, rfsl, ridx);
+ else
+ infprintf (is, dis_style_register, "C%d%d%d.q", rmtx, ridx, rfsl);
+ }
+ break;
+ }
+}
+
+
/* Record information about a register operand. */
static void
@@ -1543,6 +1591,10 @@ print_insn_arg (struct disassemble_info *info,
}
break;
+ case OP_VFPU_REG:
+ print_vfpu_reg (info, operand, uval);
+ break;
+
case OP_PERF_REG:
infprintf (is, dis_style_register, "%d", uval);
break;
@@ -1882,11 +1934,14 @@ validate_insn_args (const struct mips_opcode *opcode,
case OP_IMM_INDEX:
case OP_REG_INDEX:
case OP_SAVE_RESTORE_LIST:
+ case OP_VFPU_REG:
break;
}
}
if (*s == 'm' || *s == '+' || *s == '-')
++s;
+ if (*s == '?')
+ s += 2;
}
}
return true;
@@ -2003,6 +2058,8 @@ print_insn_args (struct disassemble_info *info,
}
if (*s == 'm' || *s == '+' || *s == '-')
++s;
+ if (*s == '?')
+ s += 2;
break;
}
}
diff --git a/opcodes/mips-formats.h b/opcodes/mips-formats.h
index aa90b2f085c..87d85e06dae 100644
--- a/opcodes/mips-formats.h
+++ b/opcodes/mips-formats.h
@@ -112,6 +112,17 @@
return &op.root; \
}
+#define VFPU_REG(SIZE, LSB, REGTYPE, REGSIZE) \
+ { \
+ static const struct mips_vfpu_reg_operand op[] = { \
+ { { OP_VFPU_REG, SIZE, LSB }, OP_VFPU_REG_##REGTYPE, 0 }, \
+ { { OP_VFPU_REG, SIZE, LSB }, OP_VFPU_REG_##REGTYPE, 1 }, \
+ { { OP_VFPU_REG, SIZE, LSB }, OP_VFPU_REG_##REGTYPE, 2 }, \
+ { { OP_VFPU_REG, SIZE, LSB }, OP_VFPU_REG_##REGTYPE, 3 }, \
+ }; \
+ return &op[REGSIZE].root; \
+ }
+
#define PCREL(SIZE, LSB, IS_SIGNED, SHIFT, ALIGN_LOG2, INCLUDE_ISA_BIT, \
FLIP_ISA_BIT) \
{ \
diff --git a/opcodes/mips-opc.c b/opcodes/mips-opc.c
index 223fb89de19..f9341c94af9 100644
--- a/opcodes/mips-opc.c
+++ b/opcodes/mips-opc.c
@@ -142,6 +142,15 @@ decode_mips_operand (const char *p)
}
break;
+ case '?':
+ switch (p[1])
+ {
+ case 'd': VFPU_REG(7, 0, D, p[2] - '0');
+ case 's': VFPU_REG(7, 8, S, p[2] - '0');
+ case 't': VFPU_REG(7, 16, T, p[2] - '0');
+ }
+ break;
+
case '<': BIT (5, 6, 0); /* (0 .. 31) */
case '>': BIT (5, 6, 32); /* (32 .. 63) */
case '%': UINT (3, 21);
@@ -668,9 +677,60 @@ const struct mips_opcode mips_builtin_opcodes[] =
{"vnop", "", 0xffff0000, 0xffffffff, CP, 0, ALX, 0, 0 },
/* Allegrex VFPU coprocessor. Redefines coprocessor 2 and 3 (and other unused opcodes). */
+{"vadd.p", "?d1,?s1,?t1", 0x60000080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vadd.q", "?d3,?s3,?t3", 0x60008080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vadd.s", "?d0,?s0,?t0", 0x60000000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vadd.t", "?d2,?s2,?t2", 0x60008000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vavg.p", "?d0,?s1", 0xd0470080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vavg.q", "?d0,?s3", 0xd0478080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vavg.t", "?d0,?s2", 0xd0478000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vdot.p", "?d0,?s1,?t1", 0x64800080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vdot.q", "?d0,?s3,?t3", 0x64808080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vdot.t", "?d0,?s2,?t2", 0x64808000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vfad.p", "?d0,?s1", 0xd0460080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vfad.q", "?d0,?s3", 0xd0468080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vfad.t", "?d0,?s2", 0xd0468000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
{"vflush", "", 0xffff040d, 0xffffffff, CP, 0, ALX, 0, 0 },
+{"vidt.p", "?d1", 0xd0030080, 0xffffff80, WR_C2, 0, ALX, 0, 0 },
+{"vidt.q", "?d3", 0xd0038080, 0xffffff80, WR_C2, 0, ALX, 0, 0 },
+{"vmax.p", "?d1,?s1,?t1", 0x6d800080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmax.q", "?d3,?s3,?t3", 0x6d808080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmax.s", "?d0,?s0,?t0", 0x6d800000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmax.t", "?d2,?s2,?t2", 0x6d808000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmin.p", "?d1,?s1,?t1", 0x6d000080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmin.q", "?d3,?s3,?t3", 0x6d008080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmin.s", "?d0,?s0,?t0", 0x6d000000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmin.t", "?d2,?s2,?t2", 0x6d008000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmov.p", "?d1,?s1", 0xd0000080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmov.q", "?d3,?s3", 0xd0008080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmov.s", "?d0,?s0", 0xd0000000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmov.t", "?d2,?s2", 0xd0008000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmul.p", "?d1,?s1,?t1", 0x64000080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmul.q", "?d3,?s3,?t3", 0x64008080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmul.s", "?d0,?s0,?t0", 0x64000000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vmul.t", "?d2,?s2,?t2", 0x64008000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vsge.p", "?d1,?s1,?t1", 0x6f000080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vsge.q", "?d3,?s3,?t3", 0x6f008080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vsge.s", "?d0,?s0,?t0", 0x6f000000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vsge.t", "?d2,?s2,?t2", 0x6f008000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vsgn.p", "?d1,?s1", 0xd04a0080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vsgn.q", "?d3,?s3", 0xd04a8080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vsgn.s", "?d0,?s0", 0xd04a0000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vsgn.t", "?d2,?s2", 0xd04a8000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vslt.p", "?d1,?s1,?t1", 0x6f800080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vslt.q", "?d3,?s3,?t3", 0x6f808080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vslt.s", "?d0,?s0,?t0", 0x6f800000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vslt.t", "?d2,?s2,?t2", 0x6f808000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vsub.p", "?d1,?s1,?t1", 0x60800080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vsub.q", "?d3,?s3,?t3", 0x60808080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vsub.s", "?d0,?s0,?t0", 0x60800000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
+{"vsub.t", "?d2,?s2,?t2", 0x60808000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 },
{"vsync", "", 0xffff0320, 0xffffffff, CP, 0, ALX, 0, 0 },
{"vsync", "i", 0xffff0000, 0xffff0000, CP, 0, ALX, 0, 0 },
+{"vzero.p", "?d1", 0xd0060080, 0xffffff80, WR_C2, 0, ALX, 0, 0 },
+{"vzero.q", "?d3", 0xd0068080, 0xffffff80, WR_C2, 0, ALX, 0, 0 },
+{"vzero.s", "?d0", 0xd0060000, 0xffffff80, WR_C2, 0, ALX, 0, 0 },
+{"vzero.t", "?d2", 0xd0068000, 0xffffff80, WR_C2, 0, ALX, 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 },
--
2.51.1
More information about the Binutils
mailing list