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 */ 52const 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 79extern inline int feclearexcept(int __excepts); 80extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); 81extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts); 82extern inline int feraiseexcept(int __excepts); 83extern inline int fetestexcept(int __excepts); 84extern inline int fegetround(void); 85extern inline int fesetround(int __round); 86extern inline int fegetenv(fenv_t *__envp); 87extern inline int feholdexcept(fenv_t *__envp); 88extern inline int fesetenv(const fenv_t *__envp); 89extern inline int feupdateenv(const fenv_t *__envp); 90extern inline int feenableexcept(int __mask); 91extern inline int fedisableexcept(int __mask); 92extern inline int fegetexcept(void); 93 94#else /* !FENV_MANGLE && SOFTFP_ABI */ 95/* Set by libc when the VFP unit is enabled */ 96extern int _libc_arm_fpu_present; 97 98int __softfp_feclearexcept(int __excepts); 99int __softfp_fegetexceptflag(fexcept_t *__flagp, int __excepts); 100int __softfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts); 101int __softfp_feraiseexcept(int __excepts); 102int __softfp_fetestexcept(int __excepts); 103int __softfp_fegetround(void); 104int __softfp_fesetround(int __round); 105int __softfp_fegetenv(fenv_t *__envp); 106int __softfp_feholdexcept(fenv_t *__envp); 107int __softfp_fesetenv(const fenv_t *__envp); 108int __softfp_feupdateenv(const fenv_t *__envp); 109int __softfp_feenableexcept(int __mask); 110int __softfp_fedisableexcept(int __mask); 111int __softfp_fegetexcept(void); 112 113int __vfp_feclearexcept(int __excepts); 114int __vfp_fegetexceptflag(fexcept_t *__flagp, int __excepts); 115int __vfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts); 116int __vfp_feraiseexcept(int __excepts); 117int __vfp_fetestexcept(int __excepts); 118int __vfp_fegetround(void); 119int __vfp_fesetround(int __round); 120int __vfp_fegetenv(fenv_t *__envp); 121int __vfp_feholdexcept(fenv_t *__envp); 122int __vfp_fesetenv(const fenv_t *__envp); 123int __vfp_feupdateenv(const fenv_t *__envp); 124int __vfp_feenableexcept(int __mask); 125int __vfp_fedisableexcept(int __mask); 126int __vfp_fegetexcept(void); 127 128static 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 145static 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 162int 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 172int 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 186int 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 196int 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 206int 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 218int fegetround(void) 219{ 220 221 if (_libc_arm_fpu_present) 222 return __softfp_round_from_vfp(__vfp_fegetround()); 223 return __softfp_fegetround(); 224} 225 226int 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 236int 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 249int 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 262int 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 272int 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 282int 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 294int 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 306int 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