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