/*- * Copyright (c) 2004-2005 David Schultz * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifdef __arm__ #include #else /* __arm__ */ #ifndef _FENV_H_ #define _FENV_H_ #include #include #ifndef __fenv_static #define __fenv_static static #endif /* The high 32 bits contain fpcr, low 32 contain fpsr. */ typedef __uint64_t fenv_t; typedef __uint64_t fexcept_t; /* Exception flags */ #define FE_INVALID 0x00000001 #define FE_DIVBYZERO 0x00000002 #define FE_OVERFLOW 0x00000004 #define FE_UNDERFLOW 0x00000008 #define FE_INEXACT 0x00000010 #define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) /* * Rounding modes * * We can't just use the hardware bit values here, because that would * make FE_UPWARD and FE_DOWNWARD negative, which is not allowed. */ #define FE_TONEAREST 0x0 #define FE_UPWARD 0x1 #define FE_DOWNWARD 0x2 #define FE_TOWARDZERO 0x3 #define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ FE_UPWARD | FE_TOWARDZERO) #define _ROUND_SHIFT 22 __BEGIN_DECLS /* Default floating-point environment */ extern const fenv_t __fe_dfl_env; #define FE_DFL_ENV (&__fe_dfl_env) /* We need to be able to map status flag positions to mask flag positions */ #define _FPUSW_SHIFT 8 #define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT) #define __mrs_fpcr(__r) __asm __volatile("mrs %0, fpcr" : "=r" (__r)) #define __msr_fpcr(__r) __asm __volatile("msr fpcr, %0" : : "r" (__r)) #define __mrs_fpsr(__r) __asm __volatile("mrs %0, fpsr" : "=r" (__r)) #define __msr_fpsr(__r) __asm __volatile("msr fpsr, %0" : : "r" (__r)) int feclearexcept(int); int fegetexceptflag(fexcept_t *, int); int fesetexceptflag(const fexcept_t *, int); int feraiseexcept(int); int fetestexcept(int); int fegetround(void); int fesetround(int); int fegetenv(fenv_t *); int feholdexcept(fenv_t *); int fesetenv(const fenv_t *); int feupdateenv(const fenv_t *); int feenableexcept(int); int fedisableexcept(int); int fegetexcept(void); #define feclearexcept(a) __feclearexcept_int(a) #define fegetexceptflag(e, a) __fegetexceptflag_int(e, a) #define fesetexceptflag(e, a) __fesetexceptflag_int(e, a) #define feraiseexcept(a) __feraiseexcept_int(a) #define fetestexcept(a) __fetestexcept_int(a) #define fegetround() __fegetround_int() #define fesetround(a) __fesetround_int(a) #define fegetenv(e) __fegetenv_int(e) #define feholdexcept(e) __feholdexcept_int(e) #define fesetenv(e) __fesetenv_int(e) #define feupdateenv(e) __feupdateenv_int(e) #define feenableexcept(a) __feenableexcept_int(a) #define fedisableexcept(a) __fedisableexcept_int(a) #define fegetexcept() __fegetexcept_int() __fenv_static inline int __feclearexcept_int(int __excepts) { fexcept_t __r; __mrs_fpsr(__r); __r &= ~__excepts; __msr_fpsr(__r); return (0); } __fenv_static inline int __fegetexceptflag_int(fexcept_t *__flagp, int __excepts) { fexcept_t __r; __mrs_fpsr(__r); *__flagp = __r & __excepts; return (0); } __fenv_static inline int __fesetexceptflag_int(const fexcept_t *__flagp, int __excepts) { fexcept_t __r; __mrs_fpsr(__r); __r &= ~__excepts; __r |= *__flagp & __excepts; __msr_fpsr(__r); return (0); } __fenv_static inline int __feraiseexcept_int(int __excepts) { fexcept_t __r; __mrs_fpsr(__r); __r |= __excepts; __msr_fpsr(__r); return (0); } __fenv_static inline int __fetestexcept_int(int __excepts) { fexcept_t __r; __mrs_fpsr(__r); return (__r & __excepts); } __fenv_static inline int __fegetround_int(void) { fenv_t __r; __mrs_fpcr(__r); return ((__r >> _ROUND_SHIFT) & _ROUND_MASK); } __fenv_static inline int __fesetround_int(int __round) { fenv_t __r; if (__round & ~_ROUND_MASK) return (-1); __mrs_fpcr(__r); __r &= ~(_ROUND_MASK << _ROUND_SHIFT); __r |= __round << _ROUND_SHIFT; __msr_fpcr(__r); return (0); } __fenv_static inline int __fegetenv_int(fenv_t *__envp) { __uint64_t fpcr; __uint64_t fpsr; __mrs_fpcr(fpcr); __mrs_fpsr(fpsr); *__envp = fpsr | (fpcr << 32); return (0); } __fenv_static inline int __feholdexcept_int(fenv_t *__envp) { fenv_t __r; __mrs_fpcr(__r); *__envp = __r << 32; __r &= ~(_ENABLE_MASK); __msr_fpcr(__r); __mrs_fpsr(__r); *__envp |= (__uint32_t)__r; __r &= ~(_ENABLE_MASK); __msr_fpsr(__r); return (0); } __fenv_static inline int __fesetenv_int(const fenv_t *__envp) { __msr_fpcr((*__envp) >> 32); __msr_fpsr((fenv_t)(__uint32_t)*__envp); return (0); } __fenv_static inline int __feupdateenv_int(const fenv_t *__envp) { fexcept_t __r; __mrs_fpsr(__r); fesetenv(__envp); feraiseexcept(__r & FE_ALL_EXCEPT); return (0); } #if __BSD_VISIBLE static inline int __feenableexcept_int(int __mask) { fenv_t __old_r, __new_r; __mrs_fpcr(__old_r); __new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); __msr_fpcr(__new_r); return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); } static inline int __fedisableexcept_int(int __mask) { fenv_t __old_r, __new_r; __mrs_fpcr(__old_r); __new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); __msr_fpcr(__new_r); return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); } static inline int __fegetexcept_int(void) { fenv_t __r; __mrs_fpcr(__r); return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT); } #endif /* __BSD_VISIBLE */ __END_DECLS #endif /* !_FENV_H_ */ #endif /* __arm__ */