diff mbox

[v11,11/14] target-mips: Add ASE DSP accumulator instructions

Message ID 1350319158-7263-12-git-send-email-proljc@gmail.com
State New
Headers show

Commit Message

Jia Liu Oct. 15, 2012, 4:39 p.m. UTC
Add MIPS ASE DSP Accumulator and DSPControl Access instructions.

Signed-off-by: Jia Liu <proljc@gmail.com>
---
 target-mips/dsp_helper.c |  609 ++++++++++++++++++++++++++++++++++++++++++++++
 target-mips/helper.h     |   35 +++
 target-mips/translate.c  |  355 +++++++++++++++++++++++++++
 3 files changed, 999 insertions(+)

Comments

Aurelien Jarno Oct. 16, 2012, 11:23 p.m. UTC | #1
On Tue, Oct 16, 2012 at 12:39:15AM +0800, Jia Liu wrote:
> Add MIPS ASE DSP Accumulator and DSPControl Access instructions.
> 
> Signed-off-by: Jia Liu <proljc@gmail.com>
> ---
>  target-mips/dsp_helper.c |  609 ++++++++++++++++++++++++++++++++++++++++++++++
>  target-mips/helper.h     |   35 +++
>  target-mips/translate.c  |  355 +++++++++++++++++++++++++++
>  3 files changed, 999 insertions(+)
> 
> diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c
> index 06c97a2..e798702 100644
> --- a/target-mips/dsp_helper.c
> +++ b/target-mips/dsp_helper.c
> @@ -3436,6 +3436,615 @@ target_ulong helper_packrl_pw(target_ulong rs, target_ulong rt)
>  }
>  #endif
>  
> +/** DSP Accumulator and DSPControl Access Sub-class insns **/
> +target_ulong helper_extr_w(target_ulong ac, target_ulong shift,
> +                           CPUMIPSState *env)
> +{
> +    int32_t tempI;
> +    int64_t tempDL[2];
> +
> +    shift = shift & 0x0F;
> +
> +    mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env);
> +    if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
> +        (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    }
> +
> +    tempI = (tempDL[0] >> 1) & MIPSDSP_LLO;
> +
> +    tempDL[0] += 1;
> +    if (tempDL[0] == 0) {
> +        tempDL[1] += 1;
> +    }
> +
> +    if ((!(tempDL[1] == 0 && (tempDL[0] & MIPSDSP_LHI) == 0x00)) &&
> +        (!(tempDL[1] == 1 && (tempDL[0] & MIPSDSP_LHI) == MIPSDSP_LHI))) {
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    }
> +
> +    return (target_long)tempI;
> +}
> +
> +target_ulong helper_extr_r_w(target_ulong ac, target_ulong shift,
> +                             CPUMIPSState *env)
> +{
> +    int64_t tempDL[2];
> +
> +    shift = shift & 0x0F;
> +
> +    mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env);
> +    if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
> +        (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    }
> +
> +    tempDL[0] += 1;
> +    if (tempDL[0] == 0) {
> +        tempDL[1] += 1;
> +    }
> +
> +    if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
> +        (tempDL[1] != 1 && (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    }
> +
> +    return (target_long)(int32_t)(tempDL[0] >> 1);
> +}
> +
> +target_ulong helper_extr_rs_w(target_ulong ac, target_ulong shift,
> +                              CPUMIPSState *env)
> +{
> +    int32_t tempI, temp64;
> +    int64_t tempDL[2];
> +
> +    shift = shift & 0x0F;
> +
> +    mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env);
> +    if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
> +        (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    }
> +    tempDL[0] += 1;
> +    if (tempDL[0] == 0) {
> +        tempDL[1] += 1;
> +    }
> +    tempI = tempDL[0] >> 1;
> +
> +    if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
> +        (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
> +        temp64 = tempDL[1];
> +        if (temp64 == 0) {
> +            tempI = 0x7FFFFFFF;
> +        } else {
> +            tempI = 0x80000000;
> +        }
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    }
> +
> +    return (target_long)tempI;
> +}
> +
> +#if defined(TARGET_MIPS64)
> +target_ulong helper_dextr_w(target_ulong ac, target_ulong shift,
> +                            CPUMIPSState *env)
> +{
> +    uint64_t temp[3];
> +
> +    shift = shift & 0x3F;
> +
> +    mipsdsp_rndrashift_acc(temp, ac, shift, env);
> +
> +    return (int64_t)(int32_t)(temp[0] >> 1);
> +}
> +
> +target_ulong helper_dextr_r_w(target_ulong ac, target_ulong shift,
> +                              CPUMIPSState *env)
> +{
> +    uint64_t temp[3];
> +    uint32_t temp128;
> +
> +    shift = shift & 0x3F;
> +    mipsdsp_rndrashift_acc(temp, ac, shift, env);
> +
> +    temp[0] += 1;
> +    if (temp[0] == 0) {
> +        temp[1] += 1;
> +        if (temp[1] == 0) {
> +            temp[2] += 1;
> +        }
> +    }
> +
> +    temp128 = temp[2] & 0x01;
> +
> +    if ((temp128 != 0 || temp[1] != 0) &&
> +       (temp128 != 1 || temp[1] != ~0ull)) {
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    }
> +
> +    return (int64_t)(int32_t)(temp[0] >> 1);
> +}
> +
> +target_ulong helper_dextr_rs_w(target_ulong ac, target_ulong shift,
> +                               CPUMIPSState *env)
> +{
> +    uint64_t temp[3];
> +    uint32_t temp128;
> +
> +    shift = shift & 0x3F;
> +    mipsdsp_rndrashift_acc(temp, ac, shift, env);
> +
> +    temp[0] += 1;
> +    if (temp[0] == 0) {
> +        temp[1] += 1;
> +        if (temp[1] == 0) {
> +            temp[2] += 1;
> +        }
> +    }
> +
> +    temp128 = temp[2] & 0x01;
> +
> +    if ((temp128 != 0 || temp[1] != 0) &&
> +       (temp128 != 1 || temp[1] != ~0ull)) {
> +        if (temp128 == 0) {
> +            temp[0] = 0x0FFFFFFFF;
> +        } else {
> +            temp[0] = 0x0100000000;
> +        }
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    }
> +
> +    return (int64_t)(int32_t)(temp[0] >> 1);
> +}
> +
> +target_ulong helper_dextr_l(target_ulong ac, target_ulong shift,
> +                            CPUMIPSState *env)
> +{
> +    uint64_t temp[3];
> +    target_ulong result;
> +
> +    shift = shift & 0x3F;
> +
> +    mipsdsp_rndrashift_acc(temp, ac, shift, env);
> +    result = (temp[1] << 63) | (temp[0] >> 1);
> +
> +    return result;
> +}
> +
> +target_ulong helper_dextr_r_l(target_ulong ac, target_ulong shift,
> +                              CPUMIPSState *env)
> +{
> +    uint64_t temp[3];
> +    uint32_t temp128;
> +    target_ulong result;
> +
> +    shift = shift & 0x3F;
> +    mipsdsp_rndrashift_acc(temp, ac, shift, env);
> +
> +    temp[0] += 1;
> +    if (temp[0] == 0) {
> +        temp[1] += 1;
> +        if (temp[1] == 0) {
> +            temp[2] += 1;
> +        }
> +    }
> +
> +    temp128 = temp[2] & 0x01;
> +
> +    if ((temp128 != 0 || temp[1] != 0) &&
> +       (temp128 != 1 || temp[1] != ~0ull)) {
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    }
> +
> +    result = (temp[1] << 63) | (temp[0] >> 1);
> +
> +    return result;
> +}
> +
> +target_ulong helper_dextr_rs_l(target_ulong ac, target_ulong shift,
> +                               CPUMIPSState *env)
> +{
> +    uint64_t temp[3];
> +    uint32_t temp128;
> +    target_ulong result;
> +
> +    shift = shift & 0x3F;
> +    mipsdsp_rndrashift_acc(temp, ac, shift, env);
> +
> +    temp[0] += 1;
> +    if (temp[0] == 0) {
> +        temp[1] += 1;
> +        if (temp[1] == 0) {
> +            temp[2] += 1;
> +        }
> +    }
> +
> +    temp128 = temp[2] & 0x01;
> +
> +    if ((temp128 != 0 || temp[1] != 0) &&
> +       (temp128 != 1 || temp[1] != ~0ull)) {
> +        if (temp128 == 0) {
> +            temp[1] &= 0xFFFFFFFFFFFFFFFEull;
> +            temp[0] |= 0xFFFFFFFFFFFFFFFEull;
> +        } else {
> +            temp[1] |= 0x01;
> +            temp[0] &= 0x01;
> +        }
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    }
> +    result = (temp[1] << 63) | (temp[0] >> 1);
> +
> +    return result;
> +}
> +#endif
> +
> +target_ulong helper_extr_s_h(target_ulong ac, target_ulong shift,
> +                             CPUMIPSState *env)
> +{
> +    int64_t temp;
> +
> +    shift = shift & 0x0F;
> +
> +    temp = mipsdsp_rashift_short_acc(ac, shift, env);
> +    if (temp > 0x0000000000007FFFull) {
> +        temp = 0x00007FFF;
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    } else if (temp < 0xFFFFFFFFFFFF8000ull) {
> +        temp = 0xFFFF8000;
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    }
> +
> +    return (target_long)(int32_t)(temp & 0xFFFFFFFF);
> +}
> +
> +
> +#if defined(TARGET_MIPS64)
> +target_ulong helper_dextr_s_h(target_ulong ac, target_ulong shift,
> +                              CPUMIPSState *env)
> +{
> +    int64_t temp[2];
> +    uint32_t temp127;
> +
> +    shift = shift & 0x1F;
> +
> +    mipsdsp_rashift_acc((uint64_t *)temp, ac, shift, env);
> +
> +    temp127 = (temp[1] >> 63) & 0x01;
> +
> +    if ((temp127 == 0) && (temp[1] > 0 || temp[0] > 32767)) {
> +        temp[0] &= 0xFFFF0000;
> +        temp[0] |= 0x00007FFF;
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    } else if ((temp127 == 1) &&
> +            (temp[1] < 0xFFFFFFFFFFFFFFFFll
> +             || temp[0] < 0xFFFFFFFFFFFF1000ll)) {
> +        temp[0] &= 0xFFFF0000;
> +        temp[0] |= 0x00008000;
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    }
> +
> +    return (int64_t)(int16_t)(temp[0] & MIPSDSP_LO);
> +}
> +
> +#endif
> +
> +target_ulong helper_extp(target_ulong ac, target_ulong size, CPUMIPSState *env)
> +{
> +    int32_t start_pos;
> +    int sub;
> +    uint32_t temp;
> +    uint64_t acc;
> +
> +    size = size & 0x1F;
> +
> +    temp = 0;
> +    start_pos = get_DSPControl_pos(env);
> +    sub = start_pos - (size + 1);
> +    if (sub >= -1) {
> +        acc = ((uint64_t)env->active_tc.HI[ac] << 32) |
> +              ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);
> +        temp = (acc >> (start_pos - size)) &
> +               (((uint32_t)0x01 << (size + 1)) - 1);
> +        set_DSPControl_efi(0, env);
> +    } else {
> +        set_DSPControl_efi(1, env);
> +    }
> +
> +    return (target_ulong)temp;
> +}
> +
> +target_ulong helper_extpdp(target_ulong ac, target_ulong size,
> +                           CPUMIPSState *env)
> +{
> +    int32_t start_pos;
> +    int sub;
> +    uint32_t temp;
> +    uint64_t acc;
> +
> +    size = size & 0x1F;
> +    temp = 0;
> +    start_pos = get_DSPControl_pos(env);
> +    sub = start_pos - (size + 1);
> +    if (sub >= -1) {
> +        acc  = ((uint64_t)env->active_tc.HI[ac] << 32) |
> +               ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);
> +        temp = (acc >> (start_pos - size)) &
> +               (((uint32_t)0x01 << (size + 1)) - 1);
> +
> +        set_DSPControl_pos(start_pos - (size + 1), env);
> +        set_DSPControl_efi(0, env);
> +    } else {
> +        set_DSPControl_efi(1, env);
> +    }
> +
> +    return (target_ulong)temp;
> +}
> +
> +
> +#if defined(TARGET_MIPS64)
> +target_ulong helper_dextp(target_ulong ac, target_ulong size, CPUMIPSState *env)
> +{
> +    int start_pos;
> +    int len;
> +    int sub;
> +    uint64_t tempB, tempA;
> +    uint64_t temp;
> +
> +    temp = 0;
> +
> +    size = size & 0x3F;
> +    start_pos = get_DSPControl_pos(env);
> +    len = start_pos - size;
> +    tempB = env->active_tc.HI[ac];
> +    tempA = env->active_tc.LO[ac];
> +
> +    sub = start_pos - (size + 1);
> +
> +    if (sub >= -1) {
> +        temp = (tempB << (64 - len)) | (tempA >> len);
> +        temp = temp & ((0x01 << (size + 1)) - 1);
> +        set_DSPControl_efi(0, env);
> +    } else {
> +        set_DSPControl_efi(1, env);
> +    }
> +
> +    return temp;
> +}
> +
> +target_ulong helper_dextpdp(target_ulong ac, target_ulong size,
> +                            CPUMIPSState *env)
> +{
> +    int start_pos;
> +    int len;
> +    int sub;
> +    uint64_t tempB, tempA;
> +    uint64_t temp;
> +
> +    temp = 0;
> +    size = size & 0x3F;
> +    start_pos = get_DSPControl_pos(env);
> +    len = start_pos - size;
> +    tempB = env->active_tc.HI[ac];
> +    tempA = env->active_tc.LO[ac];
> +
> +    sub = start_pos - (size + 1);
> +
> +    if (sub >= -1) {
> +        temp = (tempB << (64 - len)) | (tempA >> len);
> +        temp = temp & ((0x01 << (size + 1)) - 1);
> +        set_DSPControl_pos(sub, env);
> +        set_DSPControl_efi(0, env);
> +    } else {
> +        set_DSPControl_efi(1, env);
> +    }
> +
> +    return temp;
> +}
> +
> +#endif
> +
> +void helper_shilo(target_ulong ac, target_ulong rs, CPUMIPSState *env)
> +{
> +    int8_t  rs5_0;
> +    uint64_t temp, acc;
> +
> +    rs5_0 = rs & 0x3F;
> +    rs5_0 = (int8_t)(rs5_0 << 2) >> 2;
> +    rs5_0 = MIPSDSP_ABS(rs5_0);
> +    acc   = (((uint64_t)env->active_tc.HI[ac] << 32) & MIPSDSP_LHI) |
> +            ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);
> +    if (rs5_0 == 0) {
> +        temp = acc;
> +    } else {
> +        if (rs5_0 > 0) {
> +            temp = acc >> rs5_0;
> +        } else {
> +            temp = acc << rs5_0;
> +        }
> +    }
> +
> +    env->active_tc.HI[ac] = (target_ulong)(int32_t)((temp & MIPSDSP_LHI) >> 32);
> +    env->active_tc.LO[ac] = (target_ulong)(int32_t)(temp & MIPSDSP_LLO);
> +}
> +
> +#if defined(TARGET_MIPS64)
> +void helper_dshilo(target_ulong shift, target_ulong ac, CPUMIPSState *env)
> +{
> +    int8_t shift_t;
> +    uint64_t tempB, tempA;
> +
> +    shift_t = (uint8_t)(shift << 1) >> 1;
> +    shift_t = MIPSDSP_ABS(shift_t);
> +
> +    tempB = env->active_tc.HI[ac];
> +    tempA = env->active_tc.LO[ac];
> +
> +    if (shift_t != 0) {
> +        if (shift_t >= 0) {
> +            tempA = (tempB << (64 - shift)) | (tempA >> shift);
> +            tempB = tempB >> shift;
> +        } else {
> +            tempB = (tempB << shift) | (tempA >> (64 - shift));
> +            tempA = tempA << shift;
> +        }
> +    }
> +
> +    env->active_tc.HI[ac] = tempB;
> +    env->active_tc.LO[ac] = tempA;
> +}
> +
> +#endif
> +void helper_mthlip(target_ulong ac, target_ulong rs, CPUMIPSState *env)
> +{
> +    int32_t tempA, tempB, pos;
> +
> +    tempA = rs;
> +    tempB = env->active_tc.LO[ac];
> +    env->active_tc.HI[ac] = (target_long)tempB;
> +    env->active_tc.LO[ac] = (target_long)tempA;
> +    pos = get_DSPControl_pos(env);
> +
> +    if (pos > 32) {
> +        return;
> +    } else {
> +        set_DSPControl_pos(pos + 32, env);
> +    }
> +}
> +
> +#if defined(TARGET_MIPS64)
> +void helper_dmthlip(target_ulong rs, target_ulong ac, CPUMIPSState *env)
> +{
> +    uint8_t ac_t;
> +    uint8_t pos;
> +    uint64_t tempB, tempA;
> +
> +    ac_t = ac & 0x3;
> +
> +    tempA = rs;
> +    tempB = env->active_tc.LO[ac_t];
> +
> +    env->active_tc.HI[ac_t] = tempB;
> +    env->active_tc.LO[ac_t] = tempA;
> +
> +    pos = get_DSPControl_pos(env);
> +
> +    if (pos <= 64) {
> +        pos = pos + 64;
> +        set_DSPControl_pos(pos, env);
> +    }
> +}
> +#endif
> +
> +void helper_wrdsp(target_ulong rs, target_ulong mask_num, CPUMIPSState *env)
> +{
> +    uint8_t  mask[6];
> +    uint8_t  i;
> +    uint32_t newbits, overwrite;
> +    target_ulong dsp;
> +
> +    newbits   = 0x00;
> +    overwrite = 0xFFFFFFFF;
> +    dsp = env->active_tc.DSPControl;
> +
> +    for (i = 0; i < 6; i++) {
> +        mask[i] = (mask_num >> i) & 0x01;
> +    }
> +
> +    if (mask[0] == 1) {
> +#if defined(TARGET_MIPS64)
> +        overwrite &= 0xFFFFFF80;
> +        newbits   &= 0xFFFFFF80;
> +        newbits   |= 0x0000007F & rs;
> +#else
> +        overwrite &= 0xFFFFFFC0;
> +        newbits   &= 0xFFFFFFC0;
> +        newbits   |= 0x0000003F & rs;
> +#endif
> +    }
> +
> +    if (mask[1] == 1) {
> +        overwrite &= 0xFFFFE07F;
> +        newbits   &= 0xFFFFE07F;
> +        newbits   |= 0x00001F80 & rs;
> +    }
> +
> +    if (mask[2] == 1) {
> +        overwrite &= 0xFFFFDFFF;
> +        newbits   &= 0xFFFFDFFF;
> +        newbits   |= 0x00002000 & rs;
> +    }
> +
> +    if (mask[3] == 1) {
> +        overwrite &= 0xFF00FFFF;
> +        newbits   &= 0xFF00FFFF;
> +        newbits   |= 0x00FF0000 & rs;
> +    }
> +
> +    if (mask[4] == 1) {
> +        overwrite &= 0x00FFFFFF;
> +        newbits   &= 0x00FFFFFF;
> +        newbits   |= 0xFF000000 & rs;
> +    }
> +
> +    if (mask[5] == 1) {
> +        overwrite &= 0xFFFFBFFF;
> +        newbits   &= 0xFFFFBFFF;
> +        newbits   |= 0x00004000 & rs;
> +    }
> +
> +    dsp = dsp & overwrite;
> +    dsp = dsp | newbits;
> +    env->active_tc.DSPControl = dsp;
> +}
> +
> +target_ulong helper_rddsp(target_ulong masknum, CPUMIPSState *env)
> +{
> +    uint8_t  mask[6];
> +    uint32_t ruler, i;
> +    target_ulong temp;
> +    target_ulong dsp;
> +
> +    ruler = 0x01;
> +    for (i = 0; i < 6; i++) {
> +        mask[i] = (masknum & ruler) >> i ;
> +        ruler = ruler << 1;
> +    }
> +
> +    temp  = 0x00;
> +    dsp = env->active_tc.DSPControl;
> +
> +    if (mask[0] == 1) {
> +#if defined(TARGET_MIPS64)
> +        temp |= dsp & 0x7F;
> +#else
> +        temp |= dsp & 0x3F;
> +#endif
> +    }
> +
> +    if (mask[1] == 1) {
> +        temp |= dsp & 0x1F80;
> +    }
> +
> +    if (mask[2] == 1) {
> +        temp |= dsp & 0x2000;
> +    }
> +
> +    if (mask[3] == 1) {
> +        temp |= dsp & 0x00FF0000;
> +    }
> +
> +    if (mask[4] == 1) {
> +        temp |= dsp & 0xFF000000;
> +    }
> +
> +    if (mask[5] == 1) {
> +        temp |= dsp & 0x4000;
> +    }
> +
> +    return temp;
> +}
> +
> +
>  #undef MIPSDSP_LHI
>  #undef MIPSDSP_LLO
>  #undef MIPSDSP_HI
> diff --git a/target-mips/helper.h b/target-mips/helper.h
> index 3d3c596..45af62f 100644
> --- a/target-mips/helper.h
> +++ b/target-mips/helper.h
> @@ -676,4 +676,39 @@ DEF_HELPER_FLAGS_2(packrl_ph, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
>  DEF_HELPER_FLAGS_2(packrl_pw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
>  #endif
>  
> +/* DSP Accumulator and DSPControl Access Sub-class insns */
> +DEF_HELPER_FLAGS_3(extr_w, 0, tl, tl, tl, env)
> +DEF_HELPER_FLAGS_3(extr_r_w, 0, tl, tl, tl, env)
> +DEF_HELPER_FLAGS_3(extr_rs_w, 0, tl, tl, tl, env)
> +#if defined(TARGET_MIPS64)
> +DEF_HELPER_FLAGS_3(dextr_w, 0, tl, tl, tl, env)
> +DEF_HELPER_FLAGS_3(dextr_r_w, 0, tl, tl, tl, env)
> +DEF_HELPER_FLAGS_3(dextr_rs_w, 0, tl, tl, tl, env)
> +DEF_HELPER_FLAGS_3(dextr_l, 0, tl, tl, tl, env)
> +DEF_HELPER_FLAGS_3(dextr_r_l, 0, tl, tl, tl, env)
> +DEF_HELPER_FLAGS_3(dextr_rs_l, 0, tl, tl, tl, env)
> +#endif
> +DEF_HELPER_FLAGS_3(extr_s_h, 0, tl, tl, tl, env)
> +#if defined(TARGET_MIPS64)
> +DEF_HELPER_FLAGS_3(dextr_s_h, 0, tl, tl, tl, env)
> +#endif
> +DEF_HELPER_FLAGS_3(extp, 0, tl, tl, tl, env)
> +DEF_HELPER_FLAGS_3(extpdp, 0, tl, tl, tl, env)
> +#if defined(TARGET_MIPS64)
> +DEF_HELPER_FLAGS_3(dextp, 0, tl, tl, tl, env)
> +DEF_HELPER_FLAGS_3(dextpdp, 0, tl, tl, tl, env)
> +#endif
> +DEF_HELPER_FLAGS_3(shilo, 0, void, tl, tl, env)
> +#if defined(TARGET_MIPS64)
> +DEF_HELPER_FLAGS_3(dshilo, 0, void, tl, tl, env)
> +#endif
> +DEF_HELPER_FLAGS_3(mthlip, 0, void, tl, tl, env)
> +#if defined(TARGET_MIPS64)
> +DEF_HELPER_FLAGS_3(dmthlip, 0, void, tl, tl, env)
> +#endif
> +DEF_HELPER_FLAGS_3(wrdsp, 0, void, tl, tl, env)
> +DEF_HELPER_FLAGS_2(rddsp, 0, tl, tl, env)
> +
> +
> +
>  #include "def-helper.h"
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index ea939d7..3442d8c 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -353,6 +353,11 @@ enum {
>  #if defined(TARGET_MIPS64)
>      OPC_DAPPEND_DSP    = 0x35 | OPC_SPECIAL3,
>  #endif
> +    /* MIPS DSP Accumulator and DSPControl Access Sub-class */
> +    OPC_EXTR_W_DSP     = 0x38 | OPC_SPECIAL3,
> +#if defined(TARGET_MIPS64)
> +    OPC_DEXTR_W_DSP    = 0x3C | OPC_SPECIAL3,
> +#endif
>  };
>  
>  /* BSHFL opcodes */
> @@ -564,6 +569,30 @@ enum {
>      OPC_BALIGN  = (0x10 << 6) | OPC_APPEND_DSP,
>  };
>  
> +#define MASK_EXTR_W(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
> +enum {
> +    /* MIPS DSP Accumulator and DSPControl Access Sub-class */
> +    OPC_EXTR_W     = (0x00 << 6) | OPC_EXTR_W_DSP,
> +    OPC_EXTR_R_W   = (0x04 << 6) | OPC_EXTR_W_DSP,
> +    OPC_EXTR_RS_W  = (0x06 << 6) | OPC_EXTR_W_DSP,
> +    OPC_EXTR_S_H   = (0x0E << 6) | OPC_EXTR_W_DSP,
> +    OPC_EXTRV_S_H  = (0x0F << 6) | OPC_EXTR_W_DSP,
> +    OPC_EXTRV_W    = (0x01 << 6) | OPC_EXTR_W_DSP,
> +    OPC_EXTRV_R_W  = (0x05 << 6) | OPC_EXTR_W_DSP,
> +    OPC_EXTRV_RS_W = (0x07 << 6) | OPC_EXTR_W_DSP,
> +    OPC_EXTP       = (0x02 << 6) | OPC_EXTR_W_DSP,
> +    OPC_EXTPV      = (0x03 << 6) | OPC_EXTR_W_DSP,
> +    OPC_EXTPDP     = (0x0A << 6) | OPC_EXTR_W_DSP,
> +    OPC_EXTPDPV    = (0x0B << 6) | OPC_EXTR_W_DSP,
> +    OPC_SHILO      = (0x1A << 6) | OPC_EXTR_W_DSP,
> +    OPC_SHILOV     = (0x1B << 6) | OPC_EXTR_W_DSP,
> +    OPC_MTHLIP     = (0x1F << 6) | OPC_EXTR_W_DSP,
> +    OPC_WRDSP      = (0x13 << 6) | OPC_EXTR_W_DSP,
> +    OPC_RDDSP      = (0x12 << 6) | OPC_EXTR_W_DSP,
> +};
> +
> +
> +
>  #if defined(TARGET_MIPS64)
>  #define MASK_ABSQ_S_QH(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
>  enum {
> @@ -676,6 +705,32 @@ enum {
>  #endif
>  
>  #if defined(TARGET_MIPS64)
> +#define MASK_DEXTR_W(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
> +enum {
> +    /* MIPS DSP Accumulator and DSPControl Access Sub-class */
> +    OPC_DMTHLIP     = (0x1F << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DSHILO      = (0x1A << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTP       = (0x02 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTPDP     = (0x0A << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTPDPV    = (0x0B << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTPV      = (0x03 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTR_L     = (0x10 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTR_R_L   = (0x14 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTR_RS_L  = (0x16 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTR_W     = (0x00 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTR_R_W   = (0x04 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTR_RS_W  = (0x06 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTR_S_H   = (0x0E << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTRV_L    = (0x11 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTRV_R_L  = (0x15 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTRV_RS_L = (0x17 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTRV_S_H  = (0x0F << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTRV_W    = (0x01 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTRV_R_W  = (0x05 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DEXTRV_RS_W = (0x07 << 6) | OPC_DEXTR_W_DSP,
> +    OPC_DSHILOV     = (0x1B << 6) | OPC_DEXTR_W_DSP,
> +};
> +
>  #define MASK_DINSV(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
>  enum {
>      /* DSP Bit/Manipulation Sub-class */
> @@ -14217,6 +14272,240 @@ static void gen_mipsdsp_add_cmp_pick(DisasContext *ctx,
>      MIPS_DEBUG("%s", opn);
>  }
>  
> +static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2,
> +                                int ret, int v1, int v2, int check_ret)
> +
> +{
> +    const char *opn = "mipsdsp accumulator";
> +    TCGv t0 = tcg_temp_new();
> +    TCGv t1 = tcg_temp_new();
> +    TCGv v1_t = tcg_temp_new();
> +    TCGv v2_t = tcg_temp_new();
> +    int16_t imm;
> +
> +    if ((ret == 0) && (check_ret == 1)) {
> +        /* Treat as NOP. */
> +        MIPS_DEBUG("NOP");
> +        return;
> +    }
> +
> +    if (v1 == 0) {
> +        tcg_gen_movi_tl(v1_t, 0);
> +    } else {
> +        gen_load_gpr(v1_t, v1);
> +    }
> +
> +    if (v2 == 0) {
> +        tcg_gen_movi_tl(v2_t, 0);
> +    } else {
> +        gen_load_gpr(v2_t, v2);
> +    }
> +

Same comments as the previous patches apply here.

> +    switch (op1) {
> +    case OPC_EXTR_W_DSP:
> +        check_dsp(ctx);
> +        switch (op2) {
> +        case OPC_EXTR_W:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_extr_w(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_EXTR_R_W:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_extr_r_w(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_EXTR_RS_W:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_extr_rs_w(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_EXTR_S_H:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_extr_s_h(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_EXTRV_S_H:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_extr_s_h(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        case OPC_EXTRV_W:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_extr_w(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        case OPC_EXTRV_R_W:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_extr_r_w(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        case OPC_EXTRV_RS_W:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_extr_rs_w(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        case OPC_EXTP:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_extp(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_EXTPV:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_extp(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        case OPC_EXTPDP:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_extpdp(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_EXTPDPV:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_extpdp(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        case OPC_SHILO:
> +            imm = (ctx->opcode >> 20) & 0x3F;
> +            tcg_gen_movi_tl(t0, ret);
> +            tcg_gen_movi_tl(t1, imm);
> +            gen_helper_shilo(t0, t1, cpu_env);
> +            break;
> +        case OPC_SHILOV:
> +            tcg_gen_movi_tl(t0, ret);
> +            gen_helper_shilo(t0, v1_t, cpu_env);
> +            break;
> +        case OPC_MTHLIP:
> +            tcg_gen_movi_tl(t0, ret);
> +            gen_helper_mthlip(t0, v1_t, cpu_env);
> +            break;
> +        case OPC_WRDSP:
> +            imm = (ctx->opcode >> 11) & 0x3FF;
> +            tcg_gen_movi_tl(t0, imm);
> +            gen_helper_wrdsp(v1_t, t0, cpu_env);
> +            break;
> +        case OPC_RDDSP:
> +            imm = (ctx->opcode >> 16) & 0x03FF;
> +            tcg_gen_movi_tl(t0, imm);
> +            gen_helper_rddsp(cpu_gpr[ret], t0, cpu_env);
> +            break;
> +        }
> +        break;
> +#ifdef TARGET_MIPS64
> +    case OPC_DEXTR_W_DSP:
> +        check_dsp(ctx);
> +        switch (op2) {
> +        case OPC_DMTHLIP:
> +            tcg_gen_movi_tl(t0, ret);
> +            gen_helper_dmthlip(v1_t, t0, cpu_env);
> +            break;
> +        case OPC_DSHILO:
> +            {
> +                int shift = (ctx->opcode >> 19) & 0x7F;
> +                int ac = (ctx->opcode >> 11) & 0x03;
> +                tcg_gen_movi_tl(t0, shift);
> +                tcg_gen_movi_tl(t1, ac);
> +                gen_helper_dshilo(t0, t1, cpu_env);
> +                break;
> +            }
> +        case OPC_DSHILOV:
> +            {
> +                int ac = (ctx->opcode >> 11) & 0x03;
> +                tcg_gen_movi_tl(t0, ac);
> +                gen_helper_dshilo(v1_t, t0, cpu_env);
> +                break;
> +            }
> +        case OPC_DEXTP:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +
> +            gen_helper_dextp(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_DEXTPV:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_dextp(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        case OPC_DEXTPDP:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_dextpdp(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_DEXTPDPV:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_dextpdp(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        case OPC_DEXTR_L:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_dextr_l(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_DEXTR_R_L:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_dextr_r_l(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_DEXTR_RS_L:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_dextr_rs_l(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_DEXTR_W:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_dextr_w(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_DEXTR_R_W:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_dextr_r_w(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_DEXTR_RS_W:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_dextr_rs_w(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_DEXTR_S_H:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_dextr_s_h(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_DEXTRV_S_H:
> +            tcg_gen_movi_tl(t0, v2);
> +            tcg_gen_movi_tl(t1, v1);
> +            gen_helper_dextr_s_h(cpu_gpr[ret], t0, t1, cpu_env);
> +            break;
> +        case OPC_DEXTRV_L:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_dextr_l(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        case OPC_DEXTRV_R_L:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_dextr_r_l(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        case OPC_DEXTRV_RS_L:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_dextr_rs_l(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        case OPC_DEXTRV_W:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_dextr_w(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        case OPC_DEXTRV_R_W:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_dextr_r_w(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        case OPC_DEXTRV_RS_W:
> +            tcg_gen_movi_tl(t0, v2);
> +            gen_helper_dextr_rs_w(cpu_gpr[ret], t0, v1_t, cpu_env);
> +            break;
> +        }
> +        break;
> +#endif
> +    }
> +
> +    tcg_temp_free(t0);
> +    tcg_temp_free(t1);
> +    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)
> @@ -14794,6 +15083,38 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
>              op2 = MASK_APPEND(ctx->opcode);
>              gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rt, rs, rd, 1);
>              break;
> +        case OPC_EXTR_W_DSP:
> +            op2 = MASK_EXTR_W(ctx->opcode);
> +            switch (op2) {
> +            case OPC_EXTR_W:
> +            case OPC_EXTR_R_W:
> +            case OPC_EXTR_RS_W:
> +            case OPC_EXTR_S_H:
> +            case OPC_EXTRV_S_H:
> +            case OPC_EXTRV_W:
> +            case OPC_EXTRV_R_W:
> +            case OPC_EXTRV_RS_W:
> +            case OPC_EXTP:
> +            case OPC_EXTPV:
> +            case OPC_EXTPDP:
> +            case OPC_EXTPDPV:
> +                gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1);
> +                break;
> +            case OPC_RDDSP:
> +                gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 1);
> +                break;
> +            case OPC_SHILO:
> +            case OPC_SHILOV:
> +            case OPC_MTHLIP:
> +            case OPC_WRDSP:
> +                gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0);
> +                break;
> +            default:            /* Invalid */
> +                MIPS_INVAL("MASK EXTR.W");
> +                generate_exception(ctx, EXCP_RI);
> +                break;
> +            }
> +            break;
>  #if defined(TARGET_MIPS64)
>          case OPC_DEXTM ... OPC_DEXT:
>          case OPC_DINSM ... OPC_DINS:
> @@ -14938,6 +15259,40 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
>              op2 = MASK_DAPPEND(ctx->opcode);
>              gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rt, rs, rd, 1);
>              break;
> +        case OPC_DEXTR_W_DSP:
> +            op2 = MASK_DEXTR_W(ctx->opcode);
> +            switch (op2) {
> +            case OPC_DEXTP:
> +            case OPC_DEXTPDP:
> +            case OPC_DEXTPDPV:
> +            case OPC_DEXTPV:
> +            case OPC_DEXTR_L:
> +            case OPC_DEXTR_R_L:
> +            case OPC_DEXTR_RS_L:
> +            case OPC_DEXTR_W:
> +            case OPC_DEXTR_R_W:
> +            case OPC_DEXTR_RS_W:
> +            case OPC_DEXTR_S_H:
> +            case OPC_DEXTRV_L:
> +            case OPC_DEXTRV_R_L:
> +            case OPC_DEXTRV_RS_L:
> +            case OPC_DEXTRV_S_H:
> +            case OPC_DEXTRV_W:
> +            case OPC_DEXTRV_R_W:
> +            case OPC_DEXTRV_RS_W:
> +                gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1);
> +                break;
> +            case OPC_DMTHLIP:
> +            case OPC_DSHILO:
> +            case OPC_DSHILOV:
> +                gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0);
> +                break;
> +            default:            /* Invalid */
> +                MIPS_INVAL("MASK EXTR.W");
> +                generate_exception(ctx, EXCP_RI);
> +                break;
> +            }
> +            break;
>          case OPC_DPAQ_W_QH_DSP:
>              op2 = MASK_DPAQ_W_QH(ctx->opcode);
>              switch (op2) {
> -- 
> 1.7.10.2 (Apple Git-33)
> 
>
diff mbox

Patch

diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c
index 06c97a2..e798702 100644
--- a/target-mips/dsp_helper.c
+++ b/target-mips/dsp_helper.c
@@ -3436,6 +3436,615 @@  target_ulong helper_packrl_pw(target_ulong rs, target_ulong rt)
 }
 #endif
 
+/** DSP Accumulator and DSPControl Access Sub-class insns **/
+target_ulong helper_extr_w(target_ulong ac, target_ulong shift,
+                           CPUMIPSState *env)
+{
+    int32_t tempI;
+    int64_t tempDL[2];
+
+    shift = shift & 0x0F;
+
+    mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env);
+    if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
+        (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
+        set_DSPControl_overflow_flag(1, 23, env);
+    }
+
+    tempI = (tempDL[0] >> 1) & MIPSDSP_LLO;
+
+    tempDL[0] += 1;
+    if (tempDL[0] == 0) {
+        tempDL[1] += 1;
+    }
+
+    if ((!(tempDL[1] == 0 && (tempDL[0] & MIPSDSP_LHI) == 0x00)) &&
+        (!(tempDL[1] == 1 && (tempDL[0] & MIPSDSP_LHI) == MIPSDSP_LHI))) {
+        set_DSPControl_overflow_flag(1, 23, env);
+    }
+
+    return (target_long)tempI;
+}
+
+target_ulong helper_extr_r_w(target_ulong ac, target_ulong shift,
+                             CPUMIPSState *env)
+{
+    int64_t tempDL[2];
+
+    shift = shift & 0x0F;
+
+    mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env);
+    if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
+        (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
+        set_DSPControl_overflow_flag(1, 23, env);
+    }
+
+    tempDL[0] += 1;
+    if (tempDL[0] == 0) {
+        tempDL[1] += 1;
+    }
+
+    if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
+        (tempDL[1] != 1 && (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
+        set_DSPControl_overflow_flag(1, 23, env);
+    }
+
+    return (target_long)(int32_t)(tempDL[0] >> 1);
+}
+
+target_ulong helper_extr_rs_w(target_ulong ac, target_ulong shift,
+                              CPUMIPSState *env)
+{
+    int32_t tempI, temp64;
+    int64_t tempDL[2];
+
+    shift = shift & 0x0F;
+
+    mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env);
+    if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
+        (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
+        set_DSPControl_overflow_flag(1, 23, env);
+    }
+    tempDL[0] += 1;
+    if (tempDL[0] == 0) {
+        tempDL[1] += 1;
+    }
+    tempI = tempDL[0] >> 1;
+
+    if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
+        (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
+        temp64 = tempDL[1];
+        if (temp64 == 0) {
+            tempI = 0x7FFFFFFF;
+        } else {
+            tempI = 0x80000000;
+        }
+        set_DSPControl_overflow_flag(1, 23, env);
+    }
+
+    return (target_long)tempI;
+}
+
+#if defined(TARGET_MIPS64)
+target_ulong helper_dextr_w(target_ulong ac, target_ulong shift,
+                            CPUMIPSState *env)
+{
+    uint64_t temp[3];
+
+    shift = shift & 0x3F;
+
+    mipsdsp_rndrashift_acc(temp, ac, shift, env);
+
+    return (int64_t)(int32_t)(temp[0] >> 1);
+}
+
+target_ulong helper_dextr_r_w(target_ulong ac, target_ulong shift,
+                              CPUMIPSState *env)
+{
+    uint64_t temp[3];
+    uint32_t temp128;
+
+    shift = shift & 0x3F;
+    mipsdsp_rndrashift_acc(temp, ac, shift, env);
+
+    temp[0] += 1;
+    if (temp[0] == 0) {
+        temp[1] += 1;
+        if (temp[1] == 0) {
+            temp[2] += 1;
+        }
+    }
+
+    temp128 = temp[2] & 0x01;
+
+    if ((temp128 != 0 || temp[1] != 0) &&
+       (temp128 != 1 || temp[1] != ~0ull)) {
+        set_DSPControl_overflow_flag(1, 23, env);
+    }
+
+    return (int64_t)(int32_t)(temp[0] >> 1);
+}
+
+target_ulong helper_dextr_rs_w(target_ulong ac, target_ulong shift,
+                               CPUMIPSState *env)
+{
+    uint64_t temp[3];
+    uint32_t temp128;
+
+    shift = shift & 0x3F;
+    mipsdsp_rndrashift_acc(temp, ac, shift, env);
+
+    temp[0] += 1;
+    if (temp[0] == 0) {
+        temp[1] += 1;
+        if (temp[1] == 0) {
+            temp[2] += 1;
+        }
+    }
+
+    temp128 = temp[2] & 0x01;
+
+    if ((temp128 != 0 || temp[1] != 0) &&
+       (temp128 != 1 || temp[1] != ~0ull)) {
+        if (temp128 == 0) {
+            temp[0] = 0x0FFFFFFFF;
+        } else {
+            temp[0] = 0x0100000000;
+        }
+        set_DSPControl_overflow_flag(1, 23, env);
+    }
+
+    return (int64_t)(int32_t)(temp[0] >> 1);
+}
+
+target_ulong helper_dextr_l(target_ulong ac, target_ulong shift,
+                            CPUMIPSState *env)
+{
+    uint64_t temp[3];
+    target_ulong result;
+
+    shift = shift & 0x3F;
+
+    mipsdsp_rndrashift_acc(temp, ac, shift, env);
+    result = (temp[1] << 63) | (temp[0] >> 1);
+
+    return result;
+}
+
+target_ulong helper_dextr_r_l(target_ulong ac, target_ulong shift,
+                              CPUMIPSState *env)
+{
+    uint64_t temp[3];
+    uint32_t temp128;
+    target_ulong result;
+
+    shift = shift & 0x3F;
+    mipsdsp_rndrashift_acc(temp, ac, shift, env);
+
+    temp[0] += 1;
+    if (temp[0] == 0) {
+        temp[1] += 1;
+        if (temp[1] == 0) {
+            temp[2] += 1;
+        }
+    }
+
+    temp128 = temp[2] & 0x01;
+
+    if ((temp128 != 0 || temp[1] != 0) &&
+       (temp128 != 1 || temp[1] != ~0ull)) {
+        set_DSPControl_overflow_flag(1, 23, env);
+    }
+
+    result = (temp[1] << 63) | (temp[0] >> 1);
+
+    return result;
+}
+
+target_ulong helper_dextr_rs_l(target_ulong ac, target_ulong shift,
+                               CPUMIPSState *env)
+{
+    uint64_t temp[3];
+    uint32_t temp128;
+    target_ulong result;
+
+    shift = shift & 0x3F;
+    mipsdsp_rndrashift_acc(temp, ac, shift, env);
+
+    temp[0] += 1;
+    if (temp[0] == 0) {
+        temp[1] += 1;
+        if (temp[1] == 0) {
+            temp[2] += 1;
+        }
+    }
+
+    temp128 = temp[2] & 0x01;
+
+    if ((temp128 != 0 || temp[1] != 0) &&
+       (temp128 != 1 || temp[1] != ~0ull)) {
+        if (temp128 == 0) {
+            temp[1] &= 0xFFFFFFFFFFFFFFFEull;
+            temp[0] |= 0xFFFFFFFFFFFFFFFEull;
+        } else {
+            temp[1] |= 0x01;
+            temp[0] &= 0x01;
+        }
+        set_DSPControl_overflow_flag(1, 23, env);
+    }
+    result = (temp[1] << 63) | (temp[0] >> 1);
+
+    return result;
+}
+#endif
+
+target_ulong helper_extr_s_h(target_ulong ac, target_ulong shift,
+                             CPUMIPSState *env)
+{
+    int64_t temp;
+
+    shift = shift & 0x0F;
+
+    temp = mipsdsp_rashift_short_acc(ac, shift, env);
+    if (temp > 0x0000000000007FFFull) {
+        temp = 0x00007FFF;
+        set_DSPControl_overflow_flag(1, 23, env);
+    } else if (temp < 0xFFFFFFFFFFFF8000ull) {
+        temp = 0xFFFF8000;
+        set_DSPControl_overflow_flag(1, 23, env);
+    }
+
+    return (target_long)(int32_t)(temp & 0xFFFFFFFF);
+}
+
+
+#if defined(TARGET_MIPS64)
+target_ulong helper_dextr_s_h(target_ulong ac, target_ulong shift,
+                              CPUMIPSState *env)
+{
+    int64_t temp[2];
+    uint32_t temp127;
+
+    shift = shift & 0x1F;
+
+    mipsdsp_rashift_acc((uint64_t *)temp, ac, shift, env);
+
+    temp127 = (temp[1] >> 63) & 0x01;
+
+    if ((temp127 == 0) && (temp[1] > 0 || temp[0] > 32767)) {
+        temp[0] &= 0xFFFF0000;
+        temp[0] |= 0x00007FFF;
+        set_DSPControl_overflow_flag(1, 23, env);
+    } else if ((temp127 == 1) &&
+            (temp[1] < 0xFFFFFFFFFFFFFFFFll
+             || temp[0] < 0xFFFFFFFFFFFF1000ll)) {
+        temp[0] &= 0xFFFF0000;
+        temp[0] |= 0x00008000;
+        set_DSPControl_overflow_flag(1, 23, env);
+    }
+
+    return (int64_t)(int16_t)(temp[0] & MIPSDSP_LO);
+}
+
+#endif
+
+target_ulong helper_extp(target_ulong ac, target_ulong size, CPUMIPSState *env)
+{
+    int32_t start_pos;
+    int sub;
+    uint32_t temp;
+    uint64_t acc;
+
+    size = size & 0x1F;
+
+    temp = 0;
+    start_pos = get_DSPControl_pos(env);
+    sub = start_pos - (size + 1);
+    if (sub >= -1) {
+        acc = ((uint64_t)env->active_tc.HI[ac] << 32) |
+              ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);
+        temp = (acc >> (start_pos - size)) &
+               (((uint32_t)0x01 << (size + 1)) - 1);
+        set_DSPControl_efi(0, env);
+    } else {
+        set_DSPControl_efi(1, env);
+    }
+
+    return (target_ulong)temp;
+}
+
+target_ulong helper_extpdp(target_ulong ac, target_ulong size,
+                           CPUMIPSState *env)
+{
+    int32_t start_pos;
+    int sub;
+    uint32_t temp;
+    uint64_t acc;
+
+    size = size & 0x1F;
+    temp = 0;
+    start_pos = get_DSPControl_pos(env);
+    sub = start_pos - (size + 1);
+    if (sub >= -1) {
+        acc  = ((uint64_t)env->active_tc.HI[ac] << 32) |
+               ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);
+        temp = (acc >> (start_pos - size)) &
+               (((uint32_t)0x01 << (size + 1)) - 1);
+
+        set_DSPControl_pos(start_pos - (size + 1), env);
+        set_DSPControl_efi(0, env);
+    } else {
+        set_DSPControl_efi(1, env);
+    }
+
+    return (target_ulong)temp;
+}
+
+
+#if defined(TARGET_MIPS64)
+target_ulong helper_dextp(target_ulong ac, target_ulong size, CPUMIPSState *env)
+{
+    int start_pos;
+    int len;
+    int sub;
+    uint64_t tempB, tempA;
+    uint64_t temp;
+
+    temp = 0;
+
+    size = size & 0x3F;
+    start_pos = get_DSPControl_pos(env);
+    len = start_pos - size;
+    tempB = env->active_tc.HI[ac];
+    tempA = env->active_tc.LO[ac];
+
+    sub = start_pos - (size + 1);
+
+    if (sub >= -1) {
+        temp = (tempB << (64 - len)) | (tempA >> len);
+        temp = temp & ((0x01 << (size + 1)) - 1);
+        set_DSPControl_efi(0, env);
+    } else {
+        set_DSPControl_efi(1, env);
+    }
+
+    return temp;
+}
+
+target_ulong helper_dextpdp(target_ulong ac, target_ulong size,
+                            CPUMIPSState *env)
+{
+    int start_pos;
+    int len;
+    int sub;
+    uint64_t tempB, tempA;
+    uint64_t temp;
+
+    temp = 0;
+    size = size & 0x3F;
+    start_pos = get_DSPControl_pos(env);
+    len = start_pos - size;
+    tempB = env->active_tc.HI[ac];
+    tempA = env->active_tc.LO[ac];
+
+    sub = start_pos - (size + 1);
+
+    if (sub >= -1) {
+        temp = (tempB << (64 - len)) | (tempA >> len);
+        temp = temp & ((0x01 << (size + 1)) - 1);
+        set_DSPControl_pos(sub, env);
+        set_DSPControl_efi(0, env);
+    } else {
+        set_DSPControl_efi(1, env);
+    }
+
+    return temp;
+}
+
+#endif
+
+void helper_shilo(target_ulong ac, target_ulong rs, CPUMIPSState *env)
+{
+    int8_t  rs5_0;
+    uint64_t temp, acc;
+
+    rs5_0 = rs & 0x3F;
+    rs5_0 = (int8_t)(rs5_0 << 2) >> 2;
+    rs5_0 = MIPSDSP_ABS(rs5_0);
+    acc   = (((uint64_t)env->active_tc.HI[ac] << 32) & MIPSDSP_LHI) |
+            ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);
+    if (rs5_0 == 0) {
+        temp = acc;
+    } else {
+        if (rs5_0 > 0) {
+            temp = acc >> rs5_0;
+        } else {
+            temp = acc << rs5_0;
+        }
+    }
+
+    env->active_tc.HI[ac] = (target_ulong)(int32_t)((temp & MIPSDSP_LHI) >> 32);
+    env->active_tc.LO[ac] = (target_ulong)(int32_t)(temp & MIPSDSP_LLO);
+}
+
+#if defined(TARGET_MIPS64)
+void helper_dshilo(target_ulong shift, target_ulong ac, CPUMIPSState *env)
+{
+    int8_t shift_t;
+    uint64_t tempB, tempA;
+
+    shift_t = (uint8_t)(shift << 1) >> 1;
+    shift_t = MIPSDSP_ABS(shift_t);
+
+    tempB = env->active_tc.HI[ac];
+    tempA = env->active_tc.LO[ac];
+
+    if (shift_t != 0) {
+        if (shift_t >= 0) {
+            tempA = (tempB << (64 - shift)) | (tempA >> shift);
+            tempB = tempB >> shift;
+        } else {
+            tempB = (tempB << shift) | (tempA >> (64 - shift));
+            tempA = tempA << shift;
+        }
+    }
+
+    env->active_tc.HI[ac] = tempB;
+    env->active_tc.LO[ac] = tempA;
+}
+
+#endif
+void helper_mthlip(target_ulong ac, target_ulong rs, CPUMIPSState *env)
+{
+    int32_t tempA, tempB, pos;
+
+    tempA = rs;
+    tempB = env->active_tc.LO[ac];
+    env->active_tc.HI[ac] = (target_long)tempB;
+    env->active_tc.LO[ac] = (target_long)tempA;
+    pos = get_DSPControl_pos(env);
+
+    if (pos > 32) {
+        return;
+    } else {
+        set_DSPControl_pos(pos + 32, env);
+    }
+}
+
+#if defined(TARGET_MIPS64)
+void helper_dmthlip(target_ulong rs, target_ulong ac, CPUMIPSState *env)
+{
+    uint8_t ac_t;
+    uint8_t pos;
+    uint64_t tempB, tempA;
+
+    ac_t = ac & 0x3;
+
+    tempA = rs;
+    tempB = env->active_tc.LO[ac_t];
+
+    env->active_tc.HI[ac_t] = tempB;
+    env->active_tc.LO[ac_t] = tempA;
+
+    pos = get_DSPControl_pos(env);
+
+    if (pos <= 64) {
+        pos = pos + 64;
+        set_DSPControl_pos(pos, env);
+    }
+}
+#endif
+
+void helper_wrdsp(target_ulong rs, target_ulong mask_num, CPUMIPSState *env)
+{
+    uint8_t  mask[6];
+    uint8_t  i;
+    uint32_t newbits, overwrite;
+    target_ulong dsp;
+
+    newbits   = 0x00;
+    overwrite = 0xFFFFFFFF;
+    dsp = env->active_tc.DSPControl;
+
+    for (i = 0; i < 6; i++) {
+        mask[i] = (mask_num >> i) & 0x01;
+    }
+
+    if (mask[0] == 1) {
+#if defined(TARGET_MIPS64)
+        overwrite &= 0xFFFFFF80;
+        newbits   &= 0xFFFFFF80;
+        newbits   |= 0x0000007F & rs;
+#else
+        overwrite &= 0xFFFFFFC0;
+        newbits   &= 0xFFFFFFC0;
+        newbits   |= 0x0000003F & rs;
+#endif
+    }
+
+    if (mask[1] == 1) {
+        overwrite &= 0xFFFFE07F;
+        newbits   &= 0xFFFFE07F;
+        newbits   |= 0x00001F80 & rs;
+    }
+
+    if (mask[2] == 1) {
+        overwrite &= 0xFFFFDFFF;
+        newbits   &= 0xFFFFDFFF;
+        newbits   |= 0x00002000 & rs;
+    }
+
+    if (mask[3] == 1) {
+        overwrite &= 0xFF00FFFF;
+        newbits   &= 0xFF00FFFF;
+        newbits   |= 0x00FF0000 & rs;
+    }
+
+    if (mask[4] == 1) {
+        overwrite &= 0x00FFFFFF;
+        newbits   &= 0x00FFFFFF;
+        newbits   |= 0xFF000000 & rs;
+    }
+
+    if (mask[5] == 1) {
+        overwrite &= 0xFFFFBFFF;
+        newbits   &= 0xFFFFBFFF;
+        newbits   |= 0x00004000 & rs;
+    }
+
+    dsp = dsp & overwrite;
+    dsp = dsp | newbits;
+    env->active_tc.DSPControl = dsp;
+}
+
+target_ulong helper_rddsp(target_ulong masknum, CPUMIPSState *env)
+{
+    uint8_t  mask[6];
+    uint32_t ruler, i;
+    target_ulong temp;
+    target_ulong dsp;
+
+    ruler = 0x01;
+    for (i = 0; i < 6; i++) {
+        mask[i] = (masknum & ruler) >> i ;
+        ruler = ruler << 1;
+    }
+
+    temp  = 0x00;
+    dsp = env->active_tc.DSPControl;
+
+    if (mask[0] == 1) {
+#if defined(TARGET_MIPS64)
+        temp |= dsp & 0x7F;
+#else
+        temp |= dsp & 0x3F;
+#endif
+    }
+
+    if (mask[1] == 1) {
+        temp |= dsp & 0x1F80;
+    }
+
+    if (mask[2] == 1) {
+        temp |= dsp & 0x2000;
+    }
+
+    if (mask[3] == 1) {
+        temp |= dsp & 0x00FF0000;
+    }
+
+    if (mask[4] == 1) {
+        temp |= dsp & 0xFF000000;
+    }
+
+    if (mask[5] == 1) {
+        temp |= dsp & 0x4000;
+    }
+
+    return temp;
+}
+
+
 #undef MIPSDSP_LHI
 #undef MIPSDSP_LLO
 #undef MIPSDSP_HI
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 3d3c596..45af62f 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -676,4 +676,39 @@  DEF_HELPER_FLAGS_2(packrl_ph, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
 DEF_HELPER_FLAGS_2(packrl_pw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
 #endif
 
+/* DSP Accumulator and DSPControl Access Sub-class insns */
+DEF_HELPER_FLAGS_3(extr_w, 0, tl, tl, tl, env)
+DEF_HELPER_FLAGS_3(extr_r_w, 0, tl, tl, tl, env)
+DEF_HELPER_FLAGS_3(extr_rs_w, 0, tl, tl, tl, env)
+#if defined(TARGET_MIPS64)
+DEF_HELPER_FLAGS_3(dextr_w, 0, tl, tl, tl, env)
+DEF_HELPER_FLAGS_3(dextr_r_w, 0, tl, tl, tl, env)
+DEF_HELPER_FLAGS_3(dextr_rs_w, 0, tl, tl, tl, env)
+DEF_HELPER_FLAGS_3(dextr_l, 0, tl, tl, tl, env)
+DEF_HELPER_FLAGS_3(dextr_r_l, 0, tl, tl, tl, env)
+DEF_HELPER_FLAGS_3(dextr_rs_l, 0, tl, tl, tl, env)
+#endif
+DEF_HELPER_FLAGS_3(extr_s_h, 0, tl, tl, tl, env)
+#if defined(TARGET_MIPS64)
+DEF_HELPER_FLAGS_3(dextr_s_h, 0, tl, tl, tl, env)
+#endif
+DEF_HELPER_FLAGS_3(extp, 0, tl, tl, tl, env)
+DEF_HELPER_FLAGS_3(extpdp, 0, tl, tl, tl, env)
+#if defined(TARGET_MIPS64)
+DEF_HELPER_FLAGS_3(dextp, 0, tl, tl, tl, env)
+DEF_HELPER_FLAGS_3(dextpdp, 0, tl, tl, tl, env)
+#endif
+DEF_HELPER_FLAGS_3(shilo, 0, void, tl, tl, env)
+#if defined(TARGET_MIPS64)
+DEF_HELPER_FLAGS_3(dshilo, 0, void, tl, tl, env)
+#endif
+DEF_HELPER_FLAGS_3(mthlip, 0, void, tl, tl, env)
+#if defined(TARGET_MIPS64)
+DEF_HELPER_FLAGS_3(dmthlip, 0, void, tl, tl, env)
+#endif
+DEF_HELPER_FLAGS_3(wrdsp, 0, void, tl, tl, env)
+DEF_HELPER_FLAGS_2(rddsp, 0, tl, tl, env)
+
+
+
 #include "def-helper.h"
diff --git a/target-mips/translate.c b/target-mips/translate.c
index ea939d7..3442d8c 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -353,6 +353,11 @@  enum {
 #if defined(TARGET_MIPS64)
     OPC_DAPPEND_DSP    = 0x35 | OPC_SPECIAL3,
 #endif
+    /* MIPS DSP Accumulator and DSPControl Access Sub-class */
+    OPC_EXTR_W_DSP     = 0x38 | OPC_SPECIAL3,
+#if defined(TARGET_MIPS64)
+    OPC_DEXTR_W_DSP    = 0x3C | OPC_SPECIAL3,
+#endif
 };
 
 /* BSHFL opcodes */
@@ -564,6 +569,30 @@  enum {
     OPC_BALIGN  = (0x10 << 6) | OPC_APPEND_DSP,
 };
 
+#define MASK_EXTR_W(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
+enum {
+    /* MIPS DSP Accumulator and DSPControl Access Sub-class */
+    OPC_EXTR_W     = (0x00 << 6) | OPC_EXTR_W_DSP,
+    OPC_EXTR_R_W   = (0x04 << 6) | OPC_EXTR_W_DSP,
+    OPC_EXTR_RS_W  = (0x06 << 6) | OPC_EXTR_W_DSP,
+    OPC_EXTR_S_H   = (0x0E << 6) | OPC_EXTR_W_DSP,
+    OPC_EXTRV_S_H  = (0x0F << 6) | OPC_EXTR_W_DSP,
+    OPC_EXTRV_W    = (0x01 << 6) | OPC_EXTR_W_DSP,
+    OPC_EXTRV_R_W  = (0x05 << 6) | OPC_EXTR_W_DSP,
+    OPC_EXTRV_RS_W = (0x07 << 6) | OPC_EXTR_W_DSP,
+    OPC_EXTP       = (0x02 << 6) | OPC_EXTR_W_DSP,
+    OPC_EXTPV      = (0x03 << 6) | OPC_EXTR_W_DSP,
+    OPC_EXTPDP     = (0x0A << 6) | OPC_EXTR_W_DSP,
+    OPC_EXTPDPV    = (0x0B << 6) | OPC_EXTR_W_DSP,
+    OPC_SHILO      = (0x1A << 6) | OPC_EXTR_W_DSP,
+    OPC_SHILOV     = (0x1B << 6) | OPC_EXTR_W_DSP,
+    OPC_MTHLIP     = (0x1F << 6) | OPC_EXTR_W_DSP,
+    OPC_WRDSP      = (0x13 << 6) | OPC_EXTR_W_DSP,
+    OPC_RDDSP      = (0x12 << 6) | OPC_EXTR_W_DSP,
+};
+
+
+
 #if defined(TARGET_MIPS64)
 #define MASK_ABSQ_S_QH(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
 enum {
@@ -676,6 +705,32 @@  enum {
 #endif
 
 #if defined(TARGET_MIPS64)
+#define MASK_DEXTR_W(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
+enum {
+    /* MIPS DSP Accumulator and DSPControl Access Sub-class */
+    OPC_DMTHLIP     = (0x1F << 6) | OPC_DEXTR_W_DSP,
+    OPC_DSHILO      = (0x1A << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTP       = (0x02 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTPDP     = (0x0A << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTPDPV    = (0x0B << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTPV      = (0x03 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTR_L     = (0x10 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTR_R_L   = (0x14 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTR_RS_L  = (0x16 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTR_W     = (0x00 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTR_R_W   = (0x04 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTR_RS_W  = (0x06 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTR_S_H   = (0x0E << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTRV_L    = (0x11 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTRV_R_L  = (0x15 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTRV_RS_L = (0x17 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTRV_S_H  = (0x0F << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTRV_W    = (0x01 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTRV_R_W  = (0x05 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DEXTRV_RS_W = (0x07 << 6) | OPC_DEXTR_W_DSP,
+    OPC_DSHILOV     = (0x1B << 6) | OPC_DEXTR_W_DSP,
+};
+
 #define MASK_DINSV(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
 enum {
     /* DSP Bit/Manipulation Sub-class */
@@ -14217,6 +14272,240 @@  static void gen_mipsdsp_add_cmp_pick(DisasContext *ctx,
     MIPS_DEBUG("%s", opn);
 }
 
+static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2,
+                                int ret, int v1, int v2, int check_ret)
+
+{
+    const char *opn = "mipsdsp accumulator";
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    TCGv v1_t = tcg_temp_new();
+    TCGv v2_t = tcg_temp_new();
+    int16_t imm;
+
+    if ((ret == 0) && (check_ret == 1)) {
+        /* Treat as NOP. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+
+    if (v1 == 0) {
+        tcg_gen_movi_tl(v1_t, 0);
+    } else {
+        gen_load_gpr(v1_t, v1);
+    }
+
+    if (v2 == 0) {
+        tcg_gen_movi_tl(v2_t, 0);
+    } else {
+        gen_load_gpr(v2_t, v2);
+    }
+
+    switch (op1) {
+    case OPC_EXTR_W_DSP:
+        check_dsp(ctx);
+        switch (op2) {
+        case OPC_EXTR_W:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_extr_w(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_EXTR_R_W:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_extr_r_w(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_EXTR_RS_W:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_extr_rs_w(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_EXTR_S_H:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_extr_s_h(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_EXTRV_S_H:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_extr_s_h(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        case OPC_EXTRV_W:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_extr_w(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        case OPC_EXTRV_R_W:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_extr_r_w(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        case OPC_EXTRV_RS_W:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_extr_rs_w(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        case OPC_EXTP:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_extp(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_EXTPV:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_extp(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        case OPC_EXTPDP:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_extpdp(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_EXTPDPV:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_extpdp(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        case OPC_SHILO:
+            imm = (ctx->opcode >> 20) & 0x3F;
+            tcg_gen_movi_tl(t0, ret);
+            tcg_gen_movi_tl(t1, imm);
+            gen_helper_shilo(t0, t1, cpu_env);
+            break;
+        case OPC_SHILOV:
+            tcg_gen_movi_tl(t0, ret);
+            gen_helper_shilo(t0, v1_t, cpu_env);
+            break;
+        case OPC_MTHLIP:
+            tcg_gen_movi_tl(t0, ret);
+            gen_helper_mthlip(t0, v1_t, cpu_env);
+            break;
+        case OPC_WRDSP:
+            imm = (ctx->opcode >> 11) & 0x3FF;
+            tcg_gen_movi_tl(t0, imm);
+            gen_helper_wrdsp(v1_t, t0, cpu_env);
+            break;
+        case OPC_RDDSP:
+            imm = (ctx->opcode >> 16) & 0x03FF;
+            tcg_gen_movi_tl(t0, imm);
+            gen_helper_rddsp(cpu_gpr[ret], t0, cpu_env);
+            break;
+        }
+        break;
+#ifdef TARGET_MIPS64
+    case OPC_DEXTR_W_DSP:
+        check_dsp(ctx);
+        switch (op2) {
+        case OPC_DMTHLIP:
+            tcg_gen_movi_tl(t0, ret);
+            gen_helper_dmthlip(v1_t, t0, cpu_env);
+            break;
+        case OPC_DSHILO:
+            {
+                int shift = (ctx->opcode >> 19) & 0x7F;
+                int ac = (ctx->opcode >> 11) & 0x03;
+                tcg_gen_movi_tl(t0, shift);
+                tcg_gen_movi_tl(t1, ac);
+                gen_helper_dshilo(t0, t1, cpu_env);
+                break;
+            }
+        case OPC_DSHILOV:
+            {
+                int ac = (ctx->opcode >> 11) & 0x03;
+                tcg_gen_movi_tl(t0, ac);
+                gen_helper_dshilo(v1_t, t0, cpu_env);
+                break;
+            }
+        case OPC_DEXTP:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+
+            gen_helper_dextp(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_DEXTPV:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_dextp(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        case OPC_DEXTPDP:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_dextpdp(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_DEXTPDPV:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_dextpdp(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        case OPC_DEXTR_L:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_dextr_l(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_DEXTR_R_L:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_dextr_r_l(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_DEXTR_RS_L:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_dextr_rs_l(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_DEXTR_W:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_dextr_w(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_DEXTR_R_W:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_dextr_r_w(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_DEXTR_RS_W:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_dextr_rs_w(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_DEXTR_S_H:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_dextr_s_h(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_DEXTRV_S_H:
+            tcg_gen_movi_tl(t0, v2);
+            tcg_gen_movi_tl(t1, v1);
+            gen_helper_dextr_s_h(cpu_gpr[ret], t0, t1, cpu_env);
+            break;
+        case OPC_DEXTRV_L:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_dextr_l(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        case OPC_DEXTRV_R_L:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_dextr_r_l(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        case OPC_DEXTRV_RS_L:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_dextr_rs_l(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        case OPC_DEXTRV_W:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_dextr_w(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        case OPC_DEXTRV_R_W:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_dextr_r_w(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        case OPC_DEXTRV_RS_W:
+            tcg_gen_movi_tl(t0, v2);
+            gen_helper_dextr_rs_w(cpu_gpr[ret], t0, v1_t, cpu_env);
+            break;
+        }
+        break;
+#endif
+    }
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    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)
@@ -14794,6 +15083,38 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
             op2 = MASK_APPEND(ctx->opcode);
             gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rt, rs, rd, 1);
             break;
+        case OPC_EXTR_W_DSP:
+            op2 = MASK_EXTR_W(ctx->opcode);
+            switch (op2) {
+            case OPC_EXTR_W:
+            case OPC_EXTR_R_W:
+            case OPC_EXTR_RS_W:
+            case OPC_EXTR_S_H:
+            case OPC_EXTRV_S_H:
+            case OPC_EXTRV_W:
+            case OPC_EXTRV_R_W:
+            case OPC_EXTRV_RS_W:
+            case OPC_EXTP:
+            case OPC_EXTPV:
+            case OPC_EXTPDP:
+            case OPC_EXTPDPV:
+                gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1);
+                break;
+            case OPC_RDDSP:
+                gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 1);
+                break;
+            case OPC_SHILO:
+            case OPC_SHILOV:
+            case OPC_MTHLIP:
+            case OPC_WRDSP:
+                gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0);
+                break;
+            default:            /* Invalid */
+                MIPS_INVAL("MASK EXTR.W");
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
 #if defined(TARGET_MIPS64)
         case OPC_DEXTM ... OPC_DEXT:
         case OPC_DINSM ... OPC_DINS:
@@ -14938,6 +15259,40 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
             op2 = MASK_DAPPEND(ctx->opcode);
             gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rt, rs, rd, 1);
             break;
+        case OPC_DEXTR_W_DSP:
+            op2 = MASK_DEXTR_W(ctx->opcode);
+            switch (op2) {
+            case OPC_DEXTP:
+            case OPC_DEXTPDP:
+            case OPC_DEXTPDPV:
+            case OPC_DEXTPV:
+            case OPC_DEXTR_L:
+            case OPC_DEXTR_R_L:
+            case OPC_DEXTR_RS_L:
+            case OPC_DEXTR_W:
+            case OPC_DEXTR_R_W:
+            case OPC_DEXTR_RS_W:
+            case OPC_DEXTR_S_H:
+            case OPC_DEXTRV_L:
+            case OPC_DEXTRV_R_L:
+            case OPC_DEXTRV_RS_L:
+            case OPC_DEXTRV_S_H:
+            case OPC_DEXTRV_W:
+            case OPC_DEXTRV_R_W:
+            case OPC_DEXTRV_RS_W:
+                gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1);
+                break;
+            case OPC_DMTHLIP:
+            case OPC_DSHILO:
+            case OPC_DSHILOV:
+                gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0);
+                break;
+            default:            /* Invalid */
+                MIPS_INVAL("MASK EXTR.W");
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
         case OPC_DPAQ_W_QH_DSP:
             op2 = MASK_DPAQ_W_QH(ctx->opcode);
             switch (op2) {