mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 15:43:00 +00:00
174 lines
3.9 KiB
C
174 lines
3.9 KiB
C
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
|
|
|
|
#include "precomp.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);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
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__ (
|
|
"pushl %%eax \n\t" /* make room on stack */
|
|
"fstcw (%%esp) \n\t"
|
|
"fwait \n\t"
|
|
"popl %%eax \n\t"
|
|
"andl $0xffff, %%eax \n\t" /* OK; we have the old value ready */
|
|
|
|
"movl %1, %%ecx \n\t"
|
|
"notl %%ecx \n\t"
|
|
"andl %%eax, %%ecx \n\t" /* the bits we want to keep */
|
|
|
|
"movl %2, %%edx \n\t"
|
|
"andl %1, %%edx \n\t" /* the bits we want to change */
|
|
|
|
"orl %%ecx, %%edx\n\t" /* the new value */
|
|
"pushl %%edx \n\t"
|
|
"fldcw (%%esp) \n\t"
|
|
"popl %%edx \n\t"
|
|
|
|
:"=a" (__res):"r" (unNew),"r" (unMask): "dx", "cx");
|
|
#else
|
|
#endif /*__GNUC__*/
|
|
return __res;
|
|
#endif
|
|
}
|