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 <[email protected]>
---
 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

Reply via email to