diff mbox

[v12,07/14] target-mips: Add ASE DSP GPR-based shift instructions

Message ID 1351088234-7421-8-git-send-email-proljc@gmail.com
State New
Headers show

Commit Message

Jia Liu Oct. 24, 2012, 2:17 p.m. UTC
Add MIPS ASE DSP GPR-Based Shift instructions.

Signed-off-by: Jia Liu <proljc@gmail.com>
---
 target-mips/dsp_helper.c |  256 ++++++++++++++++++++++++++++++++++++
 target-mips/helper.h     |   38 ++++++
 target-mips/translate.c  |  324 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 618 insertions(+)

Comments

Aurelien Jarno Oct. 29, 2012, 1:54 p.m. UTC | #1
On Wed, Oct 24, 2012 at 10:17:07PM +0800, Jia Liu wrote:
> Add MIPS ASE DSP GPR-Based Shift instructions.
> 
> Signed-off-by: Jia Liu <proljc@gmail.com>
> ---
>  target-mips/dsp_helper.c |  256 ++++++++++++++++++++++++++++++++++++
>  target-mips/helper.h     |   38 ++++++
>  target-mips/translate.c  |  324 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 618 insertions(+)
> 
> diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c
> index 7ddad34..3c79ceb 100644
> --- a/target-mips/dsp_helper.c
> +++ b/target-mips/dsp_helper.c
> @@ -1933,6 +1933,262 @@ PRECEU_QH(obra, 48, 32, 16, 0);
>  
>  #endif
>  
> +/** DSP GPR-Based Shift Sub-class insns **/
> +#define SHIFT_QB(name, func) \
> +target_ulong helper_##name##_qb(target_ulong sa, target_ulong rt) \
> +{                                                                    \
> +    uint8_t rt3, rt2, rt1, rt0;                                      \
> +                                                                     \
> +    sa = sa & 0x07;                                                  \
> +                                                                     \
> +    MIPSDSP_SPLIT32_8(rt, rt3, rt2, rt1, rt0);                       \
> +                                                                     \
> +    rt3 = mipsdsp_##func(rt3, sa);                                   \
> +    rt2 = mipsdsp_##func(rt2, sa);                                   \
> +    rt1 = mipsdsp_##func(rt1, sa);                                   \
> +    rt0 = mipsdsp_##func(rt0, sa);                                   \
> +                                                                     \
> +    return MIPSDSP_RETURN32_8(rt3, rt2, rt1, rt0);                   \
> +}
> +
> +#define SHIFT_QB_ENV(name, func) \
> +target_ulong helper_##name##_qb(target_ulong sa, target_ulong rt,\
> +                                CPUMIPSState *env) \
> +{                                                                    \
> +    uint8_t rt3, rt2, rt1, rt0;                                      \
> +                                                                     \
> +    sa = sa & 0x07;                                                  \
> +                                                                     \
> +    MIPSDSP_SPLIT32_8(rt, rt3, rt2, rt1, rt0);                       \
> +                                                                     \
> +    rt3 = mipsdsp_##func(rt3, sa, env);                              \
> +    rt2 = mipsdsp_##func(rt2, sa, env);                              \
> +    rt1 = mipsdsp_##func(rt1, sa, env);                              \
> +    rt0 = mipsdsp_##func(rt0, sa, env);                              \
> +                                                                     \
> +    return MIPSDSP_RETURN32_8(rt3, rt2, rt1, rt0);                   \
> +}
> +
> +SHIFT_QB_ENV(shll, lshift8);
> +SHIFT_QB(shrl, rshift_u8);
> +
> +SHIFT_QB(shra, rashift8);
> +SHIFT_QB(shra_r, rnd8_rashift);
> +
> +#undef SHIFT_QB
> +#undef SHIFT_QB_ENV
> +
> +#if defined(TARGET_MIPS64)
> +#define SHIFT_OB(name, func) \
> +target_ulong helper_##name##_ob(target_ulong rt, target_ulong sa) \
> +{                                                                        \
> +    int i;                                                               \
> +    uint8_t rt_t[8];                                                     \
> +    uint64_t temp;                                                       \
> +                                                                         \
> +    sa = sa & 0x07;                                                      \
> +    temp = 0;                                                            \
> +                                                                         \
> +    for (i = 0; i < 8; i++) {                                            \
> +        rt_t[i] = (rt >> (8 * i)) & MIPSDSP_Q0;                          \
> +        rt_t[i] = mipsdsp_##func(rt_t[i], sa);                           \
> +        temp |= (uint64_t)rt_t[i] << (8 * i);                            \
> +    }                                                                    \
> +                                                                         \
> +    return temp;                                                         \
> +}
> +
> +#define SHIFT_OB_ENV(name, func) \
> +target_ulong helper_##name##_ob(target_ulong rt, target_ulong sa, \
> +                                CPUMIPSState *env)                       \
> +{                                                                        \
> +    int i;                                                               \
> +    uint8_t rt_t[8];                                                     \
> +    uint64_t temp;                                                       \
> +                                                                         \
> +    sa = sa & 0x07;                                                      \
> +    temp = 0;                                                            \
> +                                                                         \
> +    for (i = 0; i < 8; i++) {                                            \
> +        rt_t[i] = (rt >> (8 * i)) & MIPSDSP_Q0;                          \
> +        rt_t[i] = mipsdsp_##func(rt_t[i], sa, env);                      \
> +        temp |= (uint64_t)rt_t[i] << (8 * i);                            \
> +    }                                                                    \
> +                                                                         \
> +    return temp;                                                         \
> +}
> +
> +SHIFT_OB_ENV(shll, lshift8);
> +SHIFT_OB(shrl, rshift_u8);
> +
> +SHIFT_OB(shra, rashift8);
> +SHIFT_OB(shra_r, rnd8_rashift);
> +
> +#undef SHIFT_OB
> +#undef SHIFT_OB_ENV
> +
> +#endif
> +
> +#define SHIFT_PH(name, func) \
> +target_ulong helper_##name##_ph(target_ulong sa, target_ulong rt, \
> +                                CPUMIPSState *env)                \
> +{                                                                 \
> +    uint16_t rth, rtl;                                            \
> +                                                                  \
> +    sa = sa & 0x0F;                                               \
> +                                                                  \
> +    MIPSDSP_SPLIT32_16(rt, rth, rtl);                             \
> +                                                                  \
> +    rth = mipsdsp_##func(rth, sa, env);                           \
> +    rtl = mipsdsp_##func(rtl, sa, env);                           \
> +                                                                  \
> +    return MIPSDSP_RETURN32_16(rth, rtl);                         \
> +}
> +
> +SHIFT_PH(shll, lshift16);
> +SHIFT_PH(shll_s, sat16_lshift);
> +
> +#undef SHIFT_PH
> +
> +#if defined(TARGET_MIPS64)
> +#define SHIFT_QH(name, func) \
> +target_ulong helper_##name##_qh(target_ulong rt, target_ulong sa) \
> +{                                                                 \
> +    uint16_t rt3, rt2, rt1, rt0;                                  \
> +                                                                  \
> +    sa = sa & 0x0F;                                               \
> +                                                                  \
> +    MIPSDSP_SPLIT64_16(rt, rt3, rt2, rt1, rt0);                   \
> +                                                                  \
> +    rt3 = mipsdsp_##func(rt3, sa);                                \
> +    rt2 = mipsdsp_##func(rt2, sa);                                \
> +    rt1 = mipsdsp_##func(rt1, sa);                                \
> +    rt0 = mipsdsp_##func(rt0, sa);                                \
> +                                                                  \
> +    return MIPSDSP_RETURN64_16(rt3, rt2, rt1, rt0);               \
> +}
> +
> +#define SHIFT_QH_ENV(name, func) \
> +target_ulong helper_##name##_qh(target_ulong rt, target_ulong sa, \
> +                                CPUMIPSState *env)                \
> +{                                                                 \
> +    uint16_t rt3, rt2, rt1, rt0;                                  \
> +                                                                  \
> +    sa = sa & 0x0F;                                               \
> +                                                                  \
> +    MIPSDSP_SPLIT64_16(rt, rt3, rt2, rt1, rt0);                   \
> +                                                                  \
> +    rt3 = mipsdsp_##func(rt3, sa, env);                           \
> +    rt2 = mipsdsp_##func(rt2, sa, env);                           \
> +    rt1 = mipsdsp_##func(rt1, sa, env);                           \
> +    rt0 = mipsdsp_##func(rt0, sa, env);                           \
> +                                                                  \
> +    return MIPSDSP_RETURN64_16(rt3, rt2, rt1, rt0);               \
> +}
> +
> +SHIFT_QH_ENV(shll, lshift16);
> +SHIFT_QH_ENV(shll_s, sat16_lshift);
> +
> +SHIFT_QH(shrl, rshift_u16);
> +SHIFT_QH(shra, rashift16);
> +SHIFT_QH(shra_r, rnd16_rashift);
> +
> +#undef SHIFT_QH
> +#undef SHIFT_QH_ENV
> +
> +#endif
> +
> +#define SHIFT_W(name, func) \
> +target_ulong helper_##name##_w(target_ulong sa, target_ulong rt) \
> +{                                                                       \
> +    uint32_t temp;                                                      \
> +                                                                        \
> +    sa = sa & 0x1F;                                                     \
> +    temp = mipsdsp_##func(rt, sa);                                      \
> +                                                                        \
> +    return (target_long)(int32_t)temp;                                  \
> +}
> +
> +#define SHIFT_W_ENV(name, func) \
> +target_ulong helper_##name##_w(target_ulong sa, target_ulong rt, \
> +                               CPUMIPSState *env) \
> +{                                                                       \
> +    uint32_t temp;                                                      \
> +                                                                        \
> +    sa = sa & 0x1F;                                                     \
> +    temp = mipsdsp_##func(rt, sa, env);                                 \
> +                                                                        \
> +    return (target_long)(int32_t)temp;                                  \
> +}
> +
> +SHIFT_W_ENV(shll_s, sat32_lshift);
> +SHIFT_W(shra_r, rnd32_rashift);
> +
> +#undef SHIFT_W
> +#undef SHIFT_W_ENV
> +
> +#if defined(TARGET_MIPS64)
> +#define SHIFT_PW(name, func) \
> +target_ulong helper_##name##_pw(target_ulong rt, target_ulong sa) \
> +{                                                                 \
> +    uint32_t rt1, rt0;                                            \
> +                                                                  \
> +    sa = sa & 0x1F;                                               \
> +    MIPSDSP_SPLIT64_32(rt, rt1, rt0);                             \
> +                                                                  \
> +    rt1 = mipsdsp_##func(rt1, sa);                                \
> +    rt0 = mipsdsp_##func(rt0, sa);                                \
> +                                                                  \
> +    return MIPSDSP_RETURN64_32(rt1, rt0);                         \
> +}
> +
> +#define SHIFT_PW_ENV(name, func) \
> +target_ulong helper_##name##_pw(target_ulong rt, target_ulong sa, \
> +                                CPUMIPSState *env)                \
> +{                                                                 \
> +    uint32_t rt1, rt0;                                            \
> +                                                                  \
> +    sa = sa & 0x1F;                                               \
> +    MIPSDSP_SPLIT64_32(rt, rt1, rt0);                             \
> +                                                                  \
> +    rt1 = mipsdsp_##func(rt1, sa, env);                           \
> +    rt0 = mipsdsp_##func(rt0, sa, env);                           \
> +                                                                  \
> +    return MIPSDSP_RETURN64_32(rt1, rt0);                         \
> +}
> +
> +SHIFT_PW_ENV(shll, lshift32);
> +SHIFT_PW_ENV(shll_s, sat32_lshift);
> +
> +SHIFT_PW(shra, rashift32);
> +SHIFT_PW(shra_r, rnd32_rashift);
> +
> +#undef SHIFT_PW
> +#undef SHIFT_PW_ENV
> +
> +#endif
> +
> +#define SHIFT_PH(name, func) \
> +target_ulong helper_##name##_ph(target_ulong sa, target_ulong rt) \
> +{                                                                    \
> +    uint16_t rth, rtl;                                               \
> +                                                                     \
> +    sa = sa & 0x0F;                                                  \
> +                                                                     \
> +    MIPSDSP_SPLIT32_16(rt, rth, rtl);                                \
> +                                                                     \
> +    rth = mipsdsp_##func(rth, sa);                                   \
> +    rtl = mipsdsp_##func(rtl, sa);                                   \
> +                                                                     \
> +    return MIPSDSP_RETURN32_16(rth, rtl);                            \
> +}
> +
> +SHIFT_PH(shrl, rshift_u16);
> +SHIFT_PH(shra, rashift16);
> +SHIFT_PH(shra_r, rnd16_rashift);
> +
> +#undef SHIFT_PH
> +
>  #undef MIPSDSP_LHI
>  #undef MIPSDSP_LLO
>  #undef MIPSDSP_HI
> diff --git a/target-mips/helper.h b/target-mips/helper.h
> index 9201aae..5258ef6 100644
> --- a/target-mips/helper.h
> +++ b/target-mips/helper.h
> @@ -488,4 +488,42 @@ DEF_HELPER_FLAGS_1(preceu_qh_obla, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
>  DEF_HELPER_FLAGS_1(preceu_qh_obra, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
>  #endif
>  
> +/* DSP GPR-Based Shift Sub-class insns */
> +DEF_HELPER_FLAGS_3(shll_qb, 0, tl, tl, tl, env)
> +#if defined(TARGET_MIPS64)
> +DEF_HELPER_FLAGS_3(shll_ob, 0, tl, tl, tl, env)
> +#endif
> +DEF_HELPER_FLAGS_3(shll_ph, 0, tl, tl, tl, env)
> +DEF_HELPER_FLAGS_3(shll_s_ph, 0, tl, tl, tl, env)
> +#if defined(TARGET_MIPS64)
> +DEF_HELPER_FLAGS_3(shll_qh, 0, tl, tl, tl, env)
> +DEF_HELPER_FLAGS_3(shll_s_qh, 0, tl, tl, tl, env)
> +#endif
> +DEF_HELPER_FLAGS_3(shll_s_w, 0, tl, tl, tl, env)
> +#if defined(TARGET_MIPS64)
> +DEF_HELPER_FLAGS_3(shll_pw, 0, tl, tl, tl, env)
> +DEF_HELPER_FLAGS_3(shll_s_pw, 0, tl, tl, tl, env)
> +#endif
> +DEF_HELPER_FLAGS_2(shrl_qb, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +DEF_HELPER_FLAGS_2(shrl_ph, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +#if defined(TARGET_MIPS64)
> +DEF_HELPER_FLAGS_2(shrl_ob, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +DEF_HELPER_FLAGS_2(shrl_qh, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +#endif
> +DEF_HELPER_FLAGS_2(shra_qb, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +DEF_HELPER_FLAGS_2(shra_r_qb, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +#if defined(TARGET_MIPS64)
> +DEF_HELPER_FLAGS_2(shra_ob, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +DEF_HELPER_FLAGS_2(shra_r_ob, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +#endif
> +DEF_HELPER_FLAGS_2(shra_ph, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +DEF_HELPER_FLAGS_2(shra_r_ph, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +DEF_HELPER_FLAGS_2(shra_r_w, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +#if defined(TARGET_MIPS64)
> +DEF_HELPER_FLAGS_2(shra_qh, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +DEF_HELPER_FLAGS_2(shra_r_qh, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +DEF_HELPER_FLAGS_2(shra_pw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +DEF_HELPER_FLAGS_2(shra_r_pw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
> +#endif
> +
>  #include "def-helper.h"
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index c4d4c47..bcfd4b4 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -331,6 +331,18 @@ enum {
>  #if defined(TARGET_MIPS64)
>      OPC_CMPU_EQ_OB_DSP = 0x15 | OPC_SPECIAL3,
>  #endif
> +    /* MIPS DSP GPR-Based Shift Sub-class */
> +    OPC_SHLL_QB_DSP    = 0x13 | OPC_SPECIAL3,
> +#if defined(TARGET_MIPS64)
> +    OPC_SHLL_OB_DSP    = 0x17 | OPC_SPECIAL3,
> +#endif
> +    /* MIPS DSP Multiply Sub-class insns */
> +    /* OPC_MUL_PH_DSP is same as OPC_ADDUH_QB_DSP.  */
> +    /* OPC_MUL_PH_DSP     = 0x18 | OPC_SPECIAL3,  */
> +    OPC_DPA_W_PH_DSP   = 0x30 | OPC_SPECIAL3,
> +#if defined(TARGET_MIPS64)
> +    OPC_DPAQ_W_QH_DSP  = 0x34 | OPC_SPECIAL3,
> +#endif
>  };
>  
>  /* BSHFL opcodes */
> @@ -439,6 +451,32 @@ enum {
>      OPC_PRECRQ_RS_PH_W   = (0x15 << 6) | OPC_CMPU_EQ_QB_DSP,
>      OPC_PRECRQU_S_QB_PH  = (0x0F << 6) | OPC_CMPU_EQ_QB_DSP,
>  };
> +#define MASK_SHLL_QB(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
> +enum {
> +    /* MIPS DSP GPR-Based Shift Sub-class */
> +    OPC_SHLL_QB    = (0x00 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHLLV_QB   = (0x02 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHLL_PH    = (0x08 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHLLV_PH   = (0x0A << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHLL_S_PH  = (0x0C << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHLLV_S_PH = (0x0E << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHLL_S_W   = (0x14 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHLLV_S_W  = (0x16 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRL_QB    = (0x01 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRLV_QB   = (0x03 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRL_PH    = (0x19 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRLV_PH   = (0x1B << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRA_QB    = (0x04 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRA_R_QB  = (0x05 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRAV_QB   = (0x06 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRAV_R_QB = (0x07 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRA_PH    = (0x09 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRAV_PH   = (0x0B << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRA_R_PH  = (0x0D << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRAV_R_PH = (0x0F << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRA_R_W   = (0x15 << 6) | OPC_SHLL_QB_DSP,
> +    OPC_SHRAV_R_W  = (0x17 << 6) | OPC_SHLL_QB_DSP,
> +};
>  
>  #if defined(TARGET_MIPS64)
>  #define MASK_ABSQ_S_QH(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
> @@ -507,6 +545,39 @@ enum {
>  };
>  #endif
>  
> +#if defined(TARGET_MIPS64)
> +#define MASK_SHLL_OB(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
> +enum {
> +    /* MIPS DSP GPR-Based Shift Sub-class */
> +    OPC_SHLL_PW    = (0x10 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHLL_S_PW  = (0x14 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHLLV_OB   = (0x02 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHLLV_PW   = (0x12 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHLLV_S_PW = (0x16 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHLLV_QH   = (0x0A << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHLLV_S_QH = (0x0E << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRA_PW    = (0x11 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRA_R_PW  = (0x15 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRAV_OB   = (0x06 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRAV_R_OB = (0x07 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRAV_PW   = (0x13 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRAV_R_PW = (0x17 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRAV_QH   = (0x0B << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRAV_R_QH = (0x0F << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRLV_OB   = (0x03 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRLV_QH   = (0x1B << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHLL_OB    = (0x00 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHLL_QH    = (0x08 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHLL_S_QH  = (0x0C << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRA_OB    = (0x04 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRA_R_OB  = (0x05 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRA_QH    = (0x09 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRA_R_QH  = (0x0D << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRL_OB    = (0x01 << 6) | OPC_SHLL_OB_DSP,
> +    OPC_SHRL_QH    = (0x19 << 6) | OPC_SHLL_OB_DSP,
> +};
> +#endif
> +
>  /* Coprocessor 0 (rs field) */
>  #define MASK_CP0(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
>  
> @@ -12888,6 +12959,253 @@ static void gen_mipsdsp_arith(DisasContext *ctx, uint32_t op1, uint32_t op2,
>      MIPS_DEBUG("%s", opn);
>  }
>  
> +static void gen_mipsdsp_shift(DisasContext *ctx, uint32_t opc,
> +                              int ret, int v1, int v2)
> +{
> +    uint32_t op2;
> +    const char *opn = "mipsdsp shift";
> +    TCGv t0;
> +    TCGv v1_t;
> +    TCGv v2_t;
> +
> +    if (ret == 0) {
> +        /* Treat as NOP. */
> +        MIPS_DEBUG("NOP");
> +        return;
> +    }
> +
> +    t0 = tcg_temp_new();
> +    v1_t = tcg_temp_new();
> +    v2_t = tcg_temp_new();
> +
> +    tcg_gen_movi_tl(t0, v1);
> +    gen_load_gpr(v1_t, v1);
> +    gen_load_gpr(v2_t, v2);

As previously said, this won't work. When v1 is an immediate value,
gen_load_gpr() might be called with a value <= 0 or > 31. gen_load_gpr()
is defined by:

| static inline void gen_load_gpr (TCGv t, int reg)
| {
|     if (reg == 0)
|         tcg_gen_movi_tl(t, 0);
|     else
|         tcg_gen_mov_tl(t, cpu_gpr[reg]);
| }

In that case, it means the cpu_gpr array will be accessed out of bound.
The best solution for that is to split gen_mipsdsp_shift in two
functions, one for register operations, and one for immediate
operations.

> +    switch (opc) {
> +    case OPC_SHLL_QB_DSP:
> +        {
> +            op2 = MASK_SHLL_QB(ctx->opcode);
> +            switch (op2) {
> +            case OPC_SHLL_QB:
> +                check_dsp(ctx);
> +                gen_helper_shll_qb(cpu_gpr[ret], t0, v2_t, cpu_env);
> +                break;
> +            case OPC_SHLLV_QB:
> +                check_dsp(ctx);
> +                gen_helper_shll_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env);
> +                break;
> +            case OPC_SHLL_PH:
> +                check_dsp(ctx);
> +                gen_helper_shll_ph(cpu_gpr[ret], t0, v2_t, cpu_env);
> +                break;
> +            case OPC_SHLLV_PH:
> +                check_dsp(ctx);
> +                gen_helper_shll_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
> +                break;
> +            case OPC_SHLL_S_PH:
> +                check_dsp(ctx);
> +                gen_helper_shll_s_ph(cpu_gpr[ret], t0, v2_t, cpu_env);
> +                break;
> +            case OPC_SHLLV_S_PH:
> +                check_dsp(ctx);
> +                gen_helper_shll_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
> +                break;
> +            case OPC_SHLL_S_W:
> +                check_dsp(ctx);
> +                gen_helper_shll_s_w(cpu_gpr[ret], t0, v2_t, cpu_env);
> +                break;
> +            case OPC_SHLLV_S_W:
> +                check_dsp(ctx);
> +                gen_helper_shll_s_w(cpu_gpr[ret], v1_t, v2_t, cpu_env);
> +                break;
> +            case OPC_SHRL_QB:
> +                check_dsp(ctx);
> +                gen_helper_shrl_qb(cpu_gpr[ret], t0, v2_t);
> +                break;
> +            case OPC_SHRLV_QB:
> +                check_dsp(ctx);
> +                gen_helper_shrl_qb(cpu_gpr[ret], v1_t, v2_t);
> +                break;
> +            case OPC_SHRL_PH:
> +                check_dspr2(ctx);
> +                gen_helper_shrl_ph(cpu_gpr[ret], t0, v2_t);
> +                break;
> +            case OPC_SHRLV_PH:
> +                check_dspr2(ctx);
> +                gen_helper_shrl_ph(cpu_gpr[ret], v1_t, v2_t);
> +                break;
> +            case OPC_SHRA_QB:
> +                check_dspr2(ctx);
> +                gen_helper_shra_qb(cpu_gpr[ret], t0, v2_t);
> +                break;
> +            case OPC_SHRA_R_QB:
> +                check_dspr2(ctx);
> +                gen_helper_shra_r_qb(cpu_gpr[ret], t0, v2_t);
> +                break;
> +            case OPC_SHRAV_QB:
> +                check_dspr2(ctx);
> +                gen_helper_shra_qb(cpu_gpr[ret], v1_t, v2_t);
> +                break;
> +            case OPC_SHRAV_R_QB:
> +                check_dspr2(ctx);
> +                gen_helper_shra_r_qb(cpu_gpr[ret], v1_t, v2_t);
> +                break;
> +            case OPC_SHRA_PH:
> +                check_dsp(ctx);
> +                gen_helper_shra_ph(cpu_gpr[ret], t0, v2_t);
> +                break;
> +            case OPC_SHRA_R_PH:
> +                check_dsp(ctx);
> +                gen_helper_shra_r_ph(cpu_gpr[ret], t0, v2_t);
> +                break;
> +            case OPC_SHRAV_PH:
> +                check_dsp(ctx);
> +                gen_helper_shra_ph(cpu_gpr[ret], v1_t, v2_t);
> +                break;
> +            case OPC_SHRAV_R_PH:
> +                check_dsp(ctx);
> +                gen_helper_shra_r_ph(cpu_gpr[ret], v1_t, v2_t);
> +                break;
> +            case OPC_SHRA_R_W:
> +                check_dsp(ctx);
> +                gen_helper_shra_r_w(cpu_gpr[ret], t0, v2_t);
> +                break;
> +            case OPC_SHRAV_R_W:
> +                check_dsp(ctx);
> +                gen_helper_shra_r_w(cpu_gpr[ret], v1_t, v2_t);
> +                break;
> +            default:            /* Invalid */
> +                MIPS_INVAL("MASK SHLL.QB");
> +                generate_exception(ctx, EXCP_RI);
> +                break;
> +            }
> +            break;
> +        }
> +#ifdef TARGET_MIPS64
> +    case OPC_SHLL_OB_DSP:
> +        op2 = MASK_SHLL_OB(ctx->opcode);
> +        switch (op2) {
> +        case OPC_SHLL_PW:
> +            check_dsp(ctx);
> +            gen_helper_shll_pw(cpu_gpr[ret], v2_t, t0, cpu_env);
> +            break;
> +        case OPC_SHLLV_PW:
> +            check_dsp(ctx);
> +            gen_helper_shll_pw(cpu_gpr[ret], v2_t, v1_t, cpu_env);
> +            break;
> +        case OPC_SHLL_S_PW:
> +            check_dsp(ctx);
> +            gen_helper_shll_s_pw(cpu_gpr[ret], v2_t, t0, cpu_env);
> +            break;
> +        case OPC_SHLLV_S_PW:
> +            check_dsp(ctx);
> +            gen_helper_shll_s_pw(cpu_gpr[ret], v2_t, v1_t, cpu_env);
> +            break;
> +        case OPC_SHLL_OB:
> +            check_dsp(ctx);
> +            gen_helper_shll_ob(cpu_gpr[ret], v2_t, t0, cpu_env);
> +            break;
> +        case OPC_SHLLV_OB:
> +            check_dsp(ctx);
> +            gen_helper_shll_ob(cpu_gpr[ret], v2_t, v1_t, cpu_env);
> +            break;
> +        case OPC_SHLL_QH:
> +            check_dsp(ctx);
> +            gen_helper_shll_qh(cpu_gpr[ret], v2_t, t0, cpu_env);
> +            break;
> +        case OPC_SHLLV_QH:
> +            check_dsp(ctx);
> +            gen_helper_shll_qh(cpu_gpr[ret], v2_t, v1_t, cpu_env);
> +            break;
> +        case OPC_SHLL_S_QH:
> +            check_dsp(ctx);
> +            gen_helper_shll_s_qh(cpu_gpr[ret], v2_t, t0, cpu_env);
> +            break;
> +        case OPC_SHLLV_S_QH:
> +            check_dsp(ctx);
> +            gen_helper_shll_s_qh(cpu_gpr[ret], v2_t, v1_t, cpu_env);
> +            break;
> +        case OPC_SHRA_OB:
> +            check_dspr2(ctx);
> +            gen_helper_shra_ob(cpu_gpr[ret], v2_t, t0);
> +            break;
> +        case OPC_SHRAV_OB:
> +            check_dspr2(ctx);
> +            gen_helper_shra_ob(cpu_gpr[ret], v2_t, v1_t);
> +            break;
> +        case OPC_SHRA_R_OB:
> +            check_dspr2(ctx);
> +            gen_helper_shra_r_ob(cpu_gpr[ret], v2_t, t0);
> +            break;
> +        case OPC_SHRAV_R_OB:
> +            check_dspr2(ctx);
> +            gen_helper_shra_r_ob(cpu_gpr[ret], v2_t, v1_t);
> +            break;
> +        case OPC_SHRA_PW:
> +            check_dsp(ctx);
> +            gen_helper_shra_pw(cpu_gpr[ret], v2_t, t0);
> +            break;
> +        case OPC_SHRAV_PW:
> +            check_dsp(ctx);
> +            gen_helper_shra_pw(cpu_gpr[ret], v2_t, v1_t);
> +            break;
> +        case OPC_SHRA_R_PW:
> +            check_dsp(ctx);
> +            gen_helper_shra_r_pw(cpu_gpr[ret], v2_t, t0);
> +            break;
> +        case OPC_SHRAV_R_PW:
> +            check_dsp(ctx);
> +            gen_helper_shra_r_pw(cpu_gpr[ret], v2_t, v1_t);
> +            break;
> +        case OPC_SHRA_QH:
> +            check_dsp(ctx);
> +            gen_helper_shra_qh(cpu_gpr[ret], v2_t, t0);
> +            break;
> +        case OPC_SHRAV_QH:
> +            check_dsp(ctx);
> +            gen_helper_shra_qh(cpu_gpr[ret], v2_t, v1_t);
> +            break;
> +        case OPC_SHRA_R_QH:
> +            check_dsp(ctx);
> +            gen_helper_shra_r_qh(cpu_gpr[ret], v2_t, t0);
> +            break;
> +        case OPC_SHRAV_R_QH:
> +            check_dsp(ctx);
> +            gen_helper_shra_r_qh(cpu_gpr[ret], v2_t, v1_t);
> +            break;
> +        case OPC_SHRL_OB:
> +            check_dsp(ctx);
> +            gen_helper_shrl_ob(cpu_gpr[ret], v2_t, t0);
> +            break;
> +        case OPC_SHRLV_OB:
> +            check_dsp(ctx);
> +            gen_helper_shrl_ob(cpu_gpr[ret], v2_t, v1_t);
> +            break;
> +        case OPC_SHRL_QH:
> +            check_dspr2(ctx);
> +            gen_helper_shrl_qh(cpu_gpr[ret], v2_t, t0);
> +            break;
> +        case OPC_SHRLV_QH:
> +            check_dspr2(ctx);
> +            gen_helper_shrl_qh(cpu_gpr[ret], v2_t, v1_t);
> +            break;
> +        default:            /* Invalid */
> +            MIPS_INVAL("MASK SHLL.OB");
> +            generate_exception(ctx, EXCP_RI);
> +            break;
> +        }
> +        break;
> +#endif
> +    }
> +
> +    tcg_temp_free(t0);
> +    tcg_temp_free(v1_t);
> +    tcg_temp_free(v2_t);
> +    (void)opn; /* avoid a compiler warning */
> +    MIPS_DEBUG("%s", opn);
> +}
> +
>  /* End MIPSDSP functions. */
>  
>  static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
> @@ -13364,6 +13682,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
>                  break;
>              }
>              break;
> +        case OPC_SHLL_QB_DSP:
> +            gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
> +            break;
>  #if defined(TARGET_MIPS64)
>          case OPC_DEXTM ... OPC_DEXT:
>          case OPC_DINSM ... OPC_DINS:
> @@ -13465,6 +13786,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
>                  break;
>              }
>              break;
> +        case OPC_SHLL_OB_DSP:
> +            gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
> +            break;
>  #endif
>          default:            /* Invalid */
>              MIPS_INVAL("special3");
> -- 
> 1.7.10.2 (Apple Git-33)
> 
> 
>
Jia Liu Oct. 30, 2012, 3:05 p.m. UTC | #2
Hi Aurelien,

On Mon, Oct 29, 2012 at 9:54 PM, Aurelien Jarno <aurelien@aurel32.net> wrote:
> On Wed, Oct 24, 2012 at 10:17:07PM +0800, Jia Liu wrote:
>> +static void gen_mipsdsp_shift(DisasContext *ctx, uint32_t opc,
>> +                              int ret, int v1, int v2)
>> +{
>> +    uint32_t op2;
>> +    const char *opn = "mipsdsp shift";
>> +    TCGv t0;
>> +    TCGv v1_t;
>> +    TCGv v2_t;
>> +
>> +    if (ret == 0) {
>> +        /* Treat as NOP. */
>> +        MIPS_DEBUG("NOP");
>> +        return;
>> +    }
>> +
>> +    t0 = tcg_temp_new();
>> +    v1_t = tcg_temp_new();
>> +    v2_t = tcg_temp_new();
>> +
>> +    tcg_gen_movi_tl(t0, v1);
>> +    gen_load_gpr(v1_t, v1);
>> +    gen_load_gpr(v2_t, v2);
>
> As previously said, this won't work. When v1 is an immediate value,
> gen_load_gpr() might be called with a value <= 0 or > 31. gen_load_gpr()
> is defined by:
>
> | static inline void gen_load_gpr (TCGv t, int reg)
> | {
> |     if (reg == 0)
> |         tcg_gen_movi_tl(t, 0);
> |     else
> |         tcg_gen_mov_tl(t, cpu_gpr[reg]);
> | }
>
> In that case, it means the cpu_gpr array will be accessed out of bound.
> The best solution for that is to split gen_mipsdsp_shift in two
> functions, one for register operations, and one for immediate
> operations.
>

ret/v1/v2 are all reg number, so they won't out of the range 0-31.
I just use tcg_gen_movi_tl(t0, v1); to transfer reg number to
dsp_helper.c to do more compute.

Need I add a comment here, or change the variable name?

>
> --
> Aurelien Jarno                          GPG: 1024D/F1BCDB73
> aurelien@aurel32.net                 http://www.aurel32.net

Regards,
Jia.
Jia Liu Oct. 31, 2012, 1:26 p.m. UTC | #3
Hi Aurelien,

Is this time OK?

static void gen_mipsdsp_shift(DisasContext *ctx, uint32_t opc,
                              int ret, int v1, int v2)
{
    uint32_t op2;
    const char *opn = "mipsdsp shift";
    TCGv t0;
    TCGv v1_t;
    TCGv v2_t;

    if (ret == 0) {
        /* Treat as NOP. */
        MIPS_DEBUG("NOP");
        return;
    }

    if ((v1 < 0 || v1 > 32) || (v2 < 0 || v2 > 32)) {
        generate_exception(ctx, EXCP_RI);
        return;
    }

    t0 = tcg_temp_new();
    v1_t = tcg_temp_new();
    v2_t = tcg_temp_new();

    tcg_gen_movi_tl(t0, v1);
    gen_load_gpr(v1_t, v1);
    gen_load_gpr(v2_t, v2);

    switch (opc) {
    case OPC_SHLL_QB_DSP:
        {
            op2 = MASK_SHLL_QB(ctx->opcode);
            switch (op2) {
            case OPC_SHLL_QB:
                check_dsp(ctx);
                gen_helper_shll_qb(cpu_gpr[ret], t0, v2_t, cpu_env);
                break;
            case OPC_SHLLV_QB:
                check_dsp(ctx);
                gen_helper_shll_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env);
                break;
            case OPC_SHLL_PH:
                check_dsp(ctx);
                gen_helper_shll_ph(cpu_gpr[ret], t0, v2_t, cpu_env);
                break;
            case OPC_SHLLV_PH:
                check_dsp(ctx);
                gen_helper_shll_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
                break;
            case OPC_SHLL_S_PH:
                check_dsp(ctx);
                gen_helper_shll_s_ph(cpu_gpr[ret], t0, v2_t, cpu_env);
                break;
            case OPC_SHLLV_S_PH:
                check_dsp(ctx);
                gen_helper_shll_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
                break;
            case OPC_SHLL_S_W:
                check_dsp(ctx);
                gen_helper_shll_s_w(cpu_gpr[ret], t0, v2_t, cpu_env);
                break;
            case OPC_SHLLV_S_W:
                check_dsp(ctx);
                gen_helper_shll_s_w(cpu_gpr[ret], v1_t, v2_t, cpu_env);
                break;
            case OPC_SHRL_QB:
                check_dsp(ctx);
                gen_helper_shrl_qb(cpu_gpr[ret], t0, v2_t);
                break;
            case OPC_SHRLV_QB:
                check_dsp(ctx);
                gen_helper_shrl_qb(cpu_gpr[ret], v1_t, v2_t);
                break;
            case OPC_SHRL_PH:
                check_dspr2(ctx);
                gen_helper_shrl_ph(cpu_gpr[ret], t0, v2_t);
                break;
            case OPC_SHRLV_PH:
                check_dspr2(ctx);
                gen_helper_shrl_ph(cpu_gpr[ret], v1_t, v2_t);
                break;
            case OPC_SHRA_QB:
                check_dspr2(ctx);
                gen_helper_shra_qb(cpu_gpr[ret], t0, v2_t);
                break;
            case OPC_SHRA_R_QB:
                check_dspr2(ctx);
                gen_helper_shra_r_qb(cpu_gpr[ret], t0, v2_t);
                break;
            case OPC_SHRAV_QB:
                check_dspr2(ctx);
                gen_helper_shra_qb(cpu_gpr[ret], v1_t, v2_t);
                break;
            case OPC_SHRAV_R_QB:
                check_dspr2(ctx);
                gen_helper_shra_r_qb(cpu_gpr[ret], v1_t, v2_t);
                break;
            case OPC_SHRA_PH:
                check_dsp(ctx);
                gen_helper_shra_ph(cpu_gpr[ret], t0, v2_t);
                break;
            case OPC_SHRA_R_PH:
                check_dsp(ctx);
                gen_helper_shra_r_ph(cpu_gpr[ret], t0, v2_t);
                break;
            case OPC_SHRAV_PH:
                check_dsp(ctx);
                gen_helper_shra_ph(cpu_gpr[ret], v1_t, v2_t);
                break;
            case OPC_SHRAV_R_PH:
                check_dsp(ctx);
                gen_helper_shra_r_ph(cpu_gpr[ret], v1_t, v2_t);
                break;
            case OPC_SHRA_R_W:
                check_dsp(ctx);
                gen_helper_shra_r_w(cpu_gpr[ret], t0, v2_t);
                break;
            case OPC_SHRAV_R_W:
                check_dsp(ctx);
                gen_helper_shra_r_w(cpu_gpr[ret], v1_t, v2_t);
                break;
            default:            /* Invalid */
                MIPS_INVAL("MASK SHLL.QB");
                generate_exception(ctx, EXCP_RI);
                break;
            }
            break;
        }
#ifdef TARGET_MIPS64
    case OPC_SHLL_OB_DSP:
        op2 = MASK_SHLL_OB(ctx->opcode);
        switch (op2) {
        case OPC_SHLL_PW:
            check_dsp(ctx);
            gen_helper_shll_pw(cpu_gpr[ret], v2_t, t0, cpu_env);
            break;
        case OPC_SHLLV_PW:
            check_dsp(ctx);
            gen_helper_shll_pw(cpu_gpr[ret], v2_t, v1_t, cpu_env);
            break;
        case OPC_SHLL_S_PW:
            check_dsp(ctx);
            gen_helper_shll_s_pw(cpu_gpr[ret], v2_t, t0, cpu_env);
            break;
        case OPC_SHLLV_S_PW:
            check_dsp(ctx);
            gen_helper_shll_s_pw(cpu_gpr[ret], v2_t, v1_t, cpu_env);
            break;
        case OPC_SHLL_OB:
            check_dsp(ctx);
            gen_helper_shll_ob(cpu_gpr[ret], v2_t, t0, cpu_env);
            break;
        case OPC_SHLLV_OB:
            check_dsp(ctx);
            gen_helper_shll_ob(cpu_gpr[ret], v2_t, v1_t, cpu_env);
            break;
        case OPC_SHLL_QH:
            check_dsp(ctx);
            gen_helper_shll_qh(cpu_gpr[ret], v2_t, t0, cpu_env);
            break;
        case OPC_SHLLV_QH:
            check_dsp(ctx);
            gen_helper_shll_qh(cpu_gpr[ret], v2_t, v1_t, cpu_env);
            break;
        case OPC_SHLL_S_QH:
            check_dsp(ctx);
            gen_helper_shll_s_qh(cpu_gpr[ret], v2_t, t0, cpu_env);
            break;
        case OPC_SHLLV_S_QH:
            check_dsp(ctx);
            gen_helper_shll_s_qh(cpu_gpr[ret], v2_t, v1_t, cpu_env);
            break;
        case OPC_SHRA_OB:
            check_dspr2(ctx);
            gen_helper_shra_ob(cpu_gpr[ret], v2_t, t0);
            break;
        case OPC_SHRAV_OB:
            check_dspr2(ctx);
            gen_helper_shra_ob(cpu_gpr[ret], v2_t, v1_t);
            break;
        case OPC_SHRA_R_OB:
            check_dspr2(ctx);
            gen_helper_shra_r_ob(cpu_gpr[ret], v2_t, t0);
            break;
        case OPC_SHRAV_R_OB:
            check_dspr2(ctx);
            gen_helper_shra_r_ob(cpu_gpr[ret], v2_t, v1_t);
            break;
        case OPC_SHRA_PW:
            check_dsp(ctx);
            gen_helper_shra_pw(cpu_gpr[ret], v2_t, t0);
            break;
        case OPC_SHRAV_PW:
            check_dsp(ctx);
            gen_helper_shra_pw(cpu_gpr[ret], v2_t, v1_t);
            break;
        case OPC_SHRA_R_PW:
            check_dsp(ctx);
            gen_helper_shra_r_pw(cpu_gpr[ret], v2_t, t0);
            break;
        case OPC_SHRAV_R_PW:
            check_dsp(ctx);
            gen_helper_shra_r_pw(cpu_gpr[ret], v2_t, v1_t);
            break;
        case OPC_SHRA_QH:
            check_dsp(ctx);
            gen_helper_shra_qh(cpu_gpr[ret], v2_t, t0);
            break;
        case OPC_SHRAV_QH:
            check_dsp(ctx);
            gen_helper_shra_qh(cpu_gpr[ret], v2_t, v1_t);
            break;
        case OPC_SHRA_R_QH:
            check_dsp(ctx);
            gen_helper_shra_r_qh(cpu_gpr[ret], v2_t, t0);
            break;
        case OPC_SHRAV_R_QH:
            check_dsp(ctx);
            gen_helper_shra_r_qh(cpu_gpr[ret], v2_t, v1_t);
            break;
        case OPC_SHRL_OB:
            check_dsp(ctx);
            gen_helper_shrl_ob(cpu_gpr[ret], v2_t, t0);
            break;
        case OPC_SHRLV_OB:
            check_dsp(ctx);
            gen_helper_shrl_ob(cpu_gpr[ret], v2_t, v1_t);
            break;
        case OPC_SHRL_QH:
            check_dspr2(ctx);
            gen_helper_shrl_qh(cpu_gpr[ret], v2_t, t0);
            break;
        case OPC_SHRLV_QH:
            check_dspr2(ctx);
            gen_helper_shrl_qh(cpu_gpr[ret], v2_t, v1_t);
            break;
        default:            /* Invalid */
            MIPS_INVAL("MASK SHLL.OB");
            generate_exception(ctx, EXCP_RI);
            break;
        }
        break;
#endif
    }

    tcg_temp_free(t0);
    tcg_temp_free(v1_t);
    tcg_temp_free(v2_t);
    (void)opn; /* avoid a compiler warning */
    MIPS_DEBUG("%s", opn);
}

Regards,
Jia.
Aurelien Jarno Oct. 31, 2012, 8:29 p.m. UTC | #4
On Wed, Oct 31, 2012 at 09:26:08PM +0800, Jia Liu wrote:
> Hi Aurelien,
> 
> Is this time OK?

Yes, the explanation is fine, though it means the generated code is then
not really optimal. On the other hand it means the op is doing what it
is supposed to do.

> static void gen_mipsdsp_shift(DisasContext *ctx, uint32_t opc,
>                               int ret, int v1, int v2)
> {
>     uint32_t op2;
>     const char *opn = "mipsdsp shift";
>     TCGv t0;
>     TCGv v1_t;
>     TCGv v2_t;
> 
>     if (ret == 0) {
>         /* Treat as NOP. */
>         MIPS_DEBUG("NOP");
>         return;
>     }
> 
>     if ((v1 < 0 || v1 > 32) || (v2 < 0 || v2 > 32)) {
>         generate_exception(ctx, EXCP_RI);
>         return;
>     }
> 
>     t0 = tcg_temp_new();
>     v1_t = tcg_temp_new();
>     v2_t = tcg_temp_new();
> 
>     tcg_gen_movi_tl(t0, v1);
>     gen_load_gpr(v1_t, v1);
>     gen_load_gpr(v2_t, v2);
> 
>     switch (opc) {
>     case OPC_SHLL_QB_DSP:
>         {
>             op2 = MASK_SHLL_QB(ctx->opcode);
>             switch (op2) {
>             case OPC_SHLL_QB:
>                 check_dsp(ctx);
>                 gen_helper_shll_qb(cpu_gpr[ret], t0, v2_t, cpu_env);
>                 break;
>             case OPC_SHLLV_QB:
>                 check_dsp(ctx);
>                 gen_helper_shll_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env);
>                 break;
>             case OPC_SHLL_PH:
>                 check_dsp(ctx);
>                 gen_helper_shll_ph(cpu_gpr[ret], t0, v2_t, cpu_env);
>                 break;
>             case OPC_SHLLV_PH:
>                 check_dsp(ctx);
>                 gen_helper_shll_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
>                 break;
>             case OPC_SHLL_S_PH:
>                 check_dsp(ctx);
>                 gen_helper_shll_s_ph(cpu_gpr[ret], t0, v2_t, cpu_env);
>                 break;
>             case OPC_SHLLV_S_PH:
>                 check_dsp(ctx);
>                 gen_helper_shll_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
>                 break;
>             case OPC_SHLL_S_W:
>                 check_dsp(ctx);
>                 gen_helper_shll_s_w(cpu_gpr[ret], t0, v2_t, cpu_env);
>                 break;
>             case OPC_SHLLV_S_W:
>                 check_dsp(ctx);
>                 gen_helper_shll_s_w(cpu_gpr[ret], v1_t, v2_t, cpu_env);
>                 break;
>             case OPC_SHRL_QB:
>                 check_dsp(ctx);
>                 gen_helper_shrl_qb(cpu_gpr[ret], t0, v2_t);
>                 break;
>             case OPC_SHRLV_QB:
>                 check_dsp(ctx);
>                 gen_helper_shrl_qb(cpu_gpr[ret], v1_t, v2_t);
>                 break;
>             case OPC_SHRL_PH:
>                 check_dspr2(ctx);
>                 gen_helper_shrl_ph(cpu_gpr[ret], t0, v2_t);
>                 break;
>             case OPC_SHRLV_PH:
>                 check_dspr2(ctx);
>                 gen_helper_shrl_ph(cpu_gpr[ret], v1_t, v2_t);
>                 break;
>             case OPC_SHRA_QB:
>                 check_dspr2(ctx);
>                 gen_helper_shra_qb(cpu_gpr[ret], t0, v2_t);
>                 break;
>             case OPC_SHRA_R_QB:
>                 check_dspr2(ctx);
>                 gen_helper_shra_r_qb(cpu_gpr[ret], t0, v2_t);
>                 break;
>             case OPC_SHRAV_QB:
>                 check_dspr2(ctx);
>                 gen_helper_shra_qb(cpu_gpr[ret], v1_t, v2_t);
>                 break;
>             case OPC_SHRAV_R_QB:
>                 check_dspr2(ctx);
>                 gen_helper_shra_r_qb(cpu_gpr[ret], v1_t, v2_t);
>                 break;
>             case OPC_SHRA_PH:
>                 check_dsp(ctx);
>                 gen_helper_shra_ph(cpu_gpr[ret], t0, v2_t);
>                 break;
>             case OPC_SHRA_R_PH:
>                 check_dsp(ctx);
>                 gen_helper_shra_r_ph(cpu_gpr[ret], t0, v2_t);
>                 break;
>             case OPC_SHRAV_PH:
>                 check_dsp(ctx);
>                 gen_helper_shra_ph(cpu_gpr[ret], v1_t, v2_t);
>                 break;
>             case OPC_SHRAV_R_PH:
>                 check_dsp(ctx);
>                 gen_helper_shra_r_ph(cpu_gpr[ret], v1_t, v2_t);
>                 break;
>             case OPC_SHRA_R_W:
>                 check_dsp(ctx);
>                 gen_helper_shra_r_w(cpu_gpr[ret], t0, v2_t);
>                 break;
>             case OPC_SHRAV_R_W:
>                 check_dsp(ctx);
>                 gen_helper_shra_r_w(cpu_gpr[ret], v1_t, v2_t);
>                 break;
>             default:            /* Invalid */
>                 MIPS_INVAL("MASK SHLL.QB");
>                 generate_exception(ctx, EXCP_RI);
>                 break;
>             }
>             break;
>         }
> #ifdef TARGET_MIPS64
>     case OPC_SHLL_OB_DSP:
>         op2 = MASK_SHLL_OB(ctx->opcode);
>         switch (op2) {
>         case OPC_SHLL_PW:
>             check_dsp(ctx);
>             gen_helper_shll_pw(cpu_gpr[ret], v2_t, t0, cpu_env);
>             break;
>         case OPC_SHLLV_PW:
>             check_dsp(ctx);
>             gen_helper_shll_pw(cpu_gpr[ret], v2_t, v1_t, cpu_env);
>             break;
>         case OPC_SHLL_S_PW:
>             check_dsp(ctx);
>             gen_helper_shll_s_pw(cpu_gpr[ret], v2_t, t0, cpu_env);
>             break;
>         case OPC_SHLLV_S_PW:
>             check_dsp(ctx);
>             gen_helper_shll_s_pw(cpu_gpr[ret], v2_t, v1_t, cpu_env);
>             break;
>         case OPC_SHLL_OB:
>             check_dsp(ctx);
>             gen_helper_shll_ob(cpu_gpr[ret], v2_t, t0, cpu_env);
>             break;
>         case OPC_SHLLV_OB:
>             check_dsp(ctx);
>             gen_helper_shll_ob(cpu_gpr[ret], v2_t, v1_t, cpu_env);
>             break;
>         case OPC_SHLL_QH:
>             check_dsp(ctx);
>             gen_helper_shll_qh(cpu_gpr[ret], v2_t, t0, cpu_env);
>             break;
>         case OPC_SHLLV_QH:
>             check_dsp(ctx);
>             gen_helper_shll_qh(cpu_gpr[ret], v2_t, v1_t, cpu_env);
>             break;
>         case OPC_SHLL_S_QH:
>             check_dsp(ctx);
>             gen_helper_shll_s_qh(cpu_gpr[ret], v2_t, t0, cpu_env);
>             break;
>         case OPC_SHLLV_S_QH:
>             check_dsp(ctx);
>             gen_helper_shll_s_qh(cpu_gpr[ret], v2_t, v1_t, cpu_env);
>             break;
>         case OPC_SHRA_OB:
>             check_dspr2(ctx);
>             gen_helper_shra_ob(cpu_gpr[ret], v2_t, t0);
>             break;
>         case OPC_SHRAV_OB:
>             check_dspr2(ctx);
>             gen_helper_shra_ob(cpu_gpr[ret], v2_t, v1_t);
>             break;
>         case OPC_SHRA_R_OB:
>             check_dspr2(ctx);
>             gen_helper_shra_r_ob(cpu_gpr[ret], v2_t, t0);
>             break;
>         case OPC_SHRAV_R_OB:
>             check_dspr2(ctx);
>             gen_helper_shra_r_ob(cpu_gpr[ret], v2_t, v1_t);
>             break;
>         case OPC_SHRA_PW:
>             check_dsp(ctx);
>             gen_helper_shra_pw(cpu_gpr[ret], v2_t, t0);
>             break;
>         case OPC_SHRAV_PW:
>             check_dsp(ctx);
>             gen_helper_shra_pw(cpu_gpr[ret], v2_t, v1_t);
>             break;
>         case OPC_SHRA_R_PW:
>             check_dsp(ctx);
>             gen_helper_shra_r_pw(cpu_gpr[ret], v2_t, t0);
>             break;
>         case OPC_SHRAV_R_PW:
>             check_dsp(ctx);
>             gen_helper_shra_r_pw(cpu_gpr[ret], v2_t, v1_t);
>             break;
>         case OPC_SHRA_QH:
>             check_dsp(ctx);
>             gen_helper_shra_qh(cpu_gpr[ret], v2_t, t0);
>             break;
>         case OPC_SHRAV_QH:
>             check_dsp(ctx);
>             gen_helper_shra_qh(cpu_gpr[ret], v2_t, v1_t);
>             break;
>         case OPC_SHRA_R_QH:
>             check_dsp(ctx);
>             gen_helper_shra_r_qh(cpu_gpr[ret], v2_t, t0);
>             break;
>         case OPC_SHRAV_R_QH:
>             check_dsp(ctx);
>             gen_helper_shra_r_qh(cpu_gpr[ret], v2_t, v1_t);
>             break;
>         case OPC_SHRL_OB:
>             check_dsp(ctx);
>             gen_helper_shrl_ob(cpu_gpr[ret], v2_t, t0);
>             break;
>         case OPC_SHRLV_OB:
>             check_dsp(ctx);
>             gen_helper_shrl_ob(cpu_gpr[ret], v2_t, v1_t);
>             break;
>         case OPC_SHRL_QH:
>             check_dspr2(ctx);
>             gen_helper_shrl_qh(cpu_gpr[ret], v2_t, t0);
>             break;
>         case OPC_SHRLV_QH:
>             check_dspr2(ctx);
>             gen_helper_shrl_qh(cpu_gpr[ret], v2_t, v1_t);
>             break;
>         default:            /* Invalid */
>             MIPS_INVAL("MASK SHLL.OB");
>             generate_exception(ctx, EXCP_RI);
>             break;
>         }
>         break;
> #endif
>     }
> 
>     tcg_temp_free(t0);
>     tcg_temp_free(v1_t);
>     tcg_temp_free(v2_t);
>     (void)opn; /* avoid a compiler warning */
>     MIPS_DEBUG("%s", opn);
> }
> 
> Regards,
> Jia.
>
diff mbox

Patch

diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c
index 7ddad34..3c79ceb 100644
--- a/target-mips/dsp_helper.c
+++ b/target-mips/dsp_helper.c
@@ -1933,6 +1933,262 @@  PRECEU_QH(obra, 48, 32, 16, 0);
 
 #endif
 
+/** DSP GPR-Based Shift Sub-class insns **/
+#define SHIFT_QB(name, func) \
+target_ulong helper_##name##_qb(target_ulong sa, target_ulong rt) \
+{                                                                    \
+    uint8_t rt3, rt2, rt1, rt0;                                      \
+                                                                     \
+    sa = sa & 0x07;                                                  \
+                                                                     \
+    MIPSDSP_SPLIT32_8(rt, rt3, rt2, rt1, rt0);                       \
+                                                                     \
+    rt3 = mipsdsp_##func(rt3, sa);                                   \
+    rt2 = mipsdsp_##func(rt2, sa);                                   \
+    rt1 = mipsdsp_##func(rt1, sa);                                   \
+    rt0 = mipsdsp_##func(rt0, sa);                                   \
+                                                                     \
+    return MIPSDSP_RETURN32_8(rt3, rt2, rt1, rt0);                   \
+}
+
+#define SHIFT_QB_ENV(name, func) \
+target_ulong helper_##name##_qb(target_ulong sa, target_ulong rt,\
+                                CPUMIPSState *env) \
+{                                                                    \
+    uint8_t rt3, rt2, rt1, rt0;                                      \
+                                                                     \
+    sa = sa & 0x07;                                                  \
+                                                                     \
+    MIPSDSP_SPLIT32_8(rt, rt3, rt2, rt1, rt0);                       \
+                                                                     \
+    rt3 = mipsdsp_##func(rt3, sa, env);                              \
+    rt2 = mipsdsp_##func(rt2, sa, env);                              \
+    rt1 = mipsdsp_##func(rt1, sa, env);                              \
+    rt0 = mipsdsp_##func(rt0, sa, env);                              \
+                                                                     \
+    return MIPSDSP_RETURN32_8(rt3, rt2, rt1, rt0);                   \
+}
+
+SHIFT_QB_ENV(shll, lshift8);
+SHIFT_QB(shrl, rshift_u8);
+
+SHIFT_QB(shra, rashift8);
+SHIFT_QB(shra_r, rnd8_rashift);
+
+#undef SHIFT_QB
+#undef SHIFT_QB_ENV
+
+#if defined(TARGET_MIPS64)
+#define SHIFT_OB(name, func) \
+target_ulong helper_##name##_ob(target_ulong rt, target_ulong sa) \
+{                                                                        \
+    int i;                                                               \
+    uint8_t rt_t[8];                                                     \
+    uint64_t temp;                                                       \
+                                                                         \
+    sa = sa & 0x07;                                                      \
+    temp = 0;                                                            \
+                                                                         \
+    for (i = 0; i < 8; i++) {                                            \
+        rt_t[i] = (rt >> (8 * i)) & MIPSDSP_Q0;                          \
+        rt_t[i] = mipsdsp_##func(rt_t[i], sa);                           \
+        temp |= (uint64_t)rt_t[i] << (8 * i);                            \
+    }                                                                    \
+                                                                         \
+    return temp;                                                         \
+}
+
+#define SHIFT_OB_ENV(name, func) \
+target_ulong helper_##name##_ob(target_ulong rt, target_ulong sa, \
+                                CPUMIPSState *env)                       \
+{                                                                        \
+    int i;                                                               \
+    uint8_t rt_t[8];                                                     \
+    uint64_t temp;                                                       \
+                                                                         \
+    sa = sa & 0x07;                                                      \
+    temp = 0;                                                            \
+                                                                         \
+    for (i = 0; i < 8; i++) {                                            \
+        rt_t[i] = (rt >> (8 * i)) & MIPSDSP_Q0;                          \
+        rt_t[i] = mipsdsp_##func(rt_t[i], sa, env);                      \
+        temp |= (uint64_t)rt_t[i] << (8 * i);                            \
+    }                                                                    \
+                                                                         \
+    return temp;                                                         \
+}
+
+SHIFT_OB_ENV(shll, lshift8);
+SHIFT_OB(shrl, rshift_u8);
+
+SHIFT_OB(shra, rashift8);
+SHIFT_OB(shra_r, rnd8_rashift);
+
+#undef SHIFT_OB
+#undef SHIFT_OB_ENV
+
+#endif
+
+#define SHIFT_PH(name, func) \
+target_ulong helper_##name##_ph(target_ulong sa, target_ulong rt, \
+                                CPUMIPSState *env)                \
+{                                                                 \
+    uint16_t rth, rtl;                                            \
+                                                                  \
+    sa = sa & 0x0F;                                               \
+                                                                  \
+    MIPSDSP_SPLIT32_16(rt, rth, rtl);                             \
+                                                                  \
+    rth = mipsdsp_##func(rth, sa, env);                           \
+    rtl = mipsdsp_##func(rtl, sa, env);                           \
+                                                                  \
+    return MIPSDSP_RETURN32_16(rth, rtl);                         \
+}
+
+SHIFT_PH(shll, lshift16);
+SHIFT_PH(shll_s, sat16_lshift);
+
+#undef SHIFT_PH
+
+#if defined(TARGET_MIPS64)
+#define SHIFT_QH(name, func) \
+target_ulong helper_##name##_qh(target_ulong rt, target_ulong sa) \
+{                                                                 \
+    uint16_t rt3, rt2, rt1, rt0;                                  \
+                                                                  \
+    sa = sa & 0x0F;                                               \
+                                                                  \
+    MIPSDSP_SPLIT64_16(rt, rt3, rt2, rt1, rt0);                   \
+                                                                  \
+    rt3 = mipsdsp_##func(rt3, sa);                                \
+    rt2 = mipsdsp_##func(rt2, sa);                                \
+    rt1 = mipsdsp_##func(rt1, sa);                                \
+    rt0 = mipsdsp_##func(rt0, sa);                                \
+                                                                  \
+    return MIPSDSP_RETURN64_16(rt3, rt2, rt1, rt0);               \
+}
+
+#define SHIFT_QH_ENV(name, func) \
+target_ulong helper_##name##_qh(target_ulong rt, target_ulong sa, \
+                                CPUMIPSState *env)                \
+{                                                                 \
+    uint16_t rt3, rt2, rt1, rt0;                                  \
+                                                                  \
+    sa = sa & 0x0F;                                               \
+                                                                  \
+    MIPSDSP_SPLIT64_16(rt, rt3, rt2, rt1, rt0);                   \
+                                                                  \
+    rt3 = mipsdsp_##func(rt3, sa, env);                           \
+    rt2 = mipsdsp_##func(rt2, sa, env);                           \
+    rt1 = mipsdsp_##func(rt1, sa, env);                           \
+    rt0 = mipsdsp_##func(rt0, sa, env);                           \
+                                                                  \
+    return MIPSDSP_RETURN64_16(rt3, rt2, rt1, rt0);               \
+}
+
+SHIFT_QH_ENV(shll, lshift16);
+SHIFT_QH_ENV(shll_s, sat16_lshift);
+
+SHIFT_QH(shrl, rshift_u16);
+SHIFT_QH(shra, rashift16);
+SHIFT_QH(shra_r, rnd16_rashift);
+
+#undef SHIFT_QH
+#undef SHIFT_QH_ENV
+
+#endif
+
+#define SHIFT_W(name, func) \
+target_ulong helper_##name##_w(target_ulong sa, target_ulong rt) \
+{                                                                       \
+    uint32_t temp;                                                      \
+                                                                        \
+    sa = sa & 0x1F;                                                     \
+    temp = mipsdsp_##func(rt, sa);                                      \
+                                                                        \
+    return (target_long)(int32_t)temp;                                  \
+}
+
+#define SHIFT_W_ENV(name, func) \
+target_ulong helper_##name##_w(target_ulong sa, target_ulong rt, \
+                               CPUMIPSState *env) \
+{                                                                       \
+    uint32_t temp;                                                      \
+                                                                        \
+    sa = sa & 0x1F;                                                     \
+    temp = mipsdsp_##func(rt, sa, env);                                 \
+                                                                        \
+    return (target_long)(int32_t)temp;                                  \
+}
+
+SHIFT_W_ENV(shll_s, sat32_lshift);
+SHIFT_W(shra_r, rnd32_rashift);
+
+#undef SHIFT_W
+#undef SHIFT_W_ENV
+
+#if defined(TARGET_MIPS64)
+#define SHIFT_PW(name, func) \
+target_ulong helper_##name##_pw(target_ulong rt, target_ulong sa) \
+{                                                                 \
+    uint32_t rt1, rt0;                                            \
+                                                                  \
+    sa = sa & 0x1F;                                               \
+    MIPSDSP_SPLIT64_32(rt, rt1, rt0);                             \
+                                                                  \
+    rt1 = mipsdsp_##func(rt1, sa);                                \
+    rt0 = mipsdsp_##func(rt0, sa);                                \
+                                                                  \
+    return MIPSDSP_RETURN64_32(rt1, rt0);                         \
+}
+
+#define SHIFT_PW_ENV(name, func) \
+target_ulong helper_##name##_pw(target_ulong rt, target_ulong sa, \
+                                CPUMIPSState *env)                \
+{                                                                 \
+    uint32_t rt1, rt0;                                            \
+                                                                  \
+    sa = sa & 0x1F;                                               \
+    MIPSDSP_SPLIT64_32(rt, rt1, rt0);                             \
+                                                                  \
+    rt1 = mipsdsp_##func(rt1, sa, env);                           \
+    rt0 = mipsdsp_##func(rt0, sa, env);                           \
+                                                                  \
+    return MIPSDSP_RETURN64_32(rt1, rt0);                         \
+}
+
+SHIFT_PW_ENV(shll, lshift32);
+SHIFT_PW_ENV(shll_s, sat32_lshift);
+
+SHIFT_PW(shra, rashift32);
+SHIFT_PW(shra_r, rnd32_rashift);
+
+#undef SHIFT_PW
+#undef SHIFT_PW_ENV
+
+#endif
+
+#define SHIFT_PH(name, func) \
+target_ulong helper_##name##_ph(target_ulong sa, target_ulong rt) \
+{                                                                    \
+    uint16_t rth, rtl;                                               \
+                                                                     \
+    sa = sa & 0x0F;                                                  \
+                                                                     \
+    MIPSDSP_SPLIT32_16(rt, rth, rtl);                                \
+                                                                     \
+    rth = mipsdsp_##func(rth, sa);                                   \
+    rtl = mipsdsp_##func(rtl, sa);                                   \
+                                                                     \
+    return MIPSDSP_RETURN32_16(rth, rtl);                            \
+}
+
+SHIFT_PH(shrl, rshift_u16);
+SHIFT_PH(shra, rashift16);
+SHIFT_PH(shra_r, rnd16_rashift);
+
+#undef SHIFT_PH
+
 #undef MIPSDSP_LHI
 #undef MIPSDSP_LLO
 #undef MIPSDSP_HI
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 9201aae..5258ef6 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -488,4 +488,42 @@  DEF_HELPER_FLAGS_1(preceu_qh_obla, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
 DEF_HELPER_FLAGS_1(preceu_qh_obra, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
 #endif
 
+/* DSP GPR-Based Shift Sub-class insns */
+DEF_HELPER_FLAGS_3(shll_qb, 0, tl, tl, tl, env)
+#if defined(TARGET_MIPS64)
+DEF_HELPER_FLAGS_3(shll_ob, 0, tl, tl, tl, env)
+#endif
+DEF_HELPER_FLAGS_3(shll_ph, 0, tl, tl, tl, env)
+DEF_HELPER_FLAGS_3(shll_s_ph, 0, tl, tl, tl, env)
+#if defined(TARGET_MIPS64)
+DEF_HELPER_FLAGS_3(shll_qh, 0, tl, tl, tl, env)
+DEF_HELPER_FLAGS_3(shll_s_qh, 0, tl, tl, tl, env)
+#endif
+DEF_HELPER_FLAGS_3(shll_s_w, 0, tl, tl, tl, env)
+#if defined(TARGET_MIPS64)
+DEF_HELPER_FLAGS_3(shll_pw, 0, tl, tl, tl, env)
+DEF_HELPER_FLAGS_3(shll_s_pw, 0, tl, tl, tl, env)
+#endif
+DEF_HELPER_FLAGS_2(shrl_qb, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+DEF_HELPER_FLAGS_2(shrl_ph, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+#if defined(TARGET_MIPS64)
+DEF_HELPER_FLAGS_2(shrl_ob, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+DEF_HELPER_FLAGS_2(shrl_qh, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+#endif
+DEF_HELPER_FLAGS_2(shra_qb, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+DEF_HELPER_FLAGS_2(shra_r_qb, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+#if defined(TARGET_MIPS64)
+DEF_HELPER_FLAGS_2(shra_ob, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+DEF_HELPER_FLAGS_2(shra_r_ob, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+#endif
+DEF_HELPER_FLAGS_2(shra_ph, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+DEF_HELPER_FLAGS_2(shra_r_ph, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+DEF_HELPER_FLAGS_2(shra_r_w, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+#if defined(TARGET_MIPS64)
+DEF_HELPER_FLAGS_2(shra_qh, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+DEF_HELPER_FLAGS_2(shra_r_qh, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+DEF_HELPER_FLAGS_2(shra_pw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+DEF_HELPER_FLAGS_2(shra_r_pw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
+#endif
+
 #include "def-helper.h"
diff --git a/target-mips/translate.c b/target-mips/translate.c
index c4d4c47..bcfd4b4 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -331,6 +331,18 @@  enum {
 #if defined(TARGET_MIPS64)
     OPC_CMPU_EQ_OB_DSP = 0x15 | OPC_SPECIAL3,
 #endif
+    /* MIPS DSP GPR-Based Shift Sub-class */
+    OPC_SHLL_QB_DSP    = 0x13 | OPC_SPECIAL3,
+#if defined(TARGET_MIPS64)
+    OPC_SHLL_OB_DSP    = 0x17 | OPC_SPECIAL3,
+#endif
+    /* MIPS DSP Multiply Sub-class insns */
+    /* OPC_MUL_PH_DSP is same as OPC_ADDUH_QB_DSP.  */
+    /* OPC_MUL_PH_DSP     = 0x18 | OPC_SPECIAL3,  */
+    OPC_DPA_W_PH_DSP   = 0x30 | OPC_SPECIAL3,
+#if defined(TARGET_MIPS64)
+    OPC_DPAQ_W_QH_DSP  = 0x34 | OPC_SPECIAL3,
+#endif
 };
 
 /* BSHFL opcodes */
@@ -439,6 +451,32 @@  enum {
     OPC_PRECRQ_RS_PH_W   = (0x15 << 6) | OPC_CMPU_EQ_QB_DSP,
     OPC_PRECRQU_S_QB_PH  = (0x0F << 6) | OPC_CMPU_EQ_QB_DSP,
 };
+#define MASK_SHLL_QB(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
+enum {
+    /* MIPS DSP GPR-Based Shift Sub-class */
+    OPC_SHLL_QB    = (0x00 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHLLV_QB   = (0x02 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHLL_PH    = (0x08 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHLLV_PH   = (0x0A << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHLL_S_PH  = (0x0C << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHLLV_S_PH = (0x0E << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHLL_S_W   = (0x14 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHLLV_S_W  = (0x16 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRL_QB    = (0x01 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRLV_QB   = (0x03 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRL_PH    = (0x19 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRLV_PH   = (0x1B << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRA_QB    = (0x04 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRA_R_QB  = (0x05 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRAV_QB   = (0x06 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRAV_R_QB = (0x07 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRA_PH    = (0x09 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRAV_PH   = (0x0B << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRA_R_PH  = (0x0D << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRAV_R_PH = (0x0F << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRA_R_W   = (0x15 << 6) | OPC_SHLL_QB_DSP,
+    OPC_SHRAV_R_W  = (0x17 << 6) | OPC_SHLL_QB_DSP,
+};
 
 #if defined(TARGET_MIPS64)
 #define MASK_ABSQ_S_QH(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
@@ -507,6 +545,39 @@  enum {
 };
 #endif
 
+#if defined(TARGET_MIPS64)
+#define MASK_SHLL_OB(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
+enum {
+    /* MIPS DSP GPR-Based Shift Sub-class */
+    OPC_SHLL_PW    = (0x10 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHLL_S_PW  = (0x14 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHLLV_OB   = (0x02 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHLLV_PW   = (0x12 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHLLV_S_PW = (0x16 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHLLV_QH   = (0x0A << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHLLV_S_QH = (0x0E << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRA_PW    = (0x11 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRA_R_PW  = (0x15 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRAV_OB   = (0x06 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRAV_R_OB = (0x07 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRAV_PW   = (0x13 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRAV_R_PW = (0x17 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRAV_QH   = (0x0B << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRAV_R_QH = (0x0F << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRLV_OB   = (0x03 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRLV_QH   = (0x1B << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHLL_OB    = (0x00 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHLL_QH    = (0x08 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHLL_S_QH  = (0x0C << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRA_OB    = (0x04 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRA_R_OB  = (0x05 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRA_QH    = (0x09 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRA_R_QH  = (0x0D << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRL_OB    = (0x01 << 6) | OPC_SHLL_OB_DSP,
+    OPC_SHRL_QH    = (0x19 << 6) | OPC_SHLL_OB_DSP,
+};
+#endif
+
 /* Coprocessor 0 (rs field) */
 #define MASK_CP0(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
 
@@ -12888,6 +12959,253 @@  static void gen_mipsdsp_arith(DisasContext *ctx, uint32_t op1, uint32_t op2,
     MIPS_DEBUG("%s", opn);
 }
 
+static void gen_mipsdsp_shift(DisasContext *ctx, uint32_t opc,
+                              int ret, int v1, int v2)
+{
+    uint32_t op2;
+    const char *opn = "mipsdsp shift";
+    TCGv t0;
+    TCGv v1_t;
+    TCGv v2_t;
+
+    if (ret == 0) {
+        /* Treat as NOP. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    v1_t = tcg_temp_new();
+    v2_t = tcg_temp_new();
+
+    tcg_gen_movi_tl(t0, v1);
+    gen_load_gpr(v1_t, v1);
+    gen_load_gpr(v2_t, v2);
+
+    switch (opc) {
+    case OPC_SHLL_QB_DSP:
+        {
+            op2 = MASK_SHLL_QB(ctx->opcode);
+            switch (op2) {
+            case OPC_SHLL_QB:
+                check_dsp(ctx);
+                gen_helper_shll_qb(cpu_gpr[ret], t0, v2_t, cpu_env);
+                break;
+            case OPC_SHLLV_QB:
+                check_dsp(ctx);
+                gen_helper_shll_qb(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+                break;
+            case OPC_SHLL_PH:
+                check_dsp(ctx);
+                gen_helper_shll_ph(cpu_gpr[ret], t0, v2_t, cpu_env);
+                break;
+            case OPC_SHLLV_PH:
+                check_dsp(ctx);
+                gen_helper_shll_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+                break;
+            case OPC_SHLL_S_PH:
+                check_dsp(ctx);
+                gen_helper_shll_s_ph(cpu_gpr[ret], t0, v2_t, cpu_env);
+                break;
+            case OPC_SHLLV_S_PH:
+                check_dsp(ctx);
+                gen_helper_shll_s_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+                break;
+            case OPC_SHLL_S_W:
+                check_dsp(ctx);
+                gen_helper_shll_s_w(cpu_gpr[ret], t0, v2_t, cpu_env);
+                break;
+            case OPC_SHLLV_S_W:
+                check_dsp(ctx);
+                gen_helper_shll_s_w(cpu_gpr[ret], v1_t, v2_t, cpu_env);
+                break;
+            case OPC_SHRL_QB:
+                check_dsp(ctx);
+                gen_helper_shrl_qb(cpu_gpr[ret], t0, v2_t);
+                break;
+            case OPC_SHRLV_QB:
+                check_dsp(ctx);
+                gen_helper_shrl_qb(cpu_gpr[ret], v1_t, v2_t);
+                break;
+            case OPC_SHRL_PH:
+                check_dspr2(ctx);
+                gen_helper_shrl_ph(cpu_gpr[ret], t0, v2_t);
+                break;
+            case OPC_SHRLV_PH:
+                check_dspr2(ctx);
+                gen_helper_shrl_ph(cpu_gpr[ret], v1_t, v2_t);
+                break;
+            case OPC_SHRA_QB:
+                check_dspr2(ctx);
+                gen_helper_shra_qb(cpu_gpr[ret], t0, v2_t);
+                break;
+            case OPC_SHRA_R_QB:
+                check_dspr2(ctx);
+                gen_helper_shra_r_qb(cpu_gpr[ret], t0, v2_t);
+                break;
+            case OPC_SHRAV_QB:
+                check_dspr2(ctx);
+                gen_helper_shra_qb(cpu_gpr[ret], v1_t, v2_t);
+                break;
+            case OPC_SHRAV_R_QB:
+                check_dspr2(ctx);
+                gen_helper_shra_r_qb(cpu_gpr[ret], v1_t, v2_t);
+                break;
+            case OPC_SHRA_PH:
+                check_dsp(ctx);
+                gen_helper_shra_ph(cpu_gpr[ret], t0, v2_t);
+                break;
+            case OPC_SHRA_R_PH:
+                check_dsp(ctx);
+                gen_helper_shra_r_ph(cpu_gpr[ret], t0, v2_t);
+                break;
+            case OPC_SHRAV_PH:
+                check_dsp(ctx);
+                gen_helper_shra_ph(cpu_gpr[ret], v1_t, v2_t);
+                break;
+            case OPC_SHRAV_R_PH:
+                check_dsp(ctx);
+                gen_helper_shra_r_ph(cpu_gpr[ret], v1_t, v2_t);
+                break;
+            case OPC_SHRA_R_W:
+                check_dsp(ctx);
+                gen_helper_shra_r_w(cpu_gpr[ret], t0, v2_t);
+                break;
+            case OPC_SHRAV_R_W:
+                check_dsp(ctx);
+                gen_helper_shra_r_w(cpu_gpr[ret], v1_t, v2_t);
+                break;
+            default:            /* Invalid */
+                MIPS_INVAL("MASK SHLL.QB");
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
+        }
+#ifdef TARGET_MIPS64
+    case OPC_SHLL_OB_DSP:
+        op2 = MASK_SHLL_OB(ctx->opcode);
+        switch (op2) {
+        case OPC_SHLL_PW:
+            check_dsp(ctx);
+            gen_helper_shll_pw(cpu_gpr[ret], v2_t, t0, cpu_env);
+            break;
+        case OPC_SHLLV_PW:
+            check_dsp(ctx);
+            gen_helper_shll_pw(cpu_gpr[ret], v2_t, v1_t, cpu_env);
+            break;
+        case OPC_SHLL_S_PW:
+            check_dsp(ctx);
+            gen_helper_shll_s_pw(cpu_gpr[ret], v2_t, t0, cpu_env);
+            break;
+        case OPC_SHLLV_S_PW:
+            check_dsp(ctx);
+            gen_helper_shll_s_pw(cpu_gpr[ret], v2_t, v1_t, cpu_env);
+            break;
+        case OPC_SHLL_OB:
+            check_dsp(ctx);
+            gen_helper_shll_ob(cpu_gpr[ret], v2_t, t0, cpu_env);
+            break;
+        case OPC_SHLLV_OB:
+            check_dsp(ctx);
+            gen_helper_shll_ob(cpu_gpr[ret], v2_t, v1_t, cpu_env);
+            break;
+        case OPC_SHLL_QH:
+            check_dsp(ctx);
+            gen_helper_shll_qh(cpu_gpr[ret], v2_t, t0, cpu_env);
+            break;
+        case OPC_SHLLV_QH:
+            check_dsp(ctx);
+            gen_helper_shll_qh(cpu_gpr[ret], v2_t, v1_t, cpu_env);
+            break;
+        case OPC_SHLL_S_QH:
+            check_dsp(ctx);
+            gen_helper_shll_s_qh(cpu_gpr[ret], v2_t, t0, cpu_env);
+            break;
+        case OPC_SHLLV_S_QH:
+            check_dsp(ctx);
+            gen_helper_shll_s_qh(cpu_gpr[ret], v2_t, v1_t, cpu_env);
+            break;
+        case OPC_SHRA_OB:
+            check_dspr2(ctx);
+            gen_helper_shra_ob(cpu_gpr[ret], v2_t, t0);
+            break;
+        case OPC_SHRAV_OB:
+            check_dspr2(ctx);
+            gen_helper_shra_ob(cpu_gpr[ret], v2_t, v1_t);
+            break;
+        case OPC_SHRA_R_OB:
+            check_dspr2(ctx);
+            gen_helper_shra_r_ob(cpu_gpr[ret], v2_t, t0);
+            break;
+        case OPC_SHRAV_R_OB:
+            check_dspr2(ctx);
+            gen_helper_shra_r_ob(cpu_gpr[ret], v2_t, v1_t);
+            break;
+        case OPC_SHRA_PW:
+            check_dsp(ctx);
+            gen_helper_shra_pw(cpu_gpr[ret], v2_t, t0);
+            break;
+        case OPC_SHRAV_PW:
+            check_dsp(ctx);
+            gen_helper_shra_pw(cpu_gpr[ret], v2_t, v1_t);
+            break;
+        case OPC_SHRA_R_PW:
+            check_dsp(ctx);
+            gen_helper_shra_r_pw(cpu_gpr[ret], v2_t, t0);
+            break;
+        case OPC_SHRAV_R_PW:
+            check_dsp(ctx);
+            gen_helper_shra_r_pw(cpu_gpr[ret], v2_t, v1_t);
+            break;
+        case OPC_SHRA_QH:
+            check_dsp(ctx);
+            gen_helper_shra_qh(cpu_gpr[ret], v2_t, t0);
+            break;
+        case OPC_SHRAV_QH:
+            check_dsp(ctx);
+            gen_helper_shra_qh(cpu_gpr[ret], v2_t, v1_t);
+            break;
+        case OPC_SHRA_R_QH:
+            check_dsp(ctx);
+            gen_helper_shra_r_qh(cpu_gpr[ret], v2_t, t0);
+            break;
+        case OPC_SHRAV_R_QH:
+            check_dsp(ctx);
+            gen_helper_shra_r_qh(cpu_gpr[ret], v2_t, v1_t);
+            break;
+        case OPC_SHRL_OB:
+            check_dsp(ctx);
+            gen_helper_shrl_ob(cpu_gpr[ret], v2_t, t0);
+            break;
+        case OPC_SHRLV_OB:
+            check_dsp(ctx);
+            gen_helper_shrl_ob(cpu_gpr[ret], v2_t, v1_t);
+            break;
+        case OPC_SHRL_QH:
+            check_dspr2(ctx);
+            gen_helper_shrl_qh(cpu_gpr[ret], v2_t, t0);
+            break;
+        case OPC_SHRLV_QH:
+            check_dspr2(ctx);
+            gen_helper_shrl_qh(cpu_gpr[ret], v2_t, v1_t);
+            break;
+        default:            /* Invalid */
+            MIPS_INVAL("MASK SHLL.OB");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+#endif
+    }
+
+    tcg_temp_free(t0);
+    tcg_temp_free(v1_t);
+    tcg_temp_free(v2_t);
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s", opn);
+}
+
 /* End MIPSDSP functions. */
 
 static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
@@ -13364,6 +13682,9 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
                 break;
             }
             break;
+        case OPC_SHLL_QB_DSP:
+            gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
+            break;
 #if defined(TARGET_MIPS64)
         case OPC_DEXTM ... OPC_DEXT:
         case OPC_DINSM ... OPC_DINS:
@@ -13465,6 +13786,9 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
                 break;
             }
             break;
+        case OPC_SHLL_OB_DSP:
+            gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
+            break;
 #endif
         default:            /* Invalid */
             MIPS_INVAL("special3");