提交 20c334a7 编写于 作者: P Petar Jovanovic 提交者: Aurelien Jarno

target-mips: fix DSP overflow macro and affected routines

The previous implementation incorrectly used same macro to detect overflow
for addition and subtraction. This patch makes distinction between these
two, and creates separate macros. The affected routines are changed
accordingly.

This change also includes additions to the existing tests for SUBQ_S_PH and
SUBQ_S_W that would trigger the fixed issue, and it removes dead code from
the test file. The last test case in subq_s_w.c is a bug found/reported/
isolated by Klaus Peichl from Dolby.
Signed-off-by: NPetar Jovanovic <petar.jovanovic@imgtec.com>
Signed-off-by: NAurelien Jarno <aurelien@aurel32.net>
上级 71df81af
...@@ -44,7 +44,8 @@ typedef union { ...@@ -44,7 +44,8 @@ typedef union {
/*** MIPS DSP internal functions begin ***/ /*** MIPS DSP internal functions begin ***/
#define MIPSDSP_ABS(x) (((x) >= 0) ? x : -x) #define MIPSDSP_ABS(x) (((x) >= 0) ? x : -x)
#define MIPSDSP_OVERFLOW(a, b, c, d) (!(!((a ^ b ^ -1) & (a ^ c) & d))) #define MIPSDSP_OVERFLOW_ADD(a, b, c, d) (~(a ^ b) & (a ^ c) & d)
#define MIPSDSP_OVERFLOW_SUB(a, b, c, d) ((a ^ b) & (a ^ c) & d)
static inline void set_DSPControl_overflow_flag(uint32_t flag, int position, static inline void set_DSPControl_overflow_flag(uint32_t flag, int position,
CPUMIPSState *env) CPUMIPSState *env)
...@@ -142,7 +143,7 @@ static inline int16_t mipsdsp_add_i16(int16_t a, int16_t b, CPUMIPSState *env) ...@@ -142,7 +143,7 @@ static inline int16_t mipsdsp_add_i16(int16_t a, int16_t b, CPUMIPSState *env)
tempI = a + b; tempI = a + b;
if (MIPSDSP_OVERFLOW(a, b, tempI, 0x8000)) { if (MIPSDSP_OVERFLOW_ADD(a, b, tempI, 0x8000)) {
set_DSPControl_overflow_flag(1, 20, env); set_DSPControl_overflow_flag(1, 20, env);
} }
...@@ -156,7 +157,7 @@ static inline int16_t mipsdsp_sat_add_i16(int16_t a, int16_t b, ...@@ -156,7 +157,7 @@ static inline int16_t mipsdsp_sat_add_i16(int16_t a, int16_t b,
tempS = a + b; tempS = a + b;
if (MIPSDSP_OVERFLOW(a, b, tempS, 0x8000)) { if (MIPSDSP_OVERFLOW_ADD(a, b, tempS, 0x8000)) {
if (a > 0) { if (a > 0) {
tempS = 0x7FFF; tempS = 0x7FFF;
} else { } else {
...@@ -175,7 +176,7 @@ static inline int32_t mipsdsp_sat_add_i32(int32_t a, int32_t b, ...@@ -175,7 +176,7 @@ static inline int32_t mipsdsp_sat_add_i32(int32_t a, int32_t b,
tempI = a + b; tempI = a + b;
if (MIPSDSP_OVERFLOW(a, b, tempI, 0x80000000)) { if (MIPSDSP_OVERFLOW_ADD(a, b, tempI, 0x80000000)) {
if (a > 0) { if (a > 0) {
tempI = 0x7FFFFFFF; tempI = 0x7FFFFFFF;
} else { } else {
...@@ -858,7 +859,7 @@ static inline uint16_t mipsdsp_sub_i16(int16_t a, int16_t b, CPUMIPSState *env) ...@@ -858,7 +859,7 @@ static inline uint16_t mipsdsp_sub_i16(int16_t a, int16_t b, CPUMIPSState *env)
int16_t temp; int16_t temp;
temp = a - b; temp = a - b;
if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) { if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x8000)) {
set_DSPControl_overflow_flag(1, 20, env); set_DSPControl_overflow_flag(1, 20, env);
} }
...@@ -871,8 +872,8 @@ static inline uint16_t mipsdsp_sat16_sub(int16_t a, int16_t b, ...@@ -871,8 +872,8 @@ static inline uint16_t mipsdsp_sat16_sub(int16_t a, int16_t b,
int16_t temp; int16_t temp;
temp = a - b; temp = a - b;
if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) { if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x8000)) {
if (a > 0) { if (a >= 0) {
temp = 0x7FFF; temp = 0x7FFF;
} else { } else {
temp = 0x8000; temp = 0x8000;
...@@ -889,8 +890,8 @@ static inline uint32_t mipsdsp_sat32_sub(int32_t a, int32_t b, ...@@ -889,8 +890,8 @@ static inline uint32_t mipsdsp_sat32_sub(int32_t a, int32_t b,
int32_t temp; int32_t temp;
temp = a - b; temp = a - b;
if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) { if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x80000000)) {
if (a > 0) { if (a >= 0) {
temp = 0x7FFFFFFF; temp = 0x7FFFFFFF;
} else { } else {
temp = 0x80000000; temp = 0x80000000;
...@@ -1004,7 +1005,7 @@ static inline uint32_t mipsdsp_sub32(int32_t a, int32_t b, CPUMIPSState *env) ...@@ -1004,7 +1005,7 @@ static inline uint32_t mipsdsp_sub32(int32_t a, int32_t b, CPUMIPSState *env)
int32_t temp; int32_t temp;
temp = a - b; temp = a - b;
if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) { if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x80000000)) {
set_DSPControl_overflow_flag(1, 20, env); set_DSPControl_overflow_flag(1, 20, env);
} }
...@@ -1017,7 +1018,7 @@ static inline int32_t mipsdsp_add_i32(int32_t a, int32_t b, CPUMIPSState *env) ...@@ -1017,7 +1018,7 @@ static inline int32_t mipsdsp_add_i32(int32_t a, int32_t b, CPUMIPSState *env)
temp = a + b; temp = a + b;
if (MIPSDSP_OVERFLOW(a, b, temp, 0x80000000)) { if (MIPSDSP_OVERFLOW_ADD(a, b, temp, 0x80000000)) {
set_DSPControl_overflow_flag(1, 20, env); set_DSPControl_overflow_flag(1, 20, env);
} }
...@@ -2494,17 +2495,22 @@ void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt, \ ...@@ -2494,17 +2495,22 @@ void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt, \
int32_t temp63; \ int32_t temp63; \
int64_t dotp, acc; \ int64_t dotp, acc; \
uint64_t temp; \ uint64_t temp; \
bool overflow; \
\ \
dotp = mipsdsp_mul_q31_q31(ac, rs, rt, env); \ dotp = mipsdsp_mul_q31_q31(ac, rs, rt, env); \
acc = ((uint64_t)env->active_tc.HI[ac] << 32) | \ acc = ((uint64_t)env->active_tc.HI[ac] << 32) | \
((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); \ ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); \
if (!is_add) { \ if (is_add) { \
dotp = -dotp; \ temp = acc + dotp; \
overflow = MIPSDSP_OVERFLOW_ADD((uint64_t)acc, (uint64_t)dotp, \
temp, (0x01ull << 63)); \
} else { \
temp = acc - dotp; \
overflow = MIPSDSP_OVERFLOW_SUB((uint64_t)acc, (uint64_t)dotp, \
temp, (0x01ull << 63)); \
} \ } \
\ \
temp = acc + dotp; \ if (overflow) { \
if (MIPSDSP_OVERFLOW((uint64_t)acc, (uint64_t)dotp, temp, \
(0x01ull << 63))) { \
temp63 = (temp >> 63) & 0x01; \ temp63 = (temp >> 63) & 0x01; \
if (temp63 == 1) { \ if (temp63 == 1) { \
temp = (0x01ull << 63) - 1; \ temp = (0x01ull << 63) - 1; \
......
...@@ -12,7 +12,8 @@ int main() ...@@ -12,7 +12,8 @@ int main()
resultdsp = 0x01; resultdsp = 0x01;
__asm __asm
("subq_s.ph %0, %2, %3\n\t" ("wrdsp $0\n\t"
"subq_s.ph %0, %2, %3\n\t"
"rddsp %1\n\t" "rddsp %1\n\t"
: "=r"(rd), "=r"(dsp) : "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt) : "r"(rs), "r"(rt)
...@@ -27,7 +28,24 @@ int main() ...@@ -27,7 +28,24 @@ int main()
resultdsp = 0x01; resultdsp = 0x01;
__asm __asm
("subq_s.ph %0, %2, %3\n\t" ("wrdsp $0\n\t"
"subq_s.ph %0, %2, %3\n\t"
"rddsp %1\n\t"
: "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt)
);
dsp = (dsp >> 20) & 0x01;
assert(dsp == resultdsp);
assert(rd == result);
rs = 0x12340000;
rt = 0x87658000;
result = 0x7FFF7FFF;
resultdsp = 0x01;
__asm
("wrdsp $0\n\t"
"subq_s.ph %0, %2, %3\n\t"
"rddsp %1\n\t" "rddsp %1\n\t"
: "=r"(rd), "=r"(dsp) : "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt) : "r"(rs), "r"(rt)
......
...@@ -12,7 +12,8 @@ int main() ...@@ -12,7 +12,8 @@ int main()
resultdsp = 0x01; resultdsp = 0x01;
__asm __asm
("subq_s.w %0, %2, %3\n\t" ("wrdsp $0\n\t"
"subq_s.w %0, %2, %3\n\t"
"rddsp %1\n\t" "rddsp %1\n\t"
: "=r"(rd), "=r"(dsp) : "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt) : "r"(rs), "r"(rt)
...@@ -24,10 +25,11 @@ int main() ...@@ -24,10 +25,11 @@ int main()
rs = 0x66666; rs = 0x66666;
rt = 0x55555; rt = 0x55555;
result = 0x11111; result = 0x11111;
resultdsp = 0x01; resultdsp = 0x0;
__asm __asm
("subq_s.w %0, %2, %3\n\t" ("wrdsp $0\n\t"
"subq_s.w %0, %2, %3\n\t"
"rddsp %1\n\t" "rddsp %1\n\t"
: "=r"(rd), "=r"(dsp) : "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt) : "r"(rs), "r"(rt)
...@@ -36,23 +38,37 @@ int main() ...@@ -36,23 +38,37 @@ int main()
assert(dsp == resultdsp); assert(dsp == resultdsp);
assert(rd == result); assert(rd == result);
rs = 0x0;
#if 0 rt = 0x80000000;
rs = 0x35555555; result = 0x7FFFFFFF;
rt = 0xf5555555;
result = 0x80000000;
resultdsp = 0x01; resultdsp = 0x01;
__asm __asm
("subq_s.w %0, %2, %3\n\t" ("wrdsp $0\n\t"
"subq_s.w %0, %2, %3\n\t"
"rddsp %1\n\t" "rddsp %1\n\t"
: "=r"(rd), "=r"(dsp) : "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt) : "r"(rs), "r"(rt)
); );
dsp = (dsp >> 20) & 0x01;
assert(dsp == resultdsp);
assert(rd == result);
rs = 0x80000000;
rt = 0x80000000;
result = 0;
resultdsp = 0x00;
__asm
("wrdsp $0\n\t"
"subq_s.w %0, %2, %3\n\t"
"rddsp %1\n\t"
: "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt)
);
dsp = (dsp >> 20) & 0x01; dsp = (dsp >> 20) & 0x01;
assert(dsp == resultdsp); assert(dsp == resultdsp);
assert(rd == result); assert(rd == result);
#endif
return 0; return 0;
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册