Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

506 lines
12 KiB

/***
*ieee.c - ieee control and status routines
*
* Copyright (c) 1985-91, Microsoft Corporation
* Copyright (c) 1993, Digital Equipment Corporation
*
*Purpose:
* IEEE control and status routines.
*
*Revision History:
*
* 04-01-02 GDP Rewritten to use abstract control and status words
* 10-30-92 GDP fpreset now modifies the saved fp context if called
* from a signal handler
* 07-14-93 TVB Adapted for Alpha AXP.
* 04-20-95 haslock Modifications to support EV4.5 and EV5
*
*/
// #include <trans.h>
#include <float.h>
#include <nt.h>
#include <signal.h>
//
// Define forward referenced function prototypes.
//
static unsigned int _abstract_sw(unsigned int sw);
static unsigned int _abstract_cw(unsigned int cw, __int64 fpcr);
static unsigned __int64 _hw_cw(unsigned int abstr);
static unsigned int _soft_cw(unsigned int abstr);
//
// Define assembly assist function prototypes.
//
extern unsigned __int64 _get_fpcr();
extern unsigned int _get_softfpcr();
extern void _set_fpcr(unsigned __int64);
extern void _set_softfpcr(unsigned int);
//
// Define Alpha AXP (hardware) FPCR bits.
//
#define FPCR_ROUND_CHOP ((__int64)0x0000000000000000)
#define FPCR_ROUND_DOWN ((__int64)0x0400000000000000)
#define FPCR_ROUND_NEAR ((__int64)0x0800000000000000)
#define FPCR_ROUND_UP ((__int64)0x0c00000000000000)
#define FPCR_ROUND_MASK ((__int64)0x0c00000000000000)
#define FPCR_DISABLE_INVALID ((__int64)0x0002000000000000)
#define FPCR_DISABLE_DIVISION_BY_ZERO ((__int64)0x0004000000000000)
#define FPCR_DISABLE_OVERFLOW ((__int64)0x0008000000000000)
#define FPCR_DISABLE_UNDERFLOW ((__int64)0x2000000000000000)
#define FPCR_DISABLE_INEXACT ((__int64)0x4000000000000000)
#define FPCR_UNDERFLOW_TO_ZERO_ENABLE ((__int64)0x1000000000000000)
#define FPCR_STATUS_INVALID ((__int64)0x0010000000000000)
#define FPCR_STATUS_DIVISION_BY_ZERO ((__int64)0x0020000000000000)
#define FPCR_STATUS_OVERFLOW ((__int64)0x0040000000000000)
#define FPCR_STATUS_UNDERFLOW ((__int64)0x0080000000000000)
#define FPCR_STATUS_INEXACT ((__int64)0x0100000000000000)
#define FPCR_STATUS_SUMMARY ((__int64)0x8000000000000000)
#define FPCR_STATUS_MASK ((__int64)0x81f0000000000000)
#define FPCR_DISABLE_MASK ((__int64)0x700c000000000000)
//
// Define Alpha AXP Software FPCR bits (NT version).
//
#define SW_FPCR_ARITHMETIC_TRAP_IGNORE 0x00000001
#define SW_FPCR_ENABLE_INVALID 0x00000002
#define SW_FPCR_ENABLE_DIVISION_BY_ZERO 0x00000004
#define SW_FPCR_ENABLE_OVERFLOW 0x00000008
#define SW_FPCR_ENABLE_UNDERFLOW 0x00000010
#define SW_FPCR_ENABLE_INEXACT 0x00000020
#define SW_FPCR_DENORMAL_RESULT_ENABLE 0x00001000
#define SW_FPCR_NO_SOFTWARE_EMULATION 0x00002000
#define SW_FPCR_EMULATION_OCCURRED 0x00010000
#define SW_FPCR_STATUS_INVALID 0x00020000
#define SW_FPCR_STATUS_DIVISION_BY_ZERO 0x00040000
#define SW_FPCR_STATUS_OVERFLOW 0x00080000
#define SW_FPCR_STATUS_UNDERFLOW 0x00100000
#define SW_FPCR_STATUS_INEXACT 0x00200000
#define SW_FPCR_ENABLE_MASK 0x0000003e
#define SW_FPCR_STATUS_MASK 0x003e0000
/***
* _statusfp() -
*
*Purpose:
* return abstract fp status word
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
unsigned int _statusfp()
{
return _abstract_sw(_get_softfpcr());
}
/***
*_clearfp() -
*
*Purpose:
* return abstract status word and clear status
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
unsigned int _clearfp()
{
unsigned __int64 oldFpcr;
unsigned int newstatus;
unsigned int oldstatus;
oldstatus = _get_softfpcr();
newstatus = oldstatus & (~SW_FPCR_STATUS_MASK);
oldFpcr = _get_fpcr() & (FPCR_ROUND_MASK|FPCR_UNDERFLOW_TO_ZERO_ENABLE);
_set_fpcr (oldFpcr);
_set_softfpcr(newstatus);
return _abstract_sw(oldstatus);
}
/***_controlfp
* () -
*
*Purpose:
* return and set abstract user fp control word
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
unsigned int _controlfp(unsigned int newctrl, unsigned int mask)
{
unsigned __int64 oldFpcr;
unsigned __int64 newFpcr;
unsigned int oldCw;
unsigned int newCw;
unsigned int oldabs;
unsigned int newabs;
oldCw = _get_softfpcr();
oldFpcr = _get_fpcr();
oldabs = _abstract_cw(oldCw, oldFpcr);
newabs = (newctrl & mask) | (oldabs & ~mask);
if (mask & (_MCW_DN | _MCW_EM)) {
newCw = _soft_cw(newabs);
_set_softfpcr(newCw);
}
if (mask & (_MCW_RC | _MCW_EM | _MCW_DN)) {
newFpcr = _hw_cw(newabs);
// Fix hardware denormal control to match software bit
if ((newCw & SW_FPCR_DENORMAL_RESULT_ENABLE) == 0 )
newFpcr |= FPCR_UNDERFLOW_TO_ZERO_ENABLE;
else
newFpcr &= ~FPCR_UNDERFLOW_TO_ZERO_ENABLE;
// Only disable a trap if the trap is signaled in the status bit
// and the trap is not enabled.
if (newabs & _MCW_EM) {
if ((newCw & SW_FPCR_STATUS_INVALID) &&
(newCw & SW_FPCR_ENABLE_INVALID == 0 ))
newFpcr |= FPCR_DISABLE_INVALID;
if ((newCw & SW_FPCR_STATUS_DIVISION_BY_ZERO) &&
(newCw & SW_FPCR_ENABLE_DIVISION_BY_ZERO == 0 ))
newFpcr |= FPCR_DISABLE_DIVISION_BY_ZERO;
if ((newCw & SW_FPCR_STATUS_OVERFLOW) &&
(newCw & SW_FPCR_ENABLE_OVERFLOW == 0 ))
newFpcr |= FPCR_DISABLE_OVERFLOW;
if ((newCw & SW_FPCR_STATUS_UNDERFLOW) &&
(newCw & SW_FPCR_ENABLE_UNDERFLOW == 0 ))
newFpcr |= FPCR_DISABLE_UNDERFLOW;
if ((newCw & SW_FPCR_STATUS_INEXACT) &&
(newCw & SW_FPCR_ENABLE_INEXACT == 0 ))
newFpcr |= FPCR_DISABLE_INEXACT;
}
_set_fpcr(newFpcr);
}
return newabs;
} /* _controlfp() */
/***
* _fpreset() - reset fp system
*
*Purpose:
* reset fp environment to the default state
* Also reset saved fp environment if invoked from a user's
* signal handler
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
void _fpreset()
{
PEXCEPTION_POINTERS excptrs = (PEXCEPTION_POINTERS) _pxcptinfoptrs;
unsigned int status;
unsigned __int64 newFpcr;
//
// Clear IEEE status bits. Clear software IEEE trap enable bits.
// Clear denormal enable bit.
//
status = _get_softfpcr();
status &= ~(SW_FPCR_STATUS_MASK | SW_FPCR_ENABLE_MASK |
SW_FPCR_DENORMAL_RESULT_ENABLE);
_set_softfpcr(status);
//
// Set round to nearest mode. Clear FPCR status bits.
// Set Denormal Flush to Zero
//
// Exceptions enabled so first instance can set the status bit
// Exception handler will disable further exceptions if the
// exceptions mask bit is set.
_set_fpcr(FPCR_ROUND_NEAR | FPCR_UNDERFLOW_TO_ZERO_ENABLE);
if (excptrs &&
excptrs->ContextRecord->ContextFlags & CONTEXT_FLOATING_POINT) {
// _fpreset has been invoked by a signal handler which in turn
// has been invoked by the CRT filter routine. In this case
// the saved fp context should be cleared, so that the change take
// effect on continuation.
excptrs->ContextRecord->Fpcr = _get_fpcr();
excptrs->ContextRecord->SoftFpcr = _get_softfpcr();
}
}
/***
* _abstract_cw() - abstract control word
*
*Purpose:
* produce a fp control word in abstracted (machine independent) form
*
*Entry:
* cw: machine control word
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
unsigned int _abstract_cw(unsigned int cw, __int64 fpcr)
{
unsigned int abstr = 0;
//
// Set exception mask bits
//
if ((cw & SW_FPCR_ENABLE_INVALID) == 0)
abstr |= _EM_INVALID;
if ((cw & SW_FPCR_ENABLE_DIVISION_BY_ZERO) == 0)
abstr |= _EM_ZERODIVIDE;
if ((cw & SW_FPCR_ENABLE_OVERFLOW) == 0)
abstr |= _EM_OVERFLOW;
if ((cw & SW_FPCR_ENABLE_UNDERFLOW) == 0)
abstr |= _EM_UNDERFLOW;
if ((cw & SW_FPCR_ENABLE_INEXACT) == 0)
abstr |= _EM_INEXACT;
//
// Set rounding mode
//
// N.B. switch requires 32-bits, so scale quadwords.
//
#define HIGHPART(q) ( (ULONG)((q) >> 32) )
switch ( HIGHPART(fpcr & FPCR_ROUND_MASK) ) {
case HIGHPART(FPCR_ROUND_NEAR) :
abstr |= _RC_NEAR;
break;
case HIGHPART(FPCR_ROUND_UP) :
abstr |= _RC_UP;
break;
case HIGHPART(FPCR_ROUND_DOWN) :
abstr |= _RC_DOWN;
break;
case HIGHPART(FPCR_ROUND_CHOP) :
abstr |= _RC_CHOP;
break;
}
// Precision mode is ignored
//
// Set denormal control
//
if ((cw & SW_FPCR_DENORMAL_RESULT_ENABLE) == 0) {
abstr |= _DN_FLUSH;
}
return abstr;
}
/***
* _hw_cw() - h/w control word
*
*Purpose:
* produce a machine dependent fp control word
*
*
*Entry:
* abstr: abstract control word
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
unsigned __int64 _hw_cw(unsigned int abstr)
{
unsigned __int64 cw = 0;
//
// Set exception mask bits (future chip support).
//
if ((abstr & _EM_INVALID) != 0)
cw |= FPCR_DISABLE_INVALID;
if ((abstr & _EM_ZERODIVIDE) != 0)
cw |= FPCR_DISABLE_DIVISION_BY_ZERO;
if ((abstr & _EM_OVERFLOW) != 0)
cw |= FPCR_DISABLE_OVERFLOW;
if ((abstr & _EM_UNDERFLOW) != 0)
cw |= FPCR_DISABLE_UNDERFLOW;
if ((abstr & _EM_INEXACT) != 0)
cw |= FPCR_DISABLE_INEXACT;
//
// Set rounding mode
//
switch (abstr & _MCW_RC) {
case _RC_NEAR:
cw |= FPCR_ROUND_NEAR;
break;
case _RC_UP:
cw |= FPCR_ROUND_UP;
break;
case _RC_DOWN:
cw |= FPCR_ROUND_DOWN;
break;
case _RC_CHOP:
cw |= FPCR_ROUND_CHOP;
break;
}
//
// Set denormal control
//
if ((abstr & _DN_FLUSH) != 0) {
cw |= FPCR_UNDERFLOW_TO_ZERO_ENABLE;
}
return cw;
}
/***
* _soft_cw() - s/w control word
*
*Purpose:
* produce a machine dependent fp control word
*
*
*Entry:
* abstr: abstract control word
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
unsigned int _soft_cw(unsigned int abstr)
{
unsigned int cw = 0;
//
// Set exception mask bits
//
if ((abstr & _EM_INVALID) == 0)
cw |= SW_FPCR_ENABLE_INVALID;
if ((abstr & _EM_ZERODIVIDE) == 0)
cw |= SW_FPCR_ENABLE_DIVISION_BY_ZERO;
if ((abstr & _EM_OVERFLOW) == 0)
cw |= SW_FPCR_ENABLE_OVERFLOW;
if ((abstr & _EM_UNDERFLOW) == 0)
cw |= SW_FPCR_ENABLE_UNDERFLOW;
if ((abstr & _EM_INEXACT) == 0)
cw |= SW_FPCR_ENABLE_INEXACT;
//
// Set denormal control
//
if ((abstr & _DN_FLUSH) == 0) {
cw |= SW_FPCR_DENORMAL_RESULT_ENABLE;
}
return cw;
}
/***
* _abstract_sw() - abstract fp status word
*
*Purpose:
* produce an abstract (machine independent) fp status word
*
*
*Entry:
* sw: machine status word
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
unsigned int _abstract_sw(unsigned int sw)
{
unsigned int abstr = 0;
if (sw & SW_FPCR_STATUS_INVALID)
abstr |= _EM_INVALID;
if (sw & SW_FPCR_STATUS_DIVISION_BY_ZERO)
abstr |= _EM_ZERODIVIDE;
if (sw & SW_FPCR_STATUS_OVERFLOW)
abstr |= _EM_OVERFLOW;
if (sw & SW_FPCR_STATUS_UNDERFLOW)
abstr |= _EM_UNDERFLOW;
if (sw & SW_FPCR_STATUS_INEXACT)
abstr |= _EM_INEXACT;
return abstr;
}