Prefix instructions push a prefix operation onto the prefix coprocessor registers. These registers are used when reading/writing registers at a later instruction. For this reason, the assembler also supports a shorter syntax where registers are decorated and the required prefix instructions are emitted before the actual instruction.
Signed-off-by: David Guillen Fandos <[email protected]> --- gas/config/tc-mips.c | 249 +++++++++++++++++- gas/testsuite/gas/mips/allegrex-vfpu-errors.d | 3 + gas/testsuite/gas/mips/allegrex-vfpu-errors.l | 10 + gas/testsuite/gas/mips/allegrex-vfpu-errors.s | 16 ++ gas/testsuite/gas/mips/allegrex-vfpu.d | 16 ++ gas/testsuite/gas/mips/allegrex-vfpu.s | 11 + .../gas/mips/[email protected] | 2 +- gas/testsuite/gas/mips/mips.exp | 1 + include/opcode/mips.h | 5 + opcodes/mips-dis.c | 55 ++++ opcodes/mips-formats.h | 16 +- opcodes/mips-opc.c | 13 + 12 files changed, 390 insertions(+), 7 deletions(-) create mode 100644 gas/testsuite/gas/mips/allegrex-vfpu-errors.d create mode 100644 gas/testsuite/gas/mips/allegrex-vfpu-errors.l create mode 100644 gas/testsuite/gas/mips/allegrex-vfpu-errors.s diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index f46d81ecfa2..eda2b641b80 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -675,6 +675,8 @@ static int g_switch_seen = 0; #define N_RMASK 0xc4 #define N_VFP 0xd4 +#define PFX_DST 0x80 + /* If we can determine in advance that GP optimization won't be possible, we can skip the relaxation stuff that tries to produce GP-relative references. This makes delay slot optimization work @@ -3426,6 +3428,106 @@ mips_vfpu_parse_register (char **sptr, unsigned int *regval, return true; } +/* Parses one VFPU prefix channel, which can be either source or destination. + Returns NULL if the parsed data cannot be a valid prefix. */ +static char * +mips_vfpu_parse_prefix_channel (char *s, unsigned char *chan) +{ + static const struct + { + const char *token; + unsigned char value; + } fixed_tokens[] = { + { "m", PFX_DST | 4 }, { "M", PFX_DST | 4 }, + { "0:1", PFX_DST | 1 }, { "[0:1]", PFX_DST | 1 }, + { "-1:1", PFX_DST | 3 }, { "[-1:1]", PFX_DST | 3 }, + { "1/6", 0x8 | 7 }, { "-1/6", 0x10 | 0x8 | 7 }, + { "1/4", 0x8 | 6 }, { "-1/4", 0x10 | 0x8 | 6 }, + { "1/3", 0x8 | 5 }, { "-1/3", 0x10 | 0x8 | 5 }, + { "3", 0x8 | 4 }, { "-3", 0x10 | 0x8 | 4 }, + { "1/2", 0x8 | 3 }, { "-1/2", 0x10 | 0x8 | 3 }, + { "2", 0x8 | 2 }, { "-2", 0x10 | 0x8 | 2 }, + { "1", 0x8 | 1 }, { "-1", 0x10 | 0x8 | 1 }, + { "0", 0x8 | 0 }, { "-0", 0x10 | 0x8 | 0 }, + }; + + SKIP_SPACE_TABS (s); + + if (!(*s) || *s == ',' || *s == ']') + return s; + + for (unsigned i = 0; i < ARRAY_SIZE(fixed_tokens); i++) { + size_t tokenl = strlen(fixed_tokens[i].token); + if (!strncmp(s, fixed_tokens[i].token, tokenl)) { + *chan = fixed_tokens[i].value; + return &s[tokenl]; + } + } + + *chan = 0; + if (*s == '-') + { + *chan |= 0x10; + s++; + SKIP_SPACE_TABS (s); + } + + if (*s == '|') + { + *chan |= 0x4; + s++; + SKIP_SPACE_TABS (s); + } + + switch (*s++) { + case 'x': case 'X': *chan |= 0; break; + case 'y': case 'Y': *chan |= 1; break; + case 'z': case 'Z': *chan |= 2; break; + case 'w': case 'W': *chan |= 3; break; + default: + set_insn_error (0, _("invalid VFPU prefix")); + return NULL; + }; + SKIP_SPACE_TABS (s); + + if (*chan & 0x4 && *s++ != '|') + { + set_insn_error (0, _("unmatched '|' in VFPU prefix")); + return NULL; + } + return s; +} + +/* Try to parse a VFPU prefix expression only validating its syntax. */ +static char * +mips_vfpu_parse_prefix (char *s, unsigned char *channels, + unsigned int *numchs) +{ + int i; + for (i = 0; i < 4; i++) + channels[i] = 0xff; /* Unespecified channel expression. */ + + for (i = 0; i < 4; i++) + { + s = mips_vfpu_parse_prefix_channel (s, &channels[i]); + if (!s) + break; + + SKIP_SPACE_TABS (s); + *numchs = i + 1; + + if (!(*s) || *s == ']') + break; + + if (*s++ != ',') + { + set_insn_error (0, _("invalid VFPU prefix, expecting ',' or ']'")); + return NULL; + } + } + return s; +} + /* Token types for parsed operand lists. */ enum mips_operand_token_type { /* A plain register, e.g. $f2. */ @@ -3446,6 +3548,9 @@ enum mips_operand_token_type { /* A VFPU register, eg. S000.s. */ OT_REG_VFPU, + /* A VFPU prefix expression for a register or a prefix instruction. */ + OT_PFX_VFPU, + /* A (possibly relocated) expression. */ OT_INTEGER, @@ -3491,6 +3596,12 @@ struct mips_operand_token enum mips_vfpu_reg_shape shape; } reg_vfpu; + /* The prefix value (from 1 to 4 channels) to apply to a register. */ + struct { + unsigned char prefixes[4]; + unsigned int num_chs; + } pfx_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 @@ -3606,6 +3717,17 @@ mips_parse_argument_token (char *s, char float_format, if (end) return end; + /* Handle VFPU specially encoded immediates. */ + if (mo->pinfo2 & INSN2_ALLEGREX_PREFIX) + { + s = mips_vfpu_parse_prefix(s, &token.u.pfx_vfpu.prefixes[0], + &token.u.pfx_vfpu.num_chs); + if (s) + mips_add_token (&token, OT_PFX_VFPU); + + return s; + } + /* Handle other characters that end up as OT_CHARs. */ if (*s == ')' || *s == ',') { @@ -3621,6 +3743,19 @@ mips_parse_argument_token (char *s, char float_format, { token.u.reg_vfpu.regno = regno1; mips_add_token (&token, OT_REG_VFPU); + + SKIP_SPACE_TABS (s); + if (*s == '[') + { + /* The register can feature a prefix, expressed as a suffix. */ + s = mips_vfpu_parse_prefix (&s[1], &token.u.pfx_vfpu.prefixes[0], + &token.u.pfx_vfpu.num_chs); + if (s && *s == ']') + { + mips_add_token (&token, OT_PFX_VFPU); + return ++s; + } + } return s; } @@ -5099,6 +5234,7 @@ operand_reg_mask (const struct mips_cl_insn *insn, case OP_VU0_SUFFIX: case OP_VU0_MATCH_SUFFIX: case OP_VFPU_REG: + case OP_VFPU_PFX: case OP_IMM_INDEX: abort (); @@ -6683,6 +6819,83 @@ match_vu0_suffix_operand (struct mips_arg_info *arg, return true; } +/* Generates a VFPU prefix immediate for a given reg type and size. */ +static bfd_boolean +calculate_vfpu_prefix_imm (struct mips_arg_info *arg, + enum mips_vfpu_reg_type regtype, unsigned int rsize, + unsigned int *immediate) +{ + unsigned int i; + unsigned imm24 = 0; + unsigned char *pfxchan = &arg->token->u.pfx_vfpu.prefixes[0]; + + for (i = 0; i <= rsize; i++) + { + if (pfxchan[i] == 0xff) + { + if (regtype == OP_VFPU_REG_D) + pfxchan[i] = PFX_DST; + else + pfxchan[i] = i; /* Natural swizzle when not specified. */ + } + + if (regtype == OP_VFPU_REG_D) + { + if (!(pfxchan[i] & PFX_DST)) + { + set_insn_error (arg->argnum, + _("invalid destination prefix (can only contain masking/saturation)")); + return false; + } + } + else + { + if (pfxchan[i] & PFX_DST) + { + set_insn_error (arg->argnum, + _("invalid source prefix (can only contain constant/swizzle/neg/abs)")); + return false; + } + if (!(pfxchan[i] & 0x8) && (pfxchan[i] & 3) > rsize) + { + set_insn_error (arg->argnum, + _("invalid swizzle operation (out of range)")); + return false; + } + } + + imm24 |= ((pfxchan[i] & 3) << (i * 2)) + | ((pfxchan[i] & 0x4) << (6 + i)) + | ((pfxchan[i] & 0x8) << (9 + i)) + | ((pfxchan[i] & 0x10) << (12 + i)); + } + + *immediate = imm24; + return true; +} + +/* Matches VFPU prefix operands. */ +static bfd_boolean +match_vfpu_prefix_operand (struct mips_arg_info *arg, + const struct mips_operand *operand) +{ + unsigned imm24; + const struct mips_vfpu_reg_operand *regvfpuop; + if (arg->token->type != OT_PFX_VFPU) + return false; + + regvfpuop = (struct mips_vfpu_reg_operand*)operand; + + if (!calculate_vfpu_prefix_imm (arg, regvfpuop->regtype, regvfpuop->rsize, + &imm24)) + return false; + + insn_insert_operand (arg->insn, operand, imm24); + + ++arg->token; + return true; +} + /* Matches VFPU register operands. */ static bfd_boolean match_vfpu_reg_operand (struct mips_arg_info *arg, @@ -6719,8 +6932,39 @@ match_vfpu_reg_operand (struct mips_arg_info *arg, } insn_insert_operand (arg->insn, operand, uval); - ++arg->token; + + /* Check if this register has an associated prefix. */ + if (arg->token->type == OT_PFX_VFPU) + { + unsigned int imm24; + struct mips_cl_insn pfxinstr; + struct mips_opcode *pop; + bfd_reloc_code_real_type unused_reloc[3] + = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; + + const char *pfxmemo = regvfpuop->regtype == OP_VFPU_REG_S ? "vpfxs" : + regvfpuop->regtype == OP_VFPU_REG_T ? "vpfxt" : "vpfxd"; + + if (regvfpuop->rsize + 1 != arg->token->u.pfx_vfpu.num_chs) + { + set_insn_error (arg->argnum, _("invalid number of prefix elements")); + return false; + } + + /* Create a prefix instruction that precedes this one. */ + pop = (struct mips_opcode *) str_hash_find (op_hash, pfxmemo); + create_insn (&pfxinstr, pop); + + if (!calculate_vfpu_prefix_imm (arg, regvfpuop->regtype, regvfpuop->rsize, + &imm24)) + return false; + + insn_insert_operand (&pfxinstr, decode_mips_operand (pop->args), imm24); + append_insn (&pfxinstr, NULL, unused_reloc, false); + ++arg->token; + } + return true; } @@ -6794,6 +7038,9 @@ match_operand (struct mips_arg_info *arg, case OP_VFPU_REG: return match_vfpu_reg_operand (arg, operand); + case OP_VFPU_PFX: + return match_vfpu_prefix_operand (arg, operand); + case OP_IMM_INDEX: return match_imm_index_operand (arg, operand); diff --git a/gas/testsuite/gas/mips/allegrex-vfpu-errors.d b/gas/testsuite/gas/mips/allegrex-vfpu-errors.d new file mode 100644 index 00000000000..de8edaafdf7 --- /dev/null +++ b/gas/testsuite/gas/mips/allegrex-vfpu-errors.d @@ -0,0 +1,3 @@ +#name: Allegrex VFPU assembly errors +#as: -march=allegrex -mabi=32 +#error_output: allegrex-vfpu-errors.l diff --git a/gas/testsuite/gas/mips/allegrex-vfpu-errors.l b/gas/testsuite/gas/mips/allegrex-vfpu-errors.l new file mode 100644 index 00000000000..aa10cf49e75 --- /dev/null +++ b/gas/testsuite/gas/mips/allegrex-vfpu-errors.l @@ -0,0 +1,10 @@ +.*: Assembler messages: +.*:4: Error: invalid number of prefix elements `vadd.q R000\[,m,\],C000,R002' +.*:5: Error: invalid swizzle operation \(out of range\) `vadd.t R000,C000,R002\[w,x,y\]' +.*:6: Error: invalid number of prefix elements `vmul.q R000,C000,R002\[,y,z\]' +.*:7: Error: invalid VFPU prefix `vsub.s S000,S000,S000\[p\]' +.*:8: Error: invalid VFPU prefix, expecting ',' or '\]' `vsub.s S000,S000,S000\[1/7\]' +.*:9: Error: unmatched '|' in VFPU prefix `vsub.s S000,S000,S000\[|x\]' +.*:10: Error: invalid VFPU prefix, expecting ',' or '\]' `vsub.s S000,S000,S000\[xx\]' +.*:11: Error: invalid source prefix \(can only contain constant/swizzle/neg/abs\) `vsub.t R000,R000,R000\[m,m,\]' +.*:12: Error: invalid destination prefix \(can only contain masking/saturation\) `vsub.t R000\[x,y,z\],R000,R000' diff --git a/gas/testsuite/gas/mips/allegrex-vfpu-errors.s b/gas/testsuite/gas/mips/allegrex-vfpu-errors.s new file mode 100644 index 00000000000..c2fa6dda856 --- /dev/null +++ b/gas/testsuite/gas/mips/allegrex-vfpu-errors.s @@ -0,0 +1,16 @@ + .text + .set noreorder + + vadd.q R000[,m,], C000, R002 + vadd.t R000, C000, R002[w,x,y] + vmul.q R000, C000, R002[,y,z] + vsub.s S000, S000, S000[p] + vsub.s S000, S000, S000[1/7] + vsub.s S000, S000, S000[|x] + vsub.s S000, S000, S000[xx] + vsub.t R000, R000, R000[m,m,] + vsub.t R000[x,y,z], R000, R000 + +# Force some (non-delay-slot) zero bytes, to make 'objdump' print ... + .align 4, 0 + .space 16 diff --git a/gas/testsuite/gas/mips/allegrex-vfpu.d b/gas/testsuite/gas/mips/allegrex-vfpu.d index e5fb8e13595..c39541364d5 100644 --- a/gas/testsuite/gas/mips/allegrex-vfpu.d +++ b/gas/testsuite/gas/mips/allegrex-vfpu.d @@ -63,4 +63,20 @@ Disassembly of section .text: 0x000000d8 d00600e4 vzero.p R120.p 0x000000dc d0068028 vzero.t R200.t 0x000000e0 d00680a8 vzero.q R200.q +0x000000e4 dc0000e4 vpfxs x,y,z,w +0x000000e8 dd0000e4 vpfxt x,y,z,w +0x000000ec dc000000 vpfxs x,x,x,x +0x000000f0 dc08dc30 vpfxs 0,x,1/6,-3 +0x000000f4 dc0305b3 vpfxs -|w|,-x,|w|,z +0x000000f8 de000000 vpfxd ,,, +0x000000fc de000174 vpfxd m,\[0:1\],\[-1:1\],\[0:1\] +0x00000100 de000a00 vpfxd ,m,,m +0x00000104 602280a0 vadd.q R000.q,C000.q,R002.q +0x00000108 dc000050 vpfxs x,x,y,y +0x0000010c dd0000fa vpfxt z,z,w,w +0x00000110 602280a0 vadd.q R000.q,C000.q,R002.q +0x00000114 de000200 vpfxd ,m,, +0x00000118 dc00000a vpfxs z,z,x,x +0x0000011c dd000018 vpfxt x,z,y,x +0x00000120 64228020 vmul.t R000.t,C000.t,R002.t \.\.\. diff --git a/gas/testsuite/gas/mips/allegrex-vfpu.s b/gas/testsuite/gas/mips/allegrex-vfpu.s index 7bbe5db61b9..228c17229f8 100644 --- a/gas/testsuite/gas/mips/allegrex-vfpu.s +++ b/gas/testsuite/gas/mips/allegrex-vfpu.s @@ -60,6 +60,17 @@ vzero.t R200 vzero.q R200 + vpfxs ,,, + vpfxt ,,, + vpfxs x,x,x,x + vpfxs 0,x,1/6,-3 + vpfxs -|w|, -x,| w |, z + vpfxd ,,, + vpfxd m,0:1,[-1:1],[0:1] + vadd.q R000[,m,,m], C000, R002 + vadd.q R000, C000[x,x,y,y], R002[z,z,w,w] + vmul.t R000[,m,], C000[z,z,x], R002[x,z,y] + # Force some (non-delay-slot) zero bytes, to make 'objdump' print ... .align 4, 0 .space 16 diff --git a/gas/testsuite/gas/mips/[email protected] b/gas/testsuite/gas/mips/[email protected] index 99c9c129159..57e0123ee05 100644 --- a/gas/testsuite/gas/mips/[email protected] +++ b/gas/testsuite/gas/mips/[email protected] @@ -10,7 +10,7 @@ Disassembly of section \.text: [0-9a-f]+ <[^>]*> 8c830004 lw v1,4\(a0\) [0-9a-f]+ <[^>]*> 3c0189ab lui at,0x89ab [0-9a-f]+ <[^>]*> 00411025 or v0,v0,at -[0-9a-f]+ <[^>]*> dc820000 .word 0xdc820000 +[0-9a-f]+ <[^>]*> dc820000 vpfxs x,-x,x,x [0-9a-f]+ <[^>]*> 340189ab li at,0x89ab [0-9a-f]+ <[^>]*> 00010c38 .word 0x10c38 [0-9a-f]+ <[^>]*> 00411025 or v0,v0,at diff --git a/gas/testsuite/gas/mips/mips.exp b/gas/testsuite/gas/mips/mips.exp index 15aabc44e2a..f6f3a8cf0a1 100644 --- a/gas/testsuite/gas/mips/mips.exp +++ b/gas/testsuite/gas/mips/mips.exp @@ -1714,6 +1714,7 @@ if { [istarget mips*-*-vxworks*] } { run_dump_test "allegrex" run_dump_test "allegrex-removed" run_dump_test "allegrex-vfpu" + run_dump_test "allegrex-vfpu-errors" run_list_test_arches "ext-ill" [mips_arch_list_matching mips64r2] diff --git a/include/opcode/mips.h b/include/opcode/mips.h index 7c177f6a283..f535591e54d 100644 --- a/include/opcode/mips.h +++ b/include/opcode/mips.h @@ -171,6 +171,9 @@ enum mips_operand_type { /* A VFPU register. */ OP_VFPU_REG, + /* A VFPU register prefix. */ + OP_VFPU_PFX, + /* An index selected by an integer, e.g. [1]. */ OP_IMM_INDEX, @@ -915,6 +918,8 @@ mips_opcode_32bit_p (const struct mips_opcode *mo) encoding is needed or otherwise the final EXTEND entry will apply, for the disassembly of the prefix only. */ #define INSN2_SHORT_ONLY 0x00010000 +/* Has special encoded prefix expressions that require parsing. */ +#define INSN2_ALLEGREX_PREFIX 0x00020000 /* Masks used to mark instructions to indicate which MIPS ISA level they were introduced in. INSN_ISA_MASK masks an enumeration that diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c index 7ed84a952a4..ed421e2aa71 100644 --- a/opcodes/mips-dis.c +++ b/opcodes/mips-dis.c @@ -1381,6 +1381,56 @@ print_vfpu_reg (struct disassemble_info *info, } } +/* Print OP_VFPU_PFX operand OPERAND, whose value is given by UVAL. */ +static void +print_vfpu_pfx (struct disassemble_info *info, + const struct mips_operand *operand, unsigned int uval) +{ + unsigned int i; + const fprintf_styled_ftype infprintf = info->fprintf_styled_func; + void *is = info->stream; + const struct mips_vfpu_reg_operand *vfpureg_op; + + vfpureg_op = (const struct mips_vfpu_reg_operand *) operand; + + for (i = 0; i <= vfpureg_op->rsize; i++) + { + if (i) + infprintf (is, dis_style_mnemonic, ","); + + if (vfpureg_op->regtype == OP_VFPU_REG_D) + { + if (uval & (1 << (8 + i))) + infprintf (is, dis_style_mnemonic, "m"); + else + { + static const char * const satimms[] = { "", "[0:1]", "", "[-1:1]" }; + unsigned int sat = (uval >> (i * 2)) & 3; + infprintf (is, dis_style_mnemonic, "%s", satimms[sat]); + } + } + else + { + static const char * const pfxswz_str = "xyzw"; + static const char * const pfxcst_str[2][4] = { + { "0", "1", "2", "1/2" }, { "3", "1/3", "1/4", "1/6" } + }; + unsigned int hib = (uval >> (8 + i)) & 1; + unsigned int lob = (uval >> (i * 2)) & 3; + + if (uval & (1 << (16 + i))) + infprintf (is, dis_style_mnemonic, "-"); + + if (uval & (1 << (12 + i))) + infprintf (is, dis_style_mnemonic, "%s", pfxcst_str[hib][lob]); + else if (hib) + infprintf (is, dis_style_mnemonic, "|%c|", pfxswz_str[lob]); + else + infprintf (is, dis_style_mnemonic, "%c", pfxswz_str[lob]); + } + } +} + /* Record information about a register operand. */ @@ -1595,6 +1645,10 @@ print_insn_arg (struct disassemble_info *info, print_vfpu_reg (info, operand, uval); break; + case OP_VFPU_PFX: + print_vfpu_pfx (info, operand, uval); + break; + case OP_PERF_REG: infprintf (is, dis_style_register, "%d", uval); break; @@ -1935,6 +1989,7 @@ validate_insn_args (const struct mips_opcode *opcode, case OP_REG_INDEX: case OP_SAVE_RESTORE_LIST: case OP_VFPU_REG: + case OP_VFPU_PFX: break; } } diff --git a/opcodes/mips-formats.h b/opcodes/mips-formats.h index 87d85e06dae..d31a514d51e 100644 --- a/opcodes/mips-formats.h +++ b/opcodes/mips-formats.h @@ -112,17 +112,23 @@ return &op.root; \ } -#define VFPU_REG(SIZE, LSB, REGTYPE, REGSIZE) \ +#define VFPU_REGEXP(OP_TYPE, 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 }, \ + { { OP_TYPE, SIZE, LSB }, OP_VFPU_REG_##REGTYPE, 0 }, \ + { { OP_TYPE, SIZE, LSB }, OP_VFPU_REG_##REGTYPE, 1 }, \ + { { OP_TYPE, SIZE, LSB }, OP_VFPU_REG_##REGTYPE, 2 }, \ + { { OP_TYPE, SIZE, LSB }, OP_VFPU_REG_##REGTYPE, 3 }, \ }; \ return &op[REGSIZE].root; \ } +#define VFPU_REG(SIZE, LSB, REGTYPE, REGSIZE) \ + VFPU_REGEXP(OP_VFPU_REG, SIZE, LSB, REGTYPE, REGSIZE) + +#define VFPU_PFX(SIZE, LSB, REGTYPE, REGSIZE) \ + VFPU_REGEXP(OP_VFPU_PFX, SIZE, LSB, REGTYPE, REGSIZE) + #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 f9341c94af9..e8c0418f1ca 100644 --- a/opcodes/mips-opc.c +++ b/opcodes/mips-opc.c @@ -148,6 +148,13 @@ decode_mips_operand (const char *p) 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'); + case 'p': + switch (p[2]) + { + case 'd': VFPU_PFX(24, 0, D, 3); + case 's': VFPU_PFX(24, 0, S, 3); + case 't': VFPU_PFX(24, 0, T, 3); + } } break; @@ -367,6 +374,9 @@ decode_mips_operand (const char *p) #define VU0 EE #define VU0CH INSN2_VU0_CHANNEL_SUFFIX +/* Support for Allegrex VFPU Coprocessor instructions */ +#define ALXPFX INSN2_ALLEGREX_PREFIX + /* MIPS DSP ASE support. NOTE: 1. MIPS DSP ASE includes 4 accumulators ($ac0 - $ac3). $ac0 is the pair @@ -709,6 +719,9 @@ const struct mips_opcode mips_builtin_opcodes[] = {"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 }, +{"vpfxd", "?pd", 0xde000000, 0xff000000, CP, ALXPFX, ALX, 0, 0 }, +{"vpfxs", "?ps", 0xdc000000, 0xff000000, CP, ALXPFX, ALX, 0, 0 }, +{"vpfxt", "?pt", 0xdd000000, 0xff000000, CP, ALXPFX, 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 }, -- 2.51.1
