[PATCH 6/9] Add MIPS Allegrex VFPU matrix register and instruction support

David Guillen Fandos david@davidgf.net
Sat Jun 14 08:02:20 GMT 2025
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 <david@davidgf.net>
---
 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 836b0059259..91812982b6a 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -2917,7 +2917,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[] = {
@@ -3108,6 +3113,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')
@@ -3186,6 +3197,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;
   };
@@ -6509,7 +6595,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,
@@ -6526,6 +6612,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;
@@ -6657,6 +6755,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)
@@ -6687,7 +6788,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))
@@ -6700,6 +6801,9 @@ match_vfpu_reg_operand (struct mips_arg_info *arg,
     }
   }
 
+  if (regvfpuop->transpose)
+    uval ^= 0x20;
+
   insn_insert_operand (arg->insn, operand, uval);
   ++arg->token;
 
@@ -6716,16 +6820,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 de7fa212433..5ba51c7b949 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 db4a8984cfe..184c183e615 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 c642c612a10..36823083655 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 3ea00145623..40c2af6e696 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.49.0



More information about the Binutils mailing list