2
* fpuset.c -- $Id: fpuset.c,v 1.1 2003/03/08 15:26:48 travo Exp $
3
* set up FPU to trap floating point exceptions
4
* - this is very non-portable, not covered by ANSI C, POSIX, or even C9X
5
* - if you port to a new platform (eg- Ultrix) please contact the author
7
* Copyright (c) 1999. See accompanying LEGAL file for details.
14
extern void u_fpu_setup(int when);
17
/* when = -1 for initial call before setjmp
18
* 0 after each longjmp out of interrupt handler (after setjmp)
19
* 1 inside interrupt handler before signal() re-enables SIGFPE
22
#if defined(FPU_DIGITAL) || defined(FPU_ALPHA_LINUX)
24
/* FPU_ALPHA_LINUX: see README.fpu */
25
/* man pages: exception_intro, ieee */
27
# include <machine/fpu.h>
29
extern void ieee_set_fp_control(long);
30
# define IEEE_TRAP_ENABLE_INV 0x000002
31
# define IEEE_TRAP_ENABLE_DZE 0x000004
32
# define IEEE_TRAP_ENABLE_OVF 0x000008
33
# define IEEE_MAP_DMZ (1UL<<12)
34
# define IEEE_MAP_UMZ (1UL<<13)
39
/* possibly should include IEEE_MAP_DMZ and IEEE_MAP_UMZ
40
* to map denorm inputs and underflowed outputs to zero
41
* --however, these apparently only have an effect for software
42
* completed operations (the hardware always maps underflows to zero)
45
ieee_set_fp_control(IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE |
46
IEEE_TRAP_ENABLE_OVF);
50
#elif defined(FPU_AIX)
52
/* man pages: fp_trap, fp_enable */
58
fp_trap(FP_TRAP_FASTMODE);
59
fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
63
#elif defined(FPU_HPUX)
65
/* man pages: fpsetmask
67
/* HPUX turns off FP_X_* without this (_INCLUDE_HPUX_SOURCE) */
69
#define _HPUX_SOURCE 1
76
fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL); /* 0x1c */
77
fpsetfastmode(1); /* fast underflows */
81
#elif defined(FPU_IRIX)
83
/* man pages: handle_sigfpes, note lethal TRAP_FPE environment variable
85
* note: earlier versions used get_fpc_csr/set_fpc_csr?, sys/fpu.h */
91
extern void u_sigfpe(int sig); /* from handler.c (or fputest.c) */
92
handle_sigfpes(_ON, _EN_OVERFL|_EN_DIVZERO|_EN_INVALID,
93
(void (*)())0, _USER_HANDLER, (void (*)())&u_sigfpe);
97
#elif defined(FPU_SOLARIS)
99
/* man pages: fpsetmask
100
* Sun's -fnonstd compiler switch switches between __fnonstd.o
101
* and __fstd.o under Solaris, as far as I can tell. Use FPU_IGNORE
105
u_fpu_setup(int when)
108
fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL);
109
/* this doesn't set the "nonstandard arithmetic" bit, which prevents
110
* software emulation of IEEE gradual underflow
111
* -- apparently no way to do this in libc (see FPU_GCC_SPARC) */
115
#elif defined(FPU_SUN4)
117
/* man pages: ieee_handler
118
* nonstandard_arithmetic is undocumented, but rumored
119
* to be important to get rapid underflows
120
* library: -lsunmath (under /usr/lang hierarchy)
121
* may also be in -lm (standard libm)?
122
* note: libsunmath.a is provided by Sun only if you purchase their
123
* compilers; if you are trying to compile with gcc on a SPARC
124
* architecture, try FPU_GCC_SPARC
125
* Sun's -fnonstd compiler switch buggers crt1.o under SunOS 4,
126
* as far as I can tell. Use FPU_IGNORE if you do this
127
* (not possible with gcc?). */
129
u_fpu_setup(int when)
132
extern void u_sigfpe(int sig); /* from handler.c (or fputest.c) */
133
nonstandard_arithmetic();
134
ieee_handler("set","common", &u_sigfpe);
138
#elif defined(FPU_UNICOS)
140
/* delivers SIGFPE by default, this just arranges to trap on
141
* libm errors as well */
143
u_fpu_setup(int when)
151
#elif defined(FPU_GNU_FENV)
153
/* GCC enhanced C9X fenv.h interface by adding feenableexcept */
156
u_fpu_setup(int when)
159
feenableexcept(FE_DIVBYZERO | FE_OVERFLOW | FE_INVALID);
162
#elif defined(FPU_GCC_I86)
164
/* see also: fpu_control.h or i386/fpu_control.h, __setfpucw function */
166
u_fpu_setup(int when)
169
unsigned int fpucw = 0x1372;
170
__asm__ ("fldcw %0" : : "m" (fpucw));
174
#elif defined(FPU_GCC_POWERPC)
177
u_fpu_setup(int when)
180
unsigned int tmp[2] __attribute__ ((__aligned__(8)));
181
tmp[0] = 0xFFF80000; /* More-or-less arbitrary; this is a QNaN. */
183
__asm__ ("lfd 0,%0; mtfsf 255,0" : : "m" (*tmp) : "fr0");
187
#elif defined(FPU_GCC_SPARC)
190
u_fpu_setup(int when)
193
unsigned int fpucw = 0xd400000; /* the 4 is nonstandard arithmetic bit */
194
__asm__ ("ld %0,%%fsr" : : "m" (fpucw));
198
#elif defined(FPU_GCC_M68K)
200
/* works on NeXT as well as m68k Linux */
202
u_fpu_setup(int when)
205
asm("fmovel #0x7400,fpcr"); /* set OVFL and ZD bits */
206
/* unsigned int fpucw = 0x7400;
207
* __asm__ volatile ("fmove%.l %0, %!" : : "dm" (fpucw)); */
208
/* includes bit to trap on signalling NaN (may affect libm behavior) */
212
#elif defined(FPU_GCC_ARM)
215
u_fpu_setup(int when)
218
unsigned int fpucw = 0x70200;
219
__asm__ ("wfs %0" : : "r" (fpucw));
220
/* includes bit to trap on signalling NaN (may affect libm behavior) */
224
#elif defined(FPU_IGNORE)
227
u_fpu_setup(int when)
231
#elif defined(FPU_MACOSX)
233
#include <architecture/ppc/fp_regs.h>
234
#include <mach/mach.h>
237
static void *fpu_fpe_enable(void *arg);
238
#define FE0_MASK (1<<11)
239
#define FE1_MASK (1<<8)
240
/* FE0 FE1 exceptions enabled if either FE0 or FE1 set
241
* 0 0 -- floating-point exceptions disabled
242
* 0 1 -- floating-point imprecise nonrecoverable
243
* 1 0 -- floating-point imprecise recoverable
244
* 1 1 -- floating-point precise mode
246
/* for Darwin version 6.0 (MacOS X 10.2) FE0=FE1=1 initially
247
* for Darwin version 5.5 (MacOS X <=10.1) FE0=FE1=0 initially
248
* Darwin 5.5 resets MSR to FE0=FE1=0 after each SIGFPE
249
* Darwin 6.0 does not reset MSR? leave MSR reset code in case?
252
/* a thread cannot get or set its own MSR bits */
254
fpu_fpe_enable(void *arg)
256
thread_t t = *(thread_t *)arg;
257
struct ppc_thread_state state;
258
unsigned int state_size = PPC_THREAD_STATE_COUNT;
259
if (thread_get_state(t, PPC_THREAD_STATE,
260
(natural_t *)&state, &state_size) == KERN_SUCCESS) {
261
state.srr1 |= FE1_MASK;
262
state.srr1 &= ~FE0_MASK;
263
thread_set_state(t, PPC_THREAD_STATE, (natural_t *)&state, state_size);
269
u_fpu_setup(int when)
271
static volatile int looping = 0;
273
ppc_fp_scr_t r = get_fp_scr();
274
/* turn off exception bits to prevent immediate re-fault */
275
r.fx = r.fex = r.vx = r.ox = r.ux = r.zx = r.xx = r.vx_snan = r.vx_isi =
276
r.vx_idi = r.vx_zdz = r.vx_imz = r.vx_xvc = r.vx_cvi = r.vx_soft = 0;
277
/* these only have to be set once, but may as well set anyway */
278
r.ve = 1; /* invalid */
279
r.oe = 1; /* overflow */
280
r.ue = 0; /* underflow */
281
r.ze = 1; /* zero divide */
282
r.xe = 0; /* inexact */
290
thread_t self = mach_thread_self();
294
if (!pthread_create(&enabler, 0, fpu_fpe_enable, &self))
295
pthread_join(enabler, 0);
304
#error <read play/unix/README.fpu for help>