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
