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 * $FreeBSD$ 278daa8167SAndrew Turner */ 288daa8167SAndrew Turner 298daa8167SAndrew Turner #ifndef _FENV_H_ 308daa8167SAndrew Turner #define _FENV_H_ 318daa8167SAndrew Turner 328daa8167SAndrew Turner #include <sys/_types.h> 338daa8167SAndrew Turner 348daa8167SAndrew Turner #ifndef __fenv_static 358daa8167SAndrew Turner #define __fenv_static static 368daa8167SAndrew Turner #endif 378daa8167SAndrew Turner 388daa8167SAndrew Turner typedef __uint64_t fenv_t; 398daa8167SAndrew Turner typedef __uint64_t fexcept_t; 408daa8167SAndrew Turner 418daa8167SAndrew Turner /* Exception flags */ 428daa8167SAndrew Turner #define FE_INVALID 0x00000001 438daa8167SAndrew Turner #define FE_DIVBYZERO 0x00000002 448daa8167SAndrew Turner #define FE_OVERFLOW 0x00000004 458daa8167SAndrew Turner #define FE_UNDERFLOW 0x00000008 468daa8167SAndrew Turner #define FE_INEXACT 0x00000010 478daa8167SAndrew Turner #define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ 488daa8167SAndrew Turner FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) 498daa8167SAndrew Turner 508daa8167SAndrew Turner /* 518daa8167SAndrew Turner * Rounding modes 528daa8167SAndrew Turner * 538daa8167SAndrew Turner * We can't just use the hardware bit values here, because that would 548daa8167SAndrew Turner * make FE_UPWARD and FE_DOWNWARD negative, which is not allowed. 558daa8167SAndrew Turner */ 568daa8167SAndrew Turner #define FE_TONEAREST 0x0 578daa8167SAndrew Turner #define FE_UPWARD 0x1 588daa8167SAndrew Turner #define FE_DOWNWARD 0x2 598daa8167SAndrew Turner #define FE_TOWARDZERO 0x3 608daa8167SAndrew Turner #define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ 618daa8167SAndrew Turner FE_UPWARD | FE_TOWARDZERO) 628daa8167SAndrew Turner #define _ROUND_SHIFT 22 638daa8167SAndrew Turner 648daa8167SAndrew Turner __BEGIN_DECLS 658daa8167SAndrew Turner 668daa8167SAndrew Turner /* Default floating-point environment */ 678daa8167SAndrew Turner extern const fenv_t __fe_dfl_env; 688daa8167SAndrew Turner #define FE_DFL_ENV (&__fe_dfl_env) 698daa8167SAndrew Turner 708daa8167SAndrew Turner /* We need to be able to map status flag positions to mask flag positions */ 718daa8167SAndrew Turner #define _FPUSW_SHIFT 8 728daa8167SAndrew Turner #define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT) 738daa8167SAndrew Turner 74*58853f4fSEd Maste #define __mrs_fpcr(__r) __asm __volatile("mrs %0, fpcr" : "=r" (__r)) 75*58853f4fSEd Maste #define __msr_fpcr(__r) __asm __volatile("msr fpcr, %0" : : "r" (__r)) 768daa8167SAndrew Turner 77*58853f4fSEd Maste #define __mrs_fpsr(__r) __asm __volatile("mrs %0, fpsr" : "=r" (__r)) 78*58853f4fSEd Maste #define __msr_fpsr(__r) __asm __volatile("msr fpsr, %0" : : "r" (__r)) 798daa8167SAndrew Turner 808daa8167SAndrew Turner __fenv_static __inline int 818daa8167SAndrew Turner feclearexcept(int __excepts) 828daa8167SAndrew Turner { 838daa8167SAndrew Turner fexcept_t __r; 848daa8167SAndrew Turner 85*58853f4fSEd Maste __mrs_fpsr(__r); 868daa8167SAndrew Turner __r &= ~__excepts; 878daa8167SAndrew Turner __msr_fpsr(__r); 888daa8167SAndrew Turner return (0); 898daa8167SAndrew Turner } 908daa8167SAndrew Turner 918daa8167SAndrew Turner __fenv_static inline int 928daa8167SAndrew Turner fegetexceptflag(fexcept_t *__flagp, int __excepts) 938daa8167SAndrew Turner { 948daa8167SAndrew Turner fexcept_t __r; 958daa8167SAndrew Turner 96*58853f4fSEd Maste __mrs_fpsr(__r); 978daa8167SAndrew Turner *__flagp = __r & __excepts; 988daa8167SAndrew Turner return (0); 998daa8167SAndrew Turner } 1008daa8167SAndrew Turner 1018daa8167SAndrew Turner __fenv_static inline int 1028daa8167SAndrew Turner fesetexceptflag(const fexcept_t *__flagp, int __excepts) 1038daa8167SAndrew Turner { 1048daa8167SAndrew Turner fexcept_t __r; 1058daa8167SAndrew Turner 106*58853f4fSEd Maste __mrs_fpsr(__r); 1078daa8167SAndrew Turner __r &= ~__excepts; 1088daa8167SAndrew Turner __r |= *__flagp & __excepts; 1098daa8167SAndrew Turner __msr_fpsr(__r); 1108daa8167SAndrew Turner return (0); 1118daa8167SAndrew Turner } 1128daa8167SAndrew Turner 1138daa8167SAndrew Turner __fenv_static inline int 1148daa8167SAndrew Turner feraiseexcept(int __excepts) 1158daa8167SAndrew Turner { 1168daa8167SAndrew Turner fexcept_t __r; 1178daa8167SAndrew Turner 118*58853f4fSEd Maste __mrs_fpsr(__r); 1198daa8167SAndrew Turner __r |= __excepts; 1208daa8167SAndrew Turner __msr_fpsr(__r); 1218daa8167SAndrew Turner return (0); 1228daa8167SAndrew Turner } 1238daa8167SAndrew Turner 1248daa8167SAndrew Turner __fenv_static inline int 1258daa8167SAndrew Turner fetestexcept(int __excepts) 1268daa8167SAndrew Turner { 1278daa8167SAndrew Turner fexcept_t __r; 1288daa8167SAndrew Turner 129*58853f4fSEd Maste __mrs_fpsr(__r); 1308daa8167SAndrew Turner return (__r & __excepts); 1318daa8167SAndrew Turner } 1328daa8167SAndrew Turner 1338daa8167SAndrew Turner __fenv_static inline int 1348daa8167SAndrew Turner fegetround(void) 1358daa8167SAndrew Turner { 1368daa8167SAndrew Turner fenv_t __r; 1378daa8167SAndrew Turner 138*58853f4fSEd Maste __mrs_fpcr(__r); 1398daa8167SAndrew Turner return ((__r >> _ROUND_SHIFT) & _ROUND_MASK); 1408daa8167SAndrew Turner } 1418daa8167SAndrew Turner 1428daa8167SAndrew Turner __fenv_static inline int 1438daa8167SAndrew Turner fesetround(int __round) 1448daa8167SAndrew Turner { 1458daa8167SAndrew Turner fenv_t __r; 1468daa8167SAndrew Turner 1478daa8167SAndrew Turner if (__round & ~_ROUND_MASK) 1488daa8167SAndrew Turner return (-1); 149*58853f4fSEd Maste __mrs_fpcr(__r); 1508daa8167SAndrew Turner __r &= ~(_ROUND_MASK << _ROUND_SHIFT); 1518daa8167SAndrew Turner __r |= __round << _ROUND_SHIFT; 1528daa8167SAndrew Turner __msr_fpcr(__r); 1538daa8167SAndrew Turner return (0); 1548daa8167SAndrew Turner } 1558daa8167SAndrew Turner 1568daa8167SAndrew Turner __fenv_static inline int 1578daa8167SAndrew Turner fegetenv(fenv_t *__envp) 1588daa8167SAndrew Turner { 159*58853f4fSEd Maste fenv_t __r; 1608daa8167SAndrew Turner 161*58853f4fSEd Maste __mrs_fpcr(__r); 1628daa8167SAndrew Turner *__envp = __r & _ENABLE_MASK; 1638daa8167SAndrew Turner 164*58853f4fSEd Maste __mrs_fpsr(__r); 1658daa8167SAndrew Turner *__envp |= __r & (FE_ALL_EXCEPT | (_ROUND_MASK << _ROUND_SHIFT)); 1668daa8167SAndrew Turner 1678daa8167SAndrew Turner return (0); 1688daa8167SAndrew Turner } 1698daa8167SAndrew Turner 1708daa8167SAndrew Turner __fenv_static inline int 1718daa8167SAndrew Turner feholdexcept(fenv_t *__envp) 1728daa8167SAndrew Turner { 1738daa8167SAndrew Turner fenv_t __r; 1748daa8167SAndrew Turner 175*58853f4fSEd Maste __mrs_fpcr(__r); 1768daa8167SAndrew Turner *__envp = __r & _ENABLE_MASK; 1778daa8167SAndrew Turner __r &= ~(_ENABLE_MASK); 1788daa8167SAndrew Turner __msr_fpcr(__r); 1798daa8167SAndrew Turner 180*58853f4fSEd Maste __mrs_fpsr(__r); 1818daa8167SAndrew Turner *__envp |= __r & (FE_ALL_EXCEPT | (_ROUND_MASK << _ROUND_SHIFT)); 182*58853f4fSEd Maste __r &= ~(_ENABLE_MASK); 1838daa8167SAndrew Turner __msr_fpsr(__r); 1848daa8167SAndrew Turner return (0); 1858daa8167SAndrew Turner } 1868daa8167SAndrew Turner 1878daa8167SAndrew Turner __fenv_static inline int 1888daa8167SAndrew Turner fesetenv(const fenv_t *__envp) 1898daa8167SAndrew Turner { 1908daa8167SAndrew Turner 1918daa8167SAndrew Turner __msr_fpcr((*__envp) & _ENABLE_MASK); 192*58853f4fSEd Maste __msr_fpsr((*__envp) & (FE_ALL_EXCEPT | (_ROUND_MASK << _ROUND_SHIFT))); 1938daa8167SAndrew Turner return (0); 1948daa8167SAndrew Turner } 1958daa8167SAndrew Turner 1968daa8167SAndrew Turner __fenv_static inline int 1978daa8167SAndrew Turner feupdateenv(const fenv_t *__envp) 1988daa8167SAndrew Turner { 1998daa8167SAndrew Turner fexcept_t __r; 2008daa8167SAndrew Turner 201*58853f4fSEd Maste __mrs_fpsr(__r); 2028daa8167SAndrew Turner fesetenv(__envp); 2038daa8167SAndrew Turner feraiseexcept(__r & FE_ALL_EXCEPT); 2048daa8167SAndrew Turner return (0); 2058daa8167SAndrew Turner } 2068daa8167SAndrew Turner 2078daa8167SAndrew Turner #if __BSD_VISIBLE 2088daa8167SAndrew Turner 2098daa8167SAndrew Turner /* We currently provide no external definitions of the functions below. */ 2108daa8167SAndrew Turner 2118daa8167SAndrew Turner static inline int 2128daa8167SAndrew Turner feenableexcept(int __mask) 2138daa8167SAndrew Turner { 2148daa8167SAndrew Turner fenv_t __old_r, __new_r; 2158daa8167SAndrew Turner 216*58853f4fSEd Maste __mrs_fpcr(__old_r); 2178daa8167SAndrew Turner __new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); 2188daa8167SAndrew Turner __msr_fpcr(__new_r); 2198daa8167SAndrew Turner return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); 2208daa8167SAndrew Turner } 2218daa8167SAndrew Turner 2228daa8167SAndrew Turner static inline int 2238daa8167SAndrew Turner fedisableexcept(int __mask) 2248daa8167SAndrew Turner { 2258daa8167SAndrew Turner fenv_t __old_r, __new_r; 2268daa8167SAndrew Turner 227*58853f4fSEd Maste __mrs_fpcr(__old_r); 2288daa8167SAndrew Turner __new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); 2298daa8167SAndrew Turner __msr_fpcr(__new_r); 2308daa8167SAndrew Turner return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); 2318daa8167SAndrew Turner } 2328daa8167SAndrew Turner 2338daa8167SAndrew Turner static inline int 2348daa8167SAndrew Turner fegetexcept(void) 2358daa8167SAndrew Turner { 2368daa8167SAndrew Turner fenv_t __r; 2378daa8167SAndrew Turner 238*58853f4fSEd Maste __mrs_fpcr(__r); 2398daa8167SAndrew Turner return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT); 2408daa8167SAndrew Turner } 2418daa8167SAndrew Turner 2428daa8167SAndrew Turner #endif /* __BSD_VISIBLE */ 2438daa8167SAndrew Turner 2448daa8167SAndrew Turner __END_DECLS 2458daa8167SAndrew Turner 2468daa8167SAndrew Turner #endif /* !_FENV_H_ */ 247