提交 45bbbb46 编写于 作者: B bellard

added overflow exceptions in divisions


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1521 c046a42c-6fe2-441c-8c8c-71466251a162
上级 d592d303
...@@ -1209,13 +1209,13 @@ void raise_exception(int exception_index) ...@@ -1209,13 +1209,13 @@ void raise_exception(int exception_index)
#ifdef BUGGY_GCC_DIV64 #ifdef BUGGY_GCC_DIV64
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we /* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
call it from another function */ call it from another function */
uint32_t div32(uint32_t *q_ptr, uint64_t num, uint32_t den) uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den)
{ {
*q_ptr = num / den; *q_ptr = num / den;
return num % den; return num % den;
} }
int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den) int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den)
{ {
*q_ptr = num / den; *q_ptr = num / den;
return num % den; return num % den;
...@@ -1224,8 +1224,8 @@ int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den) ...@@ -1224,8 +1224,8 @@ int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den)
void helper_divl_EAX_T0(void) void helper_divl_EAX_T0(void)
{ {
unsigned int den, q, r; unsigned int den, r;
uint64_t num; uint64_t num, q;
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
den = T0; den = T0;
...@@ -1238,14 +1238,16 @@ void helper_divl_EAX_T0(void) ...@@ -1238,14 +1238,16 @@ void helper_divl_EAX_T0(void)
q = (num / den); q = (num / den);
r = (num % den); r = (num % den);
#endif #endif
if (q > 0xffffffff)
raise_exception(EXCP00_DIVZ);
EAX = (uint32_t)q; EAX = (uint32_t)q;
EDX = (uint32_t)r; EDX = (uint32_t)r;
} }
void helper_idivl_EAX_T0(void) void helper_idivl_EAX_T0(void)
{ {
int den, q, r; int den, r;
int64_t num; int64_t num, q;
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
den = T0; den = T0;
...@@ -1258,6 +1260,8 @@ void helper_idivl_EAX_T0(void) ...@@ -1258,6 +1260,8 @@ void helper_idivl_EAX_T0(void)
q = (num / den); q = (num / den);
r = (num % den); r = (num % den);
#endif #endif
if (q != (int32_t)q)
raise_exception(EXCP00_DIVZ);
EAX = (uint32_t)q; EAX = (uint32_t)q;
EDX = (uint32_t)r; EDX = (uint32_t)r;
} }
...@@ -3254,8 +3258,8 @@ static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) ...@@ -3254,8 +3258,8 @@ static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
} }
} }
/* XXX: overflow support */ /* return TRUE if overflow */
static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
{ {
uint64_t q, r, a1, a0; uint64_t q, r, a1, a0;
int i, qb; int i, qb;
...@@ -3268,6 +3272,8 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) ...@@ -3268,6 +3272,8 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
*plow = q; *plow = q;
*phigh = r; *phigh = r;
} else { } else {
if (a1 >= b)
return 1;
/* XXX: use a better algorithm */ /* XXX: use a better algorithm */
for(i = 0; i < 64; i++) { for(i = 0; i < 64; i++) {
a1 = (a1 << 1) | (a0 >> 63); a1 = (a1 << 1) | (a0 >> 63);
...@@ -3286,9 +3292,11 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) ...@@ -3286,9 +3292,11 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
*plow = a0; *plow = a0;
*phigh = a1; *phigh = a1;
} }
return 0;
} }
static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) /* return TRUE if overflow */
static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
{ {
int sa, sb; int sa, sb;
sa = ((int64_t)*phigh < 0); sa = ((int64_t)*phigh < 0);
...@@ -3297,11 +3305,19 @@ static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) ...@@ -3297,11 +3305,19 @@ static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
sb = (b < 0); sb = (b < 0);
if (sb) if (sb)
b = -b; b = -b;
div64(plow, phigh, b); if (div64(plow, phigh, b) != 0)
if (sa ^ sb) return 1;
if (sa ^ sb) {
if (*plow > (1ULL << 63))
return 1;
*plow = - *plow; *plow = - *plow;
} else {
if (*plow >= (1ULL << 63))
return 1;
}
if (sa) if (sa)
*phigh = - *phigh; *phigh = - *phigh;
return 0;
} }
void helper_mulq_EAX_T0(void) void helper_mulq_EAX_T0(void)
...@@ -3344,7 +3360,8 @@ void helper_divq_EAX_T0(void) ...@@ -3344,7 +3360,8 @@ void helper_divq_EAX_T0(void)
} }
r0 = EAX; r0 = EAX;
r1 = EDX; r1 = EDX;
div64(&r0, &r1, T0); if (div64(&r0, &r1, T0))
raise_exception(EXCP00_DIVZ);
EAX = r0; EAX = r0;
EDX = r1; EDX = r1;
} }
...@@ -3357,7 +3374,8 @@ void helper_idivq_EAX_T0(void) ...@@ -3357,7 +3374,8 @@ void helper_idivq_EAX_T0(void)
} }
r0 = EAX; r0 = EAX;
r1 = EDX; r1 = EDX;
idiv64(&r0, &r1, T0); if (idiv64(&r0, &r1, T0))
raise_exception(EXCP00_DIVZ);
EAX = r0; EAX = r0;
EDX = r1; EDX = r1;
} }
......
...@@ -328,7 +328,6 @@ void OPPROTO op_imulq_T0_T1(void) ...@@ -328,7 +328,6 @@ void OPPROTO op_imulq_T0_T1(void)
#endif #endif
/* division, flags are undefined */ /* division, flags are undefined */
/* XXX: add exceptions for overflow */
void OPPROTO op_divb_AL_T0(void) void OPPROTO op_divb_AL_T0(void)
{ {
...@@ -339,7 +338,10 @@ void OPPROTO op_divb_AL_T0(void) ...@@ -339,7 +338,10 @@ void OPPROTO op_divb_AL_T0(void)
if (den == 0) { if (den == 0) {
raise_exception(EXCP00_DIVZ); raise_exception(EXCP00_DIVZ);
} }
q = (num / den) & 0xff; q = (num / den);
if (q > 0xff)
raise_exception(EXCP00_DIVZ);
q &= 0xff;
r = (num % den) & 0xff; r = (num % den) & 0xff;
EAX = (EAX & ~0xffff) | (r << 8) | q; EAX = (EAX & ~0xffff) | (r << 8) | q;
} }
...@@ -353,7 +355,10 @@ void OPPROTO op_idivb_AL_T0(void) ...@@ -353,7 +355,10 @@ void OPPROTO op_idivb_AL_T0(void)
if (den == 0) { if (den == 0) {
raise_exception(EXCP00_DIVZ); raise_exception(EXCP00_DIVZ);
} }
q = (num / den) & 0xff; q = (num / den);
if (q != (int8_t)q)
raise_exception(EXCP00_DIVZ);
q &= 0xff;
r = (num % den) & 0xff; r = (num % den) & 0xff;
EAX = (EAX & ~0xffff) | (r << 8) | q; EAX = (EAX & ~0xffff) | (r << 8) | q;
} }
...@@ -367,7 +372,10 @@ void OPPROTO op_divw_AX_T0(void) ...@@ -367,7 +372,10 @@ void OPPROTO op_divw_AX_T0(void)
if (den == 0) { if (den == 0) {
raise_exception(EXCP00_DIVZ); raise_exception(EXCP00_DIVZ);
} }
q = (num / den) & 0xffff; q = (num / den);
if (q > 0xffff)
raise_exception(EXCP00_DIVZ);
q &= 0xffff;
r = (num % den) & 0xffff; r = (num % den) & 0xffff;
EAX = (EAX & ~0xffff) | q; EAX = (EAX & ~0xffff) | q;
EDX = (EDX & ~0xffff) | r; EDX = (EDX & ~0xffff) | r;
...@@ -382,7 +390,10 @@ void OPPROTO op_idivw_AX_T0(void) ...@@ -382,7 +390,10 @@ void OPPROTO op_idivw_AX_T0(void)
if (den == 0) { if (den == 0) {
raise_exception(EXCP00_DIVZ); raise_exception(EXCP00_DIVZ);
} }
q = (num / den) & 0xffff; q = (num / den);
if (q != (int16_t)q)
raise_exception(EXCP00_DIVZ);
q &= 0xffff;
r = (num % den) & 0xffff; r = (num % den) & 0xffff;
EAX = (EAX & ~0xffff) | q; EAX = (EAX & ~0xffff) | q;
EDX = (EDX & ~0xffff) | r; EDX = (EDX & ~0xffff) | r;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册