1/*- 2 * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29#ifndef _FENV_H_ 30#define _FENV_H_ 31 32#include <sys/_types.h> 33 34#ifndef __fenv_static 35#define __fenv_static static 36#endif 37 38typedef __uint32_t fenv_t; 39typedef __uint32_t fexcept_t; 40 41/* Exception flags */ 42#define FE_INVALID 0x0001 43#define FE_DIVBYZERO 0x0002 44#define FE_OVERFLOW 0x0004 45#define FE_UNDERFLOW 0x0008 46#define FE_INEXACT 0x0010 47#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ 48 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) 49 50/* Rounding modes */ 51#define FE_TONEAREST 0x0000 52#define FE_TOWARDZERO 0x0001 53#define FE_UPWARD 0x0002 54#define FE_DOWNWARD 0x0003 55#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ 56 FE_UPWARD | FE_TOWARDZERO) 57__BEGIN_DECLS 58 59/* Default floating-point environment */ 60extern const fenv_t __fe_dfl_env; 61#define FE_DFL_ENV (&__fe_dfl_env) 62 63/* We need to be able to map status flag positions to mask flag positions */ 64#define _FPUSW_SHIFT 16 65#define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT) 66 67#ifndef ARM_HARD_FLOAT 68 69int feclearexcept(int __excepts); 70int fegetexceptflag(fexcept_t *__flagp, int __excepts); 71int fesetexceptflag(const fexcept_t *__flagp, int __excepts); 72int feraiseexcept(int __excepts); 73int fetestexcept(int __excepts); 74int fegetround(void); 75int fesetround(int __round); 76int fegetenv(fenv_t *__envp); 77int feholdexcept(fenv_t *__envp); 78int fesetenv(const fenv_t *__envp); 79int feupdateenv(const fenv_t *__envp); 80 81#else /* ARM_HARD_FLOAT */ 82 83#define __rfs(__fpsr) __asm __volatile("rfs %0" : "=r" (*(__fpsr))) 84#define __wfs(__fpsr) __asm __volatile("wfs %0" : : "r" (__fpsr)) 85 86__fenv_static inline int 87feclearexcept(int __excepts) 88{ 89 fexcept_t __fpsr; 90 91 __rfs(&__fpsr); 92 __fpsr &= ~__excepts; 93 __wfs(__fpsr); 94 return (0); 95} 96 97__fenv_static inline int 98fegetexceptflag(fexcept_t *__flagp, int __excepts) 99{ 100 fexcept_t __fpsr; 101 102 __rfs(&__fpsr); 103 *__flagp = __fpsr & __excepts; 104 return (0); 105} 106 107__fenv_static inline int 108fesetexceptflag(const fexcept_t *__flagp, int __excepts) 109{ 110 fexcept_t __fpsr; 111 112 __rfs(&__fpsr); 113 __fpsr &= ~__excepts; 114 __fpsr |= *__flagp & __excepts; 115 __wfs(__fpsr); 116 return (0); 117} 118 119__fenv_static inline int 120feraiseexcept(int __excepts) 121{ 122 fexcept_t __ex = __excepts; 123 124 fesetexceptflag(&__ex, __excepts); /* XXX */ 125 return (0); 126} 127 128__fenv_static inline int 129fetestexcept(int __excepts) 130{ 131 fexcept_t __fpsr; 132 133 __rfs(&__fpsr); 134 return (__fpsr & __excepts); 135} 136 137__fenv_static inline int 138fegetround(void) 139{ 140 141 /* 142 * Apparently, the rounding mode is specified as part of the 143 * instruction format on ARM, so the dynamic rounding mode is 144 * indeterminate. Some FPUs may differ. 145 */ 146 return (-1); 147} 148 149__fenv_static inline int 150fesetround(int __round) 151{ 152 153 return (-1); 154} 155 156__fenv_static inline int 157fegetenv(fenv_t *__envp) 158{ 159 160 __rfs(__envp); 161 return (0); 162} 163 164__fenv_static inline int 165feholdexcept(fenv_t *__envp) 166{ 167 fenv_t __env; 168 169 __rfs(&__env); 170 *__envp = __env; 171 __env &= ~(FE_ALL_EXCEPT | _ENABLE_MASK); 172 __wfs(__env); 173 return (0); 174} 175 176__fenv_static inline int 177fesetenv(const fenv_t *__envp) 178{ 179 180 __wfs(*__envp); 181 return (0); 182} 183 184__fenv_static inline int 185feupdateenv(const fenv_t *__envp) 186{ 187 fexcept_t __fpsr; 188 189 __rfs(&__fpsr); 190 __wfs(*__envp); 191 feraiseexcept(__fpsr & FE_ALL_EXCEPT); 192 return (0); 193} 194 195#if __BSD_VISIBLE 196 197/* We currently provide no external definitions of the functions below. */ 198 199static inline int 200feenableexcept(int __mask) 201{ 202 fenv_t __old_fpsr, __new_fpsr; 203 204 __rfs(&__old_fpsr); 205 __new_fpsr = __old_fpsr | (__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT; 206 __wfs(__new_fpsr); 207 return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); 208} 209 210static inline int 211fedisableexcept(int __mask) 212{ 213 fenv_t __old_fpsr, __new_fpsr; 214 215 __rfs(&__old_fpsr); 216 __new_fpsr = __old_fpsr & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); 217 __wfs(__new_fpsr); 218 return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); 219} 220 221static inline int 222fegetexcept(void) 223{ 224 fenv_t __fpsr; 225 226 __rfs(&__fpsr); 227 return ((__fpsr & _ENABLE_MASK) >> _FPUSW_SHIFT); 228} 229 230#endif /* __BSD_VISIBLE */ 231 232#endif /* ARM_HARD_FLOAT */ 233 234__END_DECLS 235 236#endif /* !_FENV_H_ */ 237