From c233bf07af7cf2358b69c38150dbd2e3e4a399b6 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 27 Dec 2018 17:17:35 +0100 Subject: target/mips: MXU: Add missing opcodes/decoding for LX* instructions Add missing opcodes and decoding engine for LXB, LXH, LXW, LXBU, and LXHU instructions. They were for some reason forgotten in previous commits. The MXU opcode list and decoding engine should be now complete. Reviewed-by: Stefan Markovic Signed-off-by: Aleksandar Markovic --- target/mips/translate.c | 140 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 102 insertions(+), 38 deletions(-) (limited to 'target') diff --git a/target/mips/translate.c b/target/mips/translate.c index e9c23a5..e0c8d8c 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -1663,12 +1663,21 @@ enum { * │ 20..18 * ├─ 100111 ─ OPC_MXU__POOL16 ─┬─ 000 ─ OPC_MXU_D32SARW * │ ├─ 001 ─ OPC_MXU_S32ALN - * ├─ 101000 ─ OPC_MXU_LXB ├─ 010 ─ OPC_MXU_S32ALNI - * ├─ 101001 ─ ├─ 011 ─ OPC_MXU_S32NOR - * ├─ 101010 ─ OPC_MXU_S16LDD ├─ 100 ─ OPC_MXU_S32AND - * ├─ 101011 ─ OPC_MXU_S16STD ├─ 101 ─ OPC_MXU_S32OR - * ├─ 101100 ─ OPC_MXU_S16LDI ├─ 110 ─ OPC_MXU_S32XOR - * ├─ 101101 ─ OPC_MXU_S16SDI └─ 111 ─ OPC_MXU_S32LUI + * │ ├─ 010 ─ OPC_MXU_S32ALNI + * │ ├─ 011 ─ OPC_MXU_S32NOR + * │ ├─ 100 ─ OPC_MXU_S32AND + * │ ├─ 101 ─ OPC_MXU_S32OR + * │ ├─ 110 ─ OPC_MXU_S32XOR + * │ └─ 111 ─ OPC_MXU_S32LUI + * │ + * │ 7..5 + * ├─ 101000 ─ OPC_MXU__POOL17 ─┬─ 000 ─ OPC_MXU_LXB + * │ ├─ 001 ─ OPC_MXU_LXH + * ├─ 101001 ─ ├─ 011 ─ OPC_MXU_LXW + * ├─ 101010 ─ OPC_MXU_S16LDD ├─ 100 ─ OPC_MXU_LXBU + * ├─ 101011 ─ OPC_MXU_S16STD └─ 101 ─ OPC_MXU_LXHU + * ├─ 101100 ─ OPC_MXU_S16LDI + * ├─ 101101 ─ OPC_MXU_S16SDI * ├─ 101110 ─ OPC_MXU_S32M2I * ├─ 101111 ─ OPC_MXU_S32I2M * ├─ 110000 ─ OPC_MXU_D32SLL @@ -1678,15 +1687,15 @@ enum { * ├─ 110100 ─ OPC_MXU_Q16SLL ├─ 010 ─ OPC_MXU_D32SARV * ├─ 110101 ─ OPC_MXU_Q16SLR ├─ 011 ─ OPC_MXU_Q16SLLV * │ ├─ 100 ─ OPC_MXU_Q16SLRV - * ├─ 110110 ─ OPC_MXU__POOL17 ─┴─ 101 ─ OPC_MXU_Q16SARV + * ├─ 110110 ─ OPC_MXU__POOL18 ─┴─ 101 ─ OPC_MXU_Q16SARV * │ * ├─ 110111 ─ OPC_MXU_Q16SAR * │ 23..22 - * ├─ 111000 ─ OPC_MXU__POOL18 ─┬─ 00 ─ OPC_MXU_Q8MUL + * ├─ 111000 ─ OPC_MXU__POOL19 ─┬─ 00 ─ OPC_MXU_Q8MUL * │ └─ 01 ─ OPC_MXU_Q8MULSU * │ * │ 20..18 - * ├─ 111001 ─ OPC_MXU__POOL19 ─┬─ 000 ─ OPC_MXU_Q8MOVZ + * ├─ 111001 ─ OPC_MXU__POOL20 ─┬─ 000 ─ OPC_MXU_Q8MOVZ * │ ├─ 001 ─ OPC_MXU_Q8MOVN * │ ├─ 010 ─ OPC_MXU_D16MOVZ * │ ├─ 011 ─ OPC_MXU_D16MOVN @@ -1694,7 +1703,7 @@ enum { * │ └─ 101 ─ OPC_MXU_S32MOV * │ * │ 23..22 - * ├─ 111010 ─ OPC_MXU__POOL20 ─┬─ 00 ─ OPC_MXU_Q8MAC + * ├─ 111010 ─ OPC_MXU__POOL21 ─┬─ 00 ─ OPC_MXU_Q8MAC * │ └─ 10 ─ OPC_MXU_Q8MACSU * ├─ 111011 ─ OPC_MXU_Q16SCOP * ├─ 111100 ─ OPC_MXU_Q8MADL @@ -1750,7 +1759,7 @@ enum { OPC_MXU_S8SDI = 0x25, OPC_MXU__POOL15 = 0x26, OPC_MXU__POOL16 = 0x27, - OPC_MXU_LXB = 0x28, + OPC_MXU__POOL17 = 0x28, /* not assigned 0x29 */ OPC_MXU_S16LDD = 0x2A, OPC_MXU_S16STD = 0x2B, @@ -1764,11 +1773,11 @@ enum { OPC_MXU_D32SAR = 0x33, OPC_MXU_Q16SLL = 0x34, OPC_MXU_Q16SLR = 0x35, - OPC_MXU__POOL17 = 0x36, + OPC_MXU__POOL18 = 0x36, OPC_MXU_Q16SAR = 0x37, - OPC_MXU__POOL18 = 0x38, - OPC_MXU__POOL19 = 0x39, - OPC_MXU__POOL20 = 0x3A, + OPC_MXU__POOL19 = 0x38, + OPC_MXU__POOL20 = 0x39, + OPC_MXU__POOL21 = 0x3A, OPC_MXU_Q16SCOP = 0x3B, OPC_MXU_Q8MADL = 0x3C, OPC_MXU_S32SFL = 0x3D, @@ -1941,6 +1950,17 @@ enum { * MXU pool 17 */ enum { + OPC_MXU_LXB = 0x00, + OPC_MXU_LXH = 0x01, + OPC_MXU_LXW = 0x03, + OPC_MXU_LXBU = 0x04, + OPC_MXU_LXHU = 0x05, +}; + +/* + * MXU pool 18 + */ +enum { OPC_MXU_D32SLLV = 0x00, OPC_MXU_D32SLRV = 0x01, OPC_MXU_D32SARV = 0x03, @@ -1950,7 +1970,7 @@ enum { }; /* - * MXU pool 18 + * MXU pool 19 */ enum { OPC_MXU_Q8MUL = 0x00, @@ -1958,7 +1978,7 @@ enum { }; /* - * MXU pool 19 + * MXU pool 20 */ enum { OPC_MXU_Q8MOVZ = 0x00, @@ -1970,7 +1990,7 @@ enum { }; /* - * MXU pool 20 + * MXU pool 21 */ enum { OPC_MXU_Q8MAC = 0x00, @@ -25331,12 +25351,58 @@ static void decode_opc_mxu__pool16(CPUMIPSState *env, DisasContext *ctx) * Decode MXU pool17 * * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------+---------+---------+---+---------+-----+-----------+ + * | SPECIAL2 | rs | rt |0 0| rd |x x x|MXU__POOL15| + * +-----------+---------+---------+---+---------+-----+-----------+ + * + */ +static void decode_opc_mxu__pool17(CPUMIPSState *env, DisasContext *ctx) +{ + uint32_t opcode = extract32(ctx->opcode, 6, 2); + + switch (opcode) { + case OPC_MXU_LXW: + /* TODO: Implement emulation of LXW instruction. */ + MIPS_INVAL("OPC_MXU_LXW"); + generate_exception_end(ctx, EXCP_RI); + break; + case OPC_MXU_LXH: + /* TODO: Implement emulation of LXH instruction. */ + MIPS_INVAL("OPC_MXU_LXH"); + generate_exception_end(ctx, EXCP_RI); + break; + case OPC_MXU_LXHU: + /* TODO: Implement emulation of LXHU instruction. */ + MIPS_INVAL("OPC_MXU_LXHU"); + generate_exception_end(ctx, EXCP_RI); + break; + case OPC_MXU_LXB: + /* TODO: Implement emulation of LXB instruction. */ + MIPS_INVAL("OPC_MXU_LXB"); + generate_exception_end(ctx, EXCP_RI); + break; + case OPC_MXU_LXBU: + /* TODO: Implement emulation of LXBU instruction. */ + MIPS_INVAL("OPC_MXU_LXBU"); + generate_exception_end(ctx, EXCP_RI); + break; + default: + MIPS_INVAL("decode_opc_mxu"); + generate_exception_end(ctx, EXCP_RI); + break; + } +} +/* + * + * Decode MXU pool18 + * + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 * +-----------+---------+-----+-------+-------+-------+-----------+ - * | SPECIAL2 | rb |x x x| XRd | XRa |0 0 0 0|MXU__POOL17| + * | SPECIAL2 | rb |x x x| XRd | XRa |0 0 0 0|MXU__POOL18| * +-----------+---------+-----+-------+-------+-------+-----------+ * */ -static void decode_opc_mxu__pool17(CPUMIPSState *env, DisasContext *ctx) +static void decode_opc_mxu__pool18(CPUMIPSState *env, DisasContext *ctx) { uint32_t opcode = extract32(ctx->opcode, 18, 3); @@ -25380,15 +25446,15 @@ static void decode_opc_mxu__pool17(CPUMIPSState *env, DisasContext *ctx) /* * - * Decode MXU pool18 + * Decode MXU pool19 * * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 * +-----------+---+---+-------+-------+-------+-------+-----------+ - * | SPECIAL2 |0 0|x x| XRd | XRc | XRb | XRa |MXU__POOL18| + * | SPECIAL2 |0 0|x x| XRd | XRc | XRb | XRa |MXU__POOL19| * +-----------+---+---+-------+-------+-------+-------+-----------+ * */ -static void decode_opc_mxu__pool18(CPUMIPSState *env, DisasContext *ctx) +static void decode_opc_mxu__pool19(CPUMIPSState *env, DisasContext *ctx) { uint32_t opcode = extract32(ctx->opcode, 22, 2); @@ -25406,15 +25472,15 @@ static void decode_opc_mxu__pool18(CPUMIPSState *env, DisasContext *ctx) /* * - * Decode MXU pool19 + * Decode MXU pool20 * * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 * +-----------+---------+-----+-------+-------+-------+-----------+ - * | SPECIAL2 |0 0 0 0 0|x x x| XRc | XRb | XRa |MXU__POOL19| + * | SPECIAL2 |0 0 0 0 0|x x x| XRc | XRb | XRa |MXU__POOL20| * +-----------+---------+-----+-------+-------+-------+-----------+ * */ -static void decode_opc_mxu__pool19(CPUMIPSState *env, DisasContext *ctx) +static void decode_opc_mxu__pool20(CPUMIPSState *env, DisasContext *ctx) { uint32_t opcode = extract32(ctx->opcode, 18, 3); @@ -25458,15 +25524,15 @@ static void decode_opc_mxu__pool19(CPUMIPSState *env, DisasContext *ctx) /* * - * Decode MXU pool20 + * Decode MXU pool21 * * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 * +-----------+---+---+-------+-------+-------+-------+-----------+ - * | SPECIAL2 |an2|x x| XRd | XRc | XRb | XRa |MXU__POOL20| + * | SPECIAL2 |an2|x x| XRd | XRc | XRb | XRa |MXU__POOL21| * +-----------+---+---+-------+-------+-------+-------+-----------+ * */ -static void decode_opc_mxu__pool20(CPUMIPSState *env, DisasContext *ctx) +static void decode_opc_mxu__pool21(CPUMIPSState *env, DisasContext *ctx) { uint32_t opcode = extract32(ctx->opcode, 22, 2); @@ -25669,10 +25735,8 @@ static void decode_opc_mxu(CPUMIPSState *env, DisasContext *ctx) case OPC_MXU__POOL16: decode_opc_mxu__pool16(env, ctx); break; - case OPC_MXU_LXB: - /* TODO: Implement emulation of LXB instruction. */ - MIPS_INVAL("OPC_MXU_LXB"); - generate_exception_end(ctx, EXCP_RI); + case OPC_MXU__POOL17: + decode_opc_mxu__pool17(env, ctx); break; case OPC_MXU_S16LDD: /* TODO: Implement emulation of S16LDD instruction. */ @@ -25724,23 +25788,23 @@ static void decode_opc_mxu(CPUMIPSState *env, DisasContext *ctx) MIPS_INVAL("OPC_MXU_Q16SLR"); generate_exception_end(ctx, EXCP_RI); break; - case OPC_MXU__POOL17: - decode_opc_mxu__pool17(env, ctx); + case OPC_MXU__POOL18: + decode_opc_mxu__pool18(env, ctx); break; case OPC_MXU_Q16SAR: /* TODO: Implement emulation of Q16SAR instruction. */ MIPS_INVAL("OPC_MXU_Q16SAR"); generate_exception_end(ctx, EXCP_RI); break; - case OPC_MXU__POOL18: - decode_opc_mxu__pool18(env, ctx); - break; case OPC_MXU__POOL19: decode_opc_mxu__pool19(env, ctx); break; case OPC_MXU__POOL20: decode_opc_mxu__pool20(env, ctx); break; + case OPC_MXU__POOL21: + decode_opc_mxu__pool21(env, ctx); + break; case OPC_MXU_Q16SCOP: /* TODO: Implement emulation of Q16SCOP instruction. */ MIPS_INVAL("OPC_MXU_Q16SCOP"); -- cgit v1.1 From 16fef5b2214ad8491fe1ec6fdf7937dbec1daf41 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 27 Dec 2018 17:20:38 +0100 Subject: target/mips: MXU: Add generic naming for optn2 constants Add generic naming involving generig suffixes OPTN0, OPTN1, OPTN2, OPTN3 for four optn2 constants. Existing suffixes WW, LW, HW, XW are not quite appropriate for some instructions using optn2. Reviewed-by: Stefan Markovic Signed-off-by: Aleksandar Markovic --- target/mips/translate.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'target') diff --git a/target/mips/translate.c b/target/mips/translate.c index e0c8d8c..74d16ce 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -24238,6 +24238,11 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) #define MXU_EPTN2_SS 3 /* MXU operand getting pattern 'optn2' */ +#define MXU_OPTN2_PTN0 0 +#define MXU_OPTN2_PTN1 1 +#define MXU_OPTN2_PTN2 2 +#define MXU_OPTN2_PTN3 3 +/* alternative naming scheme for 'optn2' */ #define MXU_OPTN2_WW 0 #define MXU_OPTN2_LW 1 #define MXU_OPTN2_HW 2 -- cgit v1.1 From 84e2c895b12fb7056daeb7e5094656eae7b50d3d Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 27 Dec 2018 17:25:00 +0100 Subject: target/mips: MXU: Improve the comment containing MXU overview Improve textual description of MXU extension. These are mostly comment formatting changes. Reviewed-by: Stefan Markovic Signed-off-by: Aleksandar Markovic --- target/mips/translate.c | 74 +++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 30 deletions(-) (limited to 'target') diff --git a/target/mips/translate.c b/target/mips/translate.c index 74d16ce..e3a5a73 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -1399,10 +1399,12 @@ enum { /* - * AN OVERVIEW OF MXU EXTENSION INSTRUCTION SET - * ============================================ * - * MXU (full name: MIPS eXtension/enhanced Unit) is an SIMD extension of MIPS32 + * AN OVERVIEW OF MXU EXTENSION INSTRUCTION SET + * ============================================ + * + * + * MXU (full name: MIPS eXtension/enhanced Unit) is a SIMD extension of MIPS32 * instructions set. It is designed to fit the needs of signal, graphical and * video processing applications. MXU instruction set is used in Xburst family * of microprocessors by Ingenic. @@ -1410,39 +1412,31 @@ enum { * MXU unit contains 17 registers called X0-X16. X0 is always zero, and X16 is * the control register. * - * The notation used in MXU assembler mnemonics - * -------------------------------------------- * - * Registers: + * The notation used in MXU assembler mnemonics + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Register operands: * * XRa, XRb, XRc, XRd - MXU registers * Rb, Rc, Rd, Rs, Rt - general purpose MIPS registers * - * Subfields: + * Non-register operands: * - * aptn1 - 1-bit accumulate add/subtract pattern - * aptn2 - 2-bit accumulate add/subtract pattern - * eptn2 - 2-bit execute add/subtract pattern - * optn2 - 2-bit operand pattern - * optn3 - 3-bit operand pattern - * sft4 - 4-bit shift amount - * strd2 - 2-bit stride amount + * aptn1 - 1-bit accumulate add/subtract pattern + * aptn2 - 2-bit accumulate add/subtract pattern + * eptn2 - 2-bit execute add/subtract pattern + * optn2 - 2-bit operand pattern + * optn3 - 3-bit operand pattern + * sft4 - 4-bit shift amount + * strd2 - 2-bit stride amount * * Prefixes: * - * - * S 32 - * D 16 - * Q 8 - * - * Suffixes: - * - * E - Expand results - * F - Fixed point multiplication - * L - Low part result - * R - Doing rounding - * V - Variable instead of immediate - * W - Combine above L and V + * Level of parallelism: Operand size: + * S - single operation at a time 32 - word + * D - two operations in parallel 16 - half word + * Q - four operations in parallel 8 - byte * * Operations: * @@ -1486,6 +1480,19 @@ enum { * SCOP - Calculate x’s scope (-1, means x<0; 0, means x==0; 1, means x>0) * XOR - Logical bitwise 'exclusive or' operation * + * Suffixes: + * + * E - Expand results + * F - Fixed point multiplication + * L - Low part result + * R - Doing rounding + * V - Variable instead of immediate + * W - Combine above L and V + * + * + * The list of MXU instructions grouped by functionality + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * * Load/Store instructions Multiplication instructions * ----------------------- --------------------------- * @@ -1563,6 +1570,13 @@ enum { * Q16SAT XRa, XRb, XRc S32I2M XRa, Rb * * + * The opcode organization of MXU instructions + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * The bits 31..26 of all MXU instructions are equal to 0x1C (also referred + * as opcode SPECIAL2 in the base MIPS ISA). The organization and meaning of + * other bits up to the instruction level is as follows: + * * bits * 05..00 * @@ -1700,7 +1714,7 @@ enum { * │ ├─ 010 ─ OPC_MXU_D16MOVZ * │ ├─ 011 ─ OPC_MXU_D16MOVN * │ ├─ 100 ─ OPC_MXU_S32MOVZ - * │ └─ 101 ─ OPC_MXU_S32MOV + * │ └─ 101 ─ OPC_MXU_S32MOVN * │ * │ 23..22 * ├─ 111010 ─ OPC_MXU__POOL21 ─┬─ 00 ─ OPC_MXU_Q8MAC @@ -1712,10 +1726,10 @@ enum { * └─ 111111 ─ (overlaps with SDBBP) * * - * Compiled after: + * Compiled after: * * "XBurst® Instruction Set Architecture MIPS eXtension/enhanced Unit - * Programming Manual", Ingenic Semiconductor Co, Ltd., 2017 + * Programming Manual", Ingenic Semiconductor Co, Ltd., revision June 2, 2017 */ enum { -- cgit v1.1 From b621f0187ef789aeef733cf79e5ac83984752394 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 31 Dec 2018 13:14:13 +0100 Subject: target/mips: MXU: Add handlers for logic instructions Add translation handlers for four logic MXU instructions. It should be noted that there is an error in MXU documentation (dated June 2017) regarding opcodes for this group of instructions. This was confirmed by running tests on hardware, and also by looking up other related public source trees (binutils, Android NDK). In initial MXU patches to QEMU, opcodes for MXU logic instructions were created to be in accordance with the MXU documentation, therefore the error from was propagated. This patch corrects that, changing the involved code. Besides that, as MXU was designed and implemented only for 32-bit CPUs, corresponding preprosessor conditions were added around MXU code, which allows more flexible implementation of MXU handlers. Reviewed-by: Stefan Markovic Signed-off-by: Aleksandar Markovic --- target/mips/translate.c | 239 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 205 insertions(+), 34 deletions(-) (limited to 'target') diff --git a/target/mips/translate.c b/target/mips/translate.c index e3a5a73..a339f72 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -1678,11 +1678,11 @@ enum { * ├─ 100111 ─ OPC_MXU__POOL16 ─┬─ 000 ─ OPC_MXU_D32SARW * │ ├─ 001 ─ OPC_MXU_S32ALN * │ ├─ 010 ─ OPC_MXU_S32ALNI - * │ ├─ 011 ─ OPC_MXU_S32NOR - * │ ├─ 100 ─ OPC_MXU_S32AND - * │ ├─ 101 ─ OPC_MXU_S32OR - * │ ├─ 110 ─ OPC_MXU_S32XOR - * │ └─ 111 ─ OPC_MXU_S32LUI + * │ ├─ 011 ─ OPC_MXU_S32LUI + * │ ├─ 100 ─ OPC_MXU_S32NOR + * │ ├─ 101 ─ OPC_MXU_S32AND + * │ ├─ 110 ─ OPC_MXU_S32OR + * │ └─ 111 ─ OPC_MXU_S32XOR * │ * │ 7..5 * ├─ 101000 ─ OPC_MXU__POOL17 ─┬─ 000 ─ OPC_MXU_LXB @@ -1953,11 +1953,11 @@ enum { OPC_MXU_D32SARW = 0x00, OPC_MXU_S32ALN = 0x01, OPC_MXU_S32ALNI = 0x02, - OPC_MXU_S32NOR = 0x03, - OPC_MXU_S32AND = 0x04, - OPC_MXU_S32OR = 0x05, - OPC_MXU_S32XOR = 0x06, - OPC_MXU_S32LUI = 0x07, + OPC_MXU_S32LUI = 0x03, + OPC_MXU_S32NOR = 0x04, + OPC_MXU_S32AND = 0x05, + OPC_MXU_S32OR = 0x06, + OPC_MXU_S32XOR = 0x07, }; /* @@ -2455,9 +2455,11 @@ static TCGv_i32 fpu_fcr0, fpu_fcr31; static TCGv_i64 fpu_f64[32]; static TCGv_i64 msa_wr_d[64]; +#if !defined(TARGET_MIPS64) /* MXU registers */ static TCGv mxu_gpr[NUMBER_OF_MXU_REGISTERS - 1]; static TCGv mxu_CR; +#endif #include "exec/gen-icount.h" @@ -2581,10 +2583,12 @@ static const char * const msaregnames[] = { "w30.d0", "w30.d1", "w31.d0", "w31.d1", }; +#if !defined(TARGET_MIPS64) static const char * const mxuregnames[] = { "XR1", "XR2", "XR3", "XR4", "XR5", "XR6", "XR7", "XR8", "XR9", "XR10", "XR11", "XR12", "XR13", "XR14", "XR15", "MXU_CR", }; +#endif #define LOG_DISAS(...) \ do { \ @@ -2667,6 +2671,7 @@ static inline void gen_store_srsgpr (int from, int to) } } +#if !defined(TARGET_MIPS64) /* MXU General purpose registers moves. */ static inline void gen_load_mxu_gpr(TCGv t, unsigned int reg) { @@ -2695,6 +2700,7 @@ static inline void gen_store_mxu_cr(TCGv t) /* TODO: Add handling of RW rules for MXU_CR. */ tcg_gen_mov_tl(mxu_CR, t); } +#endif /* Tests */ @@ -24235,6 +24241,8 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) } +#if !defined(TARGET_MIPS64) + /* MXU accumulate add/subtract 1-bit pattern 'aptn1' */ #define MXU_APTN1_A 0 #define MXU_APTN1_S 1 @@ -24650,6 +24658,172 @@ static void gen_mxu_s32ldd_s32lddr(DisasContext *ctx) /* + * MXU instruction category: logic + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * S32NOR S32AND S32OR S32XOR + */ + +/* + * S32NOR XRa, XRb, XRc + * Update XRa with the result of logical bitwise 'nor' operation + * applied to the content of XRb and XRc. + * + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------+---------+-----+-------+-------+-------+-----------+ + * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL16| + * +-----------+---------+-----+-------+-------+-------+-----------+ + */ +static void gen_mxu_S32NOR(DisasContext *ctx) +{ + uint32_t pad, XRc, XRb, XRa; + + pad = extract32(ctx->opcode, 21, 5); + XRc = extract32(ctx->opcode, 14, 4); + XRb = extract32(ctx->opcode, 10, 4); + XRa = extract32(ctx->opcode, 6, 4); + + if (unlikely(pad != 0)) { + /* opcode padding incorrect -> do nothing */ + } else if (unlikely(XRa == 0)) { + /* destination is zero register -> do nothing */ + } else if (unlikely((XRb == 0) && (XRc == 0))) { + /* both operands zero registers -> just set destination to all 1s */ + tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0xFFFFFFFF); + } else if (unlikely(XRb == 0)) { + /* XRb zero register -> just set destination to the negation of XRc */ + tcg_gen_not_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]); + } else if (unlikely(XRc == 0)) { + /* XRa zero register -> just set destination to the negation of XRb */ + tcg_gen_not_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]); + } else if (unlikely(XRb == XRc)) { + /* both operands same -> just set destination to the negation of XRb */ + tcg_gen_not_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]); + } else { + /* the most general case */ + tcg_gen_nor_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]); + } +} + +/* + * S32AND XRa, XRb, XRc + * Update XRa with the result of logical bitwise 'and' operation + * applied to the content of XRb and XRc. + * + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------+---------+-----+-------+-------+-------+-----------+ + * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL16| + * +-----------+---------+-----+-------+-------+-------+-----------+ + */ +static void gen_mxu_S32AND(DisasContext *ctx) +{ + uint32_t pad, XRc, XRb, XRa; + + pad = extract32(ctx->opcode, 21, 5); + XRc = extract32(ctx->opcode, 14, 4); + XRb = extract32(ctx->opcode, 10, 4); + XRa = extract32(ctx->opcode, 6, 4); + + if (unlikely(pad != 0)) { + /* opcode padding incorrect -> do nothing */ + } else if (unlikely(XRa == 0)) { + /* destination is zero register -> do nothing */ + } else if (unlikely((XRb == 0) || (XRc == 0))) { + /* one of operands zero register -> just set destination to all 0s */ + tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0); + } else if (unlikely(XRb == XRc)) { + /* both operands same -> just set destination to one of them */ + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]); + } else { + /* the most general case */ + tcg_gen_and_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]); + } +} + +/* + * S32OR XRa, XRb, XRc + * Update XRa with the result of logical bitwise 'or' operation + * applied to the content of XRb and XRc. + * + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------+---------+-----+-------+-------+-------+-----------+ + * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL16| + * +-----------+---------+-----+-------+-------+-------+-----------+ + */ +static void gen_mxu_S32OR(DisasContext *ctx) +{ + uint32_t pad, XRc, XRb, XRa; + + pad = extract32(ctx->opcode, 21, 5); + XRc = extract32(ctx->opcode, 14, 4); + XRb = extract32(ctx->opcode, 10, 4); + XRa = extract32(ctx->opcode, 6, 4); + + if (unlikely(pad != 0)) { + /* opcode padding incorrect -> do nothing */ + } else if (unlikely(XRa == 0)) { + /* destination is zero register -> do nothing */ + } else if (unlikely((XRb == 0) && (XRc == 0))) { + /* both operands zero registers -> just set destination to all 0s */ + tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0); + } else if (unlikely(XRb == 0)) { + /* XRb zero register -> just set destination to the content of XRc */ + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]); + } else if (unlikely(XRc == 0)) { + /* XRc zero register -> just set destination to the content of XRb */ + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]); + } else if (unlikely(XRb == XRc)) { + /* both operands same -> just set destination to one of them */ + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]); + } else { + /* the most general case */ + tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]); + } +} + +/* + * S32XOR XRa, XRb, XRc + * Update XRa with the result of logical bitwise 'xor' operation + * applied to the content of XRb and XRc. + * + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------+---------+-----+-------+-------+-------+-----------+ + * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL16| + * +-----------+---------+-----+-------+-------+-------+-----------+ + */ +static void gen_mxu_S32XOR(DisasContext *ctx) +{ + uint32_t pad, XRc, XRb, XRa; + + pad = extract32(ctx->opcode, 21, 5); + XRc = extract32(ctx->opcode, 14, 4); + XRb = extract32(ctx->opcode, 10, 4); + XRa = extract32(ctx->opcode, 6, 4); + + if (unlikely(pad != 0)) { + /* opcode padding incorrect -> do nothing */ + } else if (unlikely(XRa == 0)) { + /* destination is zero register -> do nothing */ + } else if (unlikely((XRb == 0) && (XRc == 0))) { + /* both operands zero registers -> just set destination to all 0s */ + tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0); + } else if (unlikely(XRb == 0)) { + /* XRb zero register -> just set destination to the content of XRc */ + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]); + } else if (unlikely(XRc == 0)) { + /* XRc zero register -> just set destination to the content of XRb */ + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]); + } else if (unlikely(XRb == XRc)) { + /* both operands same -> just set destination to all 0s */ + tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0); + } else { + /* the most general case */ + tcg_gen_xor_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]); + } +} + + +/* * Decoding engine for MXU * ======================= */ @@ -25300,18 +25474,18 @@ static void decode_opc_mxu__pool15(CPUMIPSState *env, DisasContext *ctx) * | SPECIAL2 | s3 |0 0|x x x| XRc | XRb | XRa |MXU__POOL16| * +-----------+-----+---+-----+-------+-------+-------+-----------+ * - * S32NOR, S32AND, S32OR, S32XOR: - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-----------+---------+-----+-------+-------+-------+-----------+ - * | SPECIAL2 |0 0 0 0 0|x x x| XRc | XRb | XRa |MXU__POOL16| - * +-----------+---------+-----+-------+-------+-------+-----------+ - * * S32LUI: * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 * +-----------+-----+---+-----+-------+---------------+-----------+ * | SPECIAL2 |optn3|0 0|x x x| XRc | s8 |MXU__POOL16| * +-----------+-----+---+-----+-------+---------------+-----------+ * + * S32NOR, S32AND, S32OR, S32XOR: + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------+---------+-----+-------+-------+-------+-----------+ + * | SPECIAL2 |0 0 0 0 0|x x x| XRc | XRb | XRa |MXU__POOL16| + * +-----------+---------+-----+-------+-------+-------+-----------+ + * */ static void decode_opc_mxu__pool16(CPUMIPSState *env, DisasContext *ctx) { @@ -25333,30 +25507,22 @@ static void decode_opc_mxu__pool16(CPUMIPSState *env, DisasContext *ctx) MIPS_INVAL("OPC_MXU_S32ALNI"); generate_exception_end(ctx, EXCP_RI); break; - case OPC_MXU_S32NOR: - /* TODO: Implement emulation of S32NOR instruction. */ - MIPS_INVAL("OPC_MXU_S32NOR"); + case OPC_MXU_S32LUI: + /* TODO: Implement emulation of S32LUI instruction. */ + MIPS_INVAL("OPC_MXU_S32LUI"); generate_exception_end(ctx, EXCP_RI); break; + case OPC_MXU_S32NOR: + gen_mxu_S32NOR(ctx); + break; case OPC_MXU_S32AND: - /* TODO: Implement emulation of S32AND instruction. */ - MIPS_INVAL("OPC_MXU_S32AND"); - generate_exception_end(ctx, EXCP_RI); + gen_mxu_S32AND(ctx); break; case OPC_MXU_S32OR: - /* TODO: Implement emulation of S32OR instruction. */ - MIPS_INVAL("OPC_MXU_S32OR"); - generate_exception_end(ctx, EXCP_RI); + gen_mxu_S32OR(ctx); break; case OPC_MXU_S32XOR: - /* TODO: Implement emulation of S32XOR instruction. */ - MIPS_INVAL("OPC_MXU_S32XOR"); - generate_exception_end(ctx, EXCP_RI); - break; - case OPC_MXU_S32LUI: - /* TODO: Implement emulation of S32LUI instruction. */ - MIPS_INVAL("OPC_MXU_S32LUI"); - generate_exception_end(ctx, EXCP_RI); + gen_mxu_S32XOR(ctx); break; default: MIPS_INVAL("decode_opc_mxu"); @@ -25854,6 +26020,8 @@ static void decode_opc_mxu(CPUMIPSState *env, DisasContext *ctx) } } +#endif /* !defined(TARGET_MIPS64) */ + static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) { @@ -28098,8 +28266,10 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) case OPC_SPECIAL2: if ((ctx->insn_flags & INSN_R5900) && (ctx->insn_flags & ASE_MMI)) { decode_mmi(env, ctx); +#if !defined(TARGET_MIPS64) } else if (ctx->insn_flags & ASE_MXU) { decode_opc_mxu(env, ctx); +#endif } else { decode_opc_special2_legacy(env, ctx); } @@ -29108,7 +29278,7 @@ void mips_tcg_init(void) fpu_fcr31 = tcg_global_mem_new_i32(cpu_env, offsetof(CPUMIPSState, active_fpu.fcr31), "fcr31"); - +#if !defined(TARGET_MIPS64) for (i = 0; i < NUMBER_OF_MXU_REGISTERS - 1; i++) { mxu_gpr[i] = tcg_global_mem_new(cpu_env, offsetof(CPUMIPSState, @@ -29119,6 +29289,7 @@ void mips_tcg_init(void) mxu_CR = tcg_global_mem_new(cpu_env, offsetof(CPUMIPSState, active_tc.mxu_cr), mxuregnames[NUMBER_OF_MXU_REGISTERS - 1]); +#endif } #include "translate_init.inc.c" -- cgit v1.1 From bb84cbf38505bd1d800fdddcd81407a99e5c2142 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 31 Dec 2018 13:14:34 +0100 Subject: target/mips: MXU: Add handlers for max/min instructions Add translation handlers for six max/min MXU instructions. Reviewed-by: Stefan Markovic Signed-off-by: Aleksandar Markovic --- target/mips/translate.c | 300 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 279 insertions(+), 21 deletions(-) (limited to 'target') diff --git a/target/mips/translate.c b/target/mips/translate.c index a339f72..44142ea 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -24824,6 +24824,282 @@ static void gen_mxu_S32XOR(DisasContext *ctx) /* + * MXU instruction category max/min + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * S32MAX D16MAX Q8MAX + * S32MIN D16MIN Q8MIN + */ + +/* + * S32MAX XRa, XRb, XRc + * Update XRa with the maximum of signed 32-bit integers contained + * in XRb and XRc. + * + * S32MIN XRa, XRb, XRc + * Update XRa with the minimum of signed 32-bit integers contained + * in XRb and XRc. + * + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------+---------+-----+-------+-------+-------+-----------+ + * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL00| + * +-----------+---------+-----+-------+-------+-------+-----------+ + */ +static void gen_mxu_S32MAX_S32MIN(DisasContext *ctx) +{ + uint32_t pad, opc, XRc, XRb, XRa; + + pad = extract32(ctx->opcode, 21, 5); + opc = extract32(ctx->opcode, 18, 3); + XRc = extract32(ctx->opcode, 14, 4); + XRb = extract32(ctx->opcode, 10, 4); + XRa = extract32(ctx->opcode, 6, 4); + + if (unlikely(pad != 0)) { + /* opcode padding incorrect -> do nothing */ + } else if (unlikely(XRa == 0)) { + /* destination is zero register -> do nothing */ + } else if (unlikely((XRb == 0) && (XRc == 0))) { + /* both operands zero registers -> just set destination to zero */ + tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0); + } else if (unlikely((XRb == 0) || (XRc == 0))) { + /* exactly one operand is zero register - find which one is not...*/ + uint32_t XRx = XRb ? XRb : XRc; + /* ...and do max/min operation with one operand 0 */ + if (opc == OPC_MXU_S32MAX) { + tcg_gen_smax_i32(mxu_gpr[XRa - 1], mxu_gpr[XRx - 1], 0); + } else { + tcg_gen_smin_i32(mxu_gpr[XRa - 1], mxu_gpr[XRx - 1], 0); + } + } else if (unlikely(XRb == XRc)) { + /* both operands same -> just set destination to one of them */ + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]); + } else { + /* the most general case */ + if (opc == OPC_MXU_S32MAX) { + tcg_gen_smax_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], + mxu_gpr[XRc - 1]); + } else { + tcg_gen_smin_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], + mxu_gpr[XRc - 1]); + } + } +} + +/* + * D16MAX + * Update XRa with the 16-bit-wise maximums of signed integers + * contained in XRb and XRc. + * + * D16MIN + * Update XRa with the 16-bit-wise minimums of signed integers + * contained in XRb and XRc. + * + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------+---------+-----+-------+-------+-------+-----------+ + * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL00| + * +-----------+---------+-----+-------+-------+-------+-----------+ + */ +static void gen_mxu_D16MAX_D16MIN(DisasContext *ctx) +{ + uint32_t pad, opc, XRc, XRb, XRa; + + pad = extract32(ctx->opcode, 21, 5); + opc = extract32(ctx->opcode, 18, 3); + XRc = extract32(ctx->opcode, 14, 4); + XRb = extract32(ctx->opcode, 10, 4); + XRa = extract32(ctx->opcode, 6, 4); + + if (unlikely(pad != 0)) { + /* opcode padding incorrect -> do nothing */ + } else if (unlikely(XRc == 0)) { + /* destination is zero register -> do nothing */ + } else if (unlikely((XRb == 0) && (XRa == 0))) { + /* both operands zero registers -> just set destination to zero */ + tcg_gen_movi_i32(mxu_gpr[XRc - 1], 0); + } else if (unlikely((XRb == 0) || (XRa == 0))) { + /* exactly one operand is zero register - find which one is not...*/ + uint32_t XRx = XRb ? XRb : XRc; + /* ...and do half-word-wise max/min with one operand 0 */ + TCGv_i32 t0 = tcg_temp_new(); + TCGv_i32 t1 = tcg_const_i32(0); + + /* the left half-word first */ + tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0xFFFF0000); + if (opc == OPC_MXU_D16MAX) { + tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1); + } else { + tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1); + } + + /* the right half-word */ + tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0x0000FFFF); + /* move half-words to the leftmost position */ + tcg_gen_shli_i32(t0, t0, 16); + /* t0 will be max/min of t0 and t1 */ + if (opc == OPC_MXU_D16MAX) { + tcg_gen_smax_i32(t0, t0, t1); + } else { + tcg_gen_smin_i32(t0, t0, t1); + } + /* return resulting half-words to its original position */ + tcg_gen_shri_i32(t0, t0, 16); + /* finaly update the destination */ + tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0); + + tcg_temp_free(t1); + tcg_temp_free(t0); + } else if (unlikely(XRb == XRc)) { + /* both operands same -> just set destination to one of them */ + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]); + } else { + /* the most general case */ + TCGv_i32 t0 = tcg_temp_new(); + TCGv_i32 t1 = tcg_temp_new(); + + /* the left half-word first */ + tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0xFFFF0000); + tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFFFF0000); + if (opc == OPC_MXU_D16MAX) { + tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1); + } else { + tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1); + } + + /* the right half-word */ + tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x0000FFFF); + tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0x0000FFFF); + /* move half-words to the leftmost position */ + tcg_gen_shli_i32(t0, t0, 16); + tcg_gen_shli_i32(t1, t1, 16); + /* t0 will be max/min of t0 and t1 */ + if (opc == OPC_MXU_D16MAX) { + tcg_gen_smax_i32(t0, t0, t1); + } else { + tcg_gen_smin_i32(t0, t0, t1); + } + /* return resulting half-words to its original position */ + tcg_gen_shri_i32(t0, t0, 16); + /* finaly update the destination */ + tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0); + + tcg_temp_free(t1); + tcg_temp_free(t0); + } +} + +/* + * Q8MAX + * Update XRa with the 8-bit-wise maximums of signed integers + * contained in XRb and XRc. + * + * Q8MIN + * Update XRa with the 8-bit-wise minimums of signed integers + * contained in XRb and XRc. + * + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------+---------+-----+-------+-------+-------+-----------+ + * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL00| + * +-----------+---------+-----+-------+-------+-------+-----------+ + */ +static void gen_mxu_Q8MAX_Q8MIN(DisasContext *ctx) +{ + uint32_t pad, opc, XRc, XRb, XRa; + + pad = extract32(ctx->opcode, 21, 5); + opc = extract32(ctx->opcode, 18, 3); + XRc = extract32(ctx->opcode, 14, 4); + XRb = extract32(ctx->opcode, 10, 4); + XRa = extract32(ctx->opcode, 6, 4); + + if (unlikely(pad != 0)) { + /* opcode padding incorrect -> do nothing */ + } else if (unlikely(XRa == 0)) { + /* destination is zero register -> do nothing */ + } else if (unlikely((XRb == 0) && (XRc == 0))) { + /* both operands zero registers -> just set destination to zero */ + tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0); + } else if (unlikely((XRb == 0) || (XRc == 0))) { + /* exactly one operand is zero register - make it be the first...*/ + uint32_t XRx = XRb ? XRb : XRc; + /* ...and do byte-wise max/min with one operand 0 */ + TCGv_i32 t0 = tcg_temp_new(); + TCGv_i32 t1 = tcg_const_i32(0); + int32_t i; + + /* the leftmost byte (byte 3) first */ + tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0xFF000000); + if (opc == OPC_MXU_Q8MAX) { + tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1); + } else { + tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1); + } + + /* bytes 2, 1, 0 */ + for (i = 2; i >= 0; i--) { + /* extract the byte */ + tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0xFF << (8 * i)); + /* move the byte to the leftmost position */ + tcg_gen_shli_i32(t0, t0, 8 * (3 - i)); + /* t0 will be max/min of t0 and t1 */ + if (opc == OPC_MXU_Q8MAX) { + tcg_gen_smax_i32(t0, t0, t1); + } else { + tcg_gen_smin_i32(t0, t0, t1); + } + /* return resulting byte to its original position */ + tcg_gen_shri_i32(t0, t0, 8 * (3 - i)); + /* finaly update the destination */ + tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0); + } + + tcg_temp_free(t1); + tcg_temp_free(t0); + } else if (unlikely(XRb == XRc)) { + /* both operands same -> just set destination to one of them */ + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]); + } else { + /* the most general case */ + TCGv_i32 t0 = tcg_temp_new(); + TCGv_i32 t1 = tcg_temp_new(); + int32_t i; + + /* the leftmost bytes (bytes 3) first */ + tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0xFF000000); + tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFF000000); + if (opc == OPC_MXU_Q8MAX) { + tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1); + } else { + tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1); + } + + /* bytes 2, 1, 0 */ + for (i = 2; i >= 0; i--) { + /* extract corresponding bytes */ + tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0xFF << (8 * i)); + tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFF << (8 * i)); + /* move the bytes to the leftmost position */ + tcg_gen_shli_i32(t0, t0, 8 * (3 - i)); + tcg_gen_shli_i32(t1, t1, 8 * (3 - i)); + /* t0 will be max/min of t0 and t1 */ + if (opc == OPC_MXU_Q8MAX) { + tcg_gen_smax_i32(t0, t0, t1); + } else { + tcg_gen_smin_i32(t0, t0, t1); + } + /* return resulting byte to its original position */ + tcg_gen_shri_i32(t0, t0, 8 * (3 - i)); + /* finaly update the destination */ + tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0); + } + + tcg_temp_free(t1); + tcg_temp_free(t0); + } +} + + +/* * Decoding engine for MXU * ======================= */ @@ -24844,34 +25120,16 @@ static void decode_opc_mxu__pool00(CPUMIPSState *env, DisasContext *ctx) switch (opcode) { case OPC_MXU_S32MAX: - /* TODO: Implement emulation of S32MAX instruction. */ - MIPS_INVAL("OPC_MXU_S32MAX"); - generate_exception_end(ctx, EXCP_RI); - break; case OPC_MXU_S32MIN: - /* TODO: Implement emulation of S32MIN instruction. */ - MIPS_INVAL("OPC_MXU_S32MIN"); - generate_exception_end(ctx, EXCP_RI); + gen_mxu_S32MAX_S32MIN(ctx); break; case OPC_MXU_D16MAX: - /* TODO: Implement emulation of D16MAX instruction. */ - MIPS_INVAL("OPC_MXU_D16MAX"); - generate_exception_end(ctx, EXCP_RI); - break; case OPC_MXU_D16MIN: - /* TODO: Implement emulation of D16MIN instruction. */ - MIPS_INVAL("OPC_MXU_D16MIN"); - generate_exception_end(ctx, EXCP_RI); + gen_mxu_D16MAX_D16MIN(ctx); break; case OPC_MXU_Q8MAX: - /* TODO: Implement emulation of Q8MAX instruction. */ - MIPS_INVAL("OPC_MXU_Q8MAX"); - generate_exception_end(ctx, EXCP_RI); - break; case OPC_MXU_Q8MIN: - /* TODO: Implement emulation of Q8MIN instruction. */ - MIPS_INVAL("OPC_MXU_Q8MIN"); - generate_exception_end(ctx, EXCP_RI); + gen_mxu_Q8MAX_Q8MIN(ctx); break; case OPC_MXU_Q8SLT: /* TODO: Implement emulation of Q8SLT instruction. */ -- cgit v1.1 From 79f5fee7a3c53494c7ca4bc18c72944f5e2d5c2f Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 31 Dec 2018 13:14:56 +0100 Subject: target/mips: MXU: Add handler for an align instruction Add translation handler for S32ALNI MXU instruction. Reviewed-by: Stefan Markovic Signed-off-by: Aleksandar Markovic --- target/mips/translate.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 194 insertions(+), 3 deletions(-) (limited to 'target') diff --git a/target/mips/translate.c b/target/mips/translate.c index 44142ea..c79f988 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -25100,6 +25100,199 @@ static void gen_mxu_Q8MAX_Q8MIN(DisasContext *ctx) /* + * MXU instruction category: align + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * S32ALN S32ALNI + */ + +/* + * S32ALNI XRc, XRb, XRa, optn3 + * Arrange bytes from XRb and XRc according to one of five sets of + * rules determined by optn3, and place the result in XRa. + * + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------+-----+---+-----+-------+-------+-------+-----------+ + * | SPECIAL2 |optn3|0 0|x x x| XRc | XRb | XRa |MXU__POOL16| + * +-----------+-----+---+-----+-------+-------+-------+-----------+ + * + */ +static void gen_mxu_S32ALNI(DisasContext *ctx) +{ + uint32_t optn3, pad, XRc, XRb, XRa; + + optn3 = extract32(ctx->opcode, 23, 3); + pad = extract32(ctx->opcode, 21, 2); + XRc = extract32(ctx->opcode, 14, 4); + XRb = extract32(ctx->opcode, 10, 4); + XRa = extract32(ctx->opcode, 6, 4); + + if (unlikely(pad != 0)) { + /* opcode padding incorrect -> do nothing */ + } else if (unlikely(XRa == 0)) { + /* destination is zero register -> do nothing */ + } else if (unlikely((XRb == 0) && (XRc == 0))) { + /* both operands zero registers -> just set destination to all 0s */ + tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0); + } else if (unlikely(XRb == 0)) { + /* XRb zero register -> just appropriatelly shift XRc into XRa */ + switch (optn3) { + case MXU_OPTN3_PTN0: + tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0); + break; + case MXU_OPTN3_PTN1: + case MXU_OPTN3_PTN2: + case MXU_OPTN3_PTN3: + tcg_gen_shri_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1], + 8 * (4 - optn3)); + break; + case MXU_OPTN3_PTN4: + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]); + break; + } + } else if (unlikely(XRc == 0)) { + /* XRc zero register -> just appropriatelly shift XRb into XRa */ + switch (optn3) { + case MXU_OPTN3_PTN0: + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]); + break; + case MXU_OPTN3_PTN1: + case MXU_OPTN3_PTN2: + case MXU_OPTN3_PTN3: + tcg_gen_shri_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], 8 * optn3); + break; + case MXU_OPTN3_PTN4: + tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0); + break; + } + } else if (unlikely(XRb == XRc)) { + /* both operands same -> just rotation or moving from any of them */ + switch (optn3) { + case MXU_OPTN3_PTN0: + case MXU_OPTN3_PTN4: + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]); + break; + case MXU_OPTN3_PTN1: + case MXU_OPTN3_PTN2: + case MXU_OPTN3_PTN3: + tcg_gen_rotli_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], 8 * optn3); + break; + } + } else { + /* the most general case */ + switch (optn3) { + case MXU_OPTN3_PTN0: + { + /* */ + /* XRb XRc */ + /* +---------------+ */ + /* | A B C D | E F G H */ + /* +-------+-------+ */ + /* | */ + /* XRa */ + /* */ + + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]); + } + break; + case MXU_OPTN3_PTN1: + { + /* */ + /* XRb XRc */ + /* +-------------------+ */ + /* A | B C D E | F G H */ + /* +---------+---------+ */ + /* | */ + /* XRa */ + /* */ + + TCGv_i32 t0 = tcg_temp_new(); + TCGv_i32 t1 = tcg_temp_new(); + + tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x00FFFFFF); + tcg_gen_shli_i32(t0, t0, 8); + + tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFF000000); + tcg_gen_shri_i32(t1, t1, 24); + + tcg_gen_or_i32(mxu_gpr[XRa - 1], t0, t1); + + tcg_temp_free(t1); + tcg_temp_free(t0); + } + break; + case MXU_OPTN3_PTN2: + { + /* */ + /* XRb XRc */ + /* +-------------------+ */ + /* A B | C D E F | G H */ + /* +---------+---------+ */ + /* | */ + /* XRa */ + /* */ + + TCGv_i32 t0 = tcg_temp_new(); + TCGv_i32 t1 = tcg_temp_new(); + + tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x0000FFFF); + tcg_gen_shli_i32(t0, t0, 16); + + tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFFFF0000); + tcg_gen_shri_i32(t1, t1, 16); + + tcg_gen_or_i32(mxu_gpr[XRa - 1], t0, t1); + + tcg_temp_free(t1); + tcg_temp_free(t0); + } + break; + case MXU_OPTN3_PTN3: + { + /* */ + /* XRb XRc */ + /* +-------------------+ */ + /* A B C | D E F G | H */ + /* +---------+---------+ */ + /* | */ + /* XRa */ + /* */ + + TCGv_i32 t0 = tcg_temp_new(); + TCGv_i32 t1 = tcg_temp_new(); + + tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x000000FF); + tcg_gen_shli_i32(t0, t0, 24); + + tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFFFFFF00); + tcg_gen_shri_i32(t1, t1, 8); + + tcg_gen_or_i32(mxu_gpr[XRa - 1], t0, t1); + + tcg_temp_free(t1); + tcg_temp_free(t0); + } + break; + case MXU_OPTN3_PTN4: + { + /* */ + /* XRb XRc */ + /* +---------------+ */ + /* A B C D | E F G H | */ + /* +-------+-------+ */ + /* | */ + /* XRa */ + /* */ + + tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]); + } + break; + } + } +} + + +/* * Decoding engine for MXU * ======================= */ @@ -25761,9 +25954,7 @@ static void decode_opc_mxu__pool16(CPUMIPSState *env, DisasContext *ctx) generate_exception_end(ctx, EXCP_RI); break; case OPC_MXU_S32ALNI: - /* TODO: Implement emulation of S32ALNI instruction. */ - MIPS_INVAL("OPC_MXU_S32ALNI"); - generate_exception_end(ctx, EXCP_RI); + gen_mxu_S32ALNI(ctx); break; case OPC_MXU_S32LUI: /* TODO: Implement emulation of S32LUI instruction. */ -- cgit v1.1 From 3b948f053fc588154d95228da8a6561c61c66104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 27 Dec 2018 19:00:44 +0100 Subject: target/mips: Support R5900 three-operand MADD and MADDU instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The three-operand MADD and MADDU are specific to Sony R5900 core, and Toshiba TX19/TX39/TX79 cores as well. The "32-Bit TX System RISC TX39 Family Architecture manual" is available at https://wiki.qemu.org/File:DSAE0022432.pdf Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Fredrik Noring Tested-by: Fredrik Noring --- target/mips/translate.c | 58 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 5 deletions(-) (limited to 'target') diff --git a/target/mips/translate.c b/target/mips/translate.c index c79f988..0a49926 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -5033,8 +5033,8 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc, } /* - * These MULT and MULTU instructions implemented in for example the - * Toshiba/Sony R5900 and the Toshiba TX19, TX39 and TX79 core + * These MULT[U] and MADD[U] instructions implemented in for example + * the Toshiba/Sony R5900 and the Toshiba TX19, TX39 and TX79 core * architectures are special three-operand variants with the syntax * * MULT[U][1] rd, rs, rt @@ -5043,6 +5043,14 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc, * * (rd, LO, HI) <- rs * rt * + * and + * + * MADD[U] rd, rs, rt + * + * such that + * + * (rd, LO, HI) <- (LO, HI) + rs * rt + * * where the low-order 32-bits of the result is placed into both the * GPR rd and the special register LO. The high-order 32-bits of the * result is placed into the special register HI. @@ -5099,8 +5107,48 @@ static void gen_mul_txx9(DisasContext *ctx, uint32_t opc, tcg_temp_free_i32(t3); } break; + case MMI_OPC_MADD: + { + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_ext_tl_i64(t2, t0); + tcg_gen_ext_tl_i64(t3, t1); + tcg_gen_mul_i64(t2, t2, t3); + tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]); + tcg_gen_add_i64(t2, t2, t3); + tcg_temp_free_i64(t3); + gen_move_low32(cpu_LO[acc], t2); + gen_move_high32(cpu_HI[acc], t2); + if (rd) { + gen_move_low32(cpu_gpr[rd], t2); + } + tcg_temp_free_i64(t2); + } + break; + case MMI_OPC_MADDU: + { + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_extu_tl_i64(t2, t0); + tcg_gen_extu_tl_i64(t3, t1); + tcg_gen_mul_i64(t2, t2, t3); + tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]); + tcg_gen_add_i64(t2, t2, t3); + tcg_temp_free_i64(t3); + gen_move_low32(cpu_LO[acc], t2); + gen_move_high32(cpu_HI[acc], t2); + if (rd) { + gen_move_low32(cpu_gpr[rd], t2); + } + tcg_temp_free_i64(t2); + } + break; default: - MIPS_INVAL("mul TXx9"); + MIPS_INVAL("mul/madd TXx9"); generate_exception_end(ctx, EXCP_RI); goto out; } @@ -27320,6 +27368,8 @@ static void decode_mmi(CPUMIPSState *env, DisasContext *ctx) break; case MMI_OPC_MULT1: case MMI_OPC_MULTU1: + case MMI_OPC_MADD: + case MMI_OPC_MADDU: gen_mul_txx9(ctx, opc, rd, rs, rt); break; case MMI_OPC_DIV1: @@ -27334,8 +27384,6 @@ static void decode_mmi(CPUMIPSState *env, DisasContext *ctx) case MMI_OPC_MFHI1: gen_HILO1_tx79(ctx, opc, rd); break; - case MMI_OPC_MADD: /* TODO: MMI_OPC_MADD */ - case MMI_OPC_MADDU: /* TODO: MMI_OPC_MADDU */ case MMI_OPC_PLZCW: /* TODO: MMI_OPC_PLZCW */ case MMI_OPC_MADD1: /* TODO: MMI_OPC_MADD1 */ case MMI_OPC_MADDU1: /* TODO: MMI_OPC_MADDU1 */ -- cgit v1.1 From a95c4c26f1dc233987350e7cb1cf62d46ade5ce5 Mon Sep 17 00:00:00 2001 From: Fredrik Noring Date: Thu, 27 Dec 2018 20:29:14 +0100 Subject: target/mips: Support R5900 three-operand MADD1 and MADDU1 instructions The three-operand MADD and MADDU are specific to R5900 cores. Reviewed-by: Aleksandar Markovic Signed-off-by: Aleksandar Markovic Signed-off-by: Fredrik Noring --- target/mips/translate.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'target') diff --git a/target/mips/translate.c b/target/mips/translate.c index 0a49926..2636e8c 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -5045,7 +5045,7 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc, * * and * - * MADD[U] rd, rs, rt + * MADD[U][1] rd, rs, rt * * such that * @@ -5107,6 +5107,9 @@ static void gen_mul_txx9(DisasContext *ctx, uint32_t opc, tcg_temp_free_i32(t3); } break; + case MMI_OPC_MADD1: + acc = 1; + /* Fall through */ case MMI_OPC_MADD: { TCGv_i64 t2 = tcg_temp_new_i64(); @@ -5126,6 +5129,9 @@ static void gen_mul_txx9(DisasContext *ctx, uint32_t opc, tcg_temp_free_i64(t2); } break; + case MMI_OPC_MADDU1: + acc = 1; + /* Fall through */ case MMI_OPC_MADDU: { TCGv_i64 t2 = tcg_temp_new_i64(); @@ -27370,6 +27376,8 @@ static void decode_mmi(CPUMIPSState *env, DisasContext *ctx) case MMI_OPC_MULTU1: case MMI_OPC_MADD: case MMI_OPC_MADDU: + case MMI_OPC_MADD1: + case MMI_OPC_MADDU1: gen_mul_txx9(ctx, opc, rd, rs, rt); break; case MMI_OPC_DIV1: @@ -27385,8 +27393,6 @@ static void decode_mmi(CPUMIPSState *env, DisasContext *ctx) gen_HILO1_tx79(ctx, opc, rd); break; case MMI_OPC_PLZCW: /* TODO: MMI_OPC_PLZCW */ - case MMI_OPC_MADD1: /* TODO: MMI_OPC_MADD1 */ - case MMI_OPC_MADDU1: /* TODO: MMI_OPC_MADDU1 */ case MMI_OPC_PMFHL: /* TODO: MMI_OPC_PMFHL */ case MMI_OPC_PMTHL: /* TODO: MMI_OPC_PMTHL */ case MMI_OPC_PSLLH: /* TODO: MMI_OPC_PSLLH */ -- cgit v1.1