1 /*- 2 * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #ifndef _FENV_H_ 30 #define _FENV_H_ 31 32 #include <sys/_types.h> 33 34 #ifndef __fenv_static 35 #define __fenv_static static 36 #endif 37 38 typedef __uint32_t fenv_t; 39 typedef __uint32_t fexcept_t; 40 41 /* Exception flags */ 42 #define FE_INVALID 0x0001 43 #define FE_DIVBYZERO 0x0002 44 #define FE_OVERFLOW 0x0004 45 #define FE_UNDERFLOW 0x0008 46 #define FE_INEXACT 0x0010 47 #define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ 48 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) 49 50 /* Rounding modes */ 51 #define FE_TONEAREST 0x0000 52 #define FE_TOWARDZERO 0x0001 53 #define FE_UPWARD 0x0002 54 #define FE_DOWNWARD 0x0003 55 #define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ 56 FE_UPWARD | FE_TOWARDZERO) 57 __BEGIN_DECLS 58 59 /* Default floating-point environment */ 60 extern const fenv_t __fe_dfl_env; 61 #define FE_DFL_ENV (&__fe_dfl_env) 62 63 /* We need to be able to map status flag positions to mask flag positions */ 64 #define _FPUSW_SHIFT 16 65 #define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT) 66 67 #ifndef ARM_HARD_FLOAT 68 69 int feclearexcept(int __excepts); 70 int fegetexceptflag(fexcept_t *__flagp, int __excepts); 71 int fesetexceptflag(const fexcept_t *__flagp, int __excepts); 72 int feraiseexcept(int __excepts); 73 int fetestexcept(int __excepts); 74 int fegetround(void); 75 int fesetround(int __round); 76 int fegetenv(fenv_t *__envp); 77 int feholdexcept(fenv_t *__envp); 78 int fesetenv(const fenv_t *__envp); 79 int feupdateenv(const fenv_t *__envp); 80 81 #else /* ARM_HARD_FLOAT */ 82 83 #define __rfs(__fpsr) __asm __volatile("rfs %0" : "=r" (*(__fpsr))) 84 #define __wfs(__fpsr) __asm __volatile("wfs %0" : : "r" (__fpsr)) 85 86 __fenv_static inline int 87 feclearexcept(int __excepts) 88 { 89 fexcept_t __fpsr; 90 91 __rfs(&__fpsr); 92 __fpsr &= ~__excepts; 93 __wfs(__fpsr); 94 return (0); 95 } 96 97 __fenv_static inline int 98 fegetexceptflag(fexcept_t *__flagp, int __excepts) 99 { 100 fexcept_t __fpsr; 101 102 __rfs(&__fpsr); 103 *__flagp = __fpsr & __excepts; 104 return (0); 105 } 106 107 __fenv_static inline int 108 fesetexceptflag(const fexcept_t *__flagp, int __excepts) 109 { 110 fexcept_t __fpsr; 111 112 __rfs(&__fpsr); 113 __fpsr &= ~__excepts; 114 __fpsr |= *__flagp & __excepts; 115 __wfs(__fpsr); 116 return (0); 117 } 118 119 __fenv_static inline int 120 feraiseexcept(int __excepts) 121 { 122 fexcept_t __ex = __excepts; 123 124 fesetexceptflag(&__ex, __excepts); /* XXX */ 125 return (0); 126 } 127 128 __fenv_static inline int 129 fetestexcept(int __excepts) 130 { 131 fexcept_t __fpsr; 132 133 __rfs(&__fpsr); 134 return (__fpsr & __excepts); 135 } 136 137 __fenv_static inline int 138 fegetround(void) 139 { 140 141 /* 142 * Apparently, the rounding mode is specified as part of the 143 * instruction format on ARM, so the dynamic rounding mode is 144 * indeterminate. Some FPUs may differ. 145 */ 146 return (-1); 147 } 148 149 __fenv_static inline int 150 fesetround(int __round) 151 { 152 153 return (-1); 154 } 155 156 __fenv_static inline int 157 fegetenv(fenv_t *__envp) 158 { 159 160 __rfs(__envp); 161 return (0); 162 } 163 164 __fenv_static inline int 165 feholdexcept(fenv_t *__envp) 166 { 167 fenv_t __env; 168 169 __rfs(&__env); 170 *__envp = __env; 171 __env &= ~(FE_ALL_EXCEPT | _ENABLE_MASK); 172 __wfs(__env); 173 return (0); 174 } 175 176 __fenv_static inline int 177 fesetenv(const fenv_t *__envp) 178 { 179 180 __wfs(*__envp); 181 return (0); 182 } 183 184 __fenv_static inline int 185 feupdateenv(const fenv_t *__envp) 186 { 187 fexcept_t __fpsr; 188 189 __rfs(&__fpsr); 190 __wfs(*__envp); 191 feraiseexcept(__fpsr & FE_ALL_EXCEPT); 192 return (0); 193 } 194 195 #if __BSD_VISIBLE 196 197 /* We currently provide no external definitions of the functions below. */ 198 199 static inline int 200 feenableexcept(int __mask) 201 { 202 fenv_t __old_fpsr, __new_fpsr; 203 204 __rfs(&__old_fpsr); 205 __new_fpsr = __old_fpsr | (__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT; 206 __wfs(__new_fpsr); 207 return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); 208 } 209 210 static inline int 211 fedisableexcept(int __mask) 212 { 213 fenv_t __old_fpsr, __new_fpsr; 214 215 __rfs(&__old_fpsr); 216 __new_fpsr = __old_fpsr & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); 217 __wfs(__new_fpsr); 218 return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); 219 } 220 221 static inline int 222 fegetexcept(void) 223 { 224 fenv_t __fpsr; 225 226 __rfs(&__fpsr); 227 return ((__fpsr & _ENABLE_MASK) >> _FPUSW_SHIFT); 228 } 229 230 #endif /* __BSD_VISIBLE */ 231 232 #endif /* ARM_HARD_FLOAT */ 233 234 __END_DECLS 235 236 #endif /* !_FENV_H_ */ 237