diff mbox

[v11,01/14] target-mips: Add ASE DSP internal functions

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

Commit Message

Jia Liu Oct. 15, 2012, 4:39 p.m. UTC
Add internal functions using by MIPS ASE DSP instructions.

Signed-off-by: Jia Liu <proljc@gmail.com>
---
 target-mips/Makefile.objs |    2 +-
 target-mips/dsp_helper.c  | 1086 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1087 insertions(+), 1 deletion(-)
 create mode 100644 target-mips/dsp_helper.c

Comments

Aurelien Jarno Oct. 16, 2012, 11:20 p.m. UTC | #1
On Tue, Oct 16, 2012 at 12:39:05AM +0800, Jia Liu wrote:
> Add internal functions using by MIPS ASE DSP instructions.
> 
> Signed-off-by: Jia Liu <proljc@gmail.com>
> ---
>  target-mips/Makefile.objs |    2 +-
>  target-mips/dsp_helper.c  | 1086 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 1087 insertions(+), 1 deletion(-)
>  create mode 100644 target-mips/dsp_helper.c
> 
> diff --git a/target-mips/Makefile.objs b/target-mips/Makefile.objs
> index 3eeeeac..119c816 100644
> --- a/target-mips/Makefile.objs
> +++ b/target-mips/Makefile.objs
> @@ -1,2 +1,2 @@
> -obj-y += translate.o op_helper.o lmi_helper.o helper.o cpu.o
> +obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o
>  obj-$(CONFIG_SOFTMMU) += machine.o
> diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c
> new file mode 100644
> index 0000000..1c656a0
> --- /dev/null
> +++ b/target-mips/dsp_helper.c
> @@ -0,0 +1,1086 @@
> +/*
> + * MIPS ASE DSP Instruction emulation helpers for QEMU.
> + *
> + * Copyright (c) 2012  Jia Liu <proljc@gmail.com>
> + *                     Dongxue Zhang <elat.era@gmail.com>
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cpu.h"
> +#include "helper.h"
> +
> +/*** MIPS DSP internal functions begin ***/
> +#define MIPSDSP_ABS(x) (((x) >= 0) ? x : -x)
> +#define MIPSDSP_OVERFLOW(a, b, c, d) (!(!((a ^ b ^ -1) & (a ^ c) & d)))

Instead of the double not and the mask with d, you can pass the bit
number and do a shift. This would avoid passing huge constants like
0x8000000000000000ull and replace them by 63 instead. 

