1 |
< |
/* $MidnightBSD$ */ |
1 |
> |
/* $MidnightBSD: src/sys/i386/include/ieeefp.h,v 1.2 2012/03/31 17:05:09 laffer1 Exp $ */ |
2 |
|
/*- |
3 |
+ |
* Copyright (c) 2003 Peter Wemm. |
4 |
|
* Copyright (c) 1990 Andrew Moore, Talke Studio |
5 |
|
* All rights reserved. |
6 |
|
* |
33 |
|
* SUCH DAMAGE. |
34 |
|
* |
35 |
|
* from: @(#) ieeefp.h 1.0 (Berkeley) 9/23/93 |
36 |
< |
* $FreeBSD: src/sys/i386/include/ieeefp.h,v 1.11 2005/03/15 15:53:39 das Exp $ |
36 |
> |
* $FreeBSD$ |
37 |
|
*/ |
38 |
|
|
38 |
– |
/* |
39 |
– |
* IEEE floating point type and constant definitions. |
40 |
– |
*/ |
41 |
– |
|
39 |
|
#ifndef _MACHINE_IEEEFP_H_ |
40 |
|
#define _MACHINE_IEEEFP_H_ |
41 |
|
|
42 |
+ |
/* |
43 |
+ |
* IEEE floating point type, constant and function definitions. |
44 |
+ |
* XXX: FP*FLD and FP*OFF are undocumented pollution. |
45 |
+ |
*/ |
46 |
+ |
|
47 |
|
#ifndef _SYS_CDEFS_H_ |
48 |
|
#error this file needs sys/cdefs.h as a prerequisite |
49 |
|
#endif |
50 |
|
|
51 |
|
/* |
52 |
< |
* FP rounding modes |
52 |
> |
* Rounding modes. |
53 |
|
*/ |
54 |
|
typedef enum { |
55 |
|
FP_RN=0, /* round to nearest */ |
56 |
< |
FP_RM, /* round down to minus infinity */ |
57 |
< |
FP_RP, /* round up to plus infinity */ |
56 |
> |
FP_RM, /* round down towards minus infinity */ |
57 |
> |
FP_RP, /* round up towards plus infinity */ |
58 |
|
FP_RZ /* truncate */ |
59 |
|
} fp_rnd_t; |
60 |
|
|
61 |
|
/* |
62 |
< |
* FP precision modes |
62 |
> |
* Precision (i.e., rounding precision) modes. |
63 |
|
*/ |
64 |
|
typedef enum { |
65 |
|
FP_PS=0, /* 24 bit (single-precision) */ |
71 |
|
#define fp_except_t int |
72 |
|
|
73 |
|
/* |
74 |
< |
* FP exception masks |
74 |
> |
* Exception bit masks. |
75 |
|
*/ |
76 |
|
#define FP_X_INV 0x01 /* invalid operation */ |
77 |
|
#define FP_X_DNML 0x02 /* denormal */ |
82 |
|
#define FP_X_STK 0x40 /* stack fault */ |
83 |
|
|
84 |
|
/* |
85 |
< |
* FP registers |
85 |
> |
* FPU control word bit-field masks. |
86 |
|
*/ |
87 |
< |
#define FP_MSKS_REG 0 /* exception masks */ |
88 |
< |
#define FP_PRC_REG 0 /* precision */ |
89 |
< |
#define FP_RND_REG 0 /* direction */ |
88 |
< |
#define FP_STKY_REG 1 /* sticky flags */ |
87 |
> |
#define FP_MSKS_FLD 0x3f /* exception masks field */ |
88 |
> |
#define FP_PRC_FLD 0x300 /* precision control field */ |
89 |
> |
#define FP_RND_FLD 0xc00 /* rounding control field */ |
90 |
|
|
91 |
|
/* |
92 |
< |
* FP register bit field masks |
92 |
> |
* FPU status word bit-field masks. |
93 |
|
*/ |
93 |
– |
#define FP_MSKS_FLD 0x3f /* exception masks field */ |
94 |
– |
#define FP_PRC_FLD 0x300 /* precision control field */ |
95 |
– |
#define FP_RND_FLD 0xc00 /* round control field */ |
94 |
|
#define FP_STKY_FLD 0x3f /* sticky flags field */ |
95 |
|
|
96 |
|
/* |
97 |
< |
* FP register bit field offsets |
97 |
> |
* FPU control word bit-field offsets (shift counts). |
98 |
|
*/ |
99 |
|
#define FP_MSKS_OFF 0 /* exception masks offset */ |
100 |
|
#define FP_PRC_OFF 8 /* precision control offset */ |
101 |
< |
#define FP_RND_OFF 10 /* round control offset */ |
101 |
> |
#define FP_RND_OFF 10 /* rounding control offset */ |
102 |
> |
|
103 |
> |
/* |
104 |
> |
* FPU status word bit-field offsets (shift counts). |
105 |
> |
*/ |
106 |
|
#define FP_STKY_OFF 0 /* sticky flags offset */ |
107 |
|
|
108 |
|
#ifdef __GNUCLIKE_ASM |
109 |
|
|
110 |
+ |
#define __fldcw(addr) __asm __volatile("fldcw %0" : : "m" (*(addr))) |
111 |
|
#define __fldenv(addr) __asm __volatile("fldenv %0" : : "m" (*(addr))) |
112 |
< |
#define __fnstenv(addr) __asm __volatile("fnstenv %0" : "=m" (*(addr))) |
112 |
> |
#define __fnclex() __asm __volatile("fnclex") |
113 |
|
#define __fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr))) |
114 |
+ |
#define __fnstenv(addr) __asm __volatile("fnstenv %0" : "=m" (*(addr))) |
115 |
|
#define __fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr))) |
116 |
|
|
117 |
|
/* |
118 |
< |
* return the contents of a FP register |
118 |
> |
* Load the control word. Be careful not to trap if there is a currently |
119 |
> |
* unmasked exception (ones that will become freshly unmasked are not a |
120 |
> |
* problem). This case must be handled by a save/restore of the |
121 |
> |
* environment or even of the full x87 state. Accessing the environment |
122 |
> |
* is very inefficient, so only do it when necessary. |
123 |
|
*/ |
124 |
< |
static __inline__ int |
125 |
< |
__fpgetreg(int _reg) |
124 |
> |
static __inline void |
125 |
> |
__fnldcw(unsigned short _cw, unsigned short _newcw) |
126 |
|
{ |
127 |
< |
unsigned short _mem; |
127 |
> |
struct { |
128 |
> |
unsigned _cw; |
129 |
> |
unsigned _other[6]; |
130 |
> |
} _env; |
131 |
> |
unsigned short _sw; |
132 |
|
|
133 |
< |
/*- |
134 |
< |
* This is more efficient than it looks. The switch gets optimized |
135 |
< |
* away if _reg is constant. |
136 |
< |
* |
137 |
< |
* The default case only supports _reg == 0. We could handle more |
138 |
< |
* registers (e.g., tags) using fnstenv, but the interface doesn't |
139 |
< |
* support more. |
140 |
< |
*/ |
129 |
< |
switch(_reg) { |
130 |
< |
default: |
131 |
< |
__fnstcw(&_mem); |
132 |
< |
break; |
133 |
< |
case FP_STKY_REG: |
134 |
< |
__fnstsw(&_mem); |
135 |
< |
break; |
133 |
> |
if ((_cw & FP_MSKS_FLD) != FP_MSKS_FLD) { |
134 |
> |
__fnstsw(&_sw); |
135 |
> |
if (((_sw & ~_cw) & FP_STKY_FLD) != 0) { |
136 |
> |
__fnstenv(&_env); |
137 |
> |
_env._cw = _newcw; |
138 |
> |
__fldenv(&_env); |
139 |
> |
return; |
140 |
> |
} |
141 |
|
} |
142 |
< |
return _mem; |
142 |
> |
__fldcw(&_newcw); |
143 |
|
} |
144 |
|
|
145 |
< |
/* |
146 |
< |
* set a FP mode; return previous mode |
142 |
< |
*/ |
143 |
< |
static __inline__ int |
144 |
< |
__fpsetreg(int _m, int _reg, int _fld, int _off) |
145 |
> |
static __inline fp_rnd_t |
146 |
> |
fpgetround(void) |
147 |
|
{ |
148 |
< |
unsigned _env[7]; |
147 |
< |
unsigned _p; |
148 |
> |
unsigned short _cw; |
149 |
|
|
150 |
< |
/* |
151 |
< |
* _reg == 0 could be handled better using fnstcw/fldcw. |
151 |
< |
*/ |
152 |
< |
__fnstenv(_env); |
153 |
< |
_p = (_env[_reg] & _fld) >> _off; |
154 |
< |
_env[_reg] = (_env[_reg] & ~_fld) | (_m << _off & _fld); |
155 |
< |
__fldenv(_env); |
156 |
< |
return _p; |
150 |
> |
__fnstcw(&_cw); |
151 |
> |
return ((fp_rnd_t)((_cw & FP_RND_FLD) >> FP_RND_OFF)); |
152 |
|
} |
153 |
|
|
154 |
< |
#endif /* __GNUCLIKE_ASM */ |
154 |
> |
static __inline fp_rnd_t |
155 |
> |
fpsetround(fp_rnd_t _m) |
156 |
> |
{ |
157 |
> |
fp_rnd_t _p; |
158 |
> |
unsigned short _cw, _newcw; |
159 |
|
|
160 |
+ |
__fnstcw(&_cw); |
161 |
+ |
_p = (fp_rnd_t)((_cw & FP_RND_FLD) >> FP_RND_OFF); |
162 |
+ |
_newcw = _cw & ~FP_RND_FLD; |
163 |
+ |
_newcw |= (_m << FP_RND_OFF) & FP_RND_FLD; |
164 |
+ |
__fnldcw(_cw, _newcw); |
165 |
+ |
return (_p); |
166 |
+ |
} |
167 |
+ |
|
168 |
+ |
static __inline fp_prec_t |
169 |
+ |
fpgetprec(void) |
170 |
+ |
{ |
171 |
+ |
unsigned short _cw; |
172 |
+ |
|
173 |
+ |
__fnstcw(&_cw); |
174 |
+ |
return ((fp_prec_t)((_cw & FP_PRC_FLD) >> FP_PRC_OFF)); |
175 |
+ |
} |
176 |
+ |
|
177 |
+ |
static __inline fp_prec_t |
178 |
+ |
fpsetprec(fp_prec_t _m) |
179 |
+ |
{ |
180 |
+ |
fp_prec_t _p; |
181 |
+ |
unsigned short _cw, _newcw; |
182 |
+ |
|
183 |
+ |
__fnstcw(&_cw); |
184 |
+ |
_p = (fp_prec_t)((_cw & FP_PRC_FLD) >> FP_PRC_OFF); |
185 |
+ |
_newcw = _cw & ~FP_PRC_FLD; |
186 |
+ |
_newcw |= (_m << FP_PRC_OFF) & FP_PRC_FLD; |
187 |
+ |
__fnldcw(_cw, _newcw); |
188 |
+ |
return (_p); |
189 |
+ |
} |
190 |
+ |
|
191 |
|
/* |
192 |
< |
* SysV/386 FP control interface |
192 |
> |
* Get or set the exception mask. |
193 |
> |
* Note that the x87 mask bits are inverted by the API -- a mask bit of 1 |
194 |
> |
* means disable for x87 and SSE, but for fp*mask() it means enable. |
195 |
|
*/ |
196 |
< |
#define fpgetround() ((fp_rnd_t) \ |
197 |
< |
((__fpgetreg(FP_RND_REG) & FP_RND_FLD) >> FP_RND_OFF)) |
198 |
< |
#define fpsetround(m) ((fp_rnd_t) \ |
199 |
< |
__fpsetreg((m), FP_RND_REG, FP_RND_FLD, FP_RND_OFF)) |
200 |
< |
#define fpgetprec() ((fp_prec_t) \ |
201 |
< |
((__fpgetreg(FP_PRC_REG) & FP_PRC_FLD) >> FP_PRC_OFF)) |
202 |
< |
#define fpsetprec(m) ((fp_prec_t) \ |
203 |
< |
__fpsetreg((m), FP_PRC_REG, FP_PRC_FLD, FP_PRC_OFF)) |
204 |
< |
#define fpgetmask() ((fp_except_t) \ |
205 |
< |
((~__fpgetreg(FP_MSKS_REG) & FP_MSKS_FLD) >> FP_MSKS_OFF)) |
206 |
< |
#define fpsetmask(m) ((fp_except_t) \ |
207 |
< |
(~__fpsetreg(~(m), FP_MSKS_REG, FP_MSKS_FLD, FP_MSKS_OFF)) & \ |
208 |
< |
(FP_MSKS_FLD >> FP_MSKS_OFF)) |
209 |
< |
#define fpgetsticky() ((fp_except_t) \ |
210 |
< |
((__fpgetreg(FP_STKY_REG) & FP_STKY_FLD) >> FP_STKY_OFF)) |
211 |
< |
#define fpresetsticky(m) ((fp_except_t) \ |
212 |
< |
__fpsetreg(0, FP_STKY_REG, (m), FP_STKY_OFF)) |
196 |
> |
|
197 |
> |
static __inline fp_except_t |
198 |
> |
fpgetmask(void) |
199 |
> |
{ |
200 |
> |
unsigned short _cw; |
201 |
> |
|
202 |
> |
__fnstcw(&_cw); |
203 |
> |
return ((~_cw & FP_MSKS_FLD) >> FP_MSKS_OFF); |
204 |
> |
} |
205 |
> |
|
206 |
> |
static __inline fp_except_t |
207 |
> |
fpsetmask(fp_except_t _m) |
208 |
> |
{ |
209 |
> |
fp_except_t _p; |
210 |
> |
unsigned short _cw, _newcw; |
211 |
> |
|
212 |
> |
__fnstcw(&_cw); |
213 |
> |
_p = (~_cw & FP_MSKS_FLD) >> FP_MSKS_OFF; |
214 |
> |
_newcw = _cw & ~FP_MSKS_FLD; |
215 |
> |
_newcw |= (~_m << FP_MSKS_OFF) & FP_MSKS_FLD; |
216 |
> |
__fnldcw(_cw, _newcw); |
217 |
> |
return (_p); |
218 |
> |
} |
219 |
> |
|
220 |
> |
static __inline fp_except_t |
221 |
> |
fpgetsticky(void) |
222 |
> |
{ |
223 |
> |
unsigned _ex; |
224 |
> |
unsigned short _sw; |
225 |
> |
|
226 |
> |
__fnstsw(&_sw); |
227 |
> |
_ex = (_sw & FP_STKY_FLD) >> FP_STKY_OFF; |
228 |
> |
return ((fp_except_t)_ex); |
229 |
> |
} |
230 |
> |
|
231 |
> |
static __inline fp_except_t |
232 |
> |
fpresetsticky(fp_except_t _m) |
233 |
> |
{ |
234 |
> |
struct { |
235 |
> |
unsigned _cw; |
236 |
> |
unsigned _sw; |
237 |
> |
unsigned _other[5]; |
238 |
> |
} _env; |
239 |
> |
fp_except_t _p; |
240 |
> |
|
241 |
> |
_m &= FP_STKY_FLD >> FP_STKY_OFF; |
242 |
> |
_p = fpgetsticky(); |
243 |
> |
if ((_p & ~_m) == _p) |
244 |
> |
return (_p); |
245 |
> |
if ((_p & ~_m) == 0) { |
246 |
> |
__fnclex(); |
247 |
> |
return (_p); |
248 |
> |
} |
249 |
> |
__fnstenv(&_env); |
250 |
> |
_env._sw &= ~_m; |
251 |
> |
__fldenv(&_env); |
252 |
> |
return (_p); |
253 |
> |
} |
254 |
> |
|
255 |
> |
#endif /* __GNUCLIKE_ASM */ |
256 |
|
|
257 |
|
/* Suppress prototypes in the MI header. */ |
258 |
|
#define _IEEEFP_INLINED_ 1 |