18daa8167SAndrew Turner /*-
28daa8167SAndrew Turner * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
38daa8167SAndrew Turner * All rights reserved.
48daa8167SAndrew Turner *
58daa8167SAndrew Turner * Redistribution and use in source and binary forms, with or without
68daa8167SAndrew Turner * modification, are permitted provided that the following conditions
78daa8167SAndrew Turner * are met:
88daa8167SAndrew Turner * 1. Redistributions of source code must retain the above copyright
98daa8167SAndrew Turner * notice, this list of conditions and the following disclaimer.
108daa8167SAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright
118daa8167SAndrew Turner * notice, this list of conditions and the following disclaimer in the
128daa8167SAndrew Turner * documentation and/or other materials provided with the distribution.
138daa8167SAndrew Turner *
148daa8167SAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
158daa8167SAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
168daa8167SAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
178daa8167SAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
188daa8167SAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
198daa8167SAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
208daa8167SAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
218daa8167SAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
228daa8167SAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
238daa8167SAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
248daa8167SAndrew Turner * SUCH DAMAGE.
258daa8167SAndrew Turner */
268daa8167SAndrew Turner
27*d5d97bedSMike Karels #ifdef __arm__
28*d5d97bedSMike Karels #include <arm/fenv.h>
29*d5d97bedSMike Karels #else /* __arm__ */
30*d5d97bedSMike Karels
318daa8167SAndrew Turner #ifndef _FENV_H_
328daa8167SAndrew Turner #define _FENV_H_
338daa8167SAndrew Turner
348daa8167SAndrew Turner #include <sys/_types.h>
358daa8167SAndrew Turner
368daa8167SAndrew Turner #ifndef __fenv_static
378daa8167SAndrew Turner #define __fenv_static static
388daa8167SAndrew Turner #endif
398daa8167SAndrew Turner
4034cc08e3SAlex Richardson /* The high 32 bits contain fpcr, low 32 contain fpsr. */
418daa8167SAndrew Turner typedef __uint64_t fenv_t;
428daa8167SAndrew Turner typedef __uint64_t fexcept_t;
438daa8167SAndrew Turner
448daa8167SAndrew Turner /* Exception flags */
458daa8167SAndrew Turner #define FE_INVALID 0x00000001
468daa8167SAndrew Turner #define FE_DIVBYZERO 0x00000002
478daa8167SAndrew Turner #define FE_OVERFLOW 0x00000004
488daa8167SAndrew Turner #define FE_UNDERFLOW 0x00000008
498daa8167SAndrew Turner #define FE_INEXACT 0x00000010
508daa8167SAndrew Turner #define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \
518daa8167SAndrew Turner FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
528daa8167SAndrew Turner
538daa8167SAndrew Turner /*
548daa8167SAndrew Turner * Rounding modes
558daa8167SAndrew Turner *
568daa8167SAndrew Turner * We can't just use the hardware bit values here, because that would
578daa8167SAndrew Turner * make FE_UPWARD and FE_DOWNWARD negative, which is not allowed.
588daa8167SAndrew Turner */
598daa8167SAndrew Turner #define FE_TONEAREST 0x0
608daa8167SAndrew Turner #define FE_UPWARD 0x1
618daa8167SAndrew Turner #define FE_DOWNWARD 0x2
628daa8167SAndrew Turner #define FE_TOWARDZERO 0x3
638daa8167SAndrew Turner #define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \
648daa8167SAndrew Turner FE_UPWARD | FE_TOWARDZERO)
658daa8167SAndrew Turner #define _ROUND_SHIFT 22
668daa8167SAndrew Turner
678daa8167SAndrew Turner __BEGIN_DECLS
688daa8167SAndrew Turner
698daa8167SAndrew Turner /* Default floating-point environment */
708daa8167SAndrew Turner extern const fenv_t __fe_dfl_env;
718daa8167SAndrew Turner #define FE_DFL_ENV (&__fe_dfl_env)
728daa8167SAndrew Turner
738daa8167SAndrew Turner /* We need to be able to map status flag positions to mask flag positions */
748daa8167SAndrew Turner #define _FPUSW_SHIFT 8
758daa8167SAndrew Turner #define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT)
768daa8167SAndrew Turner
7758853f4fSEd Maste #define __mrs_fpcr(__r) __asm __volatile("mrs %0, fpcr" : "=r" (__r))
7858853f4fSEd Maste #define __msr_fpcr(__r) __asm __volatile("msr fpcr, %0" : : "r" (__r))
798daa8167SAndrew Turner
8058853f4fSEd Maste #define __mrs_fpsr(__r) __asm __volatile("mrs %0, fpsr" : "=r" (__r))
8158853f4fSEd Maste #define __msr_fpsr(__r) __asm __volatile("msr fpsr, %0" : : "r" (__r))
828daa8167SAndrew Turner
838daa8167SAndrew Turner __fenv_static __inline int
feclearexcept(int __excepts)848daa8167SAndrew Turner feclearexcept(int __excepts)
858daa8167SAndrew Turner {
868daa8167SAndrew Turner fexcept_t __r;
878daa8167SAndrew Turner
8858853f4fSEd Maste __mrs_fpsr(__r);
898daa8167SAndrew Turner __r &= ~__excepts;
908daa8167SAndrew Turner __msr_fpsr(__r);
918daa8167SAndrew Turner return (0);
928daa8167SAndrew Turner }
938daa8167SAndrew Turner
948daa8167SAndrew Turner __fenv_static inline int
fegetexceptflag(fexcept_t * __flagp,int __excepts)958daa8167SAndrew Turner fegetexceptflag(fexcept_t *__flagp, int __excepts)
968daa8167SAndrew Turner {
978daa8167SAndrew Turner fexcept_t __r;
988daa8167SAndrew Turner
9958853f4fSEd Maste __mrs_fpsr(__r);
1008daa8167SAndrew Turner *__flagp = __r & __excepts;
1018daa8167SAndrew Turner return (0);
1028daa8167SAndrew Turner }
1038daa8167SAndrew Turner
1048daa8167SAndrew Turner __fenv_static inline int
fesetexceptflag(const fexcept_t * __flagp,int __excepts)1058daa8167SAndrew Turner fesetexceptflag(const fexcept_t *__flagp, int __excepts)
1068daa8167SAndrew Turner {
1078daa8167SAndrew Turner fexcept_t __r;
1088daa8167SAndrew Turner
10958853f4fSEd Maste __mrs_fpsr(__r);
1108daa8167SAndrew Turner __r &= ~__excepts;
1118daa8167SAndrew Turner __r |= *__flagp & __excepts;
1128daa8167SAndrew Turner __msr_fpsr(__r);
1138daa8167SAndrew Turner return (0);
1148daa8167SAndrew Turner }
1158daa8167SAndrew Turner
1168daa8167SAndrew Turner __fenv_static inline int
feraiseexcept(int __excepts)1178daa8167SAndrew Turner feraiseexcept(int __excepts)
1188daa8167SAndrew Turner {
1198daa8167SAndrew Turner fexcept_t __r;
1208daa8167SAndrew Turner
12158853f4fSEd Maste __mrs_fpsr(__r);
1228daa8167SAndrew Turner __r |= __excepts;
1238daa8167SAndrew Turner __msr_fpsr(__r);
1248daa8167SAndrew Turner return (0);
1258daa8167SAndrew Turner }
1268daa8167SAndrew Turner
1278daa8167SAndrew Turner __fenv_static inline int
fetestexcept(int __excepts)1288daa8167SAndrew Turner fetestexcept(int __excepts)
1298daa8167SAndrew Turner {
1308daa8167SAndrew Turner fexcept_t __r;
1318daa8167SAndrew Turner
13258853f4fSEd Maste __mrs_fpsr(__r);
1338daa8167SAndrew Turner return (__r & __excepts);
1348daa8167SAndrew Turner }
1358daa8167SAndrew Turner
1368daa8167SAndrew Turner __fenv_static inline int
fegetround(void)1378daa8167SAndrew Turner fegetround(void)
1388daa8167SAndrew Turner {
1398daa8167SAndrew Turner fenv_t __r;
1408daa8167SAndrew Turner
14158853f4fSEd Maste __mrs_fpcr(__r);
1428daa8167SAndrew Turner return ((__r >> _ROUND_SHIFT) & _ROUND_MASK);
1438daa8167SAndrew Turner }
1448daa8167SAndrew Turner
1458daa8167SAndrew Turner __fenv_static inline int
fesetround(int __round)1468daa8167SAndrew Turner fesetround(int __round)
1478daa8167SAndrew Turner {
1488daa8167SAndrew Turner fenv_t __r;
1498daa8167SAndrew Turner
1508daa8167SAndrew Turner if (__round & ~_ROUND_MASK)
1518daa8167SAndrew Turner return (-1);
15258853f4fSEd Maste __mrs_fpcr(__r);
1538daa8167SAndrew Turner __r &= ~(_ROUND_MASK << _ROUND_SHIFT);
1548daa8167SAndrew Turner __r |= __round << _ROUND_SHIFT;
1558daa8167SAndrew Turner __msr_fpcr(__r);
1568daa8167SAndrew Turner return (0);
1578daa8167SAndrew Turner }
1588daa8167SAndrew Turner
1598daa8167SAndrew Turner __fenv_static inline int
fegetenv(fenv_t * __envp)1608daa8167SAndrew Turner fegetenv(fenv_t *__envp)
1618daa8167SAndrew Turner {
16234cc08e3SAlex Richardson __uint64_t fpcr;
16334cc08e3SAlex Richardson __uint64_t fpsr;
1648daa8167SAndrew Turner
16534cc08e3SAlex Richardson __mrs_fpcr(fpcr);
16634cc08e3SAlex Richardson __mrs_fpsr(fpsr);
16734cc08e3SAlex Richardson *__envp = fpsr | (fpcr << 32);
1688daa8167SAndrew Turner
1698daa8167SAndrew Turner return (0);
1708daa8167SAndrew Turner }
1718daa8167SAndrew Turner
1728daa8167SAndrew Turner __fenv_static inline int
feholdexcept(fenv_t * __envp)1738daa8167SAndrew Turner feholdexcept(fenv_t *__envp)
1748daa8167SAndrew Turner {
1758daa8167SAndrew Turner fenv_t __r;
1768daa8167SAndrew Turner
17758853f4fSEd Maste __mrs_fpcr(__r);
17834cc08e3SAlex Richardson *__envp = __r << 32;
1798daa8167SAndrew Turner __r &= ~(_ENABLE_MASK);
1808daa8167SAndrew Turner __msr_fpcr(__r);
1818daa8167SAndrew Turner
18258853f4fSEd Maste __mrs_fpsr(__r);
18334cc08e3SAlex Richardson *__envp |= (__uint32_t)__r;
18458853f4fSEd Maste __r &= ~(_ENABLE_MASK);
1858daa8167SAndrew Turner __msr_fpsr(__r);
1868daa8167SAndrew Turner return (0);
1878daa8167SAndrew Turner }
1888daa8167SAndrew Turner
1898daa8167SAndrew Turner __fenv_static inline int
fesetenv(const fenv_t * __envp)1908daa8167SAndrew Turner fesetenv(const fenv_t *__envp)
1918daa8167SAndrew Turner {
1928daa8167SAndrew Turner
19334cc08e3SAlex Richardson __msr_fpcr((*__envp) >> 32);
19434cc08e3SAlex Richardson __msr_fpsr((fenv_t)(__uint32_t)*__envp);
1958daa8167SAndrew Turner return (0);
1968daa8167SAndrew Turner }
1978daa8167SAndrew Turner
1988daa8167SAndrew Turner __fenv_static inline int
feupdateenv(const fenv_t * __envp)1998daa8167SAndrew Turner feupdateenv(const fenv_t *__envp)
2008daa8167SAndrew Turner {
2018daa8167SAndrew Turner fexcept_t __r;
2028daa8167SAndrew Turner
20358853f4fSEd Maste __mrs_fpsr(__r);
2048daa8167SAndrew Turner fesetenv(__envp);
2058daa8167SAndrew Turner feraiseexcept(__r & FE_ALL_EXCEPT);
2068daa8167SAndrew Turner return (0);
2078daa8167SAndrew Turner }
2088daa8167SAndrew Turner
2098daa8167SAndrew Turner #if __BSD_VISIBLE
2108daa8167SAndrew Turner
2118daa8167SAndrew Turner /* We currently provide no external definitions of the functions below. */
2128daa8167SAndrew Turner
2138daa8167SAndrew Turner static inline int
feenableexcept(int __mask)2148daa8167SAndrew Turner feenableexcept(int __mask)
2158daa8167SAndrew Turner {
2168daa8167SAndrew Turner fenv_t __old_r, __new_r;
2178daa8167SAndrew Turner
21858853f4fSEd Maste __mrs_fpcr(__old_r);
2198daa8167SAndrew Turner __new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
2208daa8167SAndrew Turner __msr_fpcr(__new_r);
2218daa8167SAndrew Turner return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
2228daa8167SAndrew Turner }
2238daa8167SAndrew Turner
2248daa8167SAndrew Turner static inline int
fedisableexcept(int __mask)2258daa8167SAndrew Turner fedisableexcept(int __mask)
2268daa8167SAndrew Turner {
2278daa8167SAndrew Turner fenv_t __old_r, __new_r;
2288daa8167SAndrew Turner
22958853f4fSEd Maste __mrs_fpcr(__old_r);
2308daa8167SAndrew Turner __new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
2318daa8167SAndrew Turner __msr_fpcr(__new_r);
2328daa8167SAndrew Turner return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
2338daa8167SAndrew Turner }
2348daa8167SAndrew Turner
2358daa8167SAndrew Turner static inline int
fegetexcept(void)2368daa8167SAndrew Turner fegetexcept(void)
2378daa8167SAndrew Turner {
2388daa8167SAndrew Turner fenv_t __r;
2398daa8167SAndrew Turner
24058853f4fSEd Maste __mrs_fpcr(__r);
2418daa8167SAndrew Turner return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT);
2428daa8167SAndrew Turner }
2438daa8167SAndrew Turner
2448daa8167SAndrew Turner #endif /* __BSD_VISIBLE */
2458daa8167SAndrew Turner
2468daa8167SAndrew Turner __END_DECLS
2478daa8167SAndrew Turner
2488daa8167SAndrew Turner #endif /* !_FENV_H_ */
249*d5d97bedSMike Karels
250*d5d97bedSMike Karels #endif /* __arm__ */
251