1 /*- 2 * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> 3 * Copyright (c) 2013 Andrew Turner <andrew@FreeBSD.ORG> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #define __fenv_static 31 #include "fenv.h" 32 33 #if defined(__FreeBSD_ARCH_armv6__) || (defined(__ARM_ARCH) && __ARM_ARCH >= 6) 34 #define FENV_ARMv6 35 #endif 36 37 /* When SOFTFP_ABI is defined we are using the softfp ABI. */ 38 #if defined(__VFP_FP__) && !defined(__ARM_PCS_VFP) 39 #define SOFTFP_ABI 40 #endif 41 42 43 #ifndef FENV_MANGLE 44 /* 45 * Hopefully the system ID byte is immutable, so it's valid to use 46 * this as a default environment. 47 */ 48 const fenv_t __fe_dfl_env = 0; 49 #endif 50 51 52 /* If this is a non-mangled softfp version special processing is required */ 53 #if defined(FENV_MANGLE) || !defined(SOFTFP_ABI) || !defined(FENV_ARMv6) 54 55 /* 56 * The following macros map between the softfloat emulator's flags and 57 * the hardware's FPSR. The hardware this file was written for doesn't 58 * have rounding control bits, so we stick those in the system ID byte. 59 */ 60 #ifndef __ARM_PCS_VFP 61 #define __set_env(env, flags, mask, rnd) env = ((flags) \ 62 | (mask)<<_FPUSW_SHIFT \ 63 | (rnd) << 24) 64 #define __env_flags(env) ((env) & FE_ALL_EXCEPT) 65 #define __env_mask(env) (((env) >> _FPUSW_SHIFT) \ 66 & FE_ALL_EXCEPT) 67 #define __env_round(env) (((env) >> 24) & _ROUND_MASK) 68 #include "fenv-softfloat.h" 69 #endif 70 71 #ifdef __GNUC_GNU_INLINE__ 72 #error "This file must be compiled with C99 'inline' semantics" 73 #endif 74 75 extern inline int feclearexcept(int __excepts); 76 extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); 77 extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts); 78 extern inline int feraiseexcept(int __excepts); 79 extern inline int fetestexcept(int __excepts); 80 extern inline int fegetround(void); 81 extern inline int fesetround(int __round); 82 extern inline int fegetenv(fenv_t *__envp); 83 extern inline int feholdexcept(fenv_t *__envp); 84 extern inline int fesetenv(const fenv_t *__envp); 85 extern inline int feupdateenv(const fenv_t *__envp); 86 extern inline int feenableexcept(int __mask); 87 extern inline int fedisableexcept(int __mask); 88 extern inline int fegetexcept(void); 89 90 #else /* !FENV_MANGLE && SOFTFP_ABI */ 91 /* Set by libc when the VFP unit is enabled */ 92 extern int _libc_arm_fpu_present; 93 94 int __softfp_feclearexcept(int __excepts); 95 int __softfp_fegetexceptflag(fexcept_t *__flagp, int __excepts); 96 int __softfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts); 97 int __softfp_feraiseexcept(int __excepts); 98 int __softfp_fetestexcept(int __excepts); 99 int __softfp_fegetround(void); 100 int __softfp_fesetround(int __round); 101 int __softfp_fegetenv(fenv_t *__envp); 102 int __softfp_feholdexcept(fenv_t *__envp); 103 int __softfp_fesetenv(const fenv_t *__envp); 104 int __softfp_feupdateenv(const fenv_t *__envp); 105 int __softfp_feenableexcept(int __mask); 106 int __softfp_fedisableexcept(int __mask); 107 int __softfp_fegetexcept(void); 108 109 int __vfp_feclearexcept(int __excepts); 110 int __vfp_fegetexceptflag(fexcept_t *__flagp, int __excepts); 111 int __vfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts); 112 int __vfp_feraiseexcept(int __excepts); 113 int __vfp_fetestexcept(int __excepts); 114 int __vfp_fegetround(void); 115 int __vfp_fesetround(int __round); 116 int __vfp_fegetenv(fenv_t *__envp); 117 int __vfp_feholdexcept(fenv_t *__envp); 118 int __vfp_fesetenv(const fenv_t *__envp); 119 int __vfp_feupdateenv(const fenv_t *__envp); 120 int __vfp_feenableexcept(int __mask); 121 int __vfp_fedisableexcept(int __mask); 122 int __vfp_fegetexcept(void); 123 124 static int 125 __softfp_round_to_vfp(int round) 126 { 127 128 switch (round) { 129 case FE_TONEAREST: 130 default: 131 return VFP_FE_TONEAREST; 132 case FE_TOWARDZERO: 133 return VFP_FE_TOWARDZERO; 134 case FE_UPWARD: 135 return VFP_FE_UPWARD; 136 case FE_DOWNWARD: 137 return VFP_FE_DOWNWARD; 138 } 139 } 140 141 static int 142 __softfp_round_from_vfp(int round) 143 { 144 145 switch (round) { 146 case VFP_FE_TONEAREST: 147 default: 148 return FE_TONEAREST; 149 case VFP_FE_TOWARDZERO: 150 return FE_TOWARDZERO; 151 case VFP_FE_UPWARD: 152 return FE_UPWARD; 153 case VFP_FE_DOWNWARD: 154 return FE_DOWNWARD; 155 } 156 } 157 158 int feclearexcept(int __excepts) 159 { 160 161 if (_libc_arm_fpu_present) 162 __vfp_feclearexcept(__excepts); 163 __softfp_feclearexcept(__excepts); 164 165 return (0); 166 } 167 168 int fegetexceptflag(fexcept_t *__flagp, int __excepts) 169 { 170 fexcept_t __vfp_flagp; 171 172 __vfp_flagp = 0; 173 if (_libc_arm_fpu_present) 174 __vfp_fegetexceptflag(&__vfp_flagp, __excepts); 175 __softfp_fegetexceptflag(__flagp, __excepts); 176 177 *__flagp |= __vfp_flagp; 178 179 return (0); 180 } 181 182 int fesetexceptflag(const fexcept_t *__flagp, int __excepts) 183 { 184 185 if (_libc_arm_fpu_present) 186 __vfp_fesetexceptflag(__flagp, __excepts); 187 __softfp_fesetexceptflag(__flagp, __excepts); 188 189 return (0); 190 } 191 192 int feraiseexcept(int __excepts) 193 { 194 195 if (_libc_arm_fpu_present) 196 __vfp_feraiseexcept(__excepts); 197 __softfp_feraiseexcept(__excepts); 198 199 return (0); 200 } 201 202 int fetestexcept(int __excepts) 203 { 204 int __got_excepts; 205 206 __got_excepts = 0; 207 if (_libc_arm_fpu_present) 208 __got_excepts = __vfp_fetestexcept(__excepts); 209 __got_excepts |= __softfp_fetestexcept(__excepts); 210 211 return (__got_excepts); 212 } 213 214 int fegetround(void) 215 { 216 217 if (_libc_arm_fpu_present) 218 return __softfp_round_from_vfp(__vfp_fegetround()); 219 return __softfp_fegetround(); 220 } 221 222 int fesetround(int __round) 223 { 224 225 if (_libc_arm_fpu_present) 226 __vfp_fesetround(__softfp_round_to_vfp(__round)); 227 __softfp_fesetround(__round); 228 229 return (0); 230 } 231 232 int fegetenv(fenv_t *__envp) 233 { 234 fenv_t __vfp_envp; 235 236 __vfp_envp = 0; 237 if (_libc_arm_fpu_present) 238 __vfp_fegetenv(&__vfp_envp); 239 __softfp_fegetenv(__envp); 240 *__envp |= __vfp_envp; 241 242 return (0); 243 } 244 245 int feholdexcept(fenv_t *__envp) 246 { 247 fenv_t __vfp_envp; 248 249 __vfp_envp = 0; 250 if (_libc_arm_fpu_present) 251 __vfp_feholdexcept(&__vfp_envp); 252 __softfp_feholdexcept(__envp); 253 *__envp |= __vfp_envp; 254 255 return (0); 256 } 257 258 int fesetenv(const fenv_t *__envp) 259 { 260 261 if (_libc_arm_fpu_present) 262 __vfp_fesetenv(__envp); 263 __softfp_fesetenv(__envp); 264 265 return (0); 266 } 267 268 int feupdateenv(const fenv_t *__envp) 269 { 270 271 if (_libc_arm_fpu_present) 272 __vfp_feupdateenv(__envp); 273 __softfp_feupdateenv(__envp); 274 275 return (0); 276 } 277 278 int feenableexcept(int __mask) 279 { 280 int __unmasked; 281 282 __unmasked = 0; 283 if (_libc_arm_fpu_present) 284 __unmasked = __vfp_feenableexcept(__mask); 285 __unmasked |= __softfp_feenableexcept(__mask); 286 287 return (__unmasked); 288 } 289 290 int fedisableexcept(int __mask) 291 { 292 int __unmasked; 293 294 __unmasked = 0; 295 if (_libc_arm_fpu_present) 296 __unmasked = __vfp_fedisableexcept(__mask); 297 __unmasked |= __softfp_fedisableexcept(__mask); 298 299 return (__unmasked); 300 } 301 302 int fegetexcept(void) 303 { 304 int __unmasked; 305 306 __unmasked = 0; 307 if (_libc_arm_fpu_present) 308 __unmasked = __vfp_fegetexcept(); 309 __unmasked |= __softfp_fegetexcept(); 310 311 return (__unmasked); 312 } 313 314 #endif 315 316