Adds move instructions from/to coprocessor registers as well as compare
instructions (that also update certain coprocessor registers). Add a
special move-constant instruction that loads well-known values.

These instructions require parsing some built-in string constants, such
as the comparison condition codes or the constant value names.

Signed-off-by: David Guillen Fandos <[email protected]>
---
 gas/config/tc-mips.c                          | 93 ++++++++++++++++++-
 gas/testsuite/gas/mips/allegrex-vfpu-errors.l |  6 ++
 gas/testsuite/gas/mips/allegrex-vfpu-errors.s |  6 ++
 gas/testsuite/gas/mips/allegrex-vfpu.d        | 14 +++
 gas/testsuite/gas/mips/allegrex-vfpu.s        | 15 +++
 include/opcode/mips.h                         | 13 ++-
 opcodes/mips-dis.c                            | 30 ++++++
 opcodes/mips-opc.c                            | 23 +++++
 8 files changed, 197 insertions(+), 3 deletions(-)

diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 3541179caf8..64e6ed78bee 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -2709,6 +2709,7 @@ struct regname {
 #define RTYPE_R5900_R  0x0200000
 #define RTYPE_R5900_ACC        0x0400000
 #define RTYPE_MSA      0x0800000
+#define RTYPE_VFPUCC   0x1000000
 #define RWARN          0x8000000
 
 #define GENERIC_REGISTER_NUMBERS \
@@ -3118,6 +3119,24 @@ struct regname {
     {"$ac2",   RTYPE_ACC | 2}, \
     {"$ac3",   RTYPE_ACC | 3}
 
+#define VFPU_COPROCESSOR_NUMBERS \
+    {"$128",   RTYPE_VFPUCC | 128},  \
+    {"$129",   RTYPE_VFPUCC | 129},  \
+    {"$130",   RTYPE_VFPUCC | 130},  \
+    {"$131",   RTYPE_VFPUCC | 131},  \
+    {"$132",   RTYPE_VFPUCC | 132},  \
+    {"$133",   RTYPE_VFPUCC | 133},  \
+    {"$134",   RTYPE_VFPUCC | 134},  \
+    {"$135",   RTYPE_VFPUCC | 135},  \
+    {"$136",   RTYPE_VFPUCC | 136},  \
+    {"$137",   RTYPE_VFPUCC | 137},  \
+    {"$138",   RTYPE_VFPUCC | 138},  \
+    {"$139",   RTYPE_VFPUCC | 139},  \
+    {"$140",   RTYPE_VFPUCC | 140},  \
+    {"$141",   RTYPE_VFPUCC | 141},  \
+    {"$142",   RTYPE_VFPUCC | 142},  \
+    {"$143",   RTYPE_VFPUCC | 143}
+
 /* Register shapes for VFPU registers.  */
 enum mips_vfpu_reg_shape {
   /* A vector register, number of elements from 1 to 4.  */
@@ -3152,6 +3171,7 @@ static const struct regname reg_names[] = {
   R5900_R_NAMES,
   R5900_ACC_NAMES,
   MIPS_DSP_ACCUMULATOR_NAMES,
+  VFPU_COPROCESSOR_NUMBERS,
   {0, 0}
 };
 
@@ -5761,6 +5781,9 @@ convert_reg_type (const struct mips_opcode *opcode,
 
     case OP_REG_MSA_CTRL:
       return RTYPE_NUM;
+
+    case OP_REG_VFPU_CC:
+      return RTYPE_VFPUCC;
     }
   abort ();
 }
@@ -7101,7 +7124,8 @@ match_vfpu_reg_operand (struct mips_arg_info *arg,
   }
 
   if ((rtype == OP_VFPU_REG_S || rtype == OP_VFPU_REG_T)
-      && (arg->dest_regno != ILLEGAL_REG))
+      && (arg->dest_regno != ILLEGAL_REG)
+      && !(arg->insn->insn_mo->pinfo & INSN_COPROC_MOVE))
   {
     /* The destination register could be incompatible with source regs.  */
     unsigned int dreg = arg->dest_regno & 0x7f;
@@ -7166,6 +7190,32 @@ match_vfpu_reg_operand (struct mips_arg_info *arg,
   return true;
 }
 
+/* Matches named constants or constant value.  */
+static bfd_boolean
+match_vfpu_named_constant (const expressionS *exp, unsigned int *val,
+                          const char * const *strlist, unsigned int listcnt)
+{
+  if (exp->X_op == O_symbol)
+  {
+    unsigned int i;
+    for (i = 0; i < listcnt; i++)
+      if (strlist[i] && !strcmp(S_GET_NAME(exp->X_add_symbol), strlist[i]))
+      {
+       *val = i;
+       return true;
+      }
+  }
+  else if (exp->X_op == O_constant)
+  {
+    if (exp->X_add_number < listcnt)
+    {
+      *val = exp->X_add_number;
+      return true;
+    }
+  }
+  return false;
+}
+
 /* Matches VFPU immediate operands.  */
 static bfd_boolean
 match_vfpu_imm_operand (struct mips_arg_info *arg,
@@ -7212,6 +7262,47 @@ match_vfpu_imm_operand (struct mips_arg_info *arg,
        ++arg->token;
        return true;
       }
+      return false;
+
+    case OP_VFPU_COMP:
+      {
+       static const char * const cnds[16] = {
+         "FL", "EQ", "LT", "LE", "TR", "NE", "GE", "GT",
+         "EZ", "EN", "EI", "ES", "NZ", "NN", "NI", "NS"
+       };
+       if (arg->token->type == OT_INTEGER
+           && match_vfpu_named_constant (&arg->token->u.integer.value, &uval,
+                                         cnds, ARRAY_SIZE(cnds)))
+       {
+         insn_insert_operand (arg->insn, operand, uval);
+         ++arg->token;
+         return true;
+       }
+      }
+      break;
+
+    case OP_VFPU_CONST:
+      {
+       static const char * const knsts[] = {
+         NULL, "VFPU_HUGE", "VFPU_SQRT2", "VFPU_SQRT1_2",
+         "VFPU_2_SQRTPI", "VFPU_2_PI", "VFPU_1_PI", "VFPU_PI_4",
+         "VFPU_PI_2", "VFPU_PI", "VFPU_E", "VFPU_LOG2E",
+         "VFPU_LOG10E", "VFPU_LN2", "VFPU_LN10", "VFPU_2PI",
+         "VFPU_PI_6", "VFPU_LOG10TWO", "VFPU_LOG2TEN", "VFPU_SQRT3_2",
+         NULL, NULL, NULL, NULL,
+         NULL, NULL, NULL, NULL,
+         NULL, NULL, NULL, NULL,
+       };
+       if (arg->token->type == OT_INTEGER
+           && match_vfpu_named_constant (&arg->token->u.integer.value, &uval,
+                                         knsts, ARRAY_SIZE(knsts)))
+       {
+         insn_insert_operand (arg->insn, operand, uval);
+         ++arg->token;
+         return true;
+       }
+      }
+      break;
     }
 
   return false;
diff --git a/gas/testsuite/gas/mips/allegrex-vfpu-errors.l 
b/gas/testsuite/gas/mips/allegrex-vfpu-errors.l
index 79f3a199e55..a87298aa63d 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu-errors.l
+++ b/gas/testsuite/gas/mips/allegrex-vfpu-errors.l
@@ -81,3 +81,9 @@
 .*:83: Error: no prefixes allowed for s-register `vbfy2.q R000,R000\[x,x,y,y\]'
 .*:84: Error: invalid source prefix \(only swizzle allowed\) `vi2c.q 
R000,R000\[-x,-y,-z,-w\]'
 .*:85: Error: invalid source prefix \(only swizzle allowed\) `vi2uc.q 
R000,R000\[-x,-y,-z,-w\]'
+.*:86: Error: invalid operands `mfvc \$4,\$200'
+.*:87: Error: invalid operands `mtvc \$4,\$200'
+.*:88: Error: invalid operands `vmtvc \$200,S733'
+.*:89: Error: invalid operands `vcmp.q 123,C000,R000'
+.*:90: Error: invalid operands `vcmp.q foo,C000,R000'
+.*:91: Error: invalid operands `mfvc \$4,\$4'
diff --git a/gas/testsuite/gas/mips/allegrex-vfpu-errors.s 
b/gas/testsuite/gas/mips/allegrex-vfpu-errors.s
index ce8d53a2285..baa7040499b 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu-errors.s
+++ b/gas/testsuite/gas/mips/allegrex-vfpu-errors.s
@@ -83,6 +83,12 @@
        vbfy2.q R000, R000[x,x,y,y]
        vi2c.q R000, R000[-x,-y,-z,-w]
        vi2uc.q R000, R000[-x,-y,-z,-w]
+       mfvc $4,$200
+       mtvc $4,$200
+       vmtvc $200, S733
+       vcmp.q 123, C000, R000
+       vcmp.q foo, C000, R000
+       mfvc $4,$4
 
 # 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 b0c6191e61c..789e5ae6d17 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu.d
+++ b/gas/testsuite/gas/mips/allegrex-vfpu.d
@@ -275,4 +275,18 @@ Disassembly of section .text:
 0x00000428 d03a7cbc    vus2i.p R700.q,R720.p
 0x0000042c d03a1e3c    vus2i.s R700.p,S720.s
 0x00000430 d39b2e66    vwbn.s  S123.s,S321.s,0x9b
+0x00000434 48640080    mfvc    \$4,\$128
+0x00000438 4864008c    mfvc    \$4,\$140
+0x0000043c 48e40080    mtvc    \$4,\$128
+0x00000440 48e4008c    mtvc    \$4,\$140
+0x00000444 d0517f80    vmtvc   \$128,S733.s
+0x00000448 d050807f    vmfvc   S733.s,\$128
+0x0000044c d0600000    vcst.s  S000.s,0
+0x00000450 d07f8000    vcst.t  C000.t,31
+0x00000454 d06800a0    vcst.p  R000.p,VFPU_PI_2
+0x00000458 d06580a0    vcst.q  R000.q,VFPU_2_PI
+0x0000045c 6c000001    vcmp.s  EQ,S000.s,S000.s
+0x00000460 6c202082    vcmp.p  LT,R000.p,R000.p
+0x00000464 6c20a001    vcmp.t  EQ,R000.t,R000.t
+0x00000468 6c208085    vcmp.q  NE,C000.q,R000.q
        \.\.\.
diff --git a/gas/testsuite/gas/mips/allegrex-vfpu.s 
b/gas/testsuite/gas/mips/allegrex-vfpu.s
index 4299a1b020a..79d62dd3c35 100644
--- a/gas/testsuite/gas/mips/allegrex-vfpu.s
+++ b/gas/testsuite/gas/mips/allegrex-vfpu.s
@@ -264,6 +264,21 @@
        vus2i.s R700.p, S720.s
        vwbn.s S123, S321, 155
 
+       mfvc $4,$128
+       mfvc $4,$140
+       mtvc $4,$128
+       mtvc $4,$140
+       vmtvc $128, S733
+       vmfvc S733, $128
+       vcst.s S000, 0
+       vcst.t C000, 31
+       vcst.p R000, VFPU_PI_2
+       vcst.q R000, VFPU_2_PI
+       vcmp.s EQ, S000, S000
+       vcmp.p 2, R000, R000
+       vcmp.t 1, R000, R000
+       vcmp.q NE, C000, R000
+
 # 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 0d1b4b9377e..11367e2eb88 100644
--- a/include/opcode/mips.h
+++ b/include/opcode/mips.h
@@ -242,7 +242,10 @@ enum mips_reg_operand_type {
   OP_REG_MSA,
 
   /* MSA control registers $0-$31.  */
-  OP_REG_MSA_CTRL
+  OP_REG_MSA_CTRL,
+
+  /* VFPU control registers $0-$255.  */
+  OP_REG_VFPU_CC
 };
 
 /* Enumerates the types of VFPU register.  */
@@ -258,7 +261,13 @@ enum mips_vfpu_reg_type {
 /* Enumerates the types of VFPU immediates.  */
 enum mips_vfpu_imm_type {
   /* Half-float immediate (16 bit half-precision float).  */
-  OP_VFPU_FP16
+  OP_VFPU_FP16,
+
+  /* Compare condition codes.  */
+  OP_VFPU_COMP,
+
+  /* VFPU LUT constant values.  */
+  OP_VFPU_CONST
 };
 
 /* Enumerates the types of VFPU register-prefix compatibility.  */
diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c
index 6e9c5d18e30..f847ed4e8f9 100644
--- a/opcodes/mips-dis.c
+++ b/opcodes/mips-dis.c
@@ -1287,6 +1287,10 @@ print_reg (struct disassemble_info *info, const struct 
mips_opcode *opcode,
                 msa_control_names[regno]);
       break;
 
+    case OP_REG_VFPU_CC:
+      infprintf (info->stream, dis_style_register, "$%d", regno);
+      break;
+
     }
 }
 
@@ -1496,6 +1500,32 @@ print_vfpu_imm (struct disassemble_info *info,
        }
       }
       break;
+
+    case OP_VFPU_COMP:
+      {
+       static const char * const cnames[16] = {
+         "FL", "EQ", "LT", "LE", "TR", "NE", "GE", "GT",
+         "EZ", "EN", "EI", "ES", "NZ", "NN", "NI", "NS"
+       };
+       infprintf (is, dis_style_immediate, "%s", cnames[uval]);
+      }
+      break;
+
+    case OP_VFPU_CONST:
+      {
+       static const char * const knames[] = {
+         "HUGE", "SQRT2", "SQRT1_2",
+         "2_SQRTPI", "2_PI", "1_PI", "PI_4",
+         "PI_2", "PI", "E", "LOG2E",
+         "LOG10E", "LN2", "LN10", "2PI",
+         "PI_6", "LOG10TWO", "LOG2TEN", "SQRT3_2"
+       };
+       if (uval >= 1 && uval <= 19)
+         infprintf (is, dis_style_immediate, "VFPU_%s", knames[uval - 1]);
+       else
+         infprintf (is, dis_style_immediate, "%d", uval);
+      }
+      break;
     }
 }
 
diff --git a/opcodes/mips-opc.c b/opcodes/mips-opc.c
index ab45735e20c..dd480a2a508 100644
--- a/opcodes/mips-opc.c
+++ b/opcodes/mips-opc.c
@@ -164,11 +164,21 @@ decode_mips_operand (const char *p)
          switch (p[2])
          {
            case 'f': VFPU_IMM(16, 0, FP16);
+           case 'c': VFPU_IMM(4, 0, COMP);
+           case 'k': VFPU_IMM(5, 16, CONST);
            case 's': UINT(5, 16);
            case 'e': HINT(8, 16);
            default:
              abort();
          }
+       case 'c':
+         switch (p[2])
+         {
+           case 'l': REG (8, 0, VFPU_CC);
+           case 'h': REG (8, 8, VFPU_CC);
+           default:
+             abort();
+         }
        default:
          abort();
        }
@@ -705,6 +715,9 @@ const struct mips_opcode mips_builtin_opcodes[] =
 /* Allegrex VFPU coprocessor. Redefines coprocessor 2 and 3 (and other unused 
opcodes). */
 {"mfv",                        "t,?d0n",         0x48600000, 0xffe0ff80,       
WR_1|RD_C2,     0,              ALX,            0,      0 },
 {"mtv",                        "t,?d0n",         0x48e00000, 0xffe0ff80,       
RD_1|WR_C2,     0,              ALX,            0,      0 },
+{"mfvc",               "t,?cl.",         0x48600000, 0xffe0ff00,       
WR_1|RD_C2|CM,  0,              ALX,            0,      0 },
+{"mtvc",               "t,?cl.",         0x48e00000, 0xffe0ff00,       
RD_1|WR_C2|CM,  0,              ALX,            0,      0 },
+
 {"vabs.p",             "?d1a,?s1l",      0xd0010080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vabs.q",             "?d3a,?s3l",      0xd0018080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vabs.s",             "?d0a,?s0l",      0xd0010000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
@@ -724,12 +737,20 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"vbfy1.q",            "?d3a,?s3n",      0xd0428080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vbfy2.q",            "?d3a,?s3n",      0xd0438080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vc2i.s",             "?d3l,?s0n",      0xd0390000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vcmp.p",             "?jc.,?s1a,?t1a", 0x6c000080, 0xff8080f0,       RD_C2,  
        0,              ALX,            0,      0 },
+{"vcmp.q",             "?jc.,?s3a,?t3a", 0x6c008080, 0xff8080f0,       RD_C2,  
        0,              ALX,            0,      0 },
+{"vcmp.s",             "?jc.,?s0a,?t0a", 0x6c000000, 0xff8080f0,       RD_C2,  
        0,              ALX,            0,      0 },
+{"vcmp.t",             "?jc.,?s2a,?t2a", 0x6c008000, 0xff8080f0,       RD_C2,  
        0,              ALX,            0,      0 },
 {"vcos.p",             "?D1n,?s1n",      0xd0130080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vcos.q",             "?D3n,?s3n",      0xd0138080, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vcos.s",             "?D0n,?s0n",      0xd0130000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vcos.t",             "?D2n,?s2n",      0xd0138000, 0xffff8080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vcrsp.t",            "?i2n,?s2n,?t2n", 0xf2808000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vcrs.t",             "?d2a,?s2n,?t2n", 0x66808000, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
+{"vcst.p",             "?d1a,?jk.",      0xd0600080, 0xffe0ff80,       WR_C2,  
        0,              ALX,            0,      0 },
+{"vcst.q",             "?d3a,?jk.",      0xd0608080, 0xffe0ff80,       WR_C2,  
        0,              ALX,            0,      0 },
+{"vcst.s",             "?d0a,?jk.",      0xd0600000, 0xffe0ff80,       WR_C2,  
        0,              ALX,            0,      0 },
+{"vcst.t",             "?d2a,?jk.",      0xd0608000, 0xffe0ff80,       WR_C2,  
        0,              ALX,            0,      0 },
 {"vdet.p",             "?d0a,?s1a,?t1n", 0x67000080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vdiv.p",             "?D1n,?s1n,?t1n", 0x63800080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
 {"vdiv.q",             "?D3n,?s3n,?t3n", 0x63808080, 0xff808080,       
RD_C2|WR_C2,    0,              ALX,            0,      0 },
@@ -795,6 +816,7 @@ 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 },
+{"vmfvc",              "?d0n,?ch.",      0xd0500000, 0xffff0080,       
RD_C2|WR_C2|CM, 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 },
@@ -818,6 +840,7 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"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 },
+{"vmtvc",              "?cl.,?s0n",      0xd0510000, 0xffff8000,       
RD_C2|WR_C2|CM, 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 },
-- 
2.51.1

Reply via email to