> +
> +static inline void set_DSPControl_overflow_flag(uint32_t flag, int position,
> +                                                CPUMIPSState *env)
> +{
> +    env->active_tc.DSPControl |= (target_ulong)flag << position;
> +}
> +
> +static inline void set_DSPControl_carryflag(uint32_t flag, CPUMIPSState *env)
> +{
> +    env->active_tc.DSPControl |= (target_ulong)flag << 13;
> +}
> +
> +static inline uint32_t get_DSPControl_carryflag(CPUMIPSState *env)
> +{
> +    return (env->active_tc.DSPControl >> 13) & 0x01;
> +}
> +
> +static inline void set_DSPControl_24(uint32_t flag, int len, CPUMIPSState *env)
> +{
> +  uint32_t filter;
> +
> +  filter = ((0x01 << len) - 1) << 24;
> +  filter = ~filter;
> +
> +  env->active_tc.DSPControl &= filter;
> +  env->active_tc.DSPControl |= (target_ulong)flag << 24;
> +}
> +
> +static inline uint32_t get_DSPControl_24(int len, CPUMIPSState *env)
> +{
> +  uint32_t filter;
> +
> +  filter = (0x01 << len) - 1;
> +
> +  return (env->active_tc.DSPControl >> 24) & filter;
> +}
> +
> +static inline void set_DSPControl_pos(uint32_t pos, CPUMIPSState *env)
> +{
> +    target_ulong dspc;
> +
> +    dspc = env->active_tc.DSPControl;
> +#ifndef TARGET_MIPS64
> +    dspc = dspc & 0xFFFFFFC0;
> +    dspc |= pos;
> +#else
> +    dspc = dspc & 0xFFFFFF80;
> +    dspc |= pos;
> +#endif
> +    env->active_tc.DSPControl = dspc;
> +}
> +
> +static inline uint32_t get_DSPControl_pos(CPUMIPSState *env)
> +{
> +    target_ulong dspc;
> +    uint32_t pos;
> +
> +    dspc = env->active_tc.DSPControl;
> +
> +#ifndef TARGET_MIPS64
> +    pos = dspc & 0x3F;
> +#else
> +    pos = dspc & 0x7F;
> +#endif
> +
> +    return pos;
> +}
> +
> +static inline void set_DSPControl_efi(uint32_t flag, CPUMIPSState *env)
> +{
> +    env->active_tc.DSPControl &= 0xFFFFBFFF;
> +    env->active_tc.DSPControl |= (target_ulong)flag << 14;
> +}
> +
> +#define DO_MIPS_SAT_ABS(size)                                          \
> +static inline int##size##_t mipsdsp_sat_abs##size(int##size##_t a,         \
> +                                                  CPUMIPSState *env)   \
> +{                                                                      \
> +    if (a == INT##size##_MIN) {                                        \
> +        set_DSPControl_overflow_flag(1, 20, env);                      \
> +        return INT##size##_MAX;                                        \
> +    } else {                                                           \
> +        return MIPSDSP_ABS(a);                                         \
> +    }                                                                  \
> +}
> +DO_MIPS_SAT_ABS(8)
> +DO_MIPS_SAT_ABS(16)
> +DO_MIPS_SAT_ABS(32)
> +#undef DO_MIPS_SAT_ABS
> +
> +/* get sum value */
> +static inline int16_t mipsdsp_add_i16(int16_t a, int16_t b, CPUMIPSState *env)
> +{
> +    int16_t tempI;
> +
> +    tempI = a + b;
> +
> +    if (MIPSDSP_OVERFLOW(a, b, tempI, 0x8000)) {
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return tempI;
> +}
> +
> +static inline int16_t mipsdsp_sat_add_i16(int16_t a, int16_t b,
> +                                          CPUMIPSState *env)
> +{
> +    int16_t tempS;
> +
> +    tempS = a + b;
> +
> +    if (MIPSDSP_OVERFLOW(a, b, tempS, 0x8000)) {
> +        if (a > 0) {
> +            tempS = 0x7FFF;
> +        } else {
> +            tempS = 0x8000;
> +        }
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return tempS;
> +}
> +
> +static inline int32_t mipsdsp_sat_add_i32(int32_t a, int32_t b,
> +                                          CPUMIPSState *env)
> +{
> +    int32_t tempI;
> +
> +    tempI = a + b;
> +
> +    if (MIPSDSP_OVERFLOW(a, b, tempI, 0x80000000)) {
> +        if (a > 0) {
> +            tempI = 0x7FFFFFFF;
> +        } else {
> +            tempI = 0x80000000;
> +        }
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return tempI;
> +}
> +
> +static inline uint8_t mipsdsp_add_u8(uint8_t a, uint8_t b, CPUMIPSState *env)
> +{
> +    uint16_t temp;
> +
> +    temp = (uint16_t)a + (uint16_t)b;
> +
> +    if (temp & 0x0100) {
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return temp & 0xFF;
> +}
> +
> +static inline uint16_t mipsdsp_add_u16(uint16_t a, uint16_t b,
> +                                       CPUMIPSState *env)
> +{
> +    uint32_t temp;
> +
> +    temp = (uint32_t)a + (uint32_t)b;
> +
> +    if (temp & 0x00010000) {
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return temp & 0xFFFF;
> +}
> +
> +static inline uint8_t mipsdsp_sat_add_u8(uint8_t a, uint8_t b,
> +                                         CPUMIPSState *env)
> +{
> +    uint8_t  result;
> +    uint16_t temp;
> +
> +    temp = (uint16_t)a + (uint16_t)b;
> +    result = temp & 0xFF;
> +
> +    if (0x0100 & temp) {
> +        result = 0xFF;
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return result;
> +}
> +
> +static inline uint16_t mipsdsp_sat_add_u16(uint16_t a, uint16_t b,
> +                                           CPUMIPSState *env)
> +{
> +    uint16_t result;
> +    uint32_t temp;
> +
> +    temp = (uint32_t)a + (uint32_t)b;
> +    result = temp & 0xFFFF;
> +
> +    if (0x00010000 & temp) {
> +        result = 0xFFFF;
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return result;
> +}
> +
> +static inline int32_t mipsdsp_sat32_acc_q31(int32_t acc, int32_t a,
> +                                            CPUMIPSState *env)
> +{
> +    int64_t temp;
> +    int32_t temp32, temp31, result;
> +    int64_t temp_sum;
> +
> +#ifndef TARGET_MIPS64
> +    temp = ((uint64_t)env->active_tc.HI[acc] << 32) |
> +           (uint64_t)env->active_tc.LO[acc];
> +#else
> +    temp = (uint64_t)env->active_tc.LO[acc];
> +#endif
> +
> +    temp_sum = (int64_t)a + temp;
> +
> +    temp32 = (temp_sum >> 32) & 0x01;
> +    temp31 = (temp_sum >> 31) & 0x01;
> +    result = temp_sum & 0xFFFFFFFF;
> +
> +    if (temp32 != temp31) {
> +        if (temp32 == 0) {
> +            result = 0x7FFFFFFF;
> +        } else {
> +            result = 0x80000000;
> +        }
> +        set_DSPControl_overflow_flag(1, 16 + acc, env);
> +    }
> +
> +    return result;
> +}
> +
> +/* a[0] is LO, a[1] is HI. */
> +static inline void mipsdsp_sat64_acc_add_q63(int64_t *ret,
> +                                             int32_t ac,
> +                                             int64_t *a,
> +                                             CPUMIPSState *env)
> +{
> +    int64_t temp[3];
> +    int64_t acc[3];
> +    int64_t temp_sum;
> +
> +    temp[0] = a[0];
> +    temp[1] = a[1];
> +    if (temp[1] >= 0) {
> +        temp[2] = 0x00;
> +    } else {
> +        temp[2] = ~0ull;
> +    }
> +
> +    acc[0] = env->active_tc.LO[ac];
> +    acc[1] = env->active_tc.HI[ac];
> +    if (acc[1] >= 0) {
> +        acc[2] = 0x00;
> +    } else {
> +        acc[2] = ~0ull;
> +    }
> +
> +    temp_sum = temp[0] + acc[0];
> +    if (((uint64_t)temp_sum < (uint64_t)temp[0]) &&
> +       ((uint64_t)temp_sum < (uint64_t)acc[0])) {
> +        temp[1] += 1;
> +        if (temp[1] == 0) {
> +            temp[2] += 1;
> +        }
> +    }
> +    temp[0] = temp_sum;
> +
> +    temp_sum = temp[1] + acc[1];
> +    if (((uint64_t)temp_sum < (uint64_t)temp[1]) &&
> +       ((uint64_t)temp_sum < (uint64_t)acc[1])) {
> +        temp[2] += 1;
> +    }
> +
> +    if (MIPSDSP_OVERFLOW(temp[1], acc[1], temp_sum, INT64_MIN)) {
> +        if (temp[1] > 0) {
> +            ret[0] = 0x0;
> +            ret[1] = 0x7FFFFFFFFFFFFFFFull;
> +        } else {
> +            ret[0] = 0x8000000000000000ull;
> +            ret[1] = ~0ull;
> +        }
> +        set_DSPControl_overflow_flag(1, 16 + ac, env);
> +    } else {
> +        ret[0] = temp[0];
> +        ret[1] = temp_sum;
> +    }
> +}
> +
> +/* a[0] is LO, a[1] is HI. */
> +static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
> +                                             int32_t ac,
> +                                             int64_t *a,
> +                                             CPUMIPSState *env)
> +{
> +    uint32_t temp64, temp63;
> +    int64_t temp[2];
> +    int64_t acc[2];
> +    int64_t temp_sum;
> +
> +    temp[0] = a[0];
> +    temp[1] = a[1];
> +
> +    acc[0] = env->active_tc.LO[ac];
> +    acc[1] = env->active_tc.HI[ac];
> +
> +    temp_sum = acc[0] - temp[0];
> +    if (MIPSDSP_OVERFLOW(acc[0], -temp[0], temp_sum, 0x8000000000000000ull)) {
> +        acc[1] -= 1;
> +    }
> +    acc[0] = temp_sum;
> +
> +    temp_sum = acc[1] - temp[1];
> +    acc[1] = temp_sum;
> +
> +    temp64 = acc[1] & 0x01;
> +    temp63 = (acc[0] >> 63) & 0x01;
> +
> +    /* MIPSDSP_OVERFLOW only can check if a 64 bits sub is overflow,
> +     * there are two 128 bits value subed then check the 63/64 bits are equal
> +     * or not.*/

If you disagree with what I say, you can send mail, there is no need to
put it as a comment.

That said MIPSDSP_OVERFLOW doesn't work only on 64-bit values, it can
work other size, as it is done elsewhere in this patch. The only thing
it checked is the highest bit of the two arguments and the result.
Therefore if you pass the highest part of the values, it can work.

> +    if (temp64 != temp63) {
> +        if (temp64 == 1) {
> +            ret[0] = 0x8000000000000000ull;
> +            ret[1] = ~0ull;
> +        } else {
> +            ret[0] = 0x0;
> +            ret[1] = 0x7FFFFFFFFFFFFFFFull;
> +        }
> +        set_DSPControl_overflow_flag(1, 16 + ac, env);
> +    } else {
> +        ret[0] = acc[0];
> +        ret[1] = acc[1];
> +    }
> +}
> +
> +static inline int32_t mipsdsp_mul_i16_i16(int16_t a, int16_t b,
> +                                          CPUMIPSState *env)
> +{
> +    int32_t temp;
> +
> +    temp = (int32_t)a * (int32_t)b;
> +
> +    if ((temp > 0x7FFF) || (temp < 0xFFFF8000)) {
> +        set_DSPControl_overflow_flag(1, 21, env);
> +    }
> +    temp &= 0x0000FFFF;
> +
> +    return temp;
> +}
> +
> +static inline int32_t mipsdsp_mul_u16_u16(int32_t a, int32_t b)
> +{
> +    return a * b;
> +}
> +
> +static inline int32_t mipsdsp_mul_i32_i32(int32_t a, int32_t b)
> +{
> +    return a * b;
> +}
> +
> +static inline int32_t mipsdsp_sat16_mul_i16_i16(int16_t a, int16_t b,
> +                                                CPUMIPSState *env)
> +{
> +    int32_t temp;
> +
> +    temp = (int32_t)a * (int32_t)b;
> +
> +    if (temp > 0x7FFF) {
> +        temp = 0x00007FFF;
> +        set_DSPControl_overflow_flag(1, 21, env);
> +    } else if (temp < 0x00007FFF) {
> +        temp = 0xFFFF8000;
> +        set_DSPControl_overflow_flag(1, 21, env);
> +    }
> +    temp &= 0x0000FFFF;
> +
> +    return temp;
> +}
> +
> +static inline int32_t mipsdsp_mul_q15_q15_overflowflag21(uint16_t a, uint16_t b,
> +                                                         CPUMIPSState *env)
> +{
> +    int32_t temp;
> +
> +    if ((a == 0x8000) && (b == 0x8000)) {
> +        temp = 0x7FFFFFFF;
> +        set_DSPControl_overflow_flag(1, 21, env);
> +    } else {
> +        temp = ((int32_t)(int16_t)a * (int32_t)(int16_t)b) << 1;
> +    }
> +
> +    return temp;
> +}
> +
> +/* right shift */
> +static inline uint8_t mipsdsp_rshift_u8(uint8_t a, target_ulong mov)
> +{
> +    return a >> mov;
> +}
> +
> +static inline uint16_t mipsdsp_rshift_u16(uint16_t a, target_ulong mov)
> +{
> +    return a >> mov;
> +}
> +
> +static inline int8_t mipsdsp_rashift8(int8_t a, target_ulong mov)
> +{
> +    return a >> mov;
> +}
> +
> +static inline int16_t mipsdsp_rashift16(int16_t a, target_ulong mov)
> +{
> +    return a >> mov;
> +}
> +
> +static inline int32_t mipsdsp_rashift32(int32_t a, target_ulong mov)
> +{
> +    return a >> mov;
> +}
> +
> +static inline int16_t mipsdsp_rshift1_add_q16(int16_t a, int16_t b)
> +{
> +    int32_t temp;
> +
> +    temp = (int32_t)a + (int32_t)b;
> +
> +    return (temp >> 1) & 0xFFFF;
> +}
> +
> +/* round right shift */
> +static inline int16_t mipsdsp_rrshift1_add_q16(int16_t a, int16_t b)
> +{
> +    int32_t temp;
> +
> +    temp = (int32_t)a + (int32_t)b;
> +    temp += 1;
> +
> +    return (temp >> 1) & 0xFFFF;
> +}
> +
> +static inline int32_t mipsdsp_rshift1_add_q32(int32_t a, int32_t b)
> +{
> +    int64_t temp;
> +
> +    temp = (int64_t)a + (int64_t)b;
> +
> +    return (temp >> 1) & 0xFFFFFFFF;
> +}
> +
> +static inline int32_t mipsdsp_rrshift1_add_q32(int32_t a, int32_t b)
> +{
> +    int64_t temp;
> +
> +    temp = (int64_t)a + (int64_t)b;
> +    temp += 1;
> +
> +    return (temp >> 1) & 0xFFFFFFFF;
> +}
> +
> +static inline uint8_t mipsdsp_rshift1_add_u8(uint8_t a, uint8_t b)
> +{
> +    uint16_t temp;
> +
> +    temp = (uint16_t)a + (uint16_t)b;
> +
> +    return (temp >> 1) & 0x00FF;
> +}
> +
> +static inline uint8_t mipsdsp_rrshift1_add_u8(uint8_t a, uint8_t b)
> +{
> +    uint16_t temp;
> +
> +    temp = (uint16_t)a + (uint16_t)b + 1;
> +
> +    return (temp >> 1) & 0x00FF;
> +}
> +
> +static inline uint8_t mipsdsp_rshift1_sub_u8(uint8_t a, uint8_t b)
> +{
> +    uint16_t temp;
> +
> +    temp = (uint16_t)a - (uint16_t)b;
> +
> +    return (temp >> 1) & 0x00FF;
> +}
> +
> +static inline uint8_t mipsdsp_rrshift1_sub_u8(uint8_t a, uint8_t b)
> +{
> +    uint16_t temp;
> +
> +    temp = (uint16_t)a - (uint16_t)b + 1;
> +
> +    return (temp >> 1) & 0x00FF;
> +}
> +
> +static inline int64_t mipsdsp_rashift_short_acc(int32_t ac,
> +                                                int32_t shift,
> +                                                CPUMIPSState *env)
> +{
> +    int32_t sign, temp31;
> +    int64_t temp, acc;
> +
> +    sign = (env->active_tc.HI[ac] >> 31) & 0x01;
> +    acc = ((int64_t)env->active_tc.HI[ac] << 32) |
> +          ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF);
> +    if (shift == 0) {
> +        temp = acc;
> +    } else {
> +        if (sign == 0) {
> +            temp = (((int64_t)0x01 << (32 - shift + 1)) - 1) & (acc >> shift);
> +        } else {
> +            temp = ((((int64_t)0x01 << (shift + 1)) - 1) << (32 - shift)) |
> +                   (acc >> shift);
> +        }
> +    }
> +
> +    temp31 = (temp >> 31) & 0x01;
> +    if (sign != temp31) {
> +        set_DSPControl_overflow_flag(1, 23, env);
> +    }
> +
> +    return temp;
> +}
> +
> +/*  128 bits long. p[0] is LO, p[1] is HI. */
> +static inline void mipsdsp_rndrashift_short_acc(int64_t *p,
> +                                                int32_t ac,
> +                                                int32_t shift,
> +                                                CPUMIPSState *env)
> +{
> +    int64_t acc;
> +
> +    acc = ((int64_t)env->active_tc.HI[ac] << 32) |
> +          ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF);
> +    if (shift == 0) {
> +        p[0] = acc << 1;
> +        p[1] = (acc >> 63) & 0x01;
> +    } else {
> +        p[0] = acc >> (shift - 1);
> +        p[1] = 0;
> +    }
> +}
> +
> +/* 128 bits long. p[0] is LO, p[1] is HI */
> +static inline void mipsdsp_rashift_acc(uint64_t *p,
> +                                       uint32_t ac,
> +                                       uint32_t shift,
> +                                       CPUMIPSState *env)
> +{
> +    uint64_t tempB, tempA;
> +
> +    tempB = env->active_tc.HI[ac];
> +    tempA = env->active_tc.LO[ac];
> +    shift = shift & 0x1F;
> +
> +    if (shift == 0) {
> +        p[1] = tempB;
> +        p[0] = tempA;
> +    } else {
> +        p[0] = (tempB << (64 - shift)) | (tempA >> shift);
> +        p[1] = (int64_t)tempB >> shift;
> +    }
> +}
> +
> +/* 128 bits long. p[0] is LO, p[1] is HI , p[2] is sign of HI.*/
> +static inline void mipsdsp_rndrashift_acc(uint64_t *p,
> +                                          uint32_t ac,
> +                                          uint32_t shift,
> +                                          CPUMIPSState *env)
> +{
> +    int64_t tempB, tempA;
> +
> +    tempB = env->active_tc.HI[ac];
> +    tempA = env->active_tc.LO[ac];
> +    shift = shift & 0x3F;
> +
> +    if (shift == 0) {
> +        p[2] = tempB >> 63;
> +        p[1] = (tempB << 1) | (tempA >> 63);
> +        p[0] = tempA << 1;
> +    } else {
> +        p[0] = (tempB << (65 - shift)) | (tempA >> (shift - 1));
> +        p[1] = (int64_t)tempB >> (shift - 1);
> +        if (tempB >= 0) {
> +            p[2] = 0x0;
> +        } else {
> +            p[2] = ~0ull;
> +        }
> +    }
> +}
> +
> +static inline int32_t mipsdsp_mul_q15_q15(int32_t ac, uint16_t a, uint16_t b,
> +                                          CPUMIPSState *env)
> +{
> +    int32_t temp;
> +
> +    if ((a == 0x8000) && (b == 0x8000)) {
> +        temp = 0x7FFFFFFF;
> +        set_DSPControl_overflow_flag(1, 16 + ac, env);
> +    } else {
> +        temp = ((uint32_t)a * (uint32_t)b) << 1;
> +    }
> +
> +    return temp;
> +}
> +
> +static inline int64_t mipsdsp_mul_q31_q31(int32_t ac, uint32_t a, uint32_t b,
> +                                          CPUMIPSState *env)
> +{
> +    uint64_t temp;
> +
> +    if ((a == 0x80000000) && (b == 0x80000000)) {
> +        temp = 0x7FFFFFFFFFFFFFFFull;
> +        set_DSPControl_overflow_flag(1, 16 + ac, env);
> +    } else {
> +        temp = ((uint64_t)a * (uint64_t)b) << 1;
> +    }
> +
> +    return temp;
> +}
> +
> +static inline uint16_t mipsdsp_mul_u8_u8(uint8_t a, uint8_t b)
> +{
> +    return (uint16_t)a * (uint16_t)b;
> +}
> +
> +static inline uint16_t mipsdsp_mul_u8_u16(uint8_t a, uint16_t b,
> +                                          CPUMIPSState *env)
> +{
> +    uint32_t tempI;
> +
> +    tempI = (uint32_t)a * (uint32_t)b;
> +    if (tempI > 0x0000FFFF) {
> +        tempI = 0x0000FFFF;
> +        set_DSPControl_overflow_flag(1, 21, env);
> +    }
> +
> +    return tempI & 0x0000FFFF;
> +}
> +
> +static inline uint64_t mipsdsp_mul_u32_u32(uint32_t a, uint32_t b)
> +{
> +    return (uint64_t)a * (uint64_t)b;
> +}
> +
> +static inline int16_t mipsdsp_rndq15_mul_q15_q15(uint16_t a, uint16_t b,
> +                                                 CPUMIPSState *env)
> +{
> +    uint32_t temp;
> +
> +    if ((a == 0x8000) && (b == 0x8000)) {
> +        temp = 0x7FFF0000;
> +        set_DSPControl_overflow_flag(1, 21, env);
> +    } else {
> +        temp = (a * b) << 1;
> +        temp = temp + 0x00008000;
> +    }
> +
> +    return (temp & 0xFFFF0000) >> 16;
> +}
> +
> +static inline int32_t mipsdsp_sat16_mul_q15_q15(uint16_t a, uint16_t b,
> +                                                CPUMIPSState *env)
> +{
> +    int32_t temp;
> +
> +    if ((a == 0x8000) && (b == 0x8000)) {
> +        temp = 0x7FFF0000;
> +        set_DSPControl_overflow_flag(1, 21, env);
> +    } else {
> +        temp = ((uint32_t)a * (uint32_t)b);
> +        temp = temp << 1;
> +    }
> +
> +    return (temp >> 16) & 0x0000FFFF;
> +}
> +
> +static inline uint16_t mipsdsp_trunc16_sat16_round(int32_t a,
> +                                                   CPUMIPSState *env)
> +{
> +    int64_t temp;
> +
> +    temp = (int32_t)a + 0x00008000;
> +
> +    if (a > 0x7fff8000) {
> +        temp = 0x7FFFFFFF;
> +        set_DSPControl_overflow_flag(1, 22, env);
> +    }
> +
> +    return (temp >> 16) & 0xFFFF;
> +}
> +
> +static inline uint8_t mipsdsp_sat8_reduce_precision(uint16_t a,
> +                                                    CPUMIPSState *env)
> +{
> +    uint16_t mag;
> +    uint32_t sign;
> +
> +    sign = (a >> 15) & 0x01;
> +    mag = a & 0x7FFF;
> +
> +    if (sign == 0) {
> +        if (mag > 0x7F80) {
> +            set_DSPControl_overflow_flag(1, 22, env);
> +            return 0xFF;
> +        } else {
> +            return (mag >> 7) & 0xFFFF;
> +        }
> +    } else {
> +        set_DSPControl_overflow_flag(1, 22, env);
> +        return 0x00;
> +    }
> +}
> +
> +static inline uint8_t mipsdsp_lshift8(uint8_t a, uint8_t s, CPUMIPSState *env)
> +{
> +    uint8_t sign;
> +    uint8_t discard;
> +
> +    if (s == 0) {
> +        return a;
> +    } else {
> +        sign = (a >> 7) & 0x01;
> +        if (sign != 0) {
> +            discard = (((0x01 << (8 - s)) - 1) << s) |
> +                      ((a >> (6 - (s - 1))) & ((0x01 << s) - 1));
> +        } else {
> +            discard = a >> (6 - (s - 1));
> +        }
> +
> +        if (discard != 0x00) {
> +            set_DSPControl_overflow_flag(1, 22, env);
> +        }
> +        return a << s;
> +    }
> +}
> +
> +static inline uint16_t mipsdsp_lshift16(uint16_t a, uint8_t s,
> +                                        CPUMIPSState *env)
> +{
> +    uint8_t  sign;
> +    uint16_t discard;
> +
> +    if (s == 0) {
> +        return a;
> +    } else {
> +        sign = (a >> 15) & 0x01;
> +        if (sign != 0) {
> +            discard = (((0x01 << (16 - s)) - 1) << s) |
> +                      ((a >> (14 - (s - 1))) & ((0x01 << s) - 1));
> +        } else {
> +            discard = a >> (14 - (s - 1));
> +        }
> +
> +        if ((discard != 0x0000) && (discard != 0xFFFF)) {
> +            set_DSPControl_overflow_flag(1, 22, env);
> +        }
> +        return a << s;
> +    }
> +}
> +
> +
> +static inline uint32_t mipsdsp_lshift32(uint32_t a, uint8_t s,
> +                                        CPUMIPSState *env)
> +{
> +    uint32_t discard;
> +
> +    if (s == 0) {
> +        return a;
> +    } else {
> +        discard = (int32_t)a >> (31 - (s - 1));
> +
> +        if ((discard != 0x00000000) && (discard != 0xFFFFFFFF)) {
> +            set_DSPControl_overflow_flag(1, 22, env);
> +        }
> +        return a << s;
> +    }
> +}
> +
> +static inline uint16_t mipsdsp_sat16_lshift(uint16_t a, uint8_t s,
> +                                            CPUMIPSState *env)
> +{
> +    uint8_t  sign;
> +    uint16_t discard;
> +
> +    if (s == 0) {
> +        return a;
> +    } else {
> +        sign = (a >> 15) & 0x01;
> +        if (sign != 0) {
> +            discard = (((0x01 << (16 - s)) - 1) << s) |
> +                      ((a >> (14 - (s - 1))) & ((0x01 << s) - 1));
> +        } else {
> +            discard = a >> (14 - (s - 1));
> +        }
> +
> +        if ((discard != 0x0000) && (discard != 0xFFFF)) {
> +            set_DSPControl_overflow_flag(1, 22, env);
> +            return (sign == 0) ? 0x7FFF : 0x8000;
> +        } else {
> +            return a << s;
> +        }
> +    }
> +}
> +
> +static inline uint32_t mipsdsp_sat32_lshift(uint32_t a, uint8_t s,
> +                                            CPUMIPSState *env)
> +{
> +    uint8_t  sign;
> +    uint32_t discard;
> +
> +    if (s == 0) {
> +        return a;
> +    } else {
> +        sign = (a >> 31) & 0x01;
> +        if (sign != 0) {
> +            discard = (((0x01 << (32 - s)) - 1) << s) |
> +                      ((a >> (30 - (s - 1))) & ((0x01 << s) - 1));
> +        } else {
> +            discard = a >> (30 - (s - 1));
> +        }
> +
> +        if ((discard != 0x00000000) && (discard != 0xFFFFFFFF)) {
> +            set_DSPControl_overflow_flag(1, 22, env);
> +            return (sign == 0) ? 0x7FFFFFFF : 0x80000000;
> +        } else {
> +            return a << s;
> +        }
> +    }
> +}
> +
> +static inline uint8_t mipsdsp_rnd8_rashift(uint8_t a, uint8_t s)
> +{
> +    uint32_t temp;
> +
> +    if (s == 0) {
> +        temp = (uint32_t)a << 1;
> +    } else {
> +        temp = (int32_t)(int8_t)a >> (s - 1);
> +    }
> +
> +    return (temp + 1) >> 1;
> +}
> +
> +static inline uint16_t mipsdsp_rnd16_rashift(uint16_t a, uint8_t s)
> +{
> +    uint32_t temp;
> +
> +    if (s == 0) {
> +        temp = (uint32_t)a << 1;
> +    } else {
> +        temp = (int32_t)(int16_t)a >> (s - 1);
> +    }
> +
> +    return (temp + 1) >> 1;
> +}
> +
> +static inline uint32_t mipsdsp_rnd32_rashift(uint32_t a, uint8_t s)
> +{
> +    int64_t temp;
> +
> +    if (s == 0) {
> +        temp = a << 1;
> +    } else {
> +        temp = (int64_t)(int32_t)a >> (s - 1);
> +    }
> +    temp += 1;
> +
> +    return (temp >> 1) & 0x00000000FFFFFFFFull;
> +}
> +
> +static inline uint16_t mipsdsp_sub_i16(int16_t a, int16_t b, CPUMIPSState *env)
> +{
> +    int16_t  temp;
> +
> +    temp = a - b;
> +    if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) {
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return temp;
> +}
> +
> +static inline uint16_t mipsdsp_sat16_sub(int16_t a, int16_t b,
> +                                         CPUMIPSState *env)
> +{
> +    int16_t  temp;
> +
> +    temp = a - b;
> +    if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) {
> +        if (a > 0) {
> +            temp = 0x7FFF;
> +        } else {
> +            temp = 0x8000;
> +        }
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return temp;
> +}
> +
> +static inline uint32_t mipsdsp_sat32_sub(int32_t a, int32_t b,
> +                                         CPUMIPSState *env)
> +{
> +    int32_t  temp;
> +
> +    temp = a - b;
> +    if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) {
> +        if (a > 0) {
> +            temp = 0x7FFFFFFF;
> +        } else {
> +            temp = 0x80000000;
> +        }
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return temp & 0x00000000FFFFFFFFull;
> +}
> +
> +static inline uint16_t mipsdsp_rshift1_sub_q16(int16_t a, int16_t b)
> +{
> +    int32_t  temp;
> +
> +    temp = (int32_t)a - (int32_t)b;
> +
> +    return (temp >> 1) & 0x0000FFFF;
> +}
> +
> +static inline uint16_t mipsdsp_rrshift1_sub_q16(int16_t a, int16_t b)
> +{
> +    int32_t  temp;
> +
> +    temp = (int32_t)a - (int32_t)b;
> +    temp += 1;
> +
> +    return (temp >> 1) & 0x0000FFFF;
> +}
> +
> +static inline uint32_t mipsdsp_rshift1_sub_q32(int32_t a, int32_t b)
> +{
> +    int64_t  temp;
> +
> +    temp = (int64_t)a - (int64_t)b;
> +
> +    return (temp >> 1) & 0x00000000FFFFFFFFull;
> +}
> +
> +static inline uint32_t mipsdsp_rrshift1_sub_q32(int32_t a, int32_t b)
> +{
> +    int64_t  temp;
> +
> +    temp = (int64_t)a - (int64_t)b;
> +    temp += 1;
> +
> +    return (temp >> 1) & 0x00000000FFFFFFFFull;
> +}
> +
> +static inline uint16_t mipsdsp_sub_u16_u16(uint16_t a, uint16_t b,
> +                                           CPUMIPSState *env)
> +{
> +    uint8_t  temp16;
> +    uint32_t temp;
> +
> +    temp = (uint32_t)a - (uint32_t)b;
> +    temp16 = (temp >> 16) & 0x01;
> +    if (temp16 == 1) {
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +    return temp & 0x0000FFFF;
> +}
> +
> +static inline uint16_t mipsdsp_satu16_sub_u16_u16(uint16_t a, uint16_t b,
> +                                                  CPUMIPSState *env)
> +{
> +    uint8_t  temp16;
> +    uint32_t temp;
> +
> +    temp   = (uint32_t)a - (uint32_t)b;
> +    temp16 = (temp >> 16) & 0x01;
> +
> +    if (temp16 == 1) {
> +        temp = 0x0000;
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return temp & 0x0000FFFF;
> +}
> +
> +static inline uint8_t mipsdsp_sub_u8(uint8_t a, uint8_t b, CPUMIPSState *env)
> +{
> +    uint8_t  temp8;
> +    uint16_t temp;
> +
> +    temp = (uint16_t)a - (uint16_t)b;
> +    temp8 = (temp >> 8) & 0x01;
> +    if (temp8 == 1) {
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return temp & 0x00FF;
> +}
> +
> +static inline uint8_t mipsdsp_satu8_sub(uint8_t a, uint8_t b, CPUMIPSState *env)
> +{
> +    uint8_t  temp8;
> +    uint16_t temp;
> +
> +    temp = (uint16_t)a - (uint16_t)b;
> +    temp8 = (temp >> 8) & 0x01;
> +    if (temp8 == 1) {
> +        temp = 0x00;
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return temp & 0x00FF;
> +}
> +
> +static inline uint32_t mipsdsp_sub32(int32_t a, int32_t b, CPUMIPSState *env)
> +{
> +    int32_t temp;
> +
> +    temp = a - b;
> +    if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) {
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return temp;
> +}
> +
> +static inline int32_t mipsdsp_add_i32(int32_t a, int32_t b, CPUMIPSState *env)
> +{
> +    int32_t temp;
> +
> +    temp = a + b;
> +
> +    if (MIPSDSP_OVERFLOW(a, b, temp, 0x80000000)) {
> +        set_DSPControl_overflow_flag(1, 20, env);
> +    }
> +
> +    return temp;
> +}
> +
> +static inline int32_t mipsdsp_cmp_eq(uint32_t a, uint32_t b)
> +{
> +    return a == b;
> +}
> +
> +static inline int32_t mipsdsp_cmp_le(uint32_t a, uint32_t b)
> +{
> +    return a <= b;
> +}
> +
> +static inline int32_t mipsdsp_cmp_lt(uint32_t a, uint32_t b)
> +{
> +    return a < b;
> +}
> +/*** MIPS DSP internal functions end ***/
> -- 
> 1.7.10.2 (Apple Git-33)
> 
>
Jia Liu Oct. 17, 2012, 3:39 a.m. UTC | #2
Hi Aurelien,

On Wed, Oct 17, 2012 at 7:20 AM, Aurelien Jarno <aurelien@aurel32.net> wrote:
> On Tue, Oct 16, 2012 at 12:39:05AM +0800, Jia Liu wrote:
>> Add internal functions using by MIPS ASE DSP instructions.
>>
>> Signed-off-by: Jia Liu <proljc@gmail.com>
>> ---
>>  target-mips/Makefile.objs |    2 +-
>>  target-mips/dsp_helper.c  | 1086 +++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 1087 insertions(+), 1 deletion(-)
>>  create mode 100644 target-mips/dsp_helper.c
>>
>> diff --git a/target-mips/Makefile.objs b/target-mips/Makefile.objs
>> index 3eeeeac..119c816 100644
>> --- a/target-mips/Makefile.objs
>> +++ b/target-mips/Makefile.objs
>> @@ -1,2 +1,2 @@
>> -obj-y += translate.o op_helper.o lmi_helper.o helper.o cpu.o
>> +obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o
>>  obj-$(CONFIG_SOFTMMU) += machine.o
>> diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c
>> new file mode 100644
>> index 0000000..1c656a0
>> --- /dev/null
>> +++ b/target-mips/dsp_helper.c
>> @@ -0,0 +1,1086 @@
>> +/*
>> + * MIPS ASE DSP Instruction emulation helpers for QEMU.
>> + *
>> + * Copyright (c) 2012  Jia Liu <proljc@gmail.com>
>> + *                     Dongxue Zhang <elat.era@gmail.com>
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2 of the License, or (at your option) any later version.
>> + *
>> + * This library is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include "cpu.h"
>> +#include "helper.h"
>> +
>> +/*** MIPS DSP internal functions begin ***/
>> +#define MIPSDSP_ABS(x) (((x) >= 0) ? x : -x)
>> +#define MIPSDSP_OVERFLOW(a, b, c, d) (!(!((a ^ b ^ -1) & (a ^ c) & d)))
>
> Instead of the double not and the mask with d, you can pass the bit
> number and do a shift. This would avoid passing huge constants like
> 0x8000000000000000ull and replace them by 63 instead.
>
>> +
>> +static inline void set_DSPControl_overflow_flag(uint32_t flag, int position,
>> +                                                CPUMIPSState *env)
>> +{
>> +    env->active_tc.DSPControl |= (target_ulong)flag << position;
>> +}
>> +
>> +static inline void set_DSPControl_carryflag(uint32_t flag, CPUMIPSState *env)
>> +{
>> +    env->active_tc.DSPControl |= (target_ulong)flag << 13;
>> +}
>> +
>> +static inline uint32_t get_DSPControl_carryflag(CPUMIPSState *env)
>> +{
>> +    return (env->active_tc.DSPControl >> 13) & 0x01;
>> +}
>> +
>> +static inline void set_DSPControl_24(uint32_t flag, int len, CPUMIPSState *env)
>> +{
>> +  uint32_t filter;
>> +
>> +  filter = ((0x01 << len) - 1) << 24;
>> +  filter = ~filter;
>> +
>> +  env->active_tc.DSPControl &= filter;
>> +  env->active_tc.DSPControl |= (target_ulong)flag << 24;
>> +}
>> +
>> +static inline uint32_t get_DSPControl_24(int len, CPUMIPSState *env)
>> +{
>> +  uint32_t filter;
>> +
>> +  filter = (0x01 << len) - 1;
>> +
>> +  return (env->active_tc.DSPControl >> 24) & filter;
>> +}
>> +
>> +static inline void set_DSPControl_pos(uint32_t pos, CPUMIPSState *env)
>> +{
>> +    target_ulong dspc;
>> +
>> +    dspc = env->active_tc.DSPControl;
>> +#ifndef TARGET_MIPS64
>> +    dspc = dspc & 0xFFFFFFC0;
>> +    dspc |= pos;
>> +#else
>> +    dspc = dspc & 0xFFFFFF80;
>> +    dspc |= pos;
>> +#endif
>> +    env->active_tc.DSPControl = dspc;
>> +}
>> +
>> +static inline uint32_t get_DSPControl_pos(CPUMIPSState *env)
>> +{
>> +    target_ulong dspc;
>> +    uint32_t pos;
>> +
>> +    dspc = env->active_tc.DSPControl;
>> +
>> +#ifndef TARGET_MIPS64
>> +    pos = dspc & 0x3F;
>> +#else
>> +    pos = dspc & 0x7F;
>> +#endif
>> +
>> +    return pos;
>> +}
>> +
>> +static inline void set_DSPControl_efi(uint32_t flag, CPUMIPSState *env)
>> +{
>> +    env->active_tc.DSPControl &= 0xFFFFBFFF;
>> +    env->active_tc.DSPControl |= (target_ulong)flag << 14;
>> +}
>> +
>> +#define DO_MIPS_SAT_ABS(size)                                          \
>> +static inline int##size##_t mipsdsp_sat_abs##size(int##size##_t a,         \
>> +                                                  CPUMIPSState *env)   \
>> +{                                                                      \
>> +    if (a == INT##size##_MIN) {                                        \
>> +        set_DSPControl_overflow_flag(1, 20, env);                      \
>> +        return INT##size##_MAX;                                        \
>> +    } else {                                                           \
>> +        return MIPSDSP_ABS(a);                                         \
>> +    }                                                                  \
>> +}
>> +DO_MIPS_SAT_ABS(8)
>> +DO_MIPS_SAT_ABS(16)
>> +DO_MIPS_SAT_ABS(32)
>> +#undef DO_MIPS_SAT_ABS
>> +
>> +/* get sum value */
>> +static inline int16_t mipsdsp_add_i16(int16_t a, int16_t b, CPUMIPSState *env)
>> +{
>> +    int16_t tempI;
>> +
>> +    tempI = a + b;
>> +
>> +    if (MIPSDSP_OVERFLOW(a, b, tempI, 0x8000)) {
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return tempI;
>> +}
>> +
>> +static inline int16_t mipsdsp_sat_add_i16(int16_t a, int16_t b,
>> +                                          CPUMIPSState *env)
>> +{
>> +    int16_t tempS;
>> +
>> +    tempS = a + b;
>> +
>> +    if (MIPSDSP_OVERFLOW(a, b, tempS, 0x8000)) {
>> +        if (a > 0) {
>> +            tempS = 0x7FFF;
>> +        } else {
>> +            tempS = 0x8000;
>> +        }
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return tempS;
>> +}
>> +
>> +static inline int32_t mipsdsp_sat_add_i32(int32_t a, int32_t b,
>> +                                          CPUMIPSState *env)
>> +{
>> +    int32_t tempI;
>> +
>> +    tempI = a + b;
>> +
>> +    if (MIPSDSP_OVERFLOW(a, b, tempI, 0x80000000)) {
>> +        if (a > 0) {
>> +            tempI = 0x7FFFFFFF;
>> +        } else {
>> +            tempI = 0x80000000;
>> +        }
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return tempI;
>> +}
>> +
>> +static inline uint8_t mipsdsp_add_u8(uint8_t a, uint8_t b, CPUMIPSState *env)
>> +{
>> +    uint16_t temp;
>> +
>> +    temp = (uint16_t)a + (uint16_t)b;
>> +
>> +    if (temp & 0x0100) {
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return temp & 0xFF;
>> +}
>> +
>> +static inline uint16_t mipsdsp_add_u16(uint16_t a, uint16_t b,
>> +                                       CPUMIPSState *env)
>> +{
>> +    uint32_t temp;
>> +
>> +    temp = (uint32_t)a + (uint32_t)b;
>> +
>> +    if (temp & 0x00010000) {
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return temp & 0xFFFF;
>> +}
>> +
>> +static inline uint8_t mipsdsp_sat_add_u8(uint8_t a, uint8_t b,
>> +                                         CPUMIPSState *env)
>> +{
>> +    uint8_t  result;
>> +    uint16_t temp;
>> +
>> +    temp = (uint16_t)a + (uint16_t)b;
>> +    result = temp & 0xFF;
>> +
>> +    if (0x0100 & temp) {
>> +        result = 0xFF;
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return result;
>> +}
>> +
>> +static inline uint16_t mipsdsp_sat_add_u16(uint16_t a, uint16_t b,
>> +                                           CPUMIPSState *env)
>> +{
>> +    uint16_t result;
>> +    uint32_t temp;
>> +
>> +    temp = (uint32_t)a + (uint32_t)b;
>> +    result = temp & 0xFFFF;
>> +
>> +    if (0x00010000 & temp) {
>> +        result = 0xFFFF;
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return result;
>> +}
>> +
>> +static inline int32_t mipsdsp_sat32_acc_q31(int32_t acc, int32_t a,
>> +                                            CPUMIPSState *env)
>> +{
>> +    int64_t temp;
>> +    int32_t temp32, temp31, result;
>> +    int64_t temp_sum;
>> +
>> +#ifndef TARGET_MIPS64
>> +    temp = ((uint64_t)env->active_tc.HI[acc] << 32) |
>> +           (uint64_t)env->active_tc.LO[acc];
>> +#else
>> +    temp = (uint64_t)env->active_tc.LO[acc];
>> +#endif
>> +
>> +    temp_sum = (int64_t)a + temp;
>> +
>> +    temp32 = (temp_sum >> 32) & 0x01;
>> +    temp31 = (temp_sum >> 31) & 0x01;
>> +    result = temp_sum & 0xFFFFFFFF;
>> +
>> +    if (temp32 != temp31) {
>> +        if (temp32 == 0) {
>> +            result = 0x7FFFFFFF;
>> +        } else {
>> +            result = 0x80000000;
>> +        }
>> +        set_DSPControl_overflow_flag(1, 16 + acc, env);
>> +    }
>> +
>> +    return result;
>> +}
>> +
>> +/* a[0] is LO, a[1] is HI. */
>> +static inline void mipsdsp_sat64_acc_add_q63(int64_t *ret,
>> +                                             int32_t ac,
>> +                                             int64_t *a,
>> +                                             CPUMIPSState *env)
>> +{
>> +    int64_t temp[3];
>> +    int64_t acc[3];
>> +    int64_t temp_sum;
>> +
>> +    temp[0] = a[0];
>> +    temp[1] = a[1];
>> +    if (temp[1] >= 0) {
>> +        temp[2] = 0x00;
>> +    } else {
>> +        temp[2] = ~0ull;
>> +    }
>> +
>> +    acc[0] = env->active_tc.LO[ac];
>> +    acc[1] = env->active_tc.HI[ac];
>> +    if (acc[1] >= 0) {
>> +        acc[2] = 0x00;
>> +    } else {
>> +        acc[2] = ~0ull;
>> +    }
>> +
>> +    temp_sum = temp[0] + acc[0];
>> +    if (((uint64_t)temp_sum < (uint64_t)temp[0]) &&
>> +       ((uint64_t)temp_sum < (uint64_t)acc[0])) {
>> +        temp[1] += 1;
>> +        if (temp[1] == 0) {
>> +            temp[2] += 1;
>> +        }
>> +    }
>> +    temp[0] = temp_sum;
>> +
>> +    temp_sum = temp[1] + acc[1];
>> +    if (((uint64_t)temp_sum < (uint64_t)temp[1]) &&
>> +       ((uint64_t)temp_sum < (uint64_t)acc[1])) {
>> +        temp[2] += 1;
>> +    }
>> +
>> +    if (MIPSDSP_OVERFLOW(temp[1], acc[1], temp_sum, INT64_MIN)) {
>> +        if (temp[1] > 0) {
>> +            ret[0] = 0x0;
>> +            ret[1] = 0x7FFFFFFFFFFFFFFFull;
>> +        } else {
>> +            ret[0] = 0x8000000000000000ull;
>> +            ret[1] = ~0ull;
>> +        }
>> +        set_DSPControl_overflow_flag(1, 16 + ac, env);
>> +    } else {
>> +        ret[0] = temp[0];
>> +        ret[1] = temp_sum;
>> +    }
>> +}
>> +
>> +/* a[0] is LO, a[1] is HI. */
>> +static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
>> +                                             int32_t ac,
>> +                                             int64_t *a,
>> +                                             CPUMIPSState *env)
>> +{
>> +    uint32_t temp64, temp63;
>> +    int64_t temp[2];
>> +    int64_t acc[2];
>> +    int64_t temp_sum;
>> +
>> +    temp[0] = a[0];
>> +    temp[1] = a[1];
>> +
>> +    acc[0] = env->active_tc.LO[ac];
>> +    acc[1] = env->active_tc.HI[ac];
>> +
>> +    temp_sum = acc[0] - temp[0];
>> +    if (MIPSDSP_OVERFLOW(acc[0], -temp[0], temp_sum, 0x8000000000000000ull)) {
>> +        acc[1] -= 1;
>> +    }
>> +    acc[0] = temp_sum;
>> +
>> +    temp_sum = acc[1] - temp[1];
>> +    acc[1] = temp_sum;
>> +
>> +    temp64 = acc[1] & 0x01;
>> +    temp63 = (acc[0] >> 63) & 0x01;
>> +
>> +    /* MIPSDSP_OVERFLOW only can check if a 64 bits sub is overflow,
>> +     * there are two 128 bits value subed then check the 63/64 bits are equal
>> +     * or not.*/
>
> If you disagree with what I say, you can send mail, there is no need to
> put it as a comment.
>
> That said MIPSDSP_OVERFLOW doesn't work only on 64-bit values, it can
> work other size, as it is done elsewhere in this patch. The only thing
> it checked is the highest bit of the two arguments and the result.
> Therefore if you pass the highest part of the values, it can work.
>

I did agree with you, just didn't totally get your point.

MIPSDSP_OVERFLOW used to check overflow, but here, 128bit + 128bit,
low 64bit overflow need to be checked, so, in fact, I'm not sure what
should do. Is this code right?

static inline void mipsdsp_sat64_acc_sub_q63(uint64_t *ret,
                                             int32_t ac,
                                             uint64_t *a,
                                             CPUMIPSState *env)
{
    uint32_t temp64;
    uint64_t temp[2];
    uint64_t acc[2];

    temp[0] = a[0];
    temp[1] = a[1];

    acc[0] = env->active_tc.LO[ac];
    acc[1] = env->active_tc.HI[ac];

    temp[1] = acc[1] - temp[1];
    temp[0] = acc[0] - temp[0];

    temp64 = temp[1] & 0x01;

    if (temp64 ^ MIPSDSP_OVERFLOW(acc[0], temp[0], temp[0], (0x01ull << 63))) {
        if (temp64 == 1) {
            ret[0] = (0x01ull << 63);
            ret[1] = ~0ull;
        } else {
            ret[0] = (0x01ull << 63) - 1;
            ret[1] = 0x00;
        }
        set_DSPControl_overflow_flag(1, 16 + ac, env);
    } else {
        ret[0] = temp[0];
        ret[1] = acc[0] > temp[0] ? temp[1] : temp[1] - 1;
    }
}

>> +    if (temp64 != temp63) {
>> +        if (temp64 == 1) {
>> +            ret[0] = 0x8000000000000000ull;
>> +            ret[1] = ~0ull;
>> +        } else {
>> +            ret[0] = 0x0;
>> +            ret[1] = 0x7FFFFFFFFFFFFFFFull;
>> +        }
>> +        set_DSPControl_overflow_flag(1, 16 + ac, env);
>> +    } else {
>> +        ret[0] = acc[0];
>> +        ret[1] = acc[1];
>> +    }
>> +}
>> +
>> +static inline int32_t mipsdsp_mul_i16_i16(int16_t a, int16_t b,
>> +                                          CPUMIPSState *env)
>> +{
>> +    int32_t temp;
>> +
>> +    temp = (int32_t)a * (int32_t)b;
>> +
>> +    if ((temp > 0x7FFF) || (temp < 0xFFFF8000)) {
>> +        set_DSPControl_overflow_flag(1, 21, env);
>> +    }
>> +    temp &= 0x0000FFFF;
>> +
>> +    return temp;
>> +}
>> +
>> +static inline int32_t mipsdsp_mul_u16_u16(int32_t a, int32_t b)
>> +{
>> +    return a * b;
>> +}
>> +
>> +static inline int32_t mipsdsp_mul_i32_i32(int32_t a, int32_t b)
>> +{
>> +    return a * b;
>> +}
>> +
>> +static inline int32_t mipsdsp_sat16_mul_i16_i16(int16_t a, int16_t b,
>> +                                                CPUMIPSState *env)
>> +{
>> +    int32_t temp;
>> +
>> +    temp = (int32_t)a * (int32_t)b;
>> +
>> +    if (temp > 0x7FFF) {
>> +        temp = 0x00007FFF;
>> +        set_DSPControl_overflow_flag(1, 21, env);
>> +    } else if (temp < 0x00007FFF) {
>> +        temp = 0xFFFF8000;
>> +        set_DSPControl_overflow_flag(1, 21, env);
>> +    }
>> +    temp &= 0x0000FFFF;
>> +
>> +    return temp;
>> +}
>> +
>> +static inline int32_t mipsdsp_mul_q15_q15_overflowflag21(uint16_t a, uint16_t b,
>> +                                                         CPUMIPSState *env)
>> +{
>> +    int32_t temp;
>> +
>> +    if ((a == 0x8000) && (b == 0x8000)) {
>> +        temp = 0x7FFFFFFF;
>> +        set_DSPControl_overflow_flag(1, 21, env);
>> +    } else {
>> +        temp = ((int32_t)(int16_t)a * (int32_t)(int16_t)b) << 1;
>> +    }
>> +
>> +    return temp;
>> +}
>> +
>> +/* right shift */
>> +static inline uint8_t mipsdsp_rshift_u8(uint8_t a, target_ulong mov)
>> +{
>> +    return a >> mov;
>> +}
>> +
>> +static inline uint16_t mipsdsp_rshift_u16(uint16_t a, target_ulong mov)
>> +{
>> +    return a >> mov;
>> +}
>> +
>> +static inline int8_t mipsdsp_rashift8(int8_t a, target_ulong mov)
>> +{
>> +    return a >> mov;
>> +}
>> +
>> +static inline int16_t mipsdsp_rashift16(int16_t a, target_ulong mov)
>> +{
>> +    return a >> mov;
>> +}
>> +
>> +static inline int32_t mipsdsp_rashift32(int32_t a, target_ulong mov)
>> +{
>> +    return a >> mov;
>> +}
>> +
>> +static inline int16_t mipsdsp_rshift1_add_q16(int16_t a, int16_t b)
>> +{
>> +    int32_t temp;
>> +
>> +    temp = (int32_t)a + (int32_t)b;
>> +
>> +    return (temp >> 1) & 0xFFFF;
>> +}
>> +
>> +/* round right shift */
>> +static inline int16_t mipsdsp_rrshift1_add_q16(int16_t a, int16_t b)
>> +{
>> +    int32_t temp;
>> +
>> +    temp = (int32_t)a + (int32_t)b;
>> +    temp += 1;
>> +
>> +    return (temp >> 1) & 0xFFFF;
>> +}
>> +
>> +static inline int32_t mipsdsp_rshift1_add_q32(int32_t a, int32_t b)
>> +{
>> +    int64_t temp;
>> +
>> +    temp = (int64_t)a + (int64_t)b;
>> +
>> +    return (temp >> 1) & 0xFFFFFFFF;
>> +}
>> +
>> +static inline int32_t mipsdsp_rrshift1_add_q32(int32_t a, int32_t b)
>> +{
>> +    int64_t temp;
>> +
>> +    temp = (int64_t)a + (int64_t)b;
>> +    temp += 1;
>> +
>> +    return (temp >> 1) & 0xFFFFFFFF;
>> +}
>> +
>> +static inline uint8_t mipsdsp_rshift1_add_u8(uint8_t a, uint8_t b)
>> +{
>> +    uint16_t temp;
>> +
>> +    temp = (uint16_t)a + (uint16_t)b;
>> +
>> +    return (temp >> 1) & 0x00FF;
>> +}
>> +
>> +static inline uint8_t mipsdsp_rrshift1_add_u8(uint8_t a, uint8_t b)
>> +{
>> +    uint16_t temp;
>> +
>> +    temp = (uint16_t)a + (uint16_t)b + 1;
>> +
>> +    return (temp >> 1) & 0x00FF;
>> +}
>> +
>> +static inline uint8_t mipsdsp_rshift1_sub_u8(uint8_t a, uint8_t b)
>> +{
>> +    uint16_t temp;
>> +
>> +    temp = (uint16_t)a - (uint16_t)b;
>> +
>> +    return (temp >> 1) & 0x00FF;
>> +}
>> +
>> +static inline uint8_t mipsdsp_rrshift1_sub_u8(uint8_t a, uint8_t b)
>> +{
>> +    uint16_t temp;
>> +
>> +    temp = (uint16_t)a - (uint16_t)b + 1;
>> +
>> +    return (temp >> 1) & 0x00FF;
>> +}
>> +
>> +static inline int64_t mipsdsp_rashift_short_acc(int32_t ac,
>> +                                                int32_t shift,
>> +                                                CPUMIPSState *env)
>> +{
>> +    int32_t sign, temp31;
>> +    int64_t temp, acc;
>> +
>> +    sign = (env->active_tc.HI[ac] >> 31) & 0x01;
>> +    acc = ((int64_t)env->active_tc.HI[ac] << 32) |
>> +          ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF);
>> +    if (shift == 0) {
>> +        temp = acc;
>> +    } else {
>> +        if (sign == 0) {
>> +            temp = (((int64_t)0x01 << (32 - shift + 1)) - 1) & (acc >> shift);
>> +        } else {
>> +            temp = ((((int64_t)0x01 << (shift + 1)) - 1) << (32 - shift)) |
>> +                   (acc >> shift);
>> +        }
>> +    }
>> +
>> +    temp31 = (temp >> 31) & 0x01;
>> +    if (sign != temp31) {
>> +        set_DSPControl_overflow_flag(1, 23, env);
>> +    }
>> +
>> +    return temp;
>> +}
>> +
>> +/*  128 bits long. p[0] is LO, p[1] is HI. */
>> +static inline void mipsdsp_rndrashift_short_acc(int64_t *p,
>> +                                                int32_t ac,
>> +                                                int32_t shift,
>> +                                                CPUMIPSState *env)
>> +{
>> +    int64_t acc;
>> +
>> +    acc = ((int64_t)env->active_tc.HI[ac] << 32) |
>> +          ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF);
>> +    if (shift == 0) {
>> +        p[0] = acc << 1;
>> +        p[1] = (acc >> 63) & 0x01;
>> +    } else {
>> +        p[0] = acc >> (shift - 1);
>> +        p[1] = 0;
>> +    }
>> +}
>> +
>> +/* 128 bits long. p[0] is LO, p[1] is HI */
>> +static inline void mipsdsp_rashift_acc(uint64_t *p,
>> +                                       uint32_t ac,
>> +                                       uint32_t shift,
>> +                                       CPUMIPSState *env)
>> +{
>> +    uint64_t tempB, tempA;
>> +
>> +    tempB = env->active_tc.HI[ac];
>> +    tempA = env->active_tc.LO[ac];
>> +    shift = shift & 0x1F;
>> +
>> +    if (shift == 0) {
>> +        p[1] = tempB;
>> +        p[0] = tempA;
>> +    } else {
>> +        p[0] = (tempB << (64 - shift)) | (tempA >> shift);
>> +        p[1] = (int64_t)tempB >> shift;
>> +    }
>> +}
>> +
>> +/* 128 bits long. p[0] is LO, p[1] is HI , p[2] is sign of HI.*/
>> +static inline void mipsdsp_rndrashift_acc(uint64_t *p,
>> +                                          uint32_t ac,
>> +                                          uint32_t shift,
>> +                                          CPUMIPSState *env)
>> +{
>> +    int64_t tempB, tempA;
>> +
>> +    tempB = env->active_tc.HI[ac];
>> +    tempA = env->active_tc.LO[ac];
>> +    shift = shift & 0x3F;
>> +
>> +    if (shift == 0) {
>> +        p[2] = tempB >> 63;
>> +        p[1] = (tempB << 1) | (tempA >> 63);
>> +        p[0] = tempA << 1;
>> +    } else {
>> +        p[0] = (tempB << (65 - shift)) | (tempA >> (shift - 1));
>> +        p[1] = (int64_t)tempB >> (shift - 1);
>> +        if (tempB >= 0) {
>> +            p[2] = 0x0;
>> +        } else {
>> +            p[2] = ~0ull;
>> +        }
>> +    }
>> +}
>> +
>> +static inline int32_t mipsdsp_mul_q15_q15(int32_t ac, uint16_t a, uint16_t b,
>> +                                          CPUMIPSState *env)
>> +{
>> +    int32_t temp;
>> +
>> +    if ((a == 0x8000) && (b == 0x8000)) {
>> +        temp = 0x7FFFFFFF;
>> +        set_DSPControl_overflow_flag(1, 16 + ac, env);
>> +    } else {
>> +        temp = ((uint32_t)a * (uint32_t)b) << 1;
>> +    }
>> +
>> +    return temp;
>> +}
>> +
>> +static inline int64_t mipsdsp_mul_q31_q31(int32_t ac, uint32_t a, uint32_t b,
>> +                                          CPUMIPSState *env)
>> +{
>> +    uint64_t temp;
>> +
>> +    if ((a == 0x80000000) && (b == 0x80000000)) {
>> +        temp = 0x7FFFFFFFFFFFFFFFull;
>> +        set_DSPControl_overflow_flag(1, 16 + ac, env);
>> +    } else {
>> +        temp = ((uint64_t)a * (uint64_t)b) << 1;
>> +    }
>> +
>> +    return temp;
>> +}
>> +
>> +static inline uint16_t mipsdsp_mul_u8_u8(uint8_t a, uint8_t b)
>> +{
>> +    return (uint16_t)a * (uint16_t)b;
>> +}
>> +
>> +static inline uint16_t mipsdsp_mul_u8_u16(uint8_t a, uint16_t b,
>> +                                          CPUMIPSState *env)
>> +{
>> +    uint32_t tempI;
>> +
>> +    tempI = (uint32_t)a * (uint32_t)b;
>> +    if (tempI > 0x0000FFFF) {
>> +        tempI = 0x0000FFFF;
>> +        set_DSPControl_overflow_flag(1, 21, env);
>> +    }
>> +
>> +    return tempI & 0x0000FFFF;
>> +}
>> +
>> +static inline uint64_t mipsdsp_mul_u32_u32(uint32_t a, uint32_t b)
>> +{
>> +    return (uint64_t)a * (uint64_t)b;
>> +}
>> +
>> +static inline int16_t mipsdsp_rndq15_mul_q15_q15(uint16_t a, uint16_t b,
>> +                                                 CPUMIPSState *env)
>> +{
>> +    uint32_t temp;
>> +
>> +    if ((a == 0x8000) && (b == 0x8000)) {
>> +        temp = 0x7FFF0000;
>> +        set_DSPControl_overflow_flag(1, 21, env);
>> +    } else {
>> +        temp = (a * b) << 1;
>> +        temp = temp + 0x00008000;
>> +    }
>> +
>> +    return (temp & 0xFFFF0000) >> 16;
>> +}
>> +
>> +static inline int32_t mipsdsp_sat16_mul_q15_q15(uint16_t a, uint16_t b,
>> +                                                CPUMIPSState *env)
>> +{
>> +    int32_t temp;
>> +
>> +    if ((a == 0x8000) && (b == 0x8000)) {
>> +        temp = 0x7FFF0000;
>> +        set_DSPControl_overflow_flag(1, 21, env);
>> +    } else {
>> +        temp = ((uint32_t)a * (uint32_t)b);
>> +        temp = temp << 1;
>> +    }
>> +
>> +    return (temp >> 16) & 0x0000FFFF;
>> +}
>> +
>> +static inline uint16_t mipsdsp_trunc16_sat16_round(int32_t a,
>> +                                                   CPUMIPSState *env)
>> +{
>> +    int64_t temp;
>> +
>> +    temp = (int32_t)a + 0x00008000;
>> +
>> +    if (a > 0x7fff8000) {
>> +        temp = 0x7FFFFFFF;
>> +        set_DSPControl_overflow_flag(1, 22, env);
>> +    }
>> +
>> +    return (temp >> 16) & 0xFFFF;
>> +}
>> +
>> +static inline uint8_t mipsdsp_sat8_reduce_precision(uint16_t a,
>> +                                                    CPUMIPSState *env)
>> +{
>> +    uint16_t mag;
>> +    uint32_t sign;
>> +
>> +    sign = (a >> 15) & 0x01;
>> +    mag = a & 0x7FFF;
>> +
>> +    if (sign == 0) {
>> +        if (mag > 0x7F80) {
>> +            set_DSPControl_overflow_flag(1, 22, env);
>> +            return 0xFF;
>> +        } else {
>> +            return (mag >> 7) & 0xFFFF;
>> +        }
>> +    } else {
>> +        set_DSPControl_overflow_flag(1, 22, env);
>> +        return 0x00;
>> +    }
>> +}
>> +
>> +static inline uint8_t mipsdsp_lshift8(uint8_t a, uint8_t s, CPUMIPSState *env)
>> +{
>> +    uint8_t sign;
>> +    uint8_t discard;
>> +
>> +    if (s == 0) {
>> +        return a;
>> +    } else {
>> +        sign = (a >> 7) & 0x01;
>> +        if (sign != 0) {
>> +            discard = (((0x01 << (8 - s)) - 1) << s) |
>> +                      ((a >> (6 - (s - 1))) & ((0x01 << s) - 1));
>> +        } else {
>> +            discard = a >> (6 - (s - 1));
>> +        }
>> +
>> +        if (discard != 0x00) {
>> +            set_DSPControl_overflow_flag(1, 22, env);
>> +        }
>> +        return a << s;
>> +    }
>> +}
>> +
>> +static inline uint16_t mipsdsp_lshift16(uint16_t a, uint8_t s,
>> +                                        CPUMIPSState *env)
>> +{
>> +    uint8_t  sign;
>> +    uint16_t discard;
>> +
>> +    if (s == 0) {
>> +        return a;
>> +    } else {
>> +        sign = (a >> 15) & 0x01;
>> +        if (sign != 0) {
>> +            discard = (((0x01 << (16 - s)) - 1) << s) |
>> +                      ((a >> (14 - (s - 1))) & ((0x01 << s) - 1));
>> +        } else {
>> +            discard = a >> (14 - (s - 1));
>> +        }
>> +
>> +        if ((discard != 0x0000) && (discard != 0xFFFF)) {
>> +            set_DSPControl_overflow_flag(1, 22, env);
>> +        }
>> +        return a << s;
>> +    }
>> +}
>> +
>> +
>> +static inline uint32_t mipsdsp_lshift32(uint32_t a, uint8_t s,
>> +                                        CPUMIPSState *env)
>> +{
>> +    uint32_t discard;
>> +
>> +    if (s == 0) {
>> +        return a;
>> +    } else {
>> +        discard = (int32_t)a >> (31 - (s - 1));
>> +
>> +        if ((discard != 0x00000000) && (discard != 0xFFFFFFFF)) {
>> +            set_DSPControl_overflow_flag(1, 22, env);
>> +        }
>> +        return a << s;
>> +    }
>> +}
>> +
>> +static inline uint16_t mipsdsp_sat16_lshift(uint16_t a, uint8_t s,
>> +                                            CPUMIPSState *env)
>> +{
>> +    uint8_t  sign;
>> +    uint16_t discard;
>> +
>> +    if (s == 0) {
>> +        return a;
>> +    } else {
>> +        sign = (a >> 15) & 0x01;
>> +        if (sign != 0) {
>> +            discard = (((0x01 << (16 - s)) - 1) << s) |
>> +                      ((a >> (14 - (s - 1))) & ((0x01 << s) - 1));
>> +        } else {
>> +            discard = a >> (14 - (s - 1));
>> +        }
>> +
>> +        if ((discard != 0x0000) && (discard != 0xFFFF)) {
>> +            set_DSPControl_overflow_flag(1, 22, env);
>> +            return (sign == 0) ? 0x7FFF : 0x8000;
>> +        } else {
>> +            return a << s;
>> +        }
>> +    }
>> +}
>> +
>> +static inline uint32_t mipsdsp_sat32_lshift(uint32_t a, uint8_t s,
>> +                                            CPUMIPSState *env)
>> +{
>> +    uint8_t  sign;
>> +    uint32_t discard;
>> +
>> +    if (s == 0) {
>> +        return a;
>> +    } else {
>> +        sign = (a >> 31) & 0x01;
>> +        if (sign != 0) {
>> +            discard = (((0x01 << (32 - s)) - 1) << s) |
>> +                      ((a >> (30 - (s - 1))) & ((0x01 << s) - 1));
>> +        } else {
>> +            discard = a >> (30 - (s - 1));
>> +        }
>> +
>> +        if ((discard != 0x00000000) && (discard != 0xFFFFFFFF)) {
>> +            set_DSPControl_overflow_flag(1, 22, env);
>> +            return (sign == 0) ? 0x7FFFFFFF : 0x80000000;
>> +        } else {
>> +            return a << s;
>> +        }
>> +    }
>> +}
>> +
>> +static inline uint8_t mipsdsp_rnd8_rashift(uint8_t a, uint8_t s)
>> +{
>> +    uint32_t temp;
>> +
>> +    if (s == 0) {
>> +        temp = (uint32_t)a << 1;
>> +    } else {
>> +        temp = (int32_t)(int8_t)a >> (s - 1);
>> +    }
>> +
>> +    return (temp + 1) >> 1;
>> +}
>> +
>> +static inline uint16_t mipsdsp_rnd16_rashift(uint16_t a, uint8_t s)
>> +{
>> +    uint32_t temp;
>> +
>> +    if (s == 0) {
>> +        temp = (uint32_t)a << 1;
>> +    } else {
>> +        temp = (int32_t)(int16_t)a >> (s - 1);
>> +    }
>> +
>> +    return (temp + 1) >> 1;
>> +}
>> +
>> +static inline uint32_t mipsdsp_rnd32_rashift(uint32_t a, uint8_t s)
>> +{
>> +    int64_t temp;
>> +
>> +    if (s == 0) {
>> +        temp = a << 1;
>> +    } else {
>> +        temp = (int64_t)(int32_t)a >> (s - 1);
>> +    }
>> +    temp += 1;
>> +
>> +    return (temp >> 1) & 0x00000000FFFFFFFFull;
>> +}
>> +
>> +static inline uint16_t mipsdsp_sub_i16(int16_t a, int16_t b, CPUMIPSState *env)
>> +{
>> +    int16_t  temp;
>> +
>> +    temp = a - b;
>> +    if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) {
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return temp;
>> +}
>> +
>> +static inline uint16_t mipsdsp_sat16_sub(int16_t a, int16_t b,
>> +                                         CPUMIPSState *env)
>> +{
>> +    int16_t  temp;
>> +
>> +    temp = a - b;
>> +    if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) {
>> +        if (a > 0) {
>> +            temp = 0x7FFF;
>> +        } else {
>> +            temp = 0x8000;
>> +        }
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return temp;
>> +}
>> +
>> +static inline uint32_t mipsdsp_sat32_sub(int32_t a, int32_t b,
>> +                                         CPUMIPSState *env)
>> +{
>> +    int32_t  temp;
>> +
>> +    temp = a - b;
>> +    if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) {
>> +        if (a > 0) {
>> +            temp = 0x7FFFFFFF;
>> +        } else {
>> +            temp = 0x80000000;
>> +        }
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return temp & 0x00000000FFFFFFFFull;
>> +}
>> +
>> +static inline uint16_t mipsdsp_rshift1_sub_q16(int16_t a, int16_t b)
>> +{
>> +    int32_t  temp;
>> +
>> +    temp = (int32_t)a - (int32_t)b;
>> +
>> +    return (temp >> 1) & 0x0000FFFF;
>> +}
>> +
>> +static inline uint16_t mipsdsp_rrshift1_sub_q16(int16_t a, int16_t b)
>> +{
>> +    int32_t  temp;
>> +
>> +    temp = (int32_t)a - (int32_t)b;
>> +    temp += 1;
>> +
>> +    return (temp >> 1) & 0x0000FFFF;
>> +}
>> +
>> +static inline uint32_t mipsdsp_rshift1_sub_q32(int32_t a, int32_t b)
>> +{
>> +    int64_t  temp;
>> +
>> +    temp = (int64_t)a - (int64_t)b;
>> +
>> +    return (temp >> 1) & 0x00000000FFFFFFFFull;
>> +}
>> +
>> +static inline uint32_t mipsdsp_rrshift1_sub_q32(int32_t a, int32_t b)
>> +{
>> +    int64_t  temp;
>> +
>> +    temp = (int64_t)a - (int64_t)b;
>> +    temp += 1;
>> +
>> +    return (temp >> 1) & 0x00000000FFFFFFFFull;
>> +}
>> +
>> +static inline uint16_t mipsdsp_sub_u16_u16(uint16_t a, uint16_t b,
>> +                                           CPUMIPSState *env)
>> +{
>> +    uint8_t  temp16;
>> +    uint32_t temp;
>> +
>> +    temp = (uint32_t)a - (uint32_t)b;
>> +    temp16 = (temp >> 16) & 0x01;
>> +    if (temp16 == 1) {
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +    return temp & 0x0000FFFF;
>> +}
>> +
>> +static inline uint16_t mipsdsp_satu16_sub_u16_u16(uint16_t a, uint16_t b,
>> +                                                  CPUMIPSState *env)
>> +{
>> +    uint8_t  temp16;
>> +    uint32_t temp;
>> +
>> +    temp   = (uint32_t)a - (uint32_t)b;
>> +    temp16 = (temp >> 16) & 0x01;
>> +
>> +    if (temp16 == 1) {
>> +        temp = 0x0000;
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return temp & 0x0000FFFF;
>> +}
>> +
>> +static inline uint8_t mipsdsp_sub_u8(uint8_t a, uint8_t b, CPUMIPSState *env)
>> +{
>> +    uint8_t  temp8;
>> +    uint16_t temp;
>> +
>> +    temp = (uint16_t)a - (uint16_t)b;
>> +    temp8 = (temp >> 8) & 0x01;
>> +    if (temp8 == 1) {
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return temp & 0x00FF;
>> +}
>> +
>> +static inline uint8_t mipsdsp_satu8_sub(uint8_t a, uint8_t b, CPUMIPSState *env)
>> +{
>> +    uint8_t  temp8;
>> +    uint16_t temp;
>> +
>> +    temp = (uint16_t)a - (uint16_t)b;
>> +    temp8 = (temp >> 8) & 0x01;
>> +    if (temp8 == 1) {
>> +        temp = 0x00;
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return temp & 0x00FF;
>> +}
>> +
>> +static inline uint32_t mipsdsp_sub32(int32_t a, int32_t b, CPUMIPSState *env)
>> +{
>> +    int32_t temp;
>> +
>> +    temp = a - b;
>> +    if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) {
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return temp;
>> +}
>> +
>> +static inline int32_t mipsdsp_add_i32(int32_t a, int32_t b, CPUMIPSState *env)
>> +{
>> +    int32_t temp;
>> +
>> +    temp = a + b;
>> +
>> +    if (MIPSDSP_OVERFLOW(a, b, temp, 0x80000000)) {
>> +        set_DSPControl_overflow_flag(1, 20, env);
>> +    }
>> +
>> +    return temp;
>> +}
>> +
>> +static inline int32_t mipsdsp_cmp_eq(uint32_t a, uint32_t b)
>> +{
>> +    return a == b;
>> +}
>> +
>> +static inline int32_t mipsdsp_cmp_le(uint32_t a, uint32_t b)
>> +{
>> +    return a <= b;
>> +}
>> +
>> +static inline int32_t mipsdsp_cmp_lt(uint32_t a, uint32_t b)
>> +{
>> +    return a < b;
>> +}
>> +/*** MIPS DSP internal functions end ***/
>> --
>> 1.7.10.2 (Apple Git-33)
>>
>>
>
> --
> Aurelien Jarno                          GPG: 1024D/F1BCDB73
> aurelien@aurel32.net                 http://www.aurel32.net

Regards,
Jia.
Aurelien Jarno Oct. 17, 2012, 3:15 p.m. UTC | #3
On Wed, Oct 17, 2012 at 11:39:00AM +0800, Jia Liu wrote:
> Hi Aurelien,
>
> On Wed, Oct 17, 2012 at 7:20 AM, Aurelien Jarno <aurelien@aurel32.net> wrote:
> > On Tue, Oct 16, 2012 at 12:39:05AM +0800, Jia Liu wrote:
> >> +/* a[0] is LO, a[1] is HI. */
> >> +static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
> >> +                                             int32_t ac,
> >> +                                             int64_t *a,
> >> +                                             CPUMIPSState *env)
> >> +{
> >> +    uint32_t temp64, temp63;
> >> +    int64_t temp[2];
> >> +    int64_t acc[2];
> >> +    int64_t temp_sum;
> >> +
> >> +    temp[0] = a[0];
> >> +    temp[1] = a[1];
> >> +
> >> +    acc[0] = env->active_tc.LO[ac];
> >> +    acc[1] = env->active_tc.HI[ac];
> >> +
> >> +    temp_sum = acc[0] - temp[0];
> >> +    if (MIPSDSP_OVERFLOW(acc[0], -temp[0], temp_sum, 0x8000000000000000ull)) {
> >> +        acc[1] -= 1;
> >> +    }
> >> +    acc[0] = temp_sum;
> >> +
> >> +    temp_sum = acc[1] - temp[1];
> >> +    acc[1] = temp_sum;
> >> +
> >> +    temp64 = acc[1] & 0x01;
> >> +    temp63 = (acc[0] >> 63) & 0x01;
> >> +
> >> +    /* MIPSDSP_OVERFLOW only can check if a 64 bits sub is overflow,
> >> +     * there are two 128 bits value subed then check the 63/64 bits are equal
> >> +     * or not.*/
> >
> > If you disagree with what I say, you can send mail, there is no need to
> > put it as a comment.
> >
> > That said MIPSDSP_OVERFLOW doesn't work only on 64-bit values, it can
> > work other size, as it is done elsewhere in this patch. The only thing
> > it checked is the highest bit of the two arguments and the result.
> > Therefore if you pass the highest part of the values, it can work.
> >
>
> I did agree with you, just didn't totally get your point.
>
> MIPSDSP_OVERFLOW used to check overflow, but here, 128bit + 128bit,
> low 64bit overflow need to be checked, so, in fact, I'm not sure what
> should do. Is this code right?
>
> static inline void mipsdsp_sat64_acc_sub_q63(uint64_t *ret,
>                                              int32_t ac,
>                                              uint64_t *a,
>                                              CPUMIPSState *env)
> {
>     uint32_t temp64;
>     uint64_t temp[2];
>     uint64_t acc[2];
>
>     temp[0] = a[0];
>     temp[1] = a[1];
>
>     acc[0] = env->active_tc.LO[ac];
>     acc[1] = env->active_tc.HI[ac];
>
>     temp[1] = acc[1] - temp[1];
>     temp[0] = acc[0] - temp[0];
>
>     temp64 = temp[1] & 0x01;
>
>     if (temp64 ^ MIPSDSP_OVERFLOW(acc[0], temp[0], temp[0], (0x01ull << 63))) {
>         if (temp64 == 1) {
>             ret[0] = (0x01ull << 63);
>             ret[1] = ~0ull;
>         } else {
>             ret[0] = (0x01ull << 63) - 1;
>             ret[1] = 0x00;
>         }
>         set_DSPControl_overflow_flag(1, 16 + ac, env);
>     } else {
>         ret[0] = temp[0];
>         ret[1] = acc[0] > temp[0] ? temp[1] : temp[1] - 1;
>     }
> }
>

I don't think xoring temp64 with MIPSDSP_OVERFLOW is correct. What about
about something like that (untested):

| static inline void mipsdsp_sat64_acc_sub_q63(uint64_t *ret,
|                                              int32_t ac,
|                                              uint64_t *a,
|                                              CPUMIPSState *env)
| {
|     ret[0] = env->active_tc.LO[ac] - a[0];
|     ret[1] = env->active_tc.HI[ac] - a[1];
|
|     if (MIPSDSP_OVERFLOW(env->active_tc.LO[ac], -a[0], ret[0], 0x8000000000000000ull)) {
|         if ((ret[1] - 1) & 1) {
|             ret[0] = (0x01ull << 63);
|             ret[1] = ~0ull;
|         } else {
|             ret[0] = (0x01ull << 63) - 1;
|             ret[1] = 0x00;
|         }
|         set_DSPControl_overflow_flag(1, 16 + ac, env);
|     }
| }
|

The same applies for the add function, but also to some other places in
the code.

Also note that you might want to have two version of MIPSDSP_OVERFLOW(),
one for add (like the current one), and one for sub (without the ^ -1),
so that you don't have to pass the negative value of the second
argument.

--
Aurelien Jarno                          GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net
Jia Liu Oct. 18, 2012, 1:53 a.m. UTC | #4
Hi Aurelien,

On Wed, Oct 17, 2012 at 11:15 PM, Aurelien Jarno <aurelien@aurel32.net> wrote:
> On Wed, Oct 17, 2012 at 11:39:00AM +0800, Jia Liu wrote:
>> Hi Aurelien,
>>
>> On Wed, Oct 17, 2012 at 7:20 AM, Aurelien Jarno <aurelien@aurel32.net> wrote:
>> > On Tue, Oct 16, 2012 at 12:39:05AM +0800, Jia Liu wrote:
>> >> +/* a[0] is LO, a[1] is HI. */
>> >> +static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
>> >> +                                             int32_t ac,
>> >> +                                             int64_t *a,
>> >> +                                             CPUMIPSState *env)
>> >> +{
>> >> +    uint32_t temp64, temp63;
>> >> +    int64_t temp[2];
>> >> +    int64_t acc[2];
>> >> +    int64_t temp_sum;
>> >> +
>> >> +    temp[0] = a[0];
>> >> +    temp[1] = a[1];
>> >> +
>> >> +    acc[0] = env->active_tc.LO[ac];
>> >> +    acc[1] = env->active_tc.HI[ac];
>> >> +
>> >> +    temp_sum = acc[0] - temp[0];
>> >> +    if (MIPSDSP_OVERFLOW(acc[0], -temp[0], temp_sum, 0x8000000000000000ull)) {
>> >> +        acc[1] -= 1;
>> >> +    }
>> >> +    acc[0] = temp_sum;
>> >> +
>> >> +    temp_sum = acc[1] - temp[1];
>> >> +    acc[1] = temp_sum;
>> >> +
>> >> +    temp64 = acc[1] & 0x01;
>> >> +    temp63 = (acc[0] >> 63) & 0x01;
>> >> +
>> >> +    /* MIPSDSP_OVERFLOW only can check if a 64 bits sub is overflow,
>> >> +     * there are two 128 bits value subed then check the 63/64 bits are equal
>> >> +     * or not.*/
>> >
>> > If you disagree with what I say, you can send mail, there is no need to
>> > put it as a comment.
>> >
>> > That said MIPSDSP_OVERFLOW doesn't work only on 64-bit values, it can
>> > work other size, as it is done elsewhere in this patch. The only thing
>> > it checked is the highest bit of the two arguments and the result.
>> > Therefore if you pass the highest part of the values, it can work.
>> >
>>
>> I did agree with you, just didn't totally get your point.
>>
>> MIPSDSP_OVERFLOW used to check overflow, but here, 128bit + 128bit,
>> low 64bit overflow need to be checked, so, in fact, I'm not sure what
>> should do. Is this code right?
>>
>> static inline void mipsdsp_sat64_acc_sub_q63(uint64_t *ret,
>>                                              int32_t ac,
>>                                              uint64_t *a,
>>                                              CPUMIPSState *env)
>> {
>>     uint32_t temp64;
>>     uint64_t temp[2];
>>     uint64_t acc[2];
>>
>>     temp[0] = a[0];
>>     temp[1] = a[1];
>>
>>     acc[0] = env->active_tc.LO[ac];
>>     acc[1] = env->active_tc.HI[ac];
>>
>>     temp[1] = acc[1] - temp[1];
>>     temp[0] = acc[0] - temp[0];
>>
>>     temp64 = temp[1] & 0x01;
>>
>>     if (temp64 ^ MIPSDSP_OVERFLOW(acc[0], temp[0], temp[0], (0x01ull << 63))) {
>>         if (temp64 == 1) {
>>             ret[0] = (0x01ull << 63);
>>             ret[1] = ~0ull;
>>         } else {
>>             ret[0] = (0x01ull << 63) - 1;
>>             ret[1] = 0x00;
>>         }
>>         set_DSPControl_overflow_flag(1, 16 + ac, env);
>>     } else {
>>         ret[0] = temp[0];
>>         ret[1] = acc[0] > temp[0] ? temp[1] : temp[1] - 1;
>>     }
>> }
>>
>
> I don't think xoring temp64 with MIPSDSP_OVERFLOW is correct. What about
> about something like that (untested):
>
> | static inline void mipsdsp_sat64_acc_sub_q63(uint64_t *ret,
> |                                              int32_t ac,
> |                                              uint64_t *a,
> |                                              CPUMIPSState *env)
> | {
> |     ret[0] = env->active_tc.LO[ac] - a[0];
> |     ret[1] = env->active_tc.HI[ac] - a[1];
> |

In the MIPS-DSP manual, the function is

function sat64AccumulateSubQ63( acc1..0, a127..0 )
    temp128..0 ← HI[acc]63 || HI[acc]63..0 || LO[acc]63..0
    temp128..0 ← temp - a127..0 if ( temp64 ≠ temp63 ) then
    if ( temp64 = 1 ) then
        temp127..0 ← 0xFFFFFFFFFFFFFFFF8000000000000000
    else
        temp127..0 ← 0x00000000000000007FFFFFFFFFFFFFFF
    endif
    DSPControlouflag:16+acc ← 1 endif
    return temp127..0
endfunction sat64AccumulateSubQ63

> |     if (MIPSDSP_OVERFLOW(env->active_tc.LO[ac], -a[0], ret[0], 0x8000000000000000ull)) {

The bit 64 will influence the overflow of bits 0-63.
That is, if bit 64 is 1, and bits 0-63 overflowed, it won't be caught.
So, if we use this code, it won't be handled.


> |         if ((ret[1] - 1) & 1) {
> |             ret[0] = (0x01ull << 63);
> |             ret[1] = ~0ull;
> |         } else {
> |             ret[0] = (0x01ull << 63) - 1;
> |             ret[1] = 0x00;
> |         }
> |         set_DSPControl_overflow_flag(1, 16 + ac, env);
> |     }
> | }
> |
>
> The same applies for the add function, but also to some other places in
> the code.
>
> Also note that you might want to have two version of MIPSDSP_OVERFLOW(),
> one for add (like the current one), and one for sub (without the ^ -1),
> so that you don't have to pass the negative value of the second
> argument.
>

I think it is not necessary to define a new macro very much, what do
you think about this code? Just little changed.

/* a[0] is LO, a[1] is HI. */
static inline void mipsdsp_sat64_acc_add_q63(int64_t *ret,
                                             int32_t ac,
                                             int64_t *a,
                                             CPUMIPSState *env)
{
    uint32_t temp64;

    ret[0] = env->active_tc.LO[ac] + a[0];
    ret[1] = env->active_tc.HI[ac] + a[1];

    temp64 = ret[1] & 0x01;

    if (temp64 ^ MIPSDSP_OVERFLOW(env->active_tc.LO[ac], a[0], ret[0],
                                  (0x01ull << 63))) {
        if (temp64 == 1) {
            ret[0] = (0x01ull << 63);
            ret[1] = ~0ull;
        } else {
            ret[0] = (0x01ull << 63) - 1;
            ret[1] = 0x00;
        }
        set_DSPControl_overflow_flag(1, 16 + ac, env);
    } else {
        ret[1] = (((uint64_t)env->active_tc.LO[ac] > (uint64_t)ret[0]) &&
                  ((uint64_t)a[0] > (uint64_t)ret[0])) ? ret[1] : ret[1] + 1;
    }
}

static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
                                             int32_t ac,
                                             int64_t *a,
                                             CPUMIPSState *env)
{
    uint32_t temp64;

    ret[0] = env->active_tc.LO[ac] - a[0];
    ret[1] = env->active_tc.HI[ac] - a[1];

    temp64 = ret[1] & 0x01;

    if (temp64 ^ MIPSDSP_OVERFLOW(env->active_tc.LO[ac], -a[0], ret[0],
                                  (0x01ull << 63))) {
        if (temp64 == 1) {
            ret[0] = (0x01ull << 63);
            ret[1] = ~0ull;
        } else {
            ret[0] = (0x01ull << 63) - 1;
            ret[1] = 0x00;
        }
        set_DSPControl_overflow_flag(1, 16 + ac, env);
    } else {
        ret[1] = (uint64_t)env->active_tc.LO[ac] > (uint64_t)ret[0] ?
            ret[1] : ret[1] - 1;
    }
}

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

Regards,
Jia.
Aurelien Jarno Oct. 18, 2012, 6:05 a.m. UTC | #5
On Thu, Oct 18, 2012 at 09:53:20AM +0800, Jia Liu wrote:
> Hi Aurelien,
> 
> On Wed, Oct 17, 2012 at 11:15 PM, Aurelien Jarno <aurelien@aurel32.net> wrote:
> > On Wed, Oct 17, 2012 at 11:39:00AM +0800, Jia Liu wrote:
> >> Hi Aurelien,
> >>
> >> On Wed, Oct 17, 2012 at 7:20 AM, Aurelien Jarno <aurelien@aurel32.net> wrote:
> >> > On Tue, Oct 16, 2012 at 12:39:05AM +0800, Jia Liu wrote:
> >> >> +/* a[0] is LO, a[1] is HI. */
> >> >> +static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
> >> >> +                                             int32_t ac,
> >> >> +                                             int64_t *a,
> >> >> +                                             CPUMIPSState *env)
> >> >> +{
> >> >> +    uint32_t temp64, temp63;
> >> >> +    int64_t temp[2];
> >> >> +    int64_t acc[2];
> >> >> +    int64_t temp_sum;
> >> >> +
> >> >> +    temp[0] = a[0];
> >> >> +    temp[1] = a[1];
> >> >> +
> >> >> +    acc[0] = env->active_tc.LO[ac];
> >> >> +    acc[1] = env->active_tc.HI[ac];
> >> >> +
> >> >> +    temp_sum = acc[0] - temp[0];
> >> >> +    if (MIPSDSP_OVERFLOW(acc[0], -temp[0], temp_sum, 0x8000000000000000ull)) {
> >> >> +        acc[1] -= 1;
> >> >> +    }
> >> >> +    acc[0] = temp_sum;
> >> >> +
> >> >> +    temp_sum = acc[1] - temp[1];
> >> >> +    acc[1] = temp_sum;
> >> >> +
> >> >> +    temp64 = acc[1] & 0x01;
> >> >> +    temp63 = (acc[0] >> 63) & 0x01;
> >> >> +
> >> >> +    /* MIPSDSP_OVERFLOW only can check if a 64 bits sub is overflow,
> >> >> +     * there are two 128 bits value subed then check the 63/64 bits are equal
> >> >> +     * or not.*/
> >> >
> >> > If you disagree with what I say, you can send mail, there is no need to
> >> > put it as a comment.
> >> >
> >> > That said MIPSDSP_OVERFLOW doesn't work only on 64-bit values, it can
> >> > work other size, as it is done elsewhere in this patch. The only thing
> >> > it checked is the highest bit of the two arguments and the result.
> >> > Therefore if you pass the highest part of the values, it can work.
> >> >
> >>
> >> I did agree with you, just didn't totally get your point.
> >>
> >> MIPSDSP_OVERFLOW used to check overflow, but here, 128bit + 128bit,
> >> low 64bit overflow need to be checked, so, in fact, I'm not sure what
> >> should do. Is this code right?
> >>
> >> static inline void mipsdsp_sat64_acc_sub_q63(uint64_t *ret,
> >>                                              int32_t ac,
> >>                                              uint64_t *a,
> >>                                              CPUMIPSState *env)
> >> {
> >>     uint32_t temp64;
> >>     uint64_t temp[2];
> >>     uint64_t acc[2];
> >>
> >>     temp[0] = a[0];
> >>     temp[1] = a[1];
> >>
> >>     acc[0] = env->active_tc.LO[ac];
> >>     acc[1] = env->active_tc.HI[ac];
> >>
> >>     temp[1] = acc[1] - temp[1];
> >>     temp[0] = acc[0] - temp[0];
> >>
> >>     temp64 = temp[1] & 0x01;
> >>
> >>     if (temp64 ^ MIPSDSP_OVERFLOW(acc[0], temp[0], temp[0], (0x01ull << 63))) {
> >>         if (temp64 == 1) {
> >>             ret[0] = (0x01ull << 63);
> >>             ret[1] = ~0ull;
> >>         } else {
> >>             ret[0] = (0x01ull << 63) - 1;
> >>             ret[1] = 0x00;
> >>         }
> >>         set_DSPControl_overflow_flag(1, 16 + ac, env);
> >>     } else {
> >>         ret[0] = temp[0];
> >>         ret[1] = acc[0] > temp[0] ? temp[1] : temp[1] - 1;
> >>     }
> >> }
> >>
> >
> > I don't think xoring temp64 with MIPSDSP_OVERFLOW is correct. What about
> > about something like that (untested):
> >
> > | static inline void mipsdsp_sat64_acc_sub_q63(uint64_t *ret,
> > |                                              int32_t ac,
> > |                                              uint64_t *a,
> > |                                              CPUMIPSState *env)
> > | {
> > |     ret[0] = env->active_tc.LO[ac] - a[0];
> > |     ret[1] = env->active_tc.HI[ac] - a[1];
> > |
> 
> In the MIPS-DSP manual, the function is
> 
> function sat64AccumulateSubQ63( acc1..0, a127..0 )
>     temp128..0 ← HI[acc]63 || HI[acc]63..0 || LO[acc]63..0
>     temp128..0 ← temp - a127..0 if ( temp64 ≠ temp63 ) then
>     if ( temp64 = 1 ) then
>         temp127..0 ← 0xFFFFFFFFFFFFFFFF8000000000000000
>     else
>         temp127..0 ← 0x00000000000000007FFFFFFFFFFFFFFF
>     endif
>     DSPControlouflag:16+acc ← 1 endif
>     return temp127..0
> endfunction sat64AccumulateSubQ63
> 
> > |     if (MIPSDSP_OVERFLOW(env->active_tc.LO[ac], -a[0], ret[0], 0x8000000000000000ull)) {
> 
> The bit 64 will influence the overflow of bits 0-63.
> That is, if bit 64 is 1, and bits 0-63 overflowed, it won't be caught.
> So, if we use this code, it won't be handled.
> 

I think you are correct, we have to take into account the overflow part,
but also the original value of the temp64 bit.

> > |         if ((ret[1] - 1) & 1) {
> > |             ret[0] = (0x01ull << 63);
> > |             ret[1] = ~0ull;
> > |         } else {
> > |             ret[0] = (0x01ull << 63) - 1;
> > |             ret[1] = 0x00;
> > |         }
> > |         set_DSPControl_overflow_flag(1, 16 + ac, env);
> > |     }
> > | }
> > |
> >
> > The same applies for the add function, but also to some other places in
> > the code.
> >
> > Also note that you might want to have two version of MIPSDSP_OVERFLOW(),
> > one for add (like the current one), and one for sub (without the ^ -1),
> > so that you don't have to pass the negative value of the second
> > argument.
> >
> 
> I think it is not necessary to define a new macro very much, what do
> you think about this code? Just little changed.
> 
> /* a[0] is LO, a[1] is HI. */
> static inline void mipsdsp_sat64_acc_add_q63(int64_t *ret,
>                                              int32_t ac,
>                                              int64_t *a,
>                                              CPUMIPSState *env)
> {
>     uint32_t temp64;
> 
>     ret[0] = env->active_tc.LO[ac] + a[0];
>     ret[1] = env->active_tc.HI[ac] + a[1];
> 
>     temp64 = ret[1] & 0x01;
> 
>     if (temp64 ^ MIPSDSP_OVERFLOW(env->active_tc.LO[ac], a[0], ret[0],
>                                   (0x01ull << 63))) {
>         if (temp64 == 1) {
>             ret[0] = (0x01ull << 63);
>             ret[1] = ~0ull;
>         } else {
>             ret[0] = (0x01ull << 63) - 1;
>             ret[1] = 0x00;
>         }
>         set_DSPControl_overflow_flag(1, 16 + ac, env);
>     } else {
>         ret[1] = (((uint64_t)env->active_tc.LO[ac] > (uint64_t)ret[0]) &&
>                   ((uint64_t)a[0] > (uint64_t)ret[0])) ? ret[1] : ret[1] + 1;
>     }
> }
> 
> static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
>                                              int32_t ac,
>                                              int64_t *a,
>                                              CPUMIPSState *env)
> {
>     uint32_t temp64;
> 
>     ret[0] = env->active_tc.LO[ac] - a[0];
>     ret[1] = env->active_tc.HI[ac] - a[1];
> 
>     temp64 = ret[1] & 0x01;
> 
>     if (temp64 ^ MIPSDSP_OVERFLOW(env->active_tc.LO[ac], -a[0], ret[0],
>                                   (0x01ull << 63))) {
>         if (temp64 == 1) {
>             ret[0] = (0x01ull << 63);
>             ret[1] = ~0ull;
>         } else {
>             ret[0] = (0x01ull << 63) - 1;
>             ret[1] = 0x00;
>         }
>         set_DSPControl_overflow_flag(1, 16 + ac, env);
>     } else {
>         ret[1] = (uint64_t)env->active_tc.LO[ac] > (uint64_t)ret[0] ?
>             ret[1] : ret[1] - 1;
>     }
> }
> 

That looks fine to me. That said given it mean we have to propagate the
carry, you might want to avoid the else case:

| static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
|                                              int32_t ac,
|                                              int64_t *a,
|                                              CPUMIPSState *env)
| {
|     bool temp64;
| 
|     ret[0] = env->active_tc.LO[ac] - a[0];
|     ret[1] = env->active_tc.HI[ac] - a[1];
| 
|     if (MIPSDSP_OVERFLOW(env->active_tc.LO[ac], -a[0], ret[0],
|                          (0x01ull << 63))) {
|         ret[1] -= 1;
|     }
|     temp64 = ret[1] & 1;
|     if (temp64 != (ret[0] >> 63)) {
|         if (temp64) {
|             ret[0] = (0x01ull << 63);
|             ret[1] = ~0ull;
|         } else {
|             ret[0] = (0x01ull << 63) - 1;
|             ret[1] = 0x00;
|         }
|         set_DSPControl_overflow_flag(1, 16 + ac, env);
|     }
| }
Aurelien Jarno Oct. 18, 2012, 11:18 a.m. UTC | #6
On Thu, Oct 18, 2012 at 08:05:59AM +0200, Aurelien Jarno wrote:
> On Thu, Oct 18, 2012 at 09:53:20AM +0800, Jia Liu wrote:
> > Hi Aurelien,
> > 
> > On Wed, Oct 17, 2012 at 11:15 PM, Aurelien Jarno <aurelien@aurel32.net> wrote:
> > > On Wed, Oct 17, 2012 at 11:39:00AM +0800, Jia Liu wrote:
> > >> Hi Aurelien,
> > >>
> > >> On Wed, Oct 17, 2012 at 7:20 AM, Aurelien Jarno <aurelien@aurel32.net> wrote:
> > >> > On Tue, Oct 16, 2012 at 12:39:05AM +0800, Jia Liu wrote:
> > >> >> +/* a[0] is LO, a[1] is HI. */
> > >> >> +static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
> > >> >> +                                             int32_t ac,
> > >> >> +                                             int64_t *a,
> > >> >> +                                             CPUMIPSState *env)
> > >> >> +{
> > >> >> +    uint32_t temp64, temp63;
> > >> >> +    int64_t temp[2];
> > >> >> +    int64_t acc[2];
> > >> >> +    int64_t temp_sum;
> > >> >> +
> > >> >> +    temp[0] = a[0];
> > >> >> +    temp[1] = a[1];
> > >> >> +
> > >> >> +    acc[0] = env->active_tc.LO[ac];
> > >> >> +    acc[1] = env->active_tc.HI[ac];
> > >> >> +
> > >> >> +    temp_sum = acc[0] - temp[0];
> > >> >> +    if (MIPSDSP_OVERFLOW(acc[0], -temp[0], temp_sum, 0x8000000000000000ull)) {
> > >> >> +        acc[1] -= 1;
> > >> >> +    }
> > >> >> +    acc[0] = temp_sum;
> > >> >> +
> > >> >> +    temp_sum = acc[1] - temp[1];
> > >> >> +    acc[1] = temp_sum;
> > >> >> +
> > >> >> +    temp64 = acc[1] & 0x01;
> > >> >> +    temp63 = (acc[0] >> 63) & 0x01;
> > >> >> +
> > >> >> +    /* MIPSDSP_OVERFLOW only can check if a 64 bits sub is overflow,
> > >> >> +     * there are two 128 bits value subed then check the 63/64 bits are equal
> > >> >> +     * or not.*/
> > >> >
> > >> > If you disagree with what I say, you can send mail, there is no need to
> > >> > put it as a comment.
> > >> >
> > >> > That said MIPSDSP_OVERFLOW doesn't work only on 64-bit values, it can
> > >> > work other size, as it is done elsewhere in this patch. The only thing
> > >> > it checked is the highest bit of the two arguments and the result.
> > >> > Therefore if you pass the highest part of the values, it can work.
> > >> >
> > >>
> > >> I did agree with you, just didn't totally get your point.
> > >>
> > >> MIPSDSP_OVERFLOW used to check overflow, but here, 128bit + 128bit,
> > >> low 64bit overflow need to be checked, so, in fact, I'm not sure what
> > >> should do. Is this code right?
> > >>
> > >> static inline void mipsdsp_sat64_acc_sub_q63(uint64_t *ret,
> > >>                                              int32_t ac,
> > >>                                              uint64_t *a,
> > >>                                              CPUMIPSState *env)
> > >> {
> > >>     uint32_t temp64;
> > >>     uint64_t temp[2];
> > >>     uint64_t acc[2];
> > >>
> > >>     temp[0] = a[0];
> > >>     temp[1] = a[1];
> > >>
> > >>     acc[0] = env->active_tc.LO[ac];
> > >>     acc[1] = env->active_tc.HI[ac];
> > >>
> > >>     temp[1] = acc[1] - temp[1];
> > >>     temp[0] = acc[0] - temp[0];
> > >>
> > >>     temp64 = temp[1] & 0x01;
> > >>
> > >>     if (temp64 ^ MIPSDSP_OVERFLOW(acc[0], temp[0], temp[0], (0x01ull << 63))) {
> > >>         if (temp64 == 1) {
> > >>             ret[0] = (0x01ull << 63);
> > >>             ret[1] = ~0ull;
> > >>         } else {
> > >>             ret[0] = (0x01ull << 63) - 1;
> > >>             ret[1] = 0x00;
> > >>         }
> > >>         set_DSPControl_overflow_flag(1, 16 + ac, env);
> > >>     } else {
> > >>         ret[0] = temp[0];
> > >>         ret[1] = acc[0] > temp[0] ? temp[1] : temp[1] - 1;
> > >>     }
> > >> }
> > >>
> > >
> > > I don't think xoring temp64 with MIPSDSP_OVERFLOW is correct. What about
> > > about something like that (untested):
> > >
> > > | static inline void mipsdsp_sat64_acc_sub_q63(uint64_t *ret,
> > > |                                              int32_t ac,
> > > |                                              uint64_t *a,
> > > |                                              CPUMIPSState *env)
> > > | {
> > > |     ret[0] = env->active_tc.LO[ac] - a[0];
> > > |     ret[1] = env->active_tc.HI[ac] - a[1];
> > > |
> > 
> > In the MIPS-DSP manual, the function is
> > 
> > function sat64AccumulateSubQ63( acc1..0, a127..0 )
> >     temp128..0 ← HI[acc]63 || HI[acc]63..0 || LO[acc]63..0
> >     temp128..0 ← temp - a127..0 if ( temp64 ≠ temp63 ) then
> >     if ( temp64 = 1 ) then
> >         temp127..0 ← 0xFFFFFFFFFFFFFFFF8000000000000000
> >     else
> >         temp127..0 ← 0x00000000000000007FFFFFFFFFFFFFFF
> >     endif
> >     DSPControlouflag:16+acc ← 1 endif
> >     return temp127..0
> > endfunction sat64AccumulateSubQ63
> > 
> > > |     if (MIPSDSP_OVERFLOW(env->active_tc.LO[ac], -a[0], ret[0], 0x8000000000000000ull)) {
> > 
> > The bit 64 will influence the overflow of bits 0-63.
> > That is, if bit 64 is 1, and bits 0-63 overflowed, it won't be caught.
> > So, if we use this code, it won't be handled.
> > 
> 
> I think you are correct, we have to take into account the overflow part,
> but also the original value of the temp64 bit.
> 
> > > |         if ((ret[1] - 1) & 1) {
> > > |             ret[0] = (0x01ull << 63);
> > > |             ret[1] = ~0ull;
> > > |         } else {
> > > |             ret[0] = (0x01ull << 63) - 1;
> > > |             ret[1] = 0x00;
> > > |         }
> > > |         set_DSPControl_overflow_flag(1, 16 + ac, env);
> > > |     }
> > > | }
> > > |
> > >
> > > The same applies for the add function, but also to some other places in
> > > the code.
> > >
> > > Also note that you might want to have two version of MIPSDSP_OVERFLOW(),
> > > one for add (like the current one), and one for sub (without the ^ -1),
> > > so that you don't have to pass the negative value of the second
> > > argument.
> > >
> > 
> > I think it is not necessary to define a new macro very much, what do
> > you think about this code? Just little changed.
> > 
> > /* a[0] is LO, a[1] is HI. */
> > static inline void mipsdsp_sat64_acc_add_q63(int64_t *ret,
> >                                              int32_t ac,
> >                                              int64_t *a,
> >                                              CPUMIPSState *env)
> > {
> >     uint32_t temp64;
> > 
> >     ret[0] = env->active_tc.LO[ac] + a[0];
> >     ret[1] = env->active_tc.HI[ac] + a[1];
> > 
> >     temp64 = ret[1] & 0x01;
> > 
> >     if (temp64 ^ MIPSDSP_OVERFLOW(env->active_tc.LO[ac], a[0], ret[0],
> >                                   (0x01ull << 63))) {
> >         if (temp64 == 1) {
> >             ret[0] = (0x01ull << 63);
> >             ret[1] = ~0ull;
> >         } else {
> >             ret[0] = (0x01ull << 63) - 1;
> >             ret[1] = 0x00;
> >         }
> >         set_DSPControl_overflow_flag(1, 16 + ac, env);
> >     } else {
> >         ret[1] = (((uint64_t)env->active_tc.LO[ac] > (uint64_t)ret[0]) &&
> >                   ((uint64_t)a[0] > (uint64_t)ret[0])) ? ret[1] : ret[1] + 1;
> >     }
> > }
> > 
> > static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
> >                                              int32_t ac,
> >                                              int64_t *a,
> >                                              CPUMIPSState *env)
> > {
> >     uint32_t temp64;
> > 
> >     ret[0] = env->active_tc.LO[ac] - a[0];
> >     ret[1] = env->active_tc.HI[ac] - a[1];
> > 
> >     temp64 = ret[1] & 0x01;
> > 
> >     if (temp64 ^ MIPSDSP_OVERFLOW(env->active_tc.LO[ac], -a[0], ret[0],
> >                                   (0x01ull << 63))) {
> >         if (temp64 == 1) {
> >             ret[0] = (0x01ull << 63);
> >             ret[1] = ~0ull;
> >         } else {
> >             ret[0] = (0x01ull << 63) - 1;
> >             ret[1] = 0x00;
> >         }
> >         set_DSPControl_overflow_flag(1, 16 + ac, env);
> >     } else {
> >         ret[1] = (uint64_t)env->active_tc.LO[ac] > (uint64_t)ret[0] ?
> >             ret[1] : ret[1] - 1;
> >     }
> > }
> > 
> 
> That looks fine to me. That said given it mean we have to propagate the
> carry, you might want to avoid the else case:
> 
> | static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
> |                                              int32_t ac,
> |                                              int64_t *a,
> |                                              CPUMIPSState *env)
> | {
> |     bool temp64;
> | 
> |     ret[0] = env->active_tc.LO[ac] - a[0];
> |     ret[1] = env->active_tc.HI[ac] - a[1];
> | 
> |     if (MIPSDSP_OVERFLOW(env->active_tc.LO[ac], -a[0], ret[0],
> |                          (0x01ull << 63))) {
> |         ret[1] -= 1;
> |     }
> |     temp64 = ret[1] & 1;
> |     if (temp64 != (ret[0] >> 63)) {
> |         if (temp64) {
> |             ret[0] = (0x01ull << 63);
> |             ret[1] = ~0ull;
> |         } else {
> |             ret[0] = (0x01ull << 63) - 1;
> |             ret[1] = 0x00;
> |         }
> |         set_DSPControl_overflow_flag(1, 16 + ac, env);
> |     }
> | }
> 

Actually this is likely wrong, MIPSDSP_OVERFLOW works for the overflow
detection, not for the carry detection. So something like that should
work:

| static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
|                                              int32_t ac,
|                                              int64_t *a,
|                                              CPUMIPSState *env)
| {
|     bool temp64;
| 
|     ret[0] = env->active_tc.LO[ac] - a[0];
|     ret[1] = env->active_tc.HI[ac] - a[1];
|
|     if ((uint64_t)env->active_tc.LO[ac] > (uint64_t)ret[0]) {
|         ret[1] -= 1;
|     }
|     temp64 = ret[1] & 1;
|     if (temp64 != (ret[0] >> 63)) {
|         if (temp64) {
|             ret[0] = (0x01ull << 63);
|             ret[1] = ~0ull;
|         } else {
|             ret[0] = (0x01ull << 63) - 1;
|             ret[1] = 0x00;
|         }
|         set_DSPControl_overflow_flag(1, 16 + ac, env);
|     }
| }
diff mbox

Patch

diff --git a/target-mips/Makefile.objs b/target-mips/Makefile.objs
index 3eeeeac..119c816 100644
--- a/target-mips/Makefile.objs
+++ b/target-mips/Makefile.objs
@@ -1,2 +1,2 @@ 
-obj-y += translate.o op_helper.o lmi_helper.o helper.o cpu.o
+obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o
 obj-$(CONFIG_SOFTMMU) += machine.o
diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c
new file mode 100644
index 0000000..1c656a0
--- /dev/null
+++ b/target-mips/dsp_helper.c
@@ -0,0 +1,1086 @@ 
+/*
+ * MIPS ASE DSP Instruction emulation helpers for QEMU.
+ *
+ * Copyright (c) 2012  Jia Liu <proljc@gmail.com>
+ *                     Dongxue Zhang <elat.era@gmail.com>
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+/*** MIPS DSP internal functions begin ***/
+#define MIPSDSP_ABS(x) (((x) >= 0) ? x : -x)
+#define MIPSDSP_OVERFLOW(a, b, c, d) (!(!((a ^ b ^ -1) & (a ^ c) & d)))
+
+static inline void set_DSPControl_overflow_flag(uint32_t flag, int position,
+                                                CPUMIPSState *env)
+{
+    env->active_tc.DSPControl |= (target_ulong)flag << position;
+}
+
+static inline void set_DSPControl_carryflag(uint32_t flag, CPUMIPSState *env)
+{
+    env->active_tc.DSPControl |= (target_ulong)flag << 13;
+}
+
+static inline uint32_t get_DSPControl_carryflag(CPUMIPSState *env)
+{
+    return (env->active_tc.DSPControl >> 13) & 0x01;
+}
+
+static inline void set_DSPControl_24(uint32_t flag, int len, CPUMIPSState *env)
+{
+  uint32_t filter;
+
+  filter = ((0x01 << len) - 1) << 24;
+  filter = ~filter;
+
+  env->active_tc.DSPControl &= filter;
+  env->active_tc.DSPControl |= (target_ulong)flag << 24;
+}
+
+static inline uint32_t get_DSPControl_24(int len, CPUMIPSState *env)
+{
+  uint32_t filter;
+
+  filter = (0x01 << len) - 1;
+
+  return (env->active_tc.DSPControl >> 24) & filter;
+}
+
+static inline void set_DSPControl_pos(uint32_t pos, CPUMIPSState *env)
+{
+    target_ulong dspc;
+
+    dspc = env->active_tc.DSPControl;
+#ifndef TARGET_MIPS64
+    dspc = dspc & 0xFFFFFFC0;
+    dspc |= pos;
+#else
+    dspc = dspc & 0xFFFFFF80;
+    dspc |= pos;
+#endif
+    env->active_tc.DSPControl = dspc;
+}
+
+static inline uint32_t get_DSPControl_pos(CPUMIPSState *env)
+{
+    target_ulong dspc;
+    uint32_t pos;
+
+    dspc = env->active_tc.DSPControl;
+
+#ifndef TARGET_MIPS64
+    pos = dspc & 0x3F;
+#else
+    pos = dspc & 0x7F;
+#endif
+
+    return pos;
+}
+
+static inline void set_DSPControl_efi(uint32_t flag, CPUMIPSState *env)
+{
+    env->active_tc.DSPControl &= 0xFFFFBFFF;
+    env->active_tc.DSPControl |= (target_ulong)flag << 14;
+}
+
+#define DO_MIPS_SAT_ABS(size)                                          \
+static inline int##size##_t mipsdsp_sat_abs##size(int##size##_t a,         \
+                                                  CPUMIPSState *env)   \
+{                                                                      \
+    if (a == INT##size##_MIN) {                                        \
+        set_DSPControl_overflow_flag(1, 20, env);                      \
+        return INT##size##_MAX;                                        \
+    } else {                                                           \
+        return MIPSDSP_ABS(a);                                         \
+    }                                                                  \
+}
+DO_MIPS_SAT_ABS(8)
+DO_MIPS_SAT_ABS(16)
+DO_MIPS_SAT_ABS(32)
+#undef DO_MIPS_SAT_ABS
+
+/* get sum value */
+static inline int16_t mipsdsp_add_i16(int16_t a, int16_t b, CPUMIPSState *env)
+{
+    int16_t tempI;
+
+    tempI = a + b;
+
+    if (MIPSDSP_OVERFLOW(a, b, tempI, 0x8000)) {
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return tempI;
+}
+
+static inline int16_t mipsdsp_sat_add_i16(int16_t a, int16_t b,
+                                          CPUMIPSState *env)
+{
+    int16_t tempS;
+
+    tempS = a + b;
+
+    if (MIPSDSP_OVERFLOW(a, b, tempS, 0x8000)) {
+        if (a > 0) {
+            tempS = 0x7FFF;
+        } else {
+            tempS = 0x8000;
+        }
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return tempS;
+}
+
+static inline int32_t mipsdsp_sat_add_i32(int32_t a, int32_t b,
+                                          CPUMIPSState *env)
+{
+    int32_t tempI;
+
+    tempI = a + b;
+
+    if (MIPSDSP_OVERFLOW(a, b, tempI, 0x80000000)) {
+        if (a > 0) {
+            tempI = 0x7FFFFFFF;
+        } else {
+            tempI = 0x80000000;
+        }
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return tempI;
+}
+
+static inline uint8_t mipsdsp_add_u8(uint8_t a, uint8_t b, CPUMIPSState *env)
+{
+    uint16_t temp;
+
+    temp = (uint16_t)a + (uint16_t)b;
+
+    if (temp & 0x0100) {
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return temp & 0xFF;
+}
+
+static inline uint16_t mipsdsp_add_u16(uint16_t a, uint16_t b,
+                                       CPUMIPSState *env)
+{
+    uint32_t temp;
+
+    temp = (uint32_t)a + (uint32_t)b;
+
+    if (temp & 0x00010000) {
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return temp & 0xFFFF;
+}
+
+static inline uint8_t mipsdsp_sat_add_u8(uint8_t a, uint8_t b,
+                                         CPUMIPSState *env)
+{
+    uint8_t  result;
+    uint16_t temp;
+
+    temp = (uint16_t)a + (uint16_t)b;
+    result = temp & 0xFF;
+
+    if (0x0100 & temp) {
+        result = 0xFF;
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return result;
+}
+
+static inline uint16_t mipsdsp_sat_add_u16(uint16_t a, uint16_t b,
+                                           CPUMIPSState *env)
+{
+    uint16_t result;
+    uint32_t temp;
+
+    temp = (uint32_t)a + (uint32_t)b;
+    result = temp & 0xFFFF;
+
+    if (0x00010000 & temp) {
+        result = 0xFFFF;
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return result;
+}
+
+static inline int32_t mipsdsp_sat32_acc_q31(int32_t acc, int32_t a,
+                                            CPUMIPSState *env)
+{
+    int64_t temp;
+    int32_t temp32, temp31, result;
+    int64_t temp_sum;
+
+#ifndef TARGET_MIPS64
+    temp = ((uint64_t)env->active_tc.HI[acc] << 32) |
+           (uint64_t)env->active_tc.LO[acc];
+#else
+    temp = (uint64_t)env->active_tc.LO[acc];
+#endif
+
+    temp_sum = (int64_t)a + temp;
+
+    temp32 = (temp_sum >> 32) & 0x01;
+    temp31 = (temp_sum >> 31) & 0x01;
+    result = temp_sum & 0xFFFFFFFF;
+
+    if (temp32 != temp31) {
+        if (temp32 == 0) {
+            result = 0x7FFFFFFF;
+        } else {
+            result = 0x80000000;
+        }
+        set_DSPControl_overflow_flag(1, 16 + acc, env);
+    }
+
+    return result;
+}
+
+/* a[0] is LO, a[1] is HI. */
+static inline void mipsdsp_sat64_acc_add_q63(int64_t *ret,
+                                             int32_t ac,
+                                             int64_t *a,
+                                             CPUMIPSState *env)
+{
+    int64_t temp[3];
+    int64_t acc[3];
+    int64_t temp_sum;
+
+    temp[0] = a[0];
+    temp[1] = a[1];
+    if (temp[1] >= 0) {
+        temp[2] = 0x00;
+    } else {
+        temp[2] = ~0ull;
+    }
+
+    acc[0] = env->active_tc.LO[ac];
+    acc[1] = env->active_tc.HI[ac];
+    if (acc[1] >= 0) {
+        acc[2] = 0x00;
+    } else {
+        acc[2] = ~0ull;
+    }
+
+    temp_sum = temp[0] + acc[0];
+    if (((uint64_t)temp_sum < (uint64_t)temp[0]) &&
+       ((uint64_t)temp_sum < (uint64_t)acc[0])) {
+        temp[1] += 1;
+        if (temp[1] == 0) {
+            temp[2] += 1;
+        }
+    }
+    temp[0] = temp_sum;
+
+    temp_sum = temp[1] + acc[1];
+    if (((uint64_t)temp_sum < (uint64_t)temp[1]) &&
+       ((uint64_t)temp_sum < (uint64_t)acc[1])) {
+        temp[2] += 1;
+    }
+
+    if (MIPSDSP_OVERFLOW(temp[1], acc[1], temp_sum, INT64_MIN)) {
+        if (temp[1] > 0) {
+            ret[0] = 0x0;
+            ret[1] = 0x7FFFFFFFFFFFFFFFull;
+        } else {
+            ret[0] = 0x8000000000000000ull;
+            ret[1] = ~0ull;
+        }
+        set_DSPControl_overflow_flag(1, 16 + ac, env);
+    } else {
+        ret[0] = temp[0];
+        ret[1] = temp_sum;
+    }
+}
+
+/* a[0] is LO, a[1] is HI. */
+static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
+                                             int32_t ac,
+                                             int64_t *a,
+                                             CPUMIPSState *env)
+{
+    uint32_t temp64, temp63;
+    int64_t temp[2];
+    int64_t acc[2];
+    int64_t temp_sum;
+
+    temp[0] = a[0];
+    temp[1] = a[1];
+
+    acc[0] = env->active_tc.LO[ac];
+    acc[1] = env->active_tc.HI[ac];
+
+    temp_sum = acc[0] - temp[0];
+    if (MIPSDSP_OVERFLOW(acc[0], -temp[0], temp_sum, 0x8000000000000000ull)) {
+        acc[1] -= 1;
+    }
+    acc[0] = temp_sum;
+
+    temp_sum = acc[1] - temp[1];
+    acc[1] = temp_sum;
+
+    temp64 = acc[1] & 0x01;
+    temp63 = (acc[0] >> 63) & 0x01;
+
+    /* MIPSDSP_OVERFLOW only can check if a 64 bits sub is overflow,
+     * there are two 128 bits value subed then check the 63/64 bits are equal
+     * or not.*/
+    if (temp64 != temp63) {
+        if (temp64 == 1) {
+            ret[0] = 0x8000000000000000ull;
+            ret[1] = ~0ull;
+        } else {
+            ret[0] = 0x0;
+            ret[1] = 0x7FFFFFFFFFFFFFFFull;
+        }
+        set_DSPControl_overflow_flag(1, 16 + ac, env);
+    } else {
+        ret[0] = acc[0];
+        ret[1] = acc[1];
+    }
+}
+
+static inline int32_t mipsdsp_mul_i16_i16(int16_t a, int16_t b,
+                                          CPUMIPSState *env)
+{
+    int32_t temp;
+
+    temp = (int32_t)a * (int32_t)b;
+
+    if ((temp > 0x7FFF) || (temp < 0xFFFF8000)) {
+        set_DSPControl_overflow_flag(1, 21, env);
+    }
+    temp &= 0x0000FFFF;
+
+    return temp;
+}
+
+static inline int32_t mipsdsp_mul_u16_u16(int32_t a, int32_t b)
+{
+    return a * b;
+}
+
+static inline int32_t mipsdsp_mul_i32_i32(int32_t a, int32_t b)
+{
+    return a * b;
+}
+
+static inline int32_t mipsdsp_sat16_mul_i16_i16(int16_t a, int16_t b,
+                                                CPUMIPSState *env)
+{
+    int32_t temp;
+
+    temp = (int32_t)a * (int32_t)b;
+
+    if (temp > 0x7FFF) {
+        temp = 0x00007FFF;
+        set_DSPControl_overflow_flag(1, 21, env);
+    } else if (temp < 0x00007FFF) {
+        temp = 0xFFFF8000;
+        set_DSPControl_overflow_flag(1, 21, env);
+    }
+    temp &= 0x0000FFFF;
+
+    return temp;
+}
+
+static inline int32_t mipsdsp_mul_q15_q15_overflowflag21(uint16_t a, uint16_t b,
+                                                         CPUMIPSState *env)
+{
+    int32_t temp;
+
+    if ((a == 0x8000) && (b == 0x8000)) {
+        temp = 0x7FFFFFFF;
+        set_DSPControl_overflow_flag(1, 21, env);
+    } else {
+        temp = ((int32_t)(int16_t)a * (int32_t)(int16_t)b) << 1;
+    }
+
+    return temp;
+}
+
+/* right shift */
+static inline uint8_t mipsdsp_rshift_u8(uint8_t a, target_ulong mov)
+{
+    return a >> mov;
+}
+
+static inline uint16_t mipsdsp_rshift_u16(uint16_t a, target_ulong mov)
+{
+    return a >> mov;
+}
+
+static inline int8_t mipsdsp_rashift8(int8_t a, target_ulong mov)
+{
+    return a >> mov;
+}
+
+static inline int16_t mipsdsp_rashift16(int16_t a, target_ulong mov)
+{
+    return a >> mov;
+}
+
+static inline int32_t mipsdsp_rashift32(int32_t a, target_ulong mov)
+{
+    return a >> mov;
+}
+
+static inline int16_t mipsdsp_rshift1_add_q16(int16_t a, int16_t b)
+{
+    int32_t temp;
+
+    temp = (int32_t)a + (int32_t)b;
+
+    return (temp >> 1) & 0xFFFF;
+}
+
+/* round right shift */
+static inline int16_t mipsdsp_rrshift1_add_q16(int16_t a, int16_t b)
+{
+    int32_t temp;
+
+    temp = (int32_t)a + (int32_t)b;
+    temp += 1;
+
+    return (temp >> 1) & 0xFFFF;
+}
+
+static inline int32_t mipsdsp_rshift1_add_q32(int32_t a, int32_t b)
+{
+    int64_t temp;
+
+    temp = (int64_t)a + (int64_t)b;
+
+    return (temp >> 1) & 0xFFFFFFFF;
+}
+
+static inline int32_t mipsdsp_rrshift1_add_q32(int32_t a, int32_t b)
+{
+    int64_t temp;
+
+    temp = (int64_t)a + (int64_t)b;
+    temp += 1;
+
+    return (temp >> 1) & 0xFFFFFFFF;
+}
+
+static inline uint8_t mipsdsp_rshift1_add_u8(uint8_t a, uint8_t b)
+{
+    uint16_t temp;
+
+    temp = (uint16_t)a + (uint16_t)b;
+
+    return (temp >> 1) & 0x00FF;
+}
+
+static inline uint8_t mipsdsp_rrshift1_add_u8(uint8_t a, uint8_t b)
+{
+    uint16_t temp;
+
+    temp = (uint16_t)a + (uint16_t)b + 1;
+
+    return (temp >> 1) & 0x00FF;
+}
+
+static inline uint8_t mipsdsp_rshift1_sub_u8(uint8_t a, uint8_t b)
+{
+    uint16_t temp;
+
+    temp = (uint16_t)a - (uint16_t)b;
+
+    return (temp >> 1) & 0x00FF;
+}
+
+static inline uint8_t mipsdsp_rrshift1_sub_u8(uint8_t a, uint8_t b)
+{
+    uint16_t temp;
+
+    temp = (uint16_t)a - (uint16_t)b + 1;
+
+    return (temp >> 1) & 0x00FF;
+}
+
+static inline int64_t mipsdsp_rashift_short_acc(int32_t ac,
+                                                int32_t shift,
+                                                CPUMIPSState *env)
+{
+    int32_t sign, temp31;
+    int64_t temp, acc;
+
+    sign = (env->active_tc.HI[ac] >> 31) & 0x01;
+    acc = ((int64_t)env->active_tc.HI[ac] << 32) |
+          ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF);
+    if (shift == 0) {
+        temp = acc;
+    } else {
+        if (sign == 0) {
+            temp = (((int64_t)0x01 << (32 - shift + 1)) - 1) & (acc >> shift);
+        } else {
+            temp = ((((int64_t)0x01 << (shift + 1)) - 1) << (32 - shift)) |
+                   (acc >> shift);
+        }
+    }
+
+    temp31 = (temp >> 31) & 0x01;
+    if (sign != temp31) {
+        set_DSPControl_overflow_flag(1, 23, env);
+    }
+
+    return temp;
+}
+
+/*  128 bits long. p[0] is LO, p[1] is HI. */
+static inline void mipsdsp_rndrashift_short_acc(int64_t *p,
+                                                int32_t ac,
+                                                int32_t shift,
+                                                CPUMIPSState *env)
+{
+    int64_t acc;
+
+    acc = ((int64_t)env->active_tc.HI[ac] << 32) |
+          ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF);
+    if (shift == 0) {
+        p[0] = acc << 1;
+        p[1] = (acc >> 63) & 0x01;
+    } else {
+        p[0] = acc >> (shift - 1);
+        p[1] = 0;
+    }
+}
+
+/* 128 bits long. p[0] is LO, p[1] is HI */
+static inline void mipsdsp_rashift_acc(uint64_t *p,
+                                       uint32_t ac,
+                                       uint32_t shift,
+                                       CPUMIPSState *env)
+{
+    uint64_t tempB, tempA;
+
+    tempB = env->active_tc.HI[ac];
+    tempA = env->active_tc.LO[ac];
+    shift = shift & 0x1F;
+
+    if (shift == 0) {
+        p[1] = tempB;
+        p[0] = tempA;
+    } else {
+        p[0] = (tempB << (64 - shift)) | (tempA >> shift);
+        p[1] = (int64_t)tempB >> shift;
+    }
+}
+
+/* 128 bits long. p[0] is LO, p[1] is HI , p[2] is sign of HI.*/
+static inline void mipsdsp_rndrashift_acc(uint64_t *p,
+                                          uint32_t ac,
+                                          uint32_t shift,
+                                          CPUMIPSState *env)
+{
+    int64_t tempB, tempA;
+
+    tempB = env->active_tc.HI[ac];
+    tempA = env->active_tc.LO[ac];
+    shift = shift & 0x3F;
+
+    if (shift == 0) {
+        p[2] = tempB >> 63;
+        p[1] = (tempB << 1) | (tempA >> 63);
+        p[0] = tempA << 1;
+    } else {
+        p[0] = (tempB << (65 - shift)) | (tempA >> (shift - 1));
+        p[1] = (int64_t)tempB >> (shift - 1);
+        if (tempB >= 0) {
+            p[2] = 0x0;
+        } else {
+            p[2] = ~0ull;
+        }
+    }
+}
+
+static inline int32_t mipsdsp_mul_q15_q15(int32_t ac, uint16_t a, uint16_t b,
+                                          CPUMIPSState *env)
+{
+    int32_t temp;
+
+    if ((a == 0x8000) && (b == 0x8000)) {
+        temp = 0x7FFFFFFF;
+        set_DSPControl_overflow_flag(1, 16 + ac, env);
+    } else {
+        temp = ((uint32_t)a * (uint32_t)b) << 1;
+    }
+
+    return temp;
+}
+
+static inline int64_t mipsdsp_mul_q31_q31(int32_t ac, uint32_t a, uint32_t b,
+                                          CPUMIPSState *env)
+{
+    uint64_t temp;
+
+    if ((a == 0x80000000) && (b == 0x80000000)) {
+        temp = 0x7FFFFFFFFFFFFFFFull;
+        set_DSPControl_overflow_flag(1, 16 + ac, env);
+    } else {
+        temp = ((uint64_t)a * (uint64_t)b) << 1;
+    }
+
+    return temp;
+}
+
+static inline uint16_t mipsdsp_mul_u8_u8(uint8_t a, uint8_t b)
+{
+    return (uint16_t)a * (uint16_t)b;
+}
+
+static inline uint16_t mipsdsp_mul_u8_u16(uint8_t a, uint16_t b,
+                                          CPUMIPSState *env)
+{
+    uint32_t tempI;
+
+    tempI = (uint32_t)a * (uint32_t)b;
+    if (tempI > 0x0000FFFF) {
+        tempI = 0x0000FFFF;
+        set_DSPControl_overflow_flag(1, 21, env);
+    }
+
+    return tempI & 0x0000FFFF;
+}
+
+static inline uint64_t mipsdsp_mul_u32_u32(uint32_t a, uint32_t b)
+{
+    return (uint64_t)a * (uint64_t)b;
+}
+
+static inline int16_t mipsdsp_rndq15_mul_q15_q15(uint16_t a, uint16_t b,
+                                                 CPUMIPSState *env)
+{
+    uint32_t temp;
+
+    if ((a == 0x8000) && (b == 0x8000)) {
+        temp = 0x7FFF0000;
+        set_DSPControl_overflow_flag(1, 21, env);
+    } else {
+        temp = (a * b) << 1;
+        temp = temp + 0x00008000;
+    }
+
+    return (temp & 0xFFFF0000) >> 16;
+}
+
+static inline int32_t mipsdsp_sat16_mul_q15_q15(uint16_t a, uint16_t b,
+                                                CPUMIPSState *env)
+{
+    int32_t temp;
+
+    if ((a == 0x8000) && (b == 0x8000)) {
+        temp = 0x7FFF0000;
+        set_DSPControl_overflow_flag(1, 21, env);
+    } else {
+        temp = ((uint32_t)a * (uint32_t)b);
+        temp = temp << 1;
+    }
+
+    return (temp >> 16) & 0x0000FFFF;
+}
+
+static inline uint16_t mipsdsp_trunc16_sat16_round(int32_t a,
+                                                   CPUMIPSState *env)
+{
+    int64_t temp;
+
+    temp = (int32_t)a + 0x00008000;
+
+    if (a > 0x7fff8000) {
+        temp = 0x7FFFFFFF;
+        set_DSPControl_overflow_flag(1, 22, env);
+    }
+
+    return (temp >> 16) & 0xFFFF;
+}
+
+static inline uint8_t mipsdsp_sat8_reduce_precision(uint16_t a,
+                                                    CPUMIPSState *env)
+{
+    uint16_t mag;
+    uint32_t sign;
+
+    sign = (a >> 15) & 0x01;
+    mag = a & 0x7FFF;
+
+    if (sign == 0) {
+        if (mag > 0x7F80) {
+            set_DSPControl_overflow_flag(1, 22, env);
+            return 0xFF;
+        } else {
+            return (mag >> 7) & 0xFFFF;
+        }
+    } else {
+        set_DSPControl_overflow_flag(1, 22, env);
+        return 0x00;
+    }
+}
+
+static inline uint8_t mipsdsp_lshift8(uint8_t a, uint8_t s, CPUMIPSState *env)
+{
+    uint8_t sign;
+    uint8_t discard;
+
+    if (s == 0) {
+        return a;
+    } else {
+        sign = (a >> 7) & 0x01;
+        if (sign != 0) {
+            discard = (((0x01 << (8 - s)) - 1) << s) |
+                      ((a >> (6 - (s - 1))) & ((0x01 << s) - 1));
+        } else {
+            discard = a >> (6 - (s - 1));
+        }
+
+        if (discard != 0x00) {
+            set_DSPControl_overflow_flag(1, 22, env);
+        }
+        return a << s;
+    }
+}
+
+static inline uint16_t mipsdsp_lshift16(uint16_t a, uint8_t s,
+                                        CPUMIPSState *env)
+{
+    uint8_t  sign;
+    uint16_t discard;
+
+    if (s == 0) {
+        return a;
+    } else {
+        sign = (a >> 15) & 0x01;
+        if (sign != 0) {
+            discard = (((0x01 << (16 - s)) - 1) << s) |
+                      ((a >> (14 - (s - 1))) & ((0x01 << s) - 1));
+        } else {
+            discard = a >> (14 - (s - 1));
+        }
+
+        if ((discard != 0x0000) && (discard != 0xFFFF)) {
+            set_DSPControl_overflow_flag(1, 22, env);
+        }
+        return a << s;
+    }
+}
+
+
+static inline uint32_t mipsdsp_lshift32(uint32_t a, uint8_t s,
+                                        CPUMIPSState *env)
+{
+    uint32_t discard;
+
+    if (s == 0) {
+        return a;
+    } else {
+        discard = (int32_t)a >> (31 - (s - 1));
+
+        if ((discard != 0x00000000) && (discard != 0xFFFFFFFF)) {
+            set_DSPControl_overflow_flag(1, 22, env);
+        }
+        return a << s;
+    }
+}
+
+static inline uint16_t mipsdsp_sat16_lshift(uint16_t a, uint8_t s,
+                                            CPUMIPSState *env)
+{
+    uint8_t  sign;
+    uint16_t discard;
+
+    if (s == 0) {
+        return a;
+    } else {
+        sign = (a >> 15) & 0x01;
+        if (sign != 0) {
+            discard = (((0x01 << (16 - s)) - 1) << s) |
+                      ((a >> (14 - (s - 1))) & ((0x01 << s) - 1));
+        } else {
+            discard = a >> (14 - (s - 1));
+        }
+
+        if ((discard != 0x0000) && (discard != 0xFFFF)) {
+            set_DSPControl_overflow_flag(1, 22, env);
+            return (sign == 0) ? 0x7FFF : 0x8000;
+        } else {
+            return a << s;
+        }
+    }
+}
+
+static inline uint32_t mipsdsp_sat32_lshift(uint32_t a, uint8_t s,
+                                            CPUMIPSState *env)
+{
+    uint8_t  sign;
+    uint32_t discard;
+
+    if (s == 0) {
+        return a;
+    } else {
+        sign = (a >> 31) & 0x01;
+        if (sign != 0) {
+            discard = (((0x01 << (32 - s)) - 1) << s) |
+                      ((a >> (30 - (s - 1))) & ((0x01 << s) - 1));
+        } else {
+            discard = a >> (30 - (s - 1));
+        }
+
+        if ((discard != 0x00000000) && (discard != 0xFFFFFFFF)) {
+            set_DSPControl_overflow_flag(1, 22, env);
+            return (sign == 0) ? 0x7FFFFFFF : 0x80000000;
+        } else {
+            return a << s;
+        }
+    }
+}
+
+static inline uint8_t mipsdsp_rnd8_rashift(uint8_t a, uint8_t s)
+{
+    uint32_t temp;
+
+    if (s == 0) {
+        temp = (uint32_t)a << 1;
+    } else {
+        temp = (int32_t)(int8_t)a >> (s - 1);
+    }
+
+    return (temp + 1) >> 1;
+}
+
+static inline uint16_t mipsdsp_rnd16_rashift(uint16_t a, uint8_t s)
+{
+    uint32_t temp;
+
+    if (s == 0) {
+        temp = (uint32_t)a << 1;
+    } else {
+        temp = (int32_t)(int16_t)a >> (s - 1);
+    }
+
+    return (temp + 1) >> 1;
+}
+
+static inline uint32_t mipsdsp_rnd32_rashift(uint32_t a, uint8_t s)
+{
+    int64_t temp;
+
+    if (s == 0) {
+        temp = a << 1;
+    } else {
+        temp = (int64_t)(int32_t)a >> (s - 1);
+    }
+    temp += 1;
+
+    return (temp >> 1) & 0x00000000FFFFFFFFull;
+}
+
+static inline uint16_t mipsdsp_sub_i16(int16_t a, int16_t b, CPUMIPSState *env)
+{
+    int16_t  temp;
+
+    temp = a - b;
+    if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) {
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return temp;
+}
+
+static inline uint16_t mipsdsp_sat16_sub(int16_t a, int16_t b,
+                                         CPUMIPSState *env)
+{
+    int16_t  temp;
+
+    temp = a - b;
+    if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) {
+        if (a > 0) {
+            temp = 0x7FFF;
+        } else {
+            temp = 0x8000;
+        }
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return temp;
+}
+
+static inline uint32_t mipsdsp_sat32_sub(int32_t a, int32_t b,
+                                         CPUMIPSState *env)
+{
+    int32_t  temp;
+
+    temp = a - b;
+    if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) {
+        if (a > 0) {
+            temp = 0x7FFFFFFF;
+        } else {
+            temp = 0x80000000;
+        }
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return temp & 0x00000000FFFFFFFFull;
+}
+
+static inline uint16_t mipsdsp_rshift1_sub_q16(int16_t a, int16_t b)
+{
+    int32_t  temp;
+
+    temp = (int32_t)a - (int32_t)b;
+
+    return (temp >> 1) & 0x0000FFFF;
+}
+
+static inline uint16_t mipsdsp_rrshift1_sub_q16(int16_t a, int16_t b)
+{
+    int32_t  temp;
+
+    temp = (int32_t)a - (int32_t)b;
+    temp += 1;
+
+    return (temp >> 1) & 0x0000FFFF;
+}
+
+static inline uint32_t mipsdsp_rshift1_sub_q32(int32_t a, int32_t b)
+{
+    int64_t  temp;
+
+    temp = (int64_t)a - (int64_t)b;
+
+    return (temp >> 1) & 0x00000000FFFFFFFFull;
+}
+
+static inline uint32_t mipsdsp_rrshift1_sub_q32(int32_t a, int32_t b)
+{
+    int64_t  temp;
+
+    temp = (int64_t)a - (int64_t)b;
+    temp += 1;
+
+    return (temp >> 1) & 0x00000000FFFFFFFFull;
+}
+
+static inline uint16_t mipsdsp_sub_u16_u16(uint16_t a, uint16_t b,
+                                           CPUMIPSState *env)
+{
+    uint8_t  temp16;
+    uint32_t temp;
+
+    temp = (uint32_t)a - (uint32_t)b;
+    temp16 = (temp >> 16) & 0x01;
+    if (temp16 == 1) {
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+    return temp & 0x0000FFFF;
+}
+
+static inline uint16_t mipsdsp_satu16_sub_u16_u16(uint16_t a, uint16_t b,
+                                                  CPUMIPSState *env)
+{
+    uint8_t  temp16;
+    uint32_t temp;
+
+    temp   = (uint32_t)a - (uint32_t)b;
+    temp16 = (temp >> 16) & 0x01;
+
+    if (temp16 == 1) {
+        temp = 0x0000;
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return temp & 0x0000FFFF;
+}
+
+static inline uint8_t mipsdsp_sub_u8(uint8_t a, uint8_t b, CPUMIPSState *env)
+{
+    uint8_t  temp8;
+    uint16_t temp;
+
+    temp = (uint16_t)a - (uint16_t)b;
+    temp8 = (temp >> 8) & 0x01;
+    if (temp8 == 1) {
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return temp & 0x00FF;
+}
+
+static inline uint8_t mipsdsp_satu8_sub(uint8_t a, uint8_t b, CPUMIPSState *env)
+{
+    uint8_t  temp8;
+    uint16_t temp;
+
+    temp = (uint16_t)a - (uint16_t)b;
+    temp8 = (temp >> 8) & 0x01;
+    if (temp8 == 1) {
+        temp = 0x00;
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return temp & 0x00FF;
+}
+
+static inline uint32_t mipsdsp_sub32(int32_t a, int32_t b, CPUMIPSState *env)
+{
+    int32_t temp;
+
+    temp = a - b;
+    if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) {
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return temp;
+}
+
+static inline int32_t mipsdsp_add_i32(int32_t a, int32_t b, CPUMIPSState *env)
+{
+    int32_t temp;
+
+    temp = a + b;
+
+    if (MIPSDSP_OVERFLOW(a, b, temp, 0x80000000)) {
+        set_DSPControl_overflow_flag(1, 20, env);
+    }
+
+    return temp;
+}
+
+static inline int32_t mipsdsp_cmp_eq(uint32_t a, uint32_t b)
+{
+    return a == b;
+}
+
+static inline int32_t mipsdsp_cmp_le(uint32_t a, uint32_t b)
+{
+    return a <= b;
+}
+
+static inline int32_t mipsdsp_cmp_lt(uint32_t a, uint32_t b)
+{
+    return a < b;
+}
+/*** MIPS DSP internal functions end ***/