VFPU registers can be also addressed as matrices (2x2, 3x3 and 4x4) for
certain operations. These registers are not compatible with prefixes and
are usually quite restrictive as destination registers.

Add matrix instructions (and matrix-vector too)

Signed-off-by: David Guillen Fandos <[email protected]>
---
 gas/config/tc-mips.c                          | 120 ++++++++++++++++--
 gas/testsuite/gas/mips/allegrex-vfpu-errors.l |   8 ++
 gas/testsuite/gas/mips/allegrex-vfpu-errors.s |   9 +-
 gas/testsuite/gas/mips/allegrex-vfpu.d        |  24 ++++
 gas/testsuite/gas/mips/allegrex-vfpu.s        |  25 ++++
 include/opcode/mips.h                         |   3 +
 opcodes/mips-dis.c                            |  55 ++++++--
 opcodes/mips-formats.h                        |  40 +++---
 opcodes/mips-opc.c                            |  29 ++++-
 9 files changed, 273 insertions(+), 40 deletions(-)

diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 79afc9fc9b1..5a42bd7fc28 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -3125,7 +3125,12 @@ enum mips_vfpu_reg_shape {
   VFPU_REG_SHAPE_VECTOR_2,
   VFPU_REG_SHAPE_VECTOR_3,
   VFPU_REG_SHAPE_VECTOR_4,
-  VFPU_REG_SHAPE_VECTOR_UNKNOWN
+  VFPU_REG_SHAPE_VECTOR_UNKNOWN,
+  /* A matrix register, number of elements from 2x2 to 4x4.  */
+  VFPU_REG_SHAPE_MATRIX_2x2,
+  VFPU_REG_SHAPE_MATRIX_3x3,
+  VFPU_REG_SHAPE_MATRIX_4x4,
+  VFPU_REG_SHAPE_MATRIX_UNKNOWN
 };
 
 static const struct regname reg_names[] = {
@@ -3342,6 +3347,12 @@ mips_vfpu_parse_register (char **sptr, unsigned int 
*regval,
     VFPU_REG_SHAPE_VECTOR_3, VFPU_REG_SHAPE_VECTOR_4
   };
 
+  static const enum mips_vfpu_reg_shape mtxsz[] = {
+    VFPU_REG_SHAPE_MATRIX_UNKNOWN, VFPU_REG_SHAPE_MATRIX_UNKNOWN,
+    VFPU_REG_SHAPE_MATRIX_2x2, VFPU_REG_SHAPE_MATRIX_3x3,
+    VFPU_REG_SHAPE_MATRIX_4x4,
+  };
+
   if (s[0] < '0' || s[0] > '7' ||
       s[1] < '0' || s[1] > '3' ||
       s[2] < '0' || s[2] > '3')
@@ -3420,6 +3431,81 @@ mips_vfpu_parse_register (char **sptr, unsigned int 
*regval,
     };
     break;
 
+  case 'm':
+    switch (c + r * 4) {
+    case 0:
+      *regval = m * 4;
+      *regshape = mtxsz[suffix];
+      break;
+    case 1:
+      if (suffix && suffix != 3)
+       return false;
+      *regval = (m * 4) | 1;
+      *regshape = VFPU_REG_SHAPE_MATRIX_3x3;
+      break;
+    case 2:
+      if (suffix && suffix != 2)
+       return false;
+      *regval = (m * 4) | 2;
+      *regshape = VFPU_REG_SHAPE_MATRIX_2x2;
+      break;
+    case 4:
+    case 5:
+      if (suffix && suffix != 3)
+       return false;
+      *regval = (m * 4 + c) | 64;
+      *regshape = VFPU_REG_SHAPE_MATRIX_3x3;
+      break;
+    case 8:
+    case 10:
+      if (suffix && suffix != 2)
+       return false;
+      *regval = (m * 4 + c) | 64;
+      *regshape = VFPU_REG_SHAPE_MATRIX_2x2;
+      break;
+    default:
+      return false;
+    };
+    break;
+
+  case 'e':
+    switch (c + r * 4) {
+    case 0:
+      *regval = (m * 4) | 32;
+      *regshape = mtxsz[suffix];
+      break;
+    case 1:
+      if (suffix && suffix != 3)
+       return false;
+      *regval = (m * 4) | 96;
+      *regshape = VFPU_REG_SHAPE_MATRIX_3x3;
+      break;
+    case 2:
+      if (suffix && suffix != 2)
+       return false;
+      *regval = (m * 4) | 96;
+      *regshape = VFPU_REG_SHAPE_MATRIX_2x2;
+      break;
+    case 4:
+    case 5:
+      if (suffix && suffix != 3)
+       return false;
+      *regval = (m * 4 + c * 64) | 32 | 1;
+      *regshape = VFPU_REG_SHAPE_MATRIX_3x3;
+      break;
+    case 8:
+    case 10:
+      if (suffix && suffix != 2)
+       return false;
+      *regval = (m * 4 + c * 32) | 32 | 2;
+      *regshape = VFPU_REG_SHAPE_MATRIX_2x2;
+      break;
+
+    default:
+      return false;
+    };
+    break;
+
   default:
     return false;
   };
