1 /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ 2 3 #include <precomp.h> 4 #include <float.h> 5 6 #define X87_CW_IM (1<<0) /* Invalid operation mask */ 7 #define X87_CW_DM (1<<1) /* Denormal operand mask */ 8 #define X87_CW_ZM (1<<2) /* Zero divide mask */ 9 #define X87_CW_OM (1<<3) /* Overflow mask */ 10 #define X87_CW_UM (1<<4) /* Underflow mask */ 11 #define X87_CW_PM (1<<5) /* Precision mask */ 12 13 #define X87_CW_PC_MASK (3<<8) /* precision control mask */ 14 #define X87_CW_PC24 (0<<8) /* 24 bit precision */ 15 #define X87_CW_PC53 (2<<8) /* 53 bit precision */ 16 #define X87_CW_PC64 (3<<8) /* 64 bit precision */ 17 18 #define X87_CW_RC_MASK (3<<10) /* rounding control mask */ 19 #define X87_CW_RC_NEAREST (0<<10) /* round to nearest */ 20 #define X87_CW_RC_DOWN (1<<10) /* round down */ 21 #define X87_CW_RC_UP (2<<10) /* round up */ 22 #define X87_CW_RC_ZERO (3<<10) /* round toward zero (chop) */ 23 24 #define X87_CW_IC (1<<12) /* infinity control flag */ 25 26 #ifdef _M_AMD64 27 unsigned int __getfpcw87(void); 28 void __setfpcw87(unsigned int); 29 #endif 30 31 /* 32 * @implemented 33 */ 34 35 unsigned int CDECL _controlfp(unsigned int newval, unsigned int mask) 36 { 37 return _control87( newval, mask & ~_EM_DENORMAL ); 38 } 39 40 /********************************************************************* 41 * _control87 (MSVCRT.@) 42 */ 43 unsigned int CDECL _control87(unsigned int newval, unsigned int mask) 44 { 45 unsigned short fpword = 0; 46 unsigned int flags = 0; 47 48 TRACE("(%08x, %08x): Called\n", newval, mask); 49 50 /* Get fp control word */ 51 #ifdef _M_AMD64 52 fpword = __getfpcw87(); 53 #elif defined(__GNUC__) 54 __asm__ __volatile__( "fstcw %0" : "=m" (fpword) : ); 55 #else 56 __asm fstcw [fpword]; 57 #endif 58 59 TRACE("Control word before : %08x\n", fpword); 60 61 /* Convert into mask constants */ 62 if (fpword & 0x1) flags |= _EM_INVALID; 63 if (fpword & 0x2) flags |= _EM_DENORMAL; 64 if (fpword & 0x4) flags |= _EM_ZERODIVIDE; 65 if (fpword & 0x8) flags |= _EM_OVERFLOW; 66 if (fpword & 0x10) flags |= _EM_UNDERFLOW; 67 if (fpword & 0x20) flags |= _EM_INEXACT; 68 switch(fpword & 0xC00) { 69 case 0xC00: flags |= _RC_UP|_RC_DOWN; break; 70 case 0x800: flags |= _RC_UP; break; 71 case 0x400: flags |= _RC_DOWN; break; 72 } 73 switch(fpword & 0x300) { 74 case 0x0: flags |= _PC_24; break; 75 case 0x200: flags |= _PC_53; break; 76 case 0x300: flags |= _PC_64; break; 77 } 78 if (fpword & 0x1000) flags |= _IC_AFFINE; 79 80 /* Mask with parameters */ 81 flags = (flags & ~mask) | (newval & mask); 82 83 /* Convert (masked) value back to fp word */ 84 fpword = 0; 85 if (flags & _EM_INVALID) fpword |= 0x1; 86 if (flags & _EM_DENORMAL) fpword |= 0x2; 87 if (flags & _EM_ZERODIVIDE) fpword |= 0x4; 88 if (flags & _EM_OVERFLOW) fpword |= 0x8; 89 if (flags & _EM_UNDERFLOW) fpword |= 0x10; 90 if (flags & _EM_INEXACT) fpword |= 0x20; 91 switch(flags & (_RC_UP | _RC_DOWN)) { 92 case _RC_UP|_RC_DOWN: fpword |= 0xC00; break; 93 case _RC_UP: fpword |= 0x800; break; 94 case _RC_DOWN: fpword |= 0x400; break; 95 } 96 switch (flags & (_PC_24 | _PC_53)) { 97 case _PC_64: fpword |= 0x300; break; 98 case _PC_53: fpword |= 0x200; break; 99 case _PC_24: fpword |= 0x0; break; 100 } 101 if (flags & _IC_AFFINE) fpword |= 0x1000; 102 103 TRACE("Control word after : %08x\n", fpword); 104 105 /* Put fp control word */ 106 #ifdef _M_AMD64 107 __setfpcw87(fpword); 108 #elif defined(__GNUC__) 109 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) ); 110 #else 111 __asm fldcw [fpword]; 112 #endif 113 114 return flags; 115 } 116 117 /********************************************************************* 118 * _controlfp_s (MSVCRT.@) 119 */ 120 int CDECL _controlfp_s(unsigned int *cur, unsigned int newval, unsigned int mask) 121 { 122 #ifdef __i386__ 123 unsigned int val; 124 125 if (!MSVCRT_CHECK_PMT( !(newval & mask & ~(_MCW_EM | _MCW_IC | _MCW_RC | _MCW_PC | _MCW_DN)))) 126 { 127 if (cur) *cur = _controlfp( 0, 0 ); /* retrieve it anyway */ 128 return EINVAL; 129 } 130 val = _controlfp( newval, mask ); 131 if (cur) *cur = val; 132 return 0; 133 #else 134 FIXME(":Not Implemented!\n"); 135 return 0; 136 #endif 137 } 138