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