#ifdef BUGGY_GCC_DIV64
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
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;
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;
return num % den;
void helper_divl_EAX_T0(void)
{
- unsigned int den, q, r;
- uint64_t num;
+ unsigned int den, r;
+ uint64_t num, q;
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
den = T0;
q = (num / den);
r = (num % den);
#endif
+ if (q > 0xffffffff)
+ raise_exception(EXCP00_DIVZ);
EAX = (uint32_t)q;
EDX = (uint32_t)r;
}
void helper_idivl_EAX_T0(void)
{
- int den, q, r;
- int64_t num;
+ int den, r;
+ int64_t num, q;
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
den = T0;
q = (num / den);
r = (num % den);
#endif
+ if (q != (int32_t)q)
+ raise_exception(EXCP00_DIVZ);
EAX = (uint32_t)q;
EDX = (uint32_t)r;
}
}
}
-/* XXX: overflow support */
-static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
+/* return TRUE if overflow */
+static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
{
uint64_t q, r, a1, a0;
int i, qb;
*plow = q;
*phigh = r;
} else {
+ if (a1 >= b)
+ return 1;
/* XXX: use a better algorithm */
for(i = 0; i < 64; i++) {
a1 = (a1 << 1) | (a0 >> 63);
*plow = a0;
*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;
sa = ((int64_t)*phigh < 0);
sb = (b < 0);
if (sb)
b = -b;
- div64(plow, phigh, b);
- if (sa ^ sb)
+ if (div64(plow, phigh, b) != 0)
+ return 1;
+ if (sa ^ sb) {
+ if (*plow > (1ULL << 63))
+ return 1;
*plow = - *plow;
+ } else {
+ if (*plow >= (1ULL << 63))
+ return 1;
+ }
if (sa)
*phigh = - *phigh;
+ return 0;
}
void helper_mulq_EAX_T0(void)
}
r0 = EAX;
r1 = EDX;
- div64(&r0, &r1, T0);
+ if (div64(&r0, &r1, T0))
+ raise_exception(EXCP00_DIVZ);
EAX = r0;
EDX = r1;
}
}
r0 = EAX;
r1 = EDX;
- idiv64(&r0, &r1, T0);
+ if (idiv64(&r0, &r1, T0))
+ raise_exception(EXCP00_DIVZ);
EAX = r0;
EDX = r1;
}
#endif
/* division, flags are undefined */
-/* XXX: add exceptions for overflow */
void OPPROTO op_divb_AL_T0(void)
{
if (den == 0) {
raise_exception(EXCP00_DIVZ);
}
- q = (num / den) & 0xff;
+ q = (num / den);
+ if (q > 0xff)
+ raise_exception(EXCP00_DIVZ);
+ q &= 0xff;
r = (num % den) & 0xff;
EAX = (EAX & ~0xffff) | (r << 8) | q;
}
if (den == 0) {
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;
EAX = (EAX & ~0xffff) | (r << 8) | q;
}
if (den == 0) {
raise_exception(EXCP00_DIVZ);
}
- q = (num / den) & 0xffff;
+ q = (num / den);
+ if (q > 0xffff)
+ raise_exception(EXCP00_DIVZ);
+ q &= 0xffff;
r = (num % den) & 0xffff;
EAX = (EAX & ~0xffff) | q;
EDX = (EDX & ~0xffff) | r;
if (den == 0) {
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;
EAX = (EAX & ~0xffff) | q;
EDX = (EDX & ~0xffff) | r;