target/mips: MXU: Add handlers for max/min instructions

Add translation handlers for six max/min MXU instructions.

Reviewed-by: Stefan Markovic <smarkovic@wavecomp.com>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
This commit is contained in:
Aleksandar Markovic 2018-12-31 13:14:34 +01:00
parent b621f0187e
commit bb84cbf385

View File

@ -24823,6 +24823,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 * Decoding engine for MXU
* ======================= * =======================
@ -24844,34 +25120,16 @@ static void decode_opc_mxu__pool00(CPUMIPSState *env, DisasContext *ctx)
switch (opcode) { switch (opcode) {
case OPC_MXU_S32MAX: 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: case OPC_MXU_S32MIN:
/* TODO: Implement emulation of S32MIN instruction. */ gen_mxu_S32MAX_S32MIN(ctx);
MIPS_INVAL("OPC_MXU_S32MIN");
generate_exception_end(ctx, EXCP_RI);
break; break;
case OPC_MXU_D16MAX: 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: case OPC_MXU_D16MIN:
/* TODO: Implement emulation of D16MIN instruction. */ gen_mxu_D16MAX_D16MIN(ctx);
MIPS_INVAL("OPC_MXU_D16MIN");
generate_exception_end(ctx, EXCP_RI);
break; break;
case OPC_MXU_Q8MAX: 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: case OPC_MXU_Q8MIN:
/* TODO: Implement emulation of Q8MIN instruction. */ gen_mxu_Q8MAX_Q8MIN(ctx);
MIPS_INVAL("OPC_MXU_Q8MIN");
generate_exception_end(ctx, EXCP_RI);
break; break;
case OPC_MXU_Q8SLT: case OPC_MXU_Q8SLT:
/* TODO: Implement emulation of Q8SLT instruction. */ /* TODO: Implement emulation of Q8SLT instruction. */