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: releng/11.0/lib/msun/arm/fenv.c 269956 2014-08-14 04:20:13Z imp $ 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 */ 50const 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 77extern inline int feclearexcept(int __excepts); 78extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); 79extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts); 80extern inline int feraiseexcept(int __excepts); 81extern inline int fetestexcept(int __excepts); 82extern inline int fegetround(void); 83extern inline int fesetround(int __round); 84extern inline int fegetenv(fenv_t *__envp); 85extern inline int feholdexcept(fenv_t *__envp); 86extern inline int fesetenv(const fenv_t *__envp); 87extern inline int feupdateenv(const fenv_t *__envp); 88extern inline int feenableexcept(int __mask); 89extern inline int fedisableexcept(int __mask); 90extern inline int fegetexcept(void); 91 92#else /* !FENV_MANGLE && SOFTFP_ABI */ 93/* Set by libc when the VFP unit is enabled */ 94extern int _libc_arm_fpu_present; 95 96int __softfp_feclearexcept(int __excepts); 97int __softfp_fegetexceptflag(fexcept_t *__flagp, int __excepts); 98int __softfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts); 99int __softfp_feraiseexcept(int __excepts); 100int __softfp_fetestexcept(int __excepts); 101int __softfp_fegetround(void); 102int __softfp_fesetround(int __round); 103int __softfp_fegetenv(fenv_t *__envp); 104int __softfp_feholdexcept(fenv_t *__envp); 105int __softfp_fesetenv(const fenv_t *__envp); 106int __softfp_feupdateenv(const fenv_t *__envp); 107int __softfp_feenableexcept(int __mask); 108int __softfp_fedisableexcept(int __mask); 109int __softfp_fegetexcept(void); 110 111int __vfp_feclearexcept(int __excepts); 112int __vfp_fegetexceptflag(fexcept_t *__flagp, int __excepts); 113int __vfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts); 114int __vfp_feraiseexcept(int __excepts); 115int __vfp_fetestexcept(int __excepts); 116int __vfp_fegetround(void); 117int __vfp_fesetround(int __round); 118int __vfp_fegetenv(fenv_t *__envp); 119int __vfp_feholdexcept(fenv_t *__envp); 120int __vfp_fesetenv(const fenv_t *__envp); 121int __vfp_feupdateenv(const fenv_t *__envp); 122int __vfp_feenableexcept(int __mask); 123int __vfp_fedisableexcept(int __mask); 124int __vfp_fegetexcept(void); 125 126static 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 143static 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 160int 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 170int 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 184int 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 194int 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 204int 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 216int fegetround(void) 217{ 218 219 if (_libc_arm_fpu_present) 220 return __softfp_round_from_vfp(__vfp_fegetround()); 221 return __softfp_fegetround(); 222} 223 224int 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 234int 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 247int 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 260int 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 270int 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 280int 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 292int 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 304int 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