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