1130143Sdas/*- 2143708Sdas * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> 3130143Sdas * All rights reserved. 4130143Sdas * 5130143Sdas * Redistribution and use in source and binary forms, with or without 6130143Sdas * modification, are permitted provided that the following conditions 7130143Sdas * are met: 8130143Sdas * 1. Redistributions of source code must retain the above copyright 9130143Sdas * notice, this list of conditions and the following disclaimer. 10130143Sdas * 2. Redistributions in binary form must reproduce the above copyright 11130143Sdas * notice, this list of conditions and the following disclaimer in the 12130143Sdas * documentation and/or other materials provided with the distribution. 13130143Sdas * 14130143Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15130143Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16130143Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17130143Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18130143Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19130143Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20130143Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21130143Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22130143Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23130143Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24130143Sdas * SUCH DAMAGE. 25130143Sdas * 26130143Sdas * $FreeBSD$ 27130143Sdas */ 28130143Sdas 29130143Sdas#ifndef _FENV_H_ 30130143Sdas#define _FENV_H_ 31130143Sdas 32130143Sdas#include <sys/_types.h> 33130143Sdas 34130143Sdastypedef __uint32_t fenv_t; 35130143Sdastypedef __uint32_t fexcept_t; 36130143Sdas 37130143Sdas/* Exception flags */ 38130143Sdas#define FE_INVALID 0x0001 39130143Sdas#define FE_DIVBYZERO 0x0002 40130143Sdas#define FE_OVERFLOW 0x0004 41130143Sdas#define FE_UNDERFLOW 0x0008 42130143Sdas#define FE_INEXACT 0x0010 43130143Sdas#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ 44130143Sdas FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) 45130143Sdas 46140689Scognet/* Rounding modes */ 47140689Scognet#define FE_TONEAREST 0x0000 48140689Scognet#define FE_TOWARDZERO 0x0001 49140689Scognet#define FE_UPWARD 0x0002 50140689Scognet#define FE_DOWNWARD 0x0003 51140689Scognet#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ 52140689Scognet FE_UPWARD | FE_TOWARDZERO) 53130143Sdas__BEGIN_DECLS 54130143Sdas 55130143Sdas/* Default floating-point environment */ 56130143Sdasextern const fenv_t __fe_dfl_env; 57130143Sdas#define FE_DFL_ENV (&__fe_dfl_env) 58130143Sdas 59130143Sdas/* We need to be able to map status flag positions to mask flag positions */ 60130143Sdas#define _FPUSW_SHIFT 16 61130143Sdas#define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT) 62130143Sdas 63133174Scognet#ifdef ARM_HARD_FLOAT 64140219Sdas#define __rfs(__fpsr) __asm __volatile("rfs %0" : "=r" (*(__fpsr))) 65133174Scognet#define __wfs(__fpsr) __asm __volatile("wfs %0" : : "r" (__fpsr)) 66133174Scognet#else 67133174Scognet#define __rfs(__fpsr) 68133174Scognet#define __wfs(__fpsr) 69133174Scognet#endif 70130143Sdas 71130143Sdasstatic __inline int 72130143Sdasfeclearexcept(int __excepts) 73130143Sdas{ 74130143Sdas fexcept_t __fpsr; 75130143Sdas 76130143Sdas __rfs(&__fpsr); 77130143Sdas __fpsr &= ~__excepts; 78130143Sdas __wfs(__fpsr); 79130143Sdas return (0); 80130143Sdas} 81130143Sdas 82130143Sdasstatic __inline int 83130143Sdasfegetexceptflag(fexcept_t *__flagp, int __excepts) 84130143Sdas{ 85130143Sdas fexcept_t __fpsr; 86130143Sdas 87130143Sdas __rfs(&__fpsr); 88130143Sdas *__flagp = __fpsr & __excepts; 89130143Sdas return (0); 90130143Sdas} 91130143Sdas 92130143Sdasstatic __inline int 93130143Sdasfesetexceptflag(const fexcept_t *__flagp, int __excepts) 94130143Sdas{ 95130143Sdas fexcept_t __fpsr; 96130143Sdas 97130143Sdas __rfs(&__fpsr); 98130143Sdas __fpsr &= ~__excepts; 99130143Sdas __fpsr |= *__flagp & __excepts; 100130143Sdas __wfs(__fpsr); 101130143Sdas return (0); 102130143Sdas} 103130143Sdas 104130143Sdasstatic __inline int 105130143Sdasferaiseexcept(int __excepts) 106130143Sdas{ 107130143Sdas fexcept_t __ex = __excepts; 108130143Sdas 109130143Sdas fesetexceptflag(&__ex, __excepts); /* XXX */ 110130143Sdas return (0); 111130143Sdas} 112130143Sdas 113130143Sdasstatic __inline int 114130143Sdasfetestexcept(int __excepts) 115130143Sdas{ 116130143Sdas fexcept_t __fpsr; 117130143Sdas 118130143Sdas __rfs(&__fpsr); 119130143Sdas return (__fpsr & __excepts); 120130143Sdas} 121130143Sdas 122130143Sdasstatic __inline int 123130143Sdasfegetround(void) 124130143Sdas{ 125130143Sdas 126130143Sdas /* 127130143Sdas * Apparently, the rounding mode is specified as part of the 128130143Sdas * instruction format on ARM, so the dynamic rounding mode is 129130143Sdas * indeterminate. Some FPUs may differ. 130130143Sdas */ 131130143Sdas return (-1); 132130143Sdas} 133130143Sdas 134130143Sdasstatic __inline int 135130143Sdasfesetround(int __round) 136130143Sdas{ 137130143Sdas 138130143Sdas return (-1); 139130143Sdas} 140130143Sdas 141130143Sdasstatic __inline int 142130143Sdasfegetenv(fenv_t *__envp) 143130143Sdas{ 144130143Sdas 145130143Sdas __rfs(__envp); 146130143Sdas return (0); 147130143Sdas} 148130143Sdas 149130143Sdasstatic __inline int 150130143Sdasfeholdexcept(fenv_t *__envp) 151130143Sdas{ 152130143Sdas fenv_t __env; 153130143Sdas 154130143Sdas __rfs(&__env); 155130143Sdas *__envp = __env; 156130143Sdas __env &= ~(FE_ALL_EXCEPT | _ENABLE_MASK); 157130143Sdas __wfs(__env); 158130143Sdas return (0); 159130143Sdas} 160130143Sdas 161130143Sdasstatic __inline int 162130143Sdasfesetenv(const fenv_t *__envp) 163130143Sdas{ 164130143Sdas 165130143Sdas __wfs(*__envp); 166130143Sdas return (0); 167130143Sdas} 168130143Sdas 169130143Sdasstatic __inline int 170130143Sdasfeupdateenv(const fenv_t *__envp) 171130143Sdas{ 172130143Sdas fexcept_t __fpsr; 173130143Sdas 174130143Sdas __rfs(&__fpsr); 175130143Sdas __wfs(*__envp); 176130143Sdas feraiseexcept(__fpsr & FE_ALL_EXCEPT); 177130143Sdas return (0); 178130143Sdas} 179130143Sdas 180130143Sdas#if __BSD_VISIBLE 181130143Sdas 182130143Sdasstatic __inline int 183143708Sdasfeenableexcept(int __mask) 184130143Sdas{ 185143708Sdas fenv_t __old_fpsr, __new_fpsr; 186130143Sdas 187143708Sdas __rfs(&__old_fpsr); 188143708Sdas __new_fpsr = __old_fpsr | (__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT; 189143708Sdas __wfs(__new_fpsr); 190143708Sdas return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); 191130143Sdas} 192130143Sdas 193130143Sdasstatic __inline int 194143708Sdasfedisableexcept(int __mask) 195130143Sdas{ 196143708Sdas fenv_t __old_fpsr, __new_fpsr; 197143708Sdas 198143708Sdas __rfs(&__old_fpsr); 199143708Sdas __new_fpsr = __old_fpsr & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); 200143708Sdas __wfs(__new_fpsr); 201143708Sdas return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); 202143708Sdas} 203143708Sdas 204143708Sdasstatic __inline int 205143708Sdasfegetexcept(void) 206143708Sdas{ 207130143Sdas fenv_t __fpsr; 208130143Sdas 209130143Sdas __rfs(&__fpsr); 210130143Sdas return ((__fpsr & _ENABLE_MASK) >> _FPUSW_SHIFT); 211130143Sdas} 212130143Sdas 213130143Sdas#endif /* __BSD_VISIBLE */ 214130143Sdas 215130143Sdas__END_DECLS 216130143Sdas 217130143Sdas#endif /* !_FENV_H_ */ 218