2 * Copyright (c) 2013 The NetBSD Foundation, Inc.
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Matt Thomas of 3am Software Foundry.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/cdefs.h>
31 __RCSID("$NetBSD: fenv.c,v 1.6 2014/12/29 19:11:13 martin Exp $");
33 #include <sys/types.h>
42 #include <sys/signal.h>
43 #include <sys/siginfo.h>
45 #include <arm/armreg.h>
48 #include <arm/vfpreg.h>
50 const fenv_t __fe_dfl_env
= VFP_FPSCR_FZ
|VFP_FPSCR_DN
|VFP_FPSCR_RN
;
53 * The feclearexcept() function shall attempt to clear the supported
54 * floating-point exceptions represented by excepts.
57 feclearexcept(int excepts
)
60 _DIAGASSERT((except
& ~FE_ALL_EXCEPT
) == 0);
63 fpsetsticky(fpgetsticky() & ~excepts
);
66 int tmp
= armreg_fpscr_read() & ~__SHIFTIN(excepts
, VFP_FPSCR_CSUM
);
67 armreg_fpscr_write(tmp
);
73 * The fegetexceptflag() function shall attempt to store an
74 * implementation-defined representation of the states of the floating-point
75 * status flags indicated by the argument excepts in the object pointed to by
79 fegetexceptflag(fexcept_t
*flagp
, int excepts
)
81 _DIAGASSERT((except
& ~FE_ALL_EXCEPT
) == 0);
83 *flagp
= fpgetsticky() & excepts
;
85 *flagp
= __SHIFTOUT(armreg_fpscr_read(), VFP_FPSCR_CSUM
) & excepts
;
91 * The feraiseexcept() function shall attempt to raise the supported
92 * floating-point exceptions represented by the argument excepts. The order
93 * in which these floating-point exceptions are raised is unspecified.
96 feraiseexcept(int excepts
)
99 _DIAGASSERT((except
& ~FE_ALL_EXCEPT
) == 0);
101 #if !defined(__minix) /* LSC: No sigqueueinfo on Minix. */
103 excepts
&= fpgetsticky();
107 memset(&info
, 0, sizeof info
);
108 info
.si_signo
= SIGFPE
;
109 info
.si_pid
= getpid();
110 info
.si_uid
= geteuid();
111 if (excepts
& FE_UNDERFLOW
)
112 info
.si_code
= FPE_FLTUND
;
113 else if (excepts
& FE_OVERFLOW
)
114 info
.si_code
= FPE_FLTOVF
;
115 else if (excepts
& FE_DIVBYZERO
)
116 info
.si_code
= FPE_FLTDIV
;
117 else if (excepts
& FE_INVALID
)
118 info
.si_code
= FPE_FLTINV
;
119 else if (excepts
& FE_INEXACT
)
120 info
.si_code
= FPE_FLTRES
;
121 sigqueueinfo(getpid(), &info
);
124 int fpscr
= armreg_fpscr_read();
125 fpscr
= (fpscr
& ~VFP_FPSCR_ESUM
) | __SHIFTIN(excepts
, VFP_FPSCR_ESUM
);
126 armreg_fpscr_write(fpscr
);
128 #endif /* !defined(__minix) */
133 * The fesetexceptflag() function shall attempt to set the floating-point
134 * status flags indicated by the argument excepts to the states stored in the
135 * object pointed to by flagp. The value pointed to by flagp shall have been
136 * set by a previous call to fegetexceptflag() whose second argument
137 * represented at least those floating-point exceptions represented by the
138 * argument excepts. This function does not raise floating-point exceptions,
139 * but only sets the state of the flags.
142 fesetexceptflag(const fexcept_t
*flagp
, int excepts
)
145 _DIAGASSERT((except
& ~FE_ALL_EXCEPT
) == 0);
148 fpsetsticky((fpgetsticky() & ~excepts
) | (excepts
& *flagp
));
150 int fpscr
= armreg_fpscr_read();
151 fpscr
&= ~__SHIFTIN(excepts
, VFP_FPSCR_CSUM
);
152 fpscr
|= __SHIFTIN((*flagp
& excepts
), VFP_FPSCR_CSUM
);
153 armreg_fpscr_write(fpscr
);
159 feenableexcept(int excepts
)
162 _DIAGASSERT((except
& ~FE_ALL_EXCEPT
) == 0);
165 int old
= fpgetmask();
166 fpsetmask(old
| excepts
);
169 int fpscr
= armreg_fpscr_read();
170 armreg_fpscr_write(fpscr
| __SHIFTIN((excepts
), VFP_FPSCR_ESUM
));
171 return __SHIFTOUT(fpscr
, VFP_FPSCR_ESUM
) & FE_ALL_EXCEPT
;
176 fedisableexcept(int excepts
)
179 _DIAGASSERT((except
& ~FE_ALL_EXCEPT
) == 0);
182 int old
= fpgetmask();
183 fpsetmask(old
& ~excepts
);
186 int fpscr
= armreg_fpscr_read();
187 armreg_fpscr_write(fpscr
& ~__SHIFTIN((excepts
), VFP_FPSCR_ESUM
));
188 return __SHIFTOUT(fpscr
, VFP_FPSCR_ESUM
) & FE_ALL_EXCEPT
;
193 * The fetestexcept() function shall determine which of a specified subset of
194 * the floating-point exception flags are currently set. The excepts argument
195 * specifies the floating-point status flags to be queried.
198 fetestexcept(int excepts
)
200 _DIAGASSERT((except
& ~FE_ALL_EXCEPT
) == 0);
202 return fpgetsticky() & excepts
;
204 return __SHIFTOUT(armreg_fpscr_read(), VFP_FPSCR_CSUM
) & excepts
;
214 return __SHIFTOUT(armreg_fpscr_read(), VFP_FPSCR_ESUM
);
219 * The fegetround() function shall get the current rounding direction.
227 return __SHIFTOUT(armreg_fpscr_read(), VFP_FPSCR_RMODE
);
232 * The fesetround() function shall establish the rounding direction represented
233 * by its argument round. If the argument is not equal to the value of a
234 * rounding direction macro, the rounding direction is not changed.
237 fesetround(int round
)
240 _DIAGASSERT(!(round
& ~__SHIFTOUT(VFP_FPSCR_RMODE
, VFP_FPSCR_RMODE
)));
243 (void)fpsetround(round
);
245 int fpscr
= armreg_fpscr_read() & ~VFP_FPSCR_RMODE
;
246 fpscr
|= __SHIFTIN(round
, VFP_FPSCR_RMODE
);
247 armreg_fpscr_write(fpscr
);
253 * The fegetenv() function shall attempt to store the current floating-point
254 * environment in the object pointed to by envp.
257 fegetenv(fenv_t
*envp
)
260 *envp
= __SHIFTIN(fpgetround(), VFP_FPSCR_RMODE
)
261 | __SHIFTIN(fpgetmask(), VFP_FPSCR_ESUM
)
262 | __SHIFTIN(fpgetsticky(), VFP_FPSCR_CSUM
);
264 *envp
= armreg_fpscr_read();
270 * The feholdexcept() function shall save the current floating-point
271 * environment in the object pointed to by envp, clear the floating-point
272 * status flags, and then install a non-stop (continue on floating-point
273 * exceptions) mode, if available, for all floating-point exceptions.
276 feholdexcept(fenv_t
*envp
)
279 *envp
= __SHIFTIN(fpgetround(), VFP_FPSCR_RMODE
)
280 | __SHIFTIN(fpgetmask(), VFP_FPSCR_ESUM
)
281 | __SHIFTIN(fpgetsticky(), VFP_FPSCR_CSUM
);
285 *envp
= armreg_fpscr_read();
286 armreg_fpscr_write((*envp
) & ~(VFP_FPSCR_ESUM
|VFP_FPSCR_CSUM
));
292 * The fesetenv() function shall attempt to establish the floating-point
293 * environment represented by the object pointed to by envp. The fesetenv()
294 * function does not raise floating-point exceptions, but only installs the
295 * state of the floating-point status flags represented through its argument.
298 fesetenv(const fenv_t
*envp
)
301 (void)fpsetround(__SHIFTIN(*envp
, VFP_FPSCR_RMODE
));
302 (void)fpsetmask(__SHIFTOUT(*envp
, VFP_FPSCR_ESUM
));
303 (void)fpsetsticky(__SHIFTOUT(*envp
, VFP_FPSCR_CSUM
));
305 armreg_fpscr_write(*envp
);
311 * The feupdateenv() function shall attempt to save the currently raised
312 * floating-point exceptions in its automatic storage, attempt to install the
313 * floating-point environment represented by the object pointed to by envp,
314 * and then attempt to raise the saved floating-point exceptions.
317 feupdateenv(const fenv_t
*envp
)
320 _DIAGASSERT(envp
!= NULL
);
323 (void)fpsetround(__SHIFTIN(*envp
, VFP_FPSCR_RMODE
));
324 (void)fpsetmask(fpgetmask() | __SHIFTOUT(*envp
, VFP_FPSCR_ESUM
));
325 (void)fpsetsticky(fpgetsticky() | __SHIFTOUT(*envp
, VFP_FPSCR_CSUM
));
327 int fpscr
= armreg_fpscr_read() & ~(VFP_FPSCR_ESUM
|VFP_FPSCR_CSUM
);
329 armreg_fpscr_write(fpscr
);