Add MIPS DSP Compare-Pick instructions Support. Signed-off-by: Jia Liu <pro...@gmail.com> --- target-mips/dsp_helper.c | 341 ++++++++++++++++++++++++++++++++++++++++++++++ target-mips/helper.h | 17 +++ target-mips/translate.c | 135 ++++++++++++++++++ 3 files changed, 493 insertions(+), 0 deletions(-)
diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 1c5e858..27949ab 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -3021,6 +3021,347 @@ uint32_t helper_insv(CPUMIPSState *env, uint32_t rs, uint32_t rt) return temp; } +/** DSP Compare-Pick Sub-class insns **/ +void helper_cmpu_eq_qb(CPUMIPSState *env, uint32_t rs, uint32_t rt) +{ + uint8_t rs3, rs2, rs1, rs0; + uint8_t rt3, rt2, rt1, rt0; + uint32_t cc3 = 0, cc2 = 0, cc1 = 0, cc0 = 0; + uint32_t flag; + + rs3 = (rs & MIPSDSP_Q3) >> 24; + rs2 = (rs & MIPSDSP_Q2) >> 16; + rs1 = (rs & MIPSDSP_Q1) >> 8; + rs0 = rs & MIPSDSP_Q0; + + rt3 = (rt & MIPSDSP_Q3) >> 24; + rt2 = (rt & MIPSDSP_Q2) >> 16; + rt1 = (rt & MIPSDSP_Q1) >> 8; + rt0 = rt & MIPSDSP_Q0; + + cc3 = (rs3 == rt3); + cc2 = (rs2 == rt2); + cc1 = (rs1 == rt1); + cc0 = (rs0 == rt0); + + flag = (cc3 << 3) | (cc2 << 2) | (cc1 << 1) | cc0; + set_DSPControl_24(env, flag, 4); +} + +void helper_cmpu_lt_qb(CPUMIPSState *env, uint32_t rs, uint32_t rt) +{ + uint8_t rs3, rs2, rs1, rs0; + uint8_t rt3, rt2, rt1, rt0; + uint32_t cc3 = 0, cc2 = 0, cc1 = 0, cc0 = 0; + uint32_t flag; + + rs3 = (rs & MIPSDSP_Q3) >> 24; + rs2 = (rs & MIPSDSP_Q2) >> 16; + rs1 = (rs & MIPSDSP_Q1) >> 8; + rs0 = rs & MIPSDSP_Q0; + + rt3 = (rt & MIPSDSP_Q3) >> 24; + rt2 = (rt & MIPSDSP_Q2) >> 16; + rt1 = (rt & MIPSDSP_Q1) >> 8; + rt0 = rt & MIPSDSP_Q0; + + cc3 = (rs3 < rt3); + cc2 = (rs2 < rt2); + cc1 = (rs1 < rt1); + cc0 = (rs0 < rt0); + + flag = (cc3 << 3) | (cc2 << 2) | (cc1 << 1) | cc0; + set_DSPControl_24(env, flag, 4); +} + +void helper_cmpu_le_qb(CPUMIPSState *env, uint32_t rs, uint32_t rt) +{ + uint8_t rs3, rs2, rs1, rs0; + uint8_t rt3, rt2, rt1, rt0; + uint32_t cc3 = 0, cc2 = 0, cc1 = 0, cc0 = 0; + uint32_t flag; + + rs3 = (rs & MIPSDSP_Q3) >> 24; + rs2 = (rs & MIPSDSP_Q2) >> 16; + rs1 = (rs & MIPSDSP_Q1) >> 8; + rs0 = rs & MIPSDSP_Q0; + + rt3 = (rt & MIPSDSP_Q3) >> 24; + rt2 = (rt & MIPSDSP_Q2) >> 16; + rt1 = (rt & MIPSDSP_Q1) >> 8; + rt0 = rt & MIPSDSP_Q0; + + cc3 = (rs3 <= rt3); + cc2 = (rs2 <= rt2); + cc1 = (rs1 <= rt1); + cc0 = (rs0 <= rt0); + + flag = (cc3 << 3) | (cc2 << 2) | (cc1 << 1) | cc0; + set_DSPControl_24(env, flag, 4); +} + + +uint32_t helper_cmpgu_eq_qb(uint32_t rs, uint32_t rt) +{ + uint8_t rs3, rs2, rs1, rs0; + uint8_t rt3, rt2, rt1, rt0; + uint8_t cc3 = 0, cc2 = 0, cc1 = 0, cc0 = 0; + uint32_t temp; + uint32_t rd; + + rs3 = (rs & MIPSDSP_Q3) >> 24; + rs2 = (rs & MIPSDSP_Q2) >> 16; + rs1 = (rs & MIPSDSP_Q1) >> 8; + rs0 = rs & MIPSDSP_Q0; + + rt3 = (rt & MIPSDSP_Q3) >> 24; + rt2 = (rt & MIPSDSP_Q2) >> 16; + rt1 = (rt & MIPSDSP_Q1) >> 8; + rt0 = rt & MIPSDSP_Q0; + + cc3 = (rs3 == rt3); + cc2 = (rs2 == rt2); + cc1 = (rs1 == rt1); + cc0 = (rs0 == rt0); + + temp = (cc3 << 3) | (cc2 << 2) | (cc1 << 1) | cc0; + rd = temp; + + return rd; +} + +uint32_t helper_cmpgu_lt_qb(uint32_t rs, uint32_t rt) +{ + uint8_t rs3, rs2, rs1, rs0; + uint8_t rt3, rt2, rt1, rt0; + uint32_t cc3 = 0, cc2 = 0, cc1 = 0, cc0 = 0; + uint32_t temp; + uint32_t rd; + + rs3 = (rs & MIPSDSP_Q3) >> 24; + rs2 = (rs & MIPSDSP_Q2) >> 16; + rs1 = (rs & MIPSDSP_Q1) >> 8; + rs0 = rs & MIPSDSP_Q0; + + rt3 = (rt & MIPSDSP_Q3) >> 24; + rt2 = (rt & MIPSDSP_Q2) >> 16; + rt1 = (rt & MIPSDSP_Q1) >> 8; + rt0 = rt & MIPSDSP_Q0; + + cc3 = (rs3 < rt3); + cc2 = (rs2 < rt2); + cc1 = (rs1 < rt1); + cc0 = (rs0 < rt0); + + temp = (cc3 << 3) | (cc2 << 2) | (cc1 << 1) | cc0; + rd = temp; + + return rd; +} + +uint32_t helper_cmpgu_le_qb(uint32_t rs, uint32_t rt) +{ + uint8_t rs3, rs2, rs1, rs0; + uint8_t rt3, rt2, rt1, rt0; + uint32_t cc3 = 0, cc2 = 0, cc1 = 0, cc0 = 0; + uint32_t temp; + uint32_t rd; + + rs3 = (rs & MIPSDSP_Q3) >> 24; + rs2 = (rs & MIPSDSP_Q2) >> 16; + rs1 = (rs & MIPSDSP_Q1) >> 8; + rs0 = rs & MIPSDSP_Q0; + + rt3 = (rt & MIPSDSP_Q3) >> 24; + rt2 = (rt & MIPSDSP_Q2) >> 16; + rt1 = (rt & MIPSDSP_Q1) >> 8; + rt0 = rt & MIPSDSP_Q0; + + cc3 = (rs3 <= rt3); + cc2 = (rs2 <= rt2); + cc1 = (rs1 <= rt1); + cc0 = (rs0 <= rt0); + + temp = (cc3 << 3) | (cc2 << 2) | (cc1 << 1) | cc0; + rd = temp; + + return rd; +} + +void helper_cmp_eq_ph(CPUMIPSState *env, uint32_t rs, uint32_t rt) +{ + int16_t rsh, rsl, rth, rtl; + int32_t flag; + int32_t ccA = 0, ccB = 0; + + rsh = (rs & MIPSDSP_HI) >> 16; + rsl = rs & MIPSDSP_LO; + rth = (rt & MIPSDSP_HI) >> 16; + rtl = rt & MIPSDSP_LO; + + ccB = (rsh == rth); + ccA = (rsl == rtl); + + flag = (ccB << 1) | ccA; + set_DSPControl_24(env, flag, 2); +} + +void helper_cmp_lt_ph(CPUMIPSState *env, uint32_t rs, uint32_t rt) +{ + int16_t rsh, rsl, rth, rtl; + int32_t flag; + int32_t ccA = 0, ccB = 0; + + rsh = (rs & MIPSDSP_HI) >> 16; + rsl = rs & MIPSDSP_LO; + rth = (rt & MIPSDSP_HI) >> 16; + rtl = rt & MIPSDSP_LO; + + ccB = (rsh < rth); + ccA = (rsl < rtl); + + flag = (ccB << 1) | ccA; + set_DSPControl_24(env, flag, 2); +} + +void helper_cmp_le_ph(CPUMIPSState *env, uint32_t rs, uint32_t rt) +{ + int16_t rsh, rsl, rth, rtl; + int32_t flag; + int32_t ccA = 0, ccB = 0; + + rsh = (rs & MIPSDSP_HI) >> 16; + rsl = rs & MIPSDSP_LO; + rth = (rt & MIPSDSP_HI) >> 16; + rtl = rt & MIPSDSP_LO; + + ccB = (rsh <= rth); + ccA = (rsl <= rtl); + + flag = (ccB << 1) | ccA; + set_DSPControl_24(env, flag, 2); +} + +uint32_t helper_pick_qb(CPUMIPSState *env, uint32_t rs, uint32_t rt) +{ + uint8_t rs3, rs2, rs1, rs0; + uint8_t rt3, rt2, rt1, rt0; + uint8_t tp3, tp2, tp1, tp0; + + uint32_t dsp27, dsp26, dsp25, dsp24, rd; + target_ulong dsp; + + rs3 = (rs & MIPSDSP_Q3) >> 24; + rs2 = (rs & MIPSDSP_Q2) >> 16; + rs1 = (rs & MIPSDSP_Q1) >> 8; + rs0 = rs & MIPSDSP_Q0; + rt3 = (rt & MIPSDSP_Q3) >> 24; + rt2 = (rt & MIPSDSP_Q2) >> 16; + rt1 = (rt & MIPSDSP_Q1) >> 8; + rt0 = rt & MIPSDSP_Q0; + + dsp = env->active_tc.DSPControl; + dsp27 = (dsp >> 27) & 0x01; + dsp26 = (dsp >> 26) & 0x01; + dsp25 = (dsp >> 25) & 0x01; + dsp24 = (dsp >> 24) & 0x01; + + tp3 = dsp27 == 1 ? rs3 : rt3; + tp2 = dsp26 == 1 ? rs2 : rt2; + tp1 = dsp25 == 1 ? rs1 : rt1; + tp0 = dsp24 == 1 ? rs0 : rt0; + + rd = ((uint32_t)tp3 << 24) | \ + ((uint32_t)tp2 << 16) | \ + ((uint32_t)tp1 << 8) | \ + (uint32_t)tp0; + + return rd; +} + +uint32_t helper_pick_ph(CPUMIPSState *env, uint32_t rs, uint32_t rt) +{ + uint16_t rsh, rsl, rth, rtl; + uint16_t tempB, tempA; + uint32_t dsp25, dsp24; + uint32_t rd; + target_ulong dsp; + + rsh = (rs & MIPSDSP_HI) >> 16; + rsl = rs & MIPSDSP_LO; + rth = (rt & MIPSDSP_HI) >> 16; + rtl = rt & MIPSDSP_LO; + + dsp = env->active_tc.DSPControl; + dsp25 = (dsp >> 25) & 0x01; + dsp24 = (dsp >> 24) & 0x01; + + tempB = (dsp25 == 1) ? rsh : rth; + tempA = (dsp24 == 1) ? rsl : rtl; + rd = (((uint32_t)tempB << 16) & MIPSDSP_HI) | (uint32_t)tempA; + + return rd; +} + +uint32_t helper_append(uint32_t rt, uint32_t rs, int sa) +{ + int len; + uint32_t temp; + + len = sa & 0x1F; + + if (len == 0) { + temp = rt; + } else { + temp = (rt << len) | (rs & (((uint32_t)0x01 << len) - 1)); + } + rt = temp; + + return temp; +} + +uint32_t helper_prepend(int sa, uint32_t rs, uint32_t rt) +{ + uint32_t temp; + + if (sa == 0) { + temp = rt; + } else { + temp = (rs << (32 - sa)) | rt >> sa; + } + + rt = temp; + + return rt; +} + +uint32_t helper_balign(uint32_t rt, uint32_t rs, uint32_t bp) +{ + uint32_t temp; + bp = bp & 0x03; + + if (bp == 0 || bp == 2) { + return rt; + } else { + temp = (rt << (8 * bp)) | (rs >> (8 * (4 - bp))); + } + rt = temp; + + return rt; +} + +uint32_t helper_packrl_ph(uint32_t rs, uint32_t rt) +{ + uint16_t rsl, rth; + uint32_t rd; + + rsl = rs & MIPSDSP_LO; + rth = (rt & MIPSDSP_HI) >> 16; + rd = (rsl << 16) | rth; + + return rd; +} + #undef MIPSDSP_LHI #undef MIPSDSP_LLO #undef MIPSDSP_HI diff --git a/target-mips/helper.h b/target-mips/helper.h index 669537b..7737a22 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -414,4 +414,21 @@ DEF_HELPER_FLAGS_4(mulsa_w_ph, 0, void, env, int, i32, i32) DEF_HELPER_FLAGS_1(bitrev, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) DEF_HELPER_FLAGS_3(insv, 0, i32, env, i32, i32) +/* DSP Compare-Pick Sub-class insns */ +DEF_HELPER_FLAGS_3(cmpu_eq_qb, 0, void, env, i32, i32) +DEF_HELPER_FLAGS_3(cmpu_lt_qb, 0, void, env, i32, i32) +DEF_HELPER_FLAGS_3(cmpu_le_qb, 0, void, env, i32, i32) +DEF_HELPER_FLAGS_2(cmpgu_eq_qb, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32, i32) +DEF_HELPER_FLAGS_2(cmpgu_lt_qb, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32, i32) +DEF_HELPER_FLAGS_2(cmpgu_le_qb, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32, i32) +DEF_HELPER_FLAGS_3(cmp_eq_ph, 0, void, env, i32, i32) +DEF_HELPER_FLAGS_3(cmp_lt_ph, 0, void, env, i32, i32) +DEF_HELPER_FLAGS_3(cmp_le_ph, 0, void, env, i32, i32) +DEF_HELPER_FLAGS_3(pick_qb, 0, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(pick_ph, 0, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(append, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32, i32, int) +DEF_HELPER_FLAGS_3(prepend, TCG_CALL_CONST | TCG_CALL_PURE, i32, int, i32, i32) +DEF_HELPER_FLAGS_3(balign, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32, i32, i32) +DEF_HELPER_FLAGS_2(packrl_ph, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32, i32) + #include "def-helper.h" diff --git a/target-mips/translate.c b/target-mips/translate.c index 7d385f2..f5d3859 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -329,6 +329,8 @@ enum { OPC_DPA_W_PH_DSP = 0x30 | OPC_SPECIAL3, /* DSP Bit/Manipulation Sub-class */ OPC_INSV_DSP = 0x0C | OPC_SPECIAL3, + /* MIPS DSP Compare-Pick Sub-class */ + OPC_APPEND_DSP = 0x31 | OPC_SPECIAL3, }; /* BSHFL opcodes */ @@ -448,6 +450,22 @@ enum { OPC_PRECRQ_PH_W = (0x14 << 6) | OPC_CMPU_EQ_QB_DSP, OPC_PRECRQ_RS_PH_W = (0x15 << 6) | OPC_CMPU_EQ_QB_DSP, OPC_PRECRQU_S_QB_PH = (0x0F << 6) | OPC_CMPU_EQ_QB_DSP, + /* DSP Compare-Pick Sub-class */ + OPC_CMPU_EQ_QB = (0x00 << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_CMPU_LT_QB = (0x01 << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_CMPU_LE_QB = (0x02 << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_CMPGU_EQ_QB = (0x04 << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_CMPGU_LT_QB = (0x05 << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_CMPGU_LE_QB = (0x06 << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_CMPGDU_EQ_QB = (0x18 << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_CMPGDU_LT_QB = (0x19 << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_CMPGDU_LE_QB = (0x1A << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_CMP_EQ_PH = (0x08 << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_CMP_LT_PH = (0x09 << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_CMP_LE_PH = (0x0A << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_PICK_QB = (0x03 << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_PICK_PH = (0x0B << 6) | OPC_CMPU_EQ_QB_DSP, + OPC_PACKRL_PH = (0x0E << 6) | OPC_CMPU_EQ_QB_DSP, }; #define MASK_SHLL_QB(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) @@ -510,6 +528,14 @@ enum { OPC_INSV = (0x00 << 6) | OPC_INSV_DSP, }; +#define MASK_APPEND(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) +enum { + /* MIPS DSP Compare-Pick Sub-class */ + OPC_APPEND = (0x00 << 6) | OPC_APPEND_DSP, + OPC_PREPEND = (0x01 << 6) | OPC_APPEND_DSP, + OPC_BALIGN = (0x10 << 6) | OPC_APPEND_DSP, +}; + /* Coprocessor 0 (rs field) */ #define MASK_CP0(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) @@ -12595,6 +12621,86 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) gen_helper_precrqu_s_qb_ph(cpu_gpr[rd], cpu_env, cpu_gpr[rs], cpu_gpr[rt]); break; + case OPC_CMPU_EQ_QB: + gen_helper_cmpu_eq_qb(cpu_env, cpu_gpr[rs], cpu_gpr[rt]); + break; + case OPC_CMPU_LT_QB: + gen_helper_cmpu_lt_qb(cpu_env, cpu_gpr[rs], cpu_gpr[rt]); + break; + case OPC_CMPU_LE_QB: + gen_helper_cmpu_le_qb(cpu_env, cpu_gpr[rs], cpu_gpr[rt]); + break; + case OPC_CMPGU_EQ_QB: + gen_helper_cmpgu_eq_qb(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); + break; + case OPC_CMPGU_LT_QB: + gen_helper_cmpgu_lt_qb(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); + break; + case OPC_CMPGU_LE_QB: + gen_helper_cmpgu_le_qb(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); + break; + case OPC_CMPGDU_EQ_QB: + { + TCGv dspc, t0; + dspc = tcg_const_i32(0); + t0 = tcg_const_i32(0); + gen_helper_cmpgu_eq_qb(dspc, cpu_gpr[rs], cpu_gpr[rt]); + tcg_gen_mov_tl(cpu_gpr[rd], dspc); + tcg_gen_andi_i32(cpu_dspctrl, cpu_dspctrl, 0xF0FFFFFF); + tcg_gen_shli_i32(t0, dspc, 24); + tcg_gen_or_i32(cpu_dspctrl, cpu_dspctrl, t0); + tcg_temp_free(dspc); + tcg_temp_free(t0); + break; + } + case OPC_CMPGDU_LT_QB: + { + TCGv dspc, t0; + dspc = tcg_const_i32(0); + t0 = tcg_const_i32(0); + gen_helper_cmpgu_lt_qb(dspc, cpu_gpr[rs], cpu_gpr[rt]); + tcg_gen_mov_tl(cpu_gpr[rd], dspc); + tcg_gen_andi_i32(cpu_dspctrl, cpu_dspctrl, 0xF0FFFFFF); + tcg_gen_shli_i32(t0, dspc, 24); + tcg_gen_or_i32(cpu_dspctrl, cpu_dspctrl, t0); + tcg_temp_free(dspc); + tcg_temp_free(t0); + break; + } + case OPC_CMPGDU_LE_QB: + { + TCGv dspc, t0; + dspc = tcg_const_i32(0); + t0 = tcg_const_i32(0); + gen_helper_cmpgu_le_qb(dspc, cpu_gpr[rs], cpu_gpr[rt]); + tcg_gen_mov_tl(cpu_gpr[rd], dspc); + tcg_gen_andi_i32(cpu_dspctrl, cpu_dspctrl, 0xF0FFFFFF); + tcg_gen_shli_i32(t0, dspc, 24); + tcg_gen_or_i32(cpu_dspctrl, cpu_dspctrl, t0); + tcg_temp_free(dspc); + tcg_temp_free(t0); + break; + } + case OPC_CMP_EQ_PH: + gen_helper_cmp_eq_ph(cpu_env, cpu_gpr[rs], cpu_gpr[rt]); + break; + case OPC_CMP_LT_PH: + gen_helper_cmp_lt_ph(cpu_env, cpu_gpr[rs], cpu_gpr[rt]); + break; + case OPC_CMP_LE_PH: + gen_helper_cmp_le_ph(cpu_env, cpu_gpr[rs], cpu_gpr[rt]); + break; + case OPC_PICK_QB: + gen_helper_pick_qb(cpu_gpr[rd], cpu_env, + cpu_gpr[rs], cpu_gpr[rt]); + break; + case OPC_PICK_PH: + gen_helper_pick_ph(cpu_gpr[rd], cpu_env, + cpu_gpr[rs], cpu_gpr[rt]); + break; + case OPC_PACKRL_PH: + gen_helper_packrl_ph(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); + break; } break; case OPC_SHLL_QB_DSP: @@ -12876,6 +12982,35 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) } } break; + case OPC_APPEND_DSP: + op2 = MASK_APPEND(ctx->opcode); + switch (op2) { + case OPC_APPEND: + { + TCGv temp_rd = tcg_const_i32(rd); + gen_helper_append(cpu_gpr[rt], cpu_gpr[rt], + cpu_gpr[rs], temp_rd); + tcg_temp_free(temp_rd); + break; + } + case OPC_PREPEND: + { + TCGv temp_rd = tcg_const_i32(rd); + gen_helper_prepend(cpu_gpr[rt], temp_rd, + cpu_gpr[rs], cpu_gpr[rt]); + tcg_temp_free(temp_rd); + break; + } + case OPC_BALIGN: + { + TCGv temp_rd = tcg_const_i32(rd); + gen_helper_balign(cpu_gpr[rt], cpu_gpr[rt], + cpu_gpr[rs], temp_rd); + tcg_temp_free(temp_rd); + break; + } + } + break; #if defined(TARGET_MIPS64) case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: -- 1.7.5.4