[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, &regno1, &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, &regno1, &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