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 #include <machine/acle-compat.h> 34 35 #if __ARM_ARCH >= 6 36 #define FENV_ARMv6 37 #endif 38 39 /* When SOFTFP_ABI is defined we are using the softfp ABI. */ 40 #if defined(__VFP_FP__) && !defined(__ARM_PCS_VFP) 41 #define SOFTFP_ABI 42 #endif 43 44 45 #ifndef FENV_MANGLE 46 /* 47 * Hopefully the system ID byte is immutable, so it's valid to use 48 * this as a default environment. 49 */ 50 const fenv_t __fe_dfl_env = 0; 51 #endif 52 53 54 /* If this is a non-mangled softfp version special processing is required */ 55 #if defined(FENV_MANGLE) || !defined(SOFTFP_ABI) || !defined(FENV_ARMv6) 56 57 /* 58 * The following macros map between the softfloat emulator's flags and 59 * the hardware's FPSR. The hardware this file was written for doesn't 60 * have rounding control bits, so we stick those in the system ID byte. 61 */ 62 #ifndef __ARM_PCS_VFP 63 #define __set_env(env, flags, mask, rnd) env = ((flags) \ 64 | (mask)<<_FPUSW_SHIFT \ 65 | (rnd) << 24) 66 #define __env_flags(env) ((env) & FE_ALL_EXCEPT) 67 #define __env_mask(env) (((env) >> _FPUSW_SHIFT) \ 68 & FE_ALL_EXCEPT) 69 #define __env_round(env) (((env) >> 24) & _ROUND_MASK) 70 #include "fenv-softfloat.h" 71 #endif 72 73 #ifdef __GNUC_GNU_INLINE__ 74 #error "This file must be compiled with C99 'inline' semantics" 75 #endif 76 77 extern inline int feclearexcept(int __excepts); 78 extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); 79 extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts); 80 extern inline int feraiseexcept(int __excepts); 81 extern inline int fetestexcept(int __excepts); 82 extern inline int fegetround(void); 83 extern inline int fesetround(int __round); 84 extern inline int fegetenv(fenv_t *__envp); 85 extern inline int feholdexcept(fenv_t *__envp); 86 extern inline int fesetenv(const fenv_t *__envp); 87 extern inline int feupdateenv(const fenv_t *__envp); 88 extern inline int feenableexcept(int __mask); 89 extern inline int fedisableexcept(int __mask); 90 extern inline int fegetexcept(void); 91 92 #else /* !FENV_MANGLE && SOFTFP_ABI */ 93 /* Set by libc when the VFP unit is enabled */ 94 extern int _libc_arm_fpu_present; 95 96 int __softfp_feclearexcept(int __excepts); 97 int __softfp_fegetexceptflag(fexcept_t *__flagp, int __excepts); 98 int __softfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts); 99 int __softfp_feraiseexcept(int __excepts); 100 int __softfp_fetestexcept(int __excepts); 101 int __softfp_fegetround(void); 102 int __softfp_fesetround(int __round); 103 int __softfp_fegetenv(fenv_t *__envp); 104 int __softfp_feholdexcept(fenv_t *__envp); 105 int __softfp_fesetenv(const fenv_t *__envp); 106 int __softfp_feupdateenv(const fenv_t *__envp); 107 int __softfp_feenableexcept(int __mask); 108 int __softfp_fedisableexcept(int __mask); 109 int __softfp_fegetexcept(void); 110 111 int __vfp_feclearexcept(int __excepts); 112 int __vfp_fegetexceptflag(fexcept_t *__flagp, int __excepts); 113 int __vfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts); 114 int __vfp_feraiseexcept(int __excepts); 115 int __vfp_fetestexcept(int __excepts); 116 int __vfp_fegetround(void); 117 int __vfp_fesetround(int __round); 118 int __vfp_fegetenv(fenv_t *__envp); 119 int __vfp_feholdexcept(fenv_t *__envp); 120 int __vfp_fesetenv(const fenv_t *__envp); 121 int __vfp_feupdateenv(const fenv_t *__envp); 122 int __vfp_feenableexcept(int __mask); 123 int __vfp_fedisableexcept(int __mask); 124 int __vfp_fegetexcept(void); 125 126 static int 127 __softfp_round_to_vfp(int round) 128 { 129 130 switch (round) { 131 case FE_TONEAREST: 132 default: 133 return VFP_FE_TONEAREST; 134 case FE_TOWARDZERO: 135 return VFP_FE_TOWARDZERO; 136 case FE_UPWARD: 137 return VFP_FE_UPWARD; 138 case FE_DOWNWARD: 139 return VFP_FE_DOWNWARD; 140 } 141 } 142 143 static int 144 __softfp_round_from_vfp(int round) 145 { 146 147 switch (round) { 148 case VFP_FE_TONEAREST: 149 default: 150 return FE_TONEAREST; 151 case VFP_FE_TOWARDZERO: 152 return FE_TOWARDZERO; 153 case VFP_FE_UPWARD: 154 return FE_UPWARD; 155 case VFP_FE_DOWNWARD: 156 return FE_DOWNWARD; 157 } 158 } 159 160 int feclearexcept(int __excepts) 161 { 162 163 if (_libc_arm_fpu_present) 164 __vfp_feclearexcept(__excepts); 165 __softfp_feclearexcept(__excepts); 166 167 return (0); 168 } 169 170 int fegetexceptflag(fexcept_t *__flagp, int __excepts) 171 { 172 fexcept_t __vfp_flagp; 173 174 __vfp_flagp = 0; 175 if (_libc_arm_fpu_present) 176 __vfp_fegetexceptflag(&__vfp_flagp, __excepts); 177 __softfp_fegetexceptflag(__flagp, __excepts); 178 179 *__flagp |= __vfp_flagp; 180 181 return (0); 182 } 183 184 int fesetexceptflag(const fexcept_t *__flagp, int __excepts) 185 { 186 187 if (_libc_arm_fpu_present) 188 __vfp_fesetexceptflag(__flagp, __excepts); 189 __softfp_fesetexceptflag(__flagp, __excepts); 190 191 return (0); 192 } 193 194 int feraiseexcept(int __excepts) 195 { 196 197 if (_libc_arm_fpu_present) 198 __vfp_feraiseexcept(__excepts); 199 __softfp_feraiseexcept(__excepts); 200 201 return (0); 202 } 203 204 int fetestexcept(int __excepts) 205 { 206 int __got_excepts; 207 208 __got_excepts = 0; 209 if (_libc_arm_fpu_present) 210 __got_excepts = __vfp_fetestexcept(__excepts); 211 __got_excepts |= __softfp_fetestexcept(__excepts); 212 213 return (__got_excepts); 214 } 215 216 int fegetround(void) 217 { 218 219 if (_libc_arm_fpu_present) 220 return __softfp_round_from_vfp(__vfp_fegetround()); 221 return __softfp_fegetround(); 222 } 223 224 int fesetround(int __round) 225 { 226 227 if (_libc_arm_fpu_present) 228 __vfp_fesetround(__softfp_round_to_vfp(__round)); 229 __softfp_fesetround(__round); 230 231 return (0); 232 } 233 234 int fegetenv(fenv_t *__envp) 235 { 236 fenv_t __vfp_envp; 237 238 __vfp_envp = 0; 239 if (_libc_arm_fpu_present) 240 __vfp_fegetenv(&__vfp_envp); 241 __softfp_fegetenv(__envp); 242 *__envp |= __vfp_envp; 243 244 return (0); 245 } 246 247 int feholdexcept(fenv_t *__envp) 248 { 249 fenv_t __vfp_envp; 250 251 __vfp_envp = 0; 252 if (_libc_arm_fpu_present) 253 __vfp_feholdexcept(&__vfp_envp); 254 __softfp_feholdexcept(__envp); 255 *__envp |= __vfp_envp; 256 257 return (0); 258 } 259 260 int fesetenv(const fenv_t *__envp) 261 { 262 263 if (_libc_arm_fpu_present) 264 __vfp_fesetenv(__envp); 265 __softfp_fesetenv(__envp); 266 267 return (0); 268 } 269 270 int feupdateenv(const fenv_t *__envp) 271 { 272 273 if (_libc_arm_fpu_present) 274 __vfp_feupdateenv(__envp); 275 __softfp_feupdateenv(__envp); 276 277 return (0); 278 } 279 280 int feenableexcept(int __mask) 281 { 282 int __unmasked; 283 284 __unmasked = 0; 285 if (_libc_arm_fpu_present) 286 __unmasked = __vfp_feenableexcept(__mask); 287 __unmasked |= __softfp_feenableexcept(__mask); 288 289 return (__unmasked); 290 } 291 292 int fedisableexcept(int __mask) 293 { 294 int __unmasked; 295 296 __unmasked = 0; 297 if (_libc_arm_fpu_present) 298 __unmasked = __vfp_fedisableexcept(__mask); 299 __unmasked |= __softfp_fedisableexcept(__mask); 300 301 return (__unmasked); 302 } 303 304 int fegetexcept(void) 305 { 306 int __unmasked; 307 308 __unmasked = 0; 309 if (_libc_arm_fpu_present) 310 __unmasked = __vfp_fegetexcept(); 311 __unmasked |= __softfp_fegetexcept(); 312 313 return (__unmasked); 314 } 315 316 #endif 317 318