Commit 51fe68905b7638799d32668776a589b546c5fb38
1 parent
7fe70ecc
powerpc div and rint fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@81 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
44 additions
and
0 deletions
op-i386.c
| @@ -412,6 +412,22 @@ void OPPROTO op_idivw_AX_T0(void) | @@ -412,6 +412,22 @@ void OPPROTO op_idivw_AX_T0(void) | ||
| 412 | EDX = (EDX & 0xffff0000) | r; | 412 | EDX = (EDX & 0xffff0000) | r; |
| 413 | } | 413 | } |
| 414 | 414 | ||
| 415 | +#ifdef BUGGY_GCC_DIV64 | ||
| 416 | +/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we | ||
| 417 | + call it from another function */ | ||
| 418 | +uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den) | ||
| 419 | +{ | ||
| 420 | + *q_ptr = num / den; | ||
| 421 | + return num % den; | ||
| 422 | +} | ||
| 423 | + | ||
| 424 | +int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den) | ||
| 425 | +{ | ||
| 426 | + *q_ptr = num / den; | ||
| 427 | + return num % den; | ||
| 428 | +} | ||
| 429 | +#endif | ||
| 430 | + | ||
| 415 | void OPPROTO op_divl_EAX_T0(void) | 431 | void OPPROTO op_divl_EAX_T0(void) |
| 416 | { | 432 | { |
| 417 | unsigned int den, q, r; | 433 | unsigned int den, q, r; |
| @@ -421,8 +437,12 @@ void OPPROTO op_divl_EAX_T0(void) | @@ -421,8 +437,12 @@ void OPPROTO op_divl_EAX_T0(void) | ||
| 421 | den = T0; | 437 | den = T0; |
| 422 | if (den == 0) | 438 | if (den == 0) |
| 423 | raise_exception(EXCP00_DIVZ); | 439 | raise_exception(EXCP00_DIVZ); |
| 440 | +#ifdef BUGGY_GCC_DIV64 | ||
| 441 | + r = div64(&q, num, den); | ||
| 442 | +#else | ||
| 424 | q = (num / den); | 443 | q = (num / den); |
| 425 | r = (num % den); | 444 | r = (num % den); |
| 445 | +#endif | ||
| 426 | EAX = q; | 446 | EAX = q; |
| 427 | EDX = r; | 447 | EDX = r; |
| 428 | } | 448 | } |
| @@ -436,8 +456,12 @@ void OPPROTO op_idivl_EAX_T0(void) | @@ -436,8 +456,12 @@ void OPPROTO op_idivl_EAX_T0(void) | ||
| 436 | den = T0; | 456 | den = T0; |
| 437 | if (den == 0) | 457 | if (den == 0) |
| 438 | raise_exception(EXCP00_DIVZ); | 458 | raise_exception(EXCP00_DIVZ); |
| 459 | +#ifdef BUGGY_GCC_DIV64 | ||
| 460 | + r = idiv64(&q, num, den); | ||
| 461 | +#else | ||
| 439 | q = (num / den); | 462 | q = (num / den); |
| 440 | r = (num % den); | 463 | r = (num % den); |
| 464 | +#endif | ||
| 441 | EAX = q; | 465 | EAX = q; |
| 442 | EDX = r; | 466 | EDX = r; |
| 443 | } | 467 | } |
| @@ -1503,6 +1527,26 @@ extern CPU86_LDouble floor(CPU86_LDouble x); | @@ -1503,6 +1527,26 @@ extern CPU86_LDouble floor(CPU86_LDouble x); | ||
| 1503 | extern CPU86_LDouble ceil(CPU86_LDouble x); | 1527 | extern CPU86_LDouble ceil(CPU86_LDouble x); |
| 1504 | extern CPU86_LDouble rint(CPU86_LDouble x); | 1528 | extern CPU86_LDouble rint(CPU86_LDouble x); |
| 1505 | 1529 | ||
| 1530 | +#if defined(__powerpc__) | ||
| 1531 | +extern CPU86_LDouble copysign(CPU86_LDouble, CPU86_LDouble); | ||
| 1532 | + | ||
| 1533 | +/* correct (but slow) PowerPC rint() (glibc version is incorrect) */ | ||
| 1534 | +double qemu_rint(double x) | ||
| 1535 | +{ | ||
| 1536 | + double y = 4503599627370496.0; | ||
| 1537 | + if (fabs(x) >= y) | ||
| 1538 | + return x; | ||
| 1539 | + if (x < 0) | ||
| 1540 | + y = -y; | ||
| 1541 | + y = (x + y) - y; | ||
| 1542 | + if (y == 0.0) | ||
| 1543 | + y = copysign(y, x); | ||
| 1544 | + return y; | ||
| 1545 | +} | ||
| 1546 | + | ||
| 1547 | +#define rint qemu_rint | ||
| 1548 | +#endif | ||
| 1549 | + | ||
| 1506 | #define RC_MASK 0xc00 | 1550 | #define RC_MASK 0xc00 |
| 1507 | #define RC_NEAR 0x000 | 1551 | #define RC_NEAR 0x000 |
| 1508 | #define RC_DOWN 0x400 | 1552 | #define RC_DOWN 0x400 |