@@ -6825,7 +6911,7 @@ vfpu_reg_is_compat (unsigned int dst_reg, unsigned int 
dst_rsize,
                    unsigned int src_reg, unsigned int src_rsize,
                    bool accept_partial)
 {
-  static const unsigned short vreg_usage[4][16] = {
+  static const unsigned short vreg_usage[7][16] = {
   { 0x0001, 0x0010, 0x0100, 0x1000,
     0x0002, 0x0020, 0x0200, 0x2000,
     0x0004, 0x0040, 0x0400, 0x4000,
@@ -6842,6 +6928,18 @@ vfpu_reg_is_compat (unsigned int dst_reg, unsigned int 
dst_rsize,
     0x1111, 0x2222, 0x4444, 0x8888,
     0x000f, 0x00f0, 0x0f00, 0xf000,
     0x1111, 0x2222, 0x4444, 0x8888 },
+  { 0x0033, 0x0033, 0x3300, 0x3300,
+    0x0033, 0x0033, 0x00cc, 0x00cc,
+    0x00cc, 0x00cc, 0xcc00, 0xcc00,
+    0x3300, 0x3300, 0xcc00, 0xcc00 },
+  { 0x0777, 0x7770, 0x0777, 0x7770,
+    0x0777, 0x0eee, 0x0777, 0x0eee,
+    0x0eee, 0xeee0, 0x0eee, 0xeee0,
+    0x7770, 0xeee0, 0x7770, 0xeee0 },
+  { 0xffff, 0xffff, 0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff },
   };
 
   unsigned int dmtx = (dst_reg >> 2) & 7;
@@ -6973,6 +7071,9 @@ match_vfpu_reg_operand (struct mips_arg_info *arg,
     { 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" },
+    { VFPU_REG_SHAPE_MATRIX_UNKNOWN, VFPU_REG_SHAPE_MATRIX_2x2, "2x2 matrix" },
+    { VFPU_REG_SHAPE_MATRIX_UNKNOWN, VFPU_REG_SHAPE_MATRIX_3x3, "3x3 matrix" },
+    { VFPU_REG_SHAPE_MATRIX_UNKNOWN, VFPU_REG_SHAPE_MATRIX_4x4, "4x4 matrix" },
   };
 
   if (arg->token->type != OT_REG_VFPU || uval >= 128)
@@ -7003,7 +7104,7 @@ match_vfpu_reg_operand (struct mips_arg_info *arg,
   {
     /* The destination register could be incompatible with source regs.  */
     unsigned int dreg = arg->dest_regno & 0x7f;
-    unsigned int drsize = (arg->dest_regno >> 8) & 3;
+    unsigned int drsize = (arg->dest_regno >> 8) & 7;
     bool canpartial = arg->dest_regno & 0x8000;
 
     if (!vfpu_reg_is_compat (dreg, drsize, uval, regvfpuop->rsize, canpartial))
@@ -7016,6 +7117,9 @@ match_vfpu_reg_operand (struct mips_arg_info *arg,
     }
   }
 
+  if (regvfpuop->transpose)
+    uval ^= 0x20;
+
   insn_insert_operand (arg->insn, operand, uval);
   ++arg->token;
 
@@ -7032,16 +7136,16 @@ match_vfpu_reg_operand (struct mips_arg_info *arg,
                          rtype == OP_VFPU_REG_T ? "vpfxt" : "vpfxd";
     bool pfx_lim = regvfpuop->pfxcompat == OP_VFPU_PFXCOMPAT_LIMITED;
 
-    if (regvfpuop->rsize + 1 != arg->token->u.pfx_vfpu.num_chs)
+    if (regvfpuop->pfxcompat == OP_VFPU_PFXCOMPAT_NONE)
     {
-      set_insn_error (arg->argnum, _("invalid number of prefix elements"));
+      set_insn_error_ss(arg->argnum, "no prefixes allowed for %s-%s",
+                       &pfxmemo[4], "register");
       return false;
     }
 
-    if (regvfpuop->pfxcompat == OP_VFPU_PFXCOMPAT_NONE)
+    if (regvfpuop->rsize + 1 != arg->token->u.pfx_vfpu.num_chs)
     {
-      set_insn_error_ss(arg->argnum, "no prefixes allowed for %s-%s",
-                       &pfxmemo[4], "register");
+      set_insn_error (arg->argnum, _("invalid number of prefix elements"));
       return false;
     }
 
diff --git a/gas/testsuite/gas/mips/allegrex-vfpu-errors.l 
b/gas/testsuite/gas/mips/allegrex-vfpu-errors.l
index 0c113567857..918979627d5 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu-errors.l
+++ b/gas/testsuite/gas/mips/allegrex-vfpu-errors.l
@@ -58,3 +58,11 @@
 .*:60: Error: Invalid dest and target register overlap \(identical overlap is 
allowed\) `vdiv.q C000,C000,R000'
 .*:61: Error: Invalid dest and source register overlap \(no overlap is 
allowed\) `vcrsp.t R000,R000,R100'
 .*:62: Error: Invalid dest and source register overlap \(no overlap is 
allowed\) `vqmul.q R000,R000,R100'
+.*:63: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vmmov.p M000,E000'
+.*:64: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vmmov.t M000,M011'
+.*:65: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vmmov.q M000,E000'
+.*:66: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vmscl.p M000,E000,S100'
+.*:67: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vmscl.t M000,M011,S100'
+.*:68: Error: Invalid dest and source register overlap \(identical overlap is 
allowed\) `vmscl.q M000,E000,S100'
+.*:69: Error: Invalid dest and source register overlap \(no overlap is 
allowed\) `vtfm2.p R000,M000,R200'
+.*:70: Error: Invalid dest and target register overlap \(no overlap is 
allowed\) `vtfm2.p R000,M200,R000'
diff --git a/gas/testsuite/gas/mips/allegrex-vfpu-errors.s 
b/gas/testsuite/gas/mips/allegrex-vfpu-errors.s
index 25193f0ac4a..5d3bbb59375 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu-errors.s
+++ b/gas/testsuite/gas/mips/allegrex-vfpu-errors.s
@@ -60,7 +60,14 @@
        vdiv.q C000, C000, R000
        vcrsp.t R000, R000, R100
        vqmul.q R000, R000, R100
-
+       vmmov.p M000, E000
+       vmmov.t M000, M011
+       vmmov.q M000, E000
+       vmscl.p M000, E000, S100
+       vmscl.t M000, M011, S100
+       vmscl.q M000, E000, S100
+       vtfm2.p R000, M000, R200
+       vtfm2.p R000, M200, R000
 
 # Force some (non-delay-slot) zero bytes, to make 'objdump' print ...
        .align  4, 0
diff --git a/gas/testsuite/gas/mips/allegrex-vfpu.d 
b/gas/testsuite/gas/mips/allegrex-vfpu.d
index 277b65707f7..b6cb66d5f8c 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu.d
+++ b/gas/testsuite/gas/mips/allegrex-vfpu.d
@@ -179,4 +179,28 @@ Disassembly of section .text:
 0x000002a8 d01664e4    vsqrt.p R120.p,R120.p
 0x000002ac d016e464    vsqrt.t R110.t,R110.t
 0x000002b0 d016a4a4    vsqrt.q R100.q,R100.q
+0x000002b4 f3860082    vmzero.p        M020.p
+0x000002b8 f3868020    vmzero.t        E000.t
+0x000002bc f3868080    vmzero.q        M000.q
+0x000002c0 f38300ea    vmidt.p E222.p
+0x000002c4 f3838008    vmidt.t M200.t
+0x000002c8 f38380a8    vmidt.q E200.q
+0x000002cc f38700cc    vmone.p M302.p
+0x000002d0 f387802c    vmone.t E300.t
+0x000002d4 f387808c    vmone.q M300.q
+0x000002d8 f3804280    vmmov.p M000.p,M022.p
+0x000002dc f3808000    vmmov.t M000.t,M000.t
+0x000002e0 f380a480    vmmov.q M000.q,E100.q
+0x000002e4 f2046280    vmscl.p M000.p,E022.p,S100.s
+0x000002e8 f27f8400    vmscl.t M000.t,M100.t,S733.s
+0x000002ec f2168880    vmscl.q M000.q,M200.q,S520.s
+0x000002f0 f0422280    vmmul.p M000.p,M020.p,M022.p
+0x000002f4 f008a400    vmmul.t M000.t,M100.t,M200.t
+0x000002f8 f008a480    vmmul.q M000.q,M100.q,M200.q
+0x000002fc f0a804e8    vtfm2.p R220.p,M100.p,R200.p
+0x00000300 f1288400    vtfm3.t C000.t,M100.t,R200.t
+0x00000304 f1a88480    vtfm4.q C000.q,M100.q,R200.q
+0x00000308 f0a80468    vhtfm2.p        R220.p,M100.p,R200.p
+0x0000030c f1280480    vhtfm3.t        C000.t,M100.t,R200.t
+0x00000310 f1a88400    vhtfm4.q        C000.q,M100.q,R200.q
        \.\.\.
diff --git a/gas/testsuite/gas/mips/allegrex-vfpu.s 
b/gas/testsuite/gas/mips/allegrex-vfpu.s
index 1bba03ca974..f649b53d00a 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu.s
+++ b/gas/testsuite/gas/mips/allegrex-vfpu.s
@@ -166,6 +166,31 @@
        vsqrt.t R110, R110
        vsqrt.q R100, R100
 
+       vmzero.p M020
+       vmzero.t E000
+       vmzero.q M000
+       vmidt.p E222
+       vmidt.t M200
+       vmidt.q E200
+       vmone.p M302
+       vmone.t E300
+       vmone.q M300
+       vmmov.p M000, M022
+       vmmov.t M000, M000
+       vmmov.q M000, E100
+       vmscl.p M000, E022, S100
+       vmscl.t M000, M100, S733
+       vmscl.q M000, M200, S520
+       vmmul.p M000, M020, M022
+       vmmul.t M000, M100, M200
+       vmmul.q M000, M100, M200
+       vtfm2.p R220, M100, R200
+       vtfm3.t C000, M100, R200
+       vtfm4.q C000, M100, R200
+       vhtfm2.p R220, M100, R200
+       vhtfm3.t C000, M100, R200
+       vhtfm4.q C000, M100, 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 b90f8ea33f7..e21096cfc0b 100644
--- a/include/opcode/mips.h
+++ b/include/opcode/mips.h
@@ -420,6 +420,9 @@ struct mips_vfpu_reg_operand
   /* Register (sub)type.  */
   enum mips_vfpu_reg_type regtype;
 
+  /* Register modifiers.  */
+  bool transpose;
+
   /* Register access size.  */
   unsigned int rsize;
 
diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c
index 278e09d0f76..0252f23d130 100644
--- a/opcodes/mips-dis.c
+++ b/opcodes/mips-dis.c
@@ -1337,21 +1337,19 @@ print_vu0_channel (struct disassemble_info *info,
 /* 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 struct mips_vfpu_reg_operand *vfpuop, 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.  */
+  unsigned int regn = vfpuop->transpose ?  uval ^ 0x20 : uval;
 
-  vfpureg_op = (const struct mips_vfpu_reg_operand *) operand;
+  unsigned int rmtx = (regn >> 2) & 7;  /* Matrix number.  */
+  unsigned int ridx = (regn >> 0) & 3;  /* Register index.  */
+  unsigned int rffl = (regn >> 5) & 3;  /* Register full field.  */
+  unsigned int rfsl = (regn >> 6) & 1;  /* Register field.  */
+  unsigned int rrxc = (regn >> 5) & 1;  /* Register direction.  */
 
-  switch (vfpureg_op->rsize) {
+  switch (vfpuop->rsize) {
     case 0:
       infprintf (is, dis_style_register, "S%u%u%u.s", rmtx, ridx, rffl);
       break;
@@ -1368,7 +1366,7 @@ print_vfpu_reg (struct disassemble_info *info,
        infprintf (is, dis_style_register, "C%d%d%d.t", rmtx, ridx, rfsl);
       break;
     case 3:
-      if (uval >= 64)
+      if (regn >= 64)
        infprintf (is, dis_style_register, "????.q");
       else
       {
@@ -1378,6 +1376,39 @@ print_vfpu_reg (struct disassemble_info *info,
          infprintf (is, dis_style_register, "C%d%d%d.q", rmtx, ridx, rfsl);
       }
       break;
+    case 4:
+      if (regn & 1)
+       infprintf (is, dis_style_register, "????.p");
+      else
+      {
+       if (rrxc)
+         infprintf (is, dis_style_register, "E%d%d%d.p", rmtx, rfsl<<1, ridx);
+       else
+         infprintf (is, dis_style_register, "M%d%d%d.p", rmtx, ridx, rfsl<<1);
+      }
+      break;
+    case 5:
+      if (regn & 2)
+       infprintf (is, dis_style_register, "????.t");
+      else
+      {
+       if (rrxc)
+         infprintf (is, dis_style_register, "E%d%d%d.t", rmtx, rfsl, ridx);
+       else
+         infprintf (is, dis_style_register, "M%d%d%d.t", rmtx, ridx, rfsl);
+      }
+      break;
+    case 6:
+      if (regn >= 64 || (regn & 3))
+       infprintf (is, dis_style_register, "????.q");
+      else
+      {
+       if (rrxc)
+         infprintf (is, dis_style_register, "E%d00.q", rmtx);
+       else
+         infprintf (is, dis_style_register, "M%d00.q", rmtx);
+      }
+      break;
   }
 }
 
@@ -1642,7 +1673,7 @@ print_insn_arg (struct disassemble_info *info,
       break;
 
     case OP_VFPU_REG:
-      print_vfpu_reg (info, operand, uval);
+      print_vfpu_reg (info, (struct mips_vfpu_reg_operand*)operand, uval);
       break;
 
     case OP_VFPU_PFX:
diff --git a/opcodes/mips-formats.h b/opcodes/mips-formats.h
index 9d91d83b730..53e8698e933 100644
--- a/opcodes/mips-formats.h
+++ b/opcodes/mips-formats.h
@@ -112,44 +112,50 @@
     return &op.root; \
   }
 
-#define VFPU_REGEXP(OP, SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, REG_COMPAT) \
+#define VFPU_REGEXP(OP, SIZE, LSB, RTYPE, RXC_FLIP, RSIZE, PCOMPAT, RCOMPAT) \
   { \
     static const struct mips_vfpu_reg_operand op[] = { \
-      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, 0, \
-       OP_VFPU_PFXCOMPAT_##PFX_COMPAT, OP_VFPU_REGCOMPAT_##REG_COMPAT}, \
-      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, 1, \
-       OP_VFPU_PFXCOMPAT_##PFX_COMPAT, OP_VFPU_REGCOMPAT_##REG_COMPAT}, \
-      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, 2, \
-       OP_VFPU_PFXCOMPAT_##PFX_COMPAT, OP_VFPU_REGCOMPAT_##REG_COMPAT}, \
-      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, 3, \
-       OP_VFPU_PFXCOMPAT_##PFX_COMPAT, OP_VFPU_REGCOMPAT_##REG_COMPAT}, \
+      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, RXC_FLIP, 0, \
+       OP_VFPU_PFXCOMPAT_##PCOMPAT, OP_VFPU_REGCOMPAT_##RCOMPAT}, \
+      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, RXC_FLIP, 1, \
+       OP_VFPU_PFXCOMPAT_##PCOMPAT, OP_VFPU_REGCOMPAT_##RCOMPAT}, \
+      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, RXC_FLIP, 2, \
+       OP_VFPU_PFXCOMPAT_##PCOMPAT, OP_VFPU_REGCOMPAT_##RCOMPAT}, \
+      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, RXC_FLIP, 3, \
+       OP_VFPU_PFXCOMPAT_##PCOMPAT, OP_VFPU_REGCOMPAT_##RCOMPAT}, \
+      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, RXC_FLIP, 4, \
+       OP_VFPU_PFXCOMPAT_##PCOMPAT, OP_VFPU_REGCOMPAT_##RCOMPAT}, \
+      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, RXC_FLIP, 5, \
+       OP_VFPU_PFXCOMPAT_##PCOMPAT, OP_VFPU_REGCOMPAT_##RCOMPAT}, \
+      { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, RXC_FLIP, 6, \
+       OP_VFPU_PFXCOMPAT_##PCOMPAT, OP_VFPU_REGCOMPAT_##RCOMPAT}, \
     }; \
     return &op[RSIZE].root; \
   }
 
-#define VFPU_REG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, REG_COMPAT) \
+#define VFPU_REG(SIZE, LSB, RTYPE, RXCFL, RSIZE, PFX_COMPAT, REG_COMPAT) \
   { \
     switch (PFX_COMPAT) \
     { \
       case 'a': \
-       VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, ALL, REG_COMPAT) \
+       VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RXCFL, RSIZE, ALL, REG_COMPAT) \
       case 'n': \
-       VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, NONE, REG_COMPAT) \
+       VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RXCFL, RSIZE, NONE, REG_COMPAT) \
       case 'l': \
-       VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, LIMITED, REG_COMPAT) \
+       VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RXCFL, RSIZE, LIMITED, REG_COMPAT) \
       default: \
        abort(); \
     } \
   }
 
-#define VFPU_SREG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT) \
-  VFPU_REG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, ALL)
+#define VFPU_SREG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, RXC_FLIP) \
+  VFPU_REG(SIZE, LSB, RTYPE, RXC_FLIP, RSIZE, PFX_COMPAT, ALL)
 
 #define VFPU_DREG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, REG_COMPAT) \
-  VFPU_REG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, REG_COMPAT)
+  VFPU_REG(SIZE, LSB, RTYPE, false, RSIZE, PFX_COMPAT, REG_COMPAT)
 
 #define VFPU_PFX(SIZE, LSB, RTYPE, RSIZE) \
-  VFPU_REGEXP(PFX, SIZE, LSB, RTYPE, RSIZE, ALL, ALL)
+  VFPU_REGEXP(PFX, SIZE, LSB, RTYPE, false, RSIZE, ALL, ALL)
 
 #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 847ad0f30e5..0a82435c955 100644
--- a/opcodes/mips-opc.c
+++ b/opcodes/mips-opc.c
@@ -145,8 +145,9 @@ decode_mips_operand (const char *p)
     case '?':
       switch (p[1])
        {
-       case 's': VFPU_SREG(7,  8, S, p[2] - '0', p[3]);
-       case 't': VFPU_SREG(7, 16, T, p[2] - '0', p[3]);
+       case 's': VFPU_SREG(7,  8, S, p[2] - '0', p[3], false);
+       case 'S': VFPU_SREG(7,  8, S, p[2] - '0', p[3], true);
+       case 't': VFPU_SREG(7, 16, T, p[2] - '0', p[3], false);
        case 'd': VFPU_DREG(7,  0, D, p[2] - '0', p[3], ALL);
        case 'D': VFPU_DREG(7,  0, D, p[2] - '0', p[3], SAME);
        case 'i': VFPU_DREG(7,  0, D, p[2] - '0', p[3], NONE);
@@ -729,6 +730,9 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"vfad.q",             "?d0a,?s3a",      0xd0468080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vfad.t",             "?d0a,?s2a",      0xd0468000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vflush",             "",               0xffff040d, 0xffffffff,       CP,     
        0,              ALX,            0,      0 },
+{"vhtfm2.p",           "?i1n,?s4n,?t1n", 0xf0800000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vhtfm3.t",           "?i2n,?s5n,?t2n", 0xf1000080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vhtfm4.q",           "?i3n,?s6n,?t3n", 0xf1808000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vi2us.p",            "?d0l,?s1l",      0xd03e0080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vi2us.q",            "?d1l,?s3l",      0xd03e8080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vidt.p",             "?d1a",           0xd0030080, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
@@ -741,18 +745,36 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"vmax.q",             "?d3a,?s3a,?t3a", 0x6d808080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmax.s",             "?d0a,?s0a,?t0a", 0x6d800000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmax.t",             "?d2a,?s2a,?t2a", 0x6d808000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vmidt.p",            "?d4n",           0xf3830080, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
+{"vmidt.q",            "?d6n",           0xf3838080, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
+{"vmidt.t",            "?d5n",           0xf3838000, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
 {"vmin.p",             "?d1a,?s1a,?t1a", 0x6d000080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmin.q",             "?d3a,?s3a,?t3a", 0x6d008080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmin.s",             "?d0a,?s0a,?t0a", 0x6d000000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmin.t",             "?d2a,?s2a,?t2a", 0x6d008000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vmmov.p",            "?D4n,?s4n",      0xf3800080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vmmov.q",            "?D6n,?s6n",      0xf3808080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vmmov.t",            "?D5n,?s5n",      0xf3808000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vmmul.p",            "?i4n,?S4n,?t4n", 0xf0000080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vmmul.q",            "?i6n,?S6n,?t6n", 0xf0008080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vmmul.t",            "?i5n,?S5n,?t5n", 0xf0008000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vmone.p",            "?d4n",           0xf3870080, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
+{"vmone.q",            "?d6n",           0xf3878080, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
+{"vmone.t",            "?d5n",           0xf3878000, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
 {"vmov.p",             "?d1a,?s1a",      0xd0000080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmov.q",             "?d3a,?s3a",      0xd0008080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmov.s",             "?d0a,?s0a",      0xd0000000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmov.t",             "?d2a,?s2a",      0xd0008000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vmscl.p",            "?D4n,?s4n,?t0n", 0xf2000080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vmscl.q",            "?D6n,?s6n,?t0n", 0xf2008080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vmscl.t",            "?D5n,?s5n,?t0n", 0xf2008000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmul.p",             "?d1a,?s1a,?t1a", 0x64000080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmul.q",             "?d3a,?s3a,?t3a", 0x64008080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmul.s",             "?d0a,?s0a,?t0a", 0x64000000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vmul.t",             "?d2a,?s2a,?t2a", 0x64008000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vmzero.p",           "?d4n",           0xf3860080, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
+{"vmzero.q",           "?d6n",           0xf3868080, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
+{"vmzero.t",           "?d5n",           0xf3868000, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
 {"vneg.p",             "?d1a,?s1l",      0xd0020080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vneg.q",             "?d3a,?s3l",      0xd0028080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vneg.s",             "?d0a,?s0l",      0xd0020000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
@@ -833,6 +855,9 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"vt4444.q",           "?d1n,?s3l",      0xd0598080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vt5551.q",           "?d1n,?s3l",      0xd05a8080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vt5650.q",           "?d1n,?s3l",      0xd05b8080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vtfm2.p",            "?i1n,?s4n,?t1n", 0xf0800080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vtfm3.t",            "?i2n,?s5n,?t2n", 0xf1008000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vtfm4.q",            "?i3n,?s6n,?t3n", 0xf1808080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vzero.p",            "?d1a",           0xd0060080, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
 {"vzero.q",            "?d3a",           0xd0068080, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
 {"vzero.s",            "?d0a",           0xd0060000, 0xffffff80,       WR_C2,  
        0,              ALX,            0,      0 },
-- 
2.51.1

Reply via email to