mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 17:44:45 +00:00
Fix _control87, the old implementation was terribly wrong and broken.
svn path=/trunk/; revision=11607
This commit is contained in:
parent
9e12bbeae6
commit
d5b047feae
2 changed files with 269 additions and 7 deletions
|
@ -2,19 +2,149 @@
|
|||
|
||||
#include <msvcrt/float.h>
|
||||
|
||||
#define X87_CW_IM (1<<0) /* Invalid operation mask */
|
||||
#define X87_CW_DM (1<<1) /* Denormal operand mask */
|
||||
#define X87_CW_ZM (1<<2) /* Zero divide mask */
|
||||
#define X87_CW_OM (1<<3) /* Overflow mask */
|
||||
#define X87_CW_UM (1<<4) /* Underflow mask */
|
||||
#define X87_CW_PM (1<<5) /* Precision mask */
|
||||
|
||||
#define X87_CW_PC_MASK (3<<8) /* precision control mask */
|
||||
#define X87_CW_PC24 (0<<8) /* 24 bit precision */
|
||||
#define X87_CW_PC53 (2<<8) /* 53 bit precision */
|
||||
#define X87_CW_PC64 (3<<8) /* 64 bit precision */
|
||||
|
||||
#define X87_CW_RC_MASK (3<<10) /* rounding control mask */
|
||||
#define X87_CW_RC_NEAREST (0<<10) /* round to nearest */
|
||||
#define X87_CW_RC_DOWN (1<<10) /* round down */
|
||||
#define X87_CW_RC_UP (2<<10) /* round up */
|
||||
#define X87_CW_RC_ZERO (3<<10) /* round toward zero (chop) */
|
||||
|
||||
#define X87_CW_IC (1<<12) /* infinity control flag */
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
unsigned int _controlfp (unsigned int unNew, unsigned int unMask)
|
||||
{
|
||||
return _control87(unNew,unMask);
|
||||
unsigned int _controlfp(unsigned int unNew, unsigned int unMask)
|
||||
{
|
||||
return _control87(unNew,unMask);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
unsigned int _control87 (unsigned int unNew, unsigned int unMask)
|
||||
{
|
||||
unsigned int _control87(unsigned int unNew, unsigned int unMask)
|
||||
{
|
||||
unsigned int FpuCw;
|
||||
unsigned int DummyCw = 0;
|
||||
|
||||
/* get the controlword */
|
||||
asm volatile("fstcw %0\n\t" : "=m"(FpuCw));
|
||||
FpuCw &= 0x0000ffff;
|
||||
|
||||
/* translate it into _control87 format */
|
||||
if (FpuCw & X87_CW_IM)
|
||||
DummyCw |= _EM_INVALID;
|
||||
if (FpuCw & X87_CW_DM)
|
||||
DummyCw |= _EM_DENORMAL;
|
||||
if (FpuCw & X87_CW_ZM)
|
||||
DummyCw |= _EM_ZERODIVIDE;
|
||||
if (FpuCw & X87_CW_OM)
|
||||
DummyCw |= _EM_OVERFLOW;
|
||||
if (FpuCw & X87_CW_UM)
|
||||
DummyCw |= _EM_UNDERFLOW;
|
||||
if (FpuCw & X87_CW_PM)
|
||||
DummyCw |= _EM_INEXACT;
|
||||
|
||||
switch (FpuCw & X87_CW_PC_MASK)
|
||||
{
|
||||
case X87_CW_PC24:
|
||||
DummyCw |= _PC_24;
|
||||
break;
|
||||
case X87_CW_PC53:
|
||||
DummyCw |= _PC_53;
|
||||
break;
|
||||
case X87_CW_PC64:
|
||||
DummyCw |= _PC_64;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (FpuCw & X87_CW_RC_MASK)
|
||||
{
|
||||
case X87_CW_RC_NEAREST:
|
||||
DummyCw |= _RC_NEAR;
|
||||
break;
|
||||
case X87_CW_RC_DOWN:
|
||||
DummyCw |= _RC_DOWN;
|
||||
break;
|
||||
case X87_CW_RC_UP:
|
||||
DummyCw |= _RC_UP;
|
||||
break;
|
||||
case X87_CW_RC_ZERO:
|
||||
DummyCw |= _RC_CHOP;
|
||||
break;
|
||||
}
|
||||
|
||||
/* unset (un)masked bits */
|
||||
DummyCw &= ~unMask;
|
||||
unNew &= unMask;
|
||||
|
||||
/* set new bits */
|
||||
DummyCw |= unNew;
|
||||
|
||||
/* translate back into x87 format
|
||||
* FIXME: translate infinity control!
|
||||
*/
|
||||
FpuCw = 0;
|
||||
if (DummyCw & _EM_INVALID)
|
||||
FpuCw |= X87_CW_IM;
|
||||
if (DummyCw & _EM_DENORMAL)
|
||||
FpuCw |= X87_CW_DM;
|
||||
if (DummyCw & _EM_ZERODIVIDE)
|
||||
FpuCw |= X87_CW_ZM;
|
||||
if (DummyCw & _EM_OVERFLOW)
|
||||
FpuCw |= X87_CW_OM;
|
||||
if (DummyCw & _EM_UNDERFLOW)
|
||||
FpuCw |= X87_CW_UM;
|
||||
if (DummyCw & _EM_INEXACT)
|
||||
FpuCw |= X87_CW_PM;
|
||||
|
||||
switch (DummyCw & _MCW_PC)
|
||||
{
|
||||
case _PC_24:
|
||||
FpuCw |= X87_CW_PC24;
|
||||
break;
|
||||
case _PC_53:
|
||||
FpuCw |= X87_CW_PC53;
|
||||
break;
|
||||
case _PC_64:
|
||||
default:
|
||||
FpuCw |= X87_CW_PC64;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (DummyCw & _MCW_RC)
|
||||
{
|
||||
case _RC_NEAR:
|
||||
FpuCw |= X87_CW_RC_NEAREST;
|
||||
break;
|
||||
case _RC_DOWN:
|
||||
FpuCw |= X87_CW_RC_DOWN;
|
||||
break;
|
||||
case _RC_UP:
|
||||
FpuCw |= X87_CW_RC_UP;
|
||||
break;
|
||||
case _RC_CHOP:
|
||||
FpuCw |= X87_CW_RC_ZERO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* set controlword */
|
||||
asm volatile("fldcw %0" : : "m"(FpuCw));
|
||||
|
||||
return DummyCw;
|
||||
|
||||
#if 0 /* The follwing is the original code, broken I think! -blight */
|
||||
register unsigned int __res;
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__ (
|
||||
|
@ -36,8 +166,9 @@ __asm__ __volatile__ (
|
|||
"fldcw (%%esp) \n\t"
|
||||
"popl %%edx \n\t"
|
||||
|
||||
:"=r" (__res):"r" (unNew),"r" (unMask): "ax", "dx", "cx");
|
||||
:"=a" (__res):"r" (unNew),"r" (unMask): "dx", "cx");
|
||||
#else
|
||||
#endif /*__GNUC__*/
|
||||
return __res;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -2,6 +2,26 @@
|
|||
|
||||
#include <msvcrt/float.h>
|
||||
|
||||
#define X87_CW_IM (1<<0) /* Invalid operation mask */
|
||||
#define X87_CW_DM (1<<1) /* Denormal operand mask */
|
||||
#define X87_CW_ZM (1<<2) /* Zero divide mask */
|
||||
#define X87_CW_OM (1<<3) /* Overflow mask */
|
||||
#define X87_CW_UM (1<<4) /* Underflow mask */
|
||||
#define X87_CW_PM (1<<5) /* Precision mask */
|
||||
|
||||
#define X87_CW_PC_MASK (3<<8) /* precision control mask */
|
||||
#define X87_CW_PC24 (0<<8) /* 24 bit precision */
|
||||
#define X87_CW_PC53 (2<<8) /* 53 bit precision */
|
||||
#define X87_CW_PC64 (3<<8) /* 64 bit precision */
|
||||
|
||||
#define X87_CW_RC_MASK (3<<10) /* rounding control mask */
|
||||
#define X87_CW_RC_NEAREST (0<<10) /* round to nearest */
|
||||
#define X87_CW_RC_DOWN (1<<10) /* round down */
|
||||
#define X87_CW_RC_UP (2<<10) /* round up */
|
||||
#define X87_CW_RC_ZERO (3<<10) /* round toward zero (chop) */
|
||||
|
||||
#define X87_CW_IC (1<<12) /* infinity control flag */
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
|
@ -15,6 +35,116 @@ unsigned int _controlfp(unsigned int unNew, unsigned int unMask)
|
|||
*/
|
||||
unsigned int _control87(unsigned int unNew, unsigned int unMask)
|
||||
{
|
||||
unsigned int FpuCw;
|
||||
unsigned int DummyCw = 0;
|
||||
|
||||
/* get the controlword */
|
||||
asm volatile("fstcw %0\n\t" : "=m"(FpuCw));
|
||||
FpuCw &= 0x0000ffff;
|
||||
|
||||
/* translate it into _control87 format */
|
||||
if (FpuCw & X87_CW_IM)
|
||||
DummyCw |= _EM_INVALID;
|
||||
if (FpuCw & X87_CW_DM)
|
||||
DummyCw |= _EM_DENORMAL;
|
||||
if (FpuCw & X87_CW_ZM)
|
||||
DummyCw |= _EM_ZERODIVIDE;
|
||||
if (FpuCw & X87_CW_OM)
|
||||
DummyCw |= _EM_OVERFLOW;
|
||||
if (FpuCw & X87_CW_UM)
|
||||
DummyCw |= _EM_UNDERFLOW;
|
||||
if (FpuCw & X87_CW_PM)
|
||||
DummyCw |= _EM_INEXACT;
|
||||
|
||||
switch (FpuCw & X87_CW_PC_MASK)
|
||||
{
|
||||
case X87_CW_PC24:
|
||||
DummyCw |= _PC_24;
|
||||
break;
|
||||
case X87_CW_PC53:
|
||||
DummyCw |= _PC_53;
|
||||
break;
|
||||
case X87_CW_PC64:
|
||||
DummyCw |= _PC_64;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (FpuCw & X87_CW_RC_MASK)
|
||||
{
|
||||
case X87_CW_RC_NEAREST:
|
||||
DummyCw |= _RC_NEAR;
|
||||
break;
|
||||
case X87_CW_RC_DOWN:
|
||||
DummyCw |= _RC_DOWN;
|
||||
break;
|
||||
case X87_CW_RC_UP:
|
||||
DummyCw |= _RC_UP;
|
||||
break;
|
||||
case X87_CW_RC_ZERO:
|
||||
DummyCw |= _RC_CHOP;
|
||||
break;
|
||||
}
|
||||
|
||||
/* unset (un)masked bits */
|
||||
DummyCw &= ~unMask;
|
||||
unNew &= unMask;
|
||||
|
||||
/* set new bits */
|
||||
DummyCw |= unNew;
|
||||
|
||||
/* translate back into x87 format
|
||||
* FIXME: translate infinity control!
|
||||
*/
|
||||
FpuCw = 0;
|
||||
if (DummyCw & _EM_INVALID)
|
||||
FpuCw |= X87_CW_IM;
|
||||
if (DummyCw & _EM_DENORMAL)
|
||||
FpuCw |= X87_CW_DM;
|
||||
if (DummyCw & _EM_ZERODIVIDE)
|
||||
FpuCw |= X87_CW_ZM;
|
||||
if (DummyCw & _EM_OVERFLOW)
|
||||
FpuCw |= X87_CW_OM;
|
||||
if (DummyCw & _EM_UNDERFLOW)
|
||||
FpuCw |= X87_CW_UM;
|
||||
if (DummyCw & _EM_INEXACT)
|
||||
FpuCw |= X87_CW_PM;
|
||||
|
||||
switch (DummyCw & _MCW_PC)
|
||||
{
|
||||
case _PC_24:
|
||||
FpuCw |= X87_CW_PC24;
|
||||
break;
|
||||
case _PC_53:
|
||||
FpuCw |= X87_CW_PC53;
|
||||
break;
|
||||
case _PC_64:
|
||||
default:
|
||||
FpuCw |= X87_CW_PC64;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (DummyCw & _MCW_RC)
|
||||
{
|
||||
case _RC_NEAR:
|
||||
FpuCw |= X87_CW_RC_NEAREST;
|
||||
break;
|
||||
case _RC_DOWN:
|
||||
FpuCw |= X87_CW_RC_DOWN;
|
||||
break;
|
||||
case _RC_UP:
|
||||
FpuCw |= X87_CW_RC_UP;
|
||||
break;
|
||||
case _RC_CHOP:
|
||||
FpuCw |= X87_CW_RC_ZERO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* set controlword */
|
||||
asm volatile("fldcw %0" : : "m"(FpuCw));
|
||||
|
||||
return DummyCw;
|
||||
|
||||
#if 0 /* The follwing is the original code, broken I think! -blight */
|
||||
register unsigned int __res;
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__ (
|
||||
|
@ -36,8 +166,9 @@ __asm__ __volatile__ (
|
|||
"fldcw (%%esp) \n\t"
|
||||
"popl %%edx \n\t"
|
||||
|
||||
:"=r" (__res):"r" (unNew),"r" (unMask): "ax", "dx", "cx");
|
||||
:"=a" (__res):"r" (unNew),"r" (unMask): "dx", "cx");
|
||||
#else
|
||||
#endif /*__GNUC__*/
|
||||
return __res;
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue