1*84d9c625SLionel Sambuc /*- 2*84d9c625SLionel Sambuc * Copyright (c) 2013 The NetBSD Foundation, Inc. 3*84d9c625SLionel Sambuc * All rights reserved. 4*84d9c625SLionel Sambuc * 5*84d9c625SLionel Sambuc * This code is derived from software contributed to The NetBSD Foundation 6*84d9c625SLionel Sambuc * by Matt Thomas of 3am Software Foundry. 7*84d9c625SLionel Sambuc * 8*84d9c625SLionel Sambuc * Redistribution and use in source and binary forms, with or without 9*84d9c625SLionel Sambuc * modification, are permitted provided that the following conditions 10*84d9c625SLionel Sambuc * are met: 11*84d9c625SLionel Sambuc * 1. Redistributions of source code must retain the above copyright 12*84d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer. 13*84d9c625SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright 14*84d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer in the 15*84d9c625SLionel Sambuc * documentation and/or other materials provided with the distribution. 16*84d9c625SLionel Sambuc * 17*84d9c625SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18*84d9c625SLionel Sambuc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19*84d9c625SLionel Sambuc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20*84d9c625SLionel Sambuc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21*84d9c625SLionel Sambuc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22*84d9c625SLionel Sambuc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23*84d9c625SLionel Sambuc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24*84d9c625SLionel Sambuc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25*84d9c625SLionel Sambuc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26*84d9c625SLionel Sambuc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27*84d9c625SLionel Sambuc * POSSIBILITY OF SUCH DAMAGE. 28*84d9c625SLionel Sambuc */ 29*84d9c625SLionel Sambuc 30*84d9c625SLionel Sambuc #include <sys/cdefs.h> 31*84d9c625SLionel Sambuc __RCSID("$NetBSD: fenv.c,v 1.3 2013/05/01 04:04:54 matt Exp $"); 32*84d9c625SLionel Sambuc 33*84d9c625SLionel Sambuc #include <sys/types.h> 34*84d9c625SLionel Sambuc #include <assert.h> 35*84d9c625SLionel Sambuc #include <fenv.h> 36*84d9c625SLionel Sambuc #include <string.h> 37*84d9c625SLionel Sambuc #include <unistd.h> 38*84d9c625SLionel Sambuc #include <inttypes.h> 39*84d9c625SLionel Sambuc 40*84d9c625SLionel Sambuc #ifdef __SOFTFP__ 41*84d9c625SLionel Sambuc #include <ieeefp.h> 42*84d9c625SLionel Sambuc #include <sys/signal.h> 43*84d9c625SLionel Sambuc #include <sys/siginfo.h> 44*84d9c625SLionel Sambuc #else 45*84d9c625SLionel Sambuc #include <arm/armreg.h> 46*84d9c625SLionel Sambuc #endif 47*84d9c625SLionel Sambuc 48*84d9c625SLionel Sambuc #include <arm/vfpreg.h> 49*84d9c625SLionel Sambuc 50*84d9c625SLionel Sambuc const fenv_t __fe_dfl_env = VFP_FPSCR_FZ|VFP_FPSCR_DN|VFP_FPSCR_RN; 51*84d9c625SLionel Sambuc 52*84d9c625SLionel Sambuc /* 53*84d9c625SLionel Sambuc * The feclearexcept() function shall attempt to clear the supported 54*84d9c625SLionel Sambuc * floating-point exceptions represented by excepts. 55*84d9c625SLionel Sambuc */ 56*84d9c625SLionel Sambuc int 57*84d9c625SLionel Sambuc feclearexcept(int excepts) 58*84d9c625SLionel Sambuc { 59*84d9c625SLionel Sambuc #ifndef lint 60*84d9c625SLionel Sambuc _DIAGASSERT((except & ~FE_EXCEPT_ALL) == 0); 61*84d9c625SLionel Sambuc #endif 62*84d9c625SLionel Sambuc #ifdef __SOFTFP__ 63*84d9c625SLionel Sambuc fpsetsticky(fpgetsticky() & ~excepts); 64*84d9c625SLionel Sambuc return 0; 65*84d9c625SLionel Sambuc #else 66*84d9c625SLionel Sambuc int tmp = armreg_fpscr_read() & ~__SHIFTIN(excepts, VFP_FPSCR_CSUM); 67*84d9c625SLionel Sambuc armreg_fpscr_write(tmp); 68*84d9c625SLionel Sambuc return 0; 69*84d9c625SLionel Sambuc #endif 70*84d9c625SLionel Sambuc } 71*84d9c625SLionel Sambuc 72*84d9c625SLionel Sambuc /* 73*84d9c625SLionel Sambuc * The fegetexceptflag() function shall attempt to store an 74*84d9c625SLionel Sambuc * implementation-defined representation of the states of the floating-point 75*84d9c625SLionel Sambuc * status flags indicated by the argument excepts in the object pointed to by 76*84d9c625SLionel Sambuc * the argument flagp. 77*84d9c625SLionel Sambuc */ 78*84d9c625SLionel Sambuc int 79*84d9c625SLionel Sambuc fegetexceptflag(fexcept_t *flagp, int excepts) 80*84d9c625SLionel Sambuc { 81*84d9c625SLionel Sambuc _DIAGASSERT((except & ~FE_EXCEPT_ALL) == 0); 82*84d9c625SLionel Sambuc #ifdef __SOFTFP__ 83*84d9c625SLionel Sambuc *flagp = fpgetsticky() & excepts; 84*84d9c625SLionel Sambuc #else 85*84d9c625SLionel Sambuc *flagp = __SHIFTOUT(armreg_fpscr_read(), VFP_FPSCR_CSUM) & excepts; 86*84d9c625SLionel Sambuc #endif 87*84d9c625SLionel Sambuc return 0; 88*84d9c625SLionel Sambuc } 89*84d9c625SLionel Sambuc 90*84d9c625SLionel Sambuc /* 91*84d9c625SLionel Sambuc * The feraiseexcept() function shall attempt to raise the supported 92*84d9c625SLionel Sambuc * floating-point exceptions represented by the argument excepts. The order 93*84d9c625SLionel Sambuc * in which these floating-point exceptions are raised is unspecified. 94*84d9c625SLionel Sambuc */ 95*84d9c625SLionel Sambuc int 96*84d9c625SLionel Sambuc feraiseexcept(int excepts) 97*84d9c625SLionel Sambuc { 98*84d9c625SLionel Sambuc #ifndef lint 99*84d9c625SLionel Sambuc _DIAGASSERT((except & ~FE_EXCEPT_ALL) == 0); 100*84d9c625SLionel Sambuc #endif 101*84d9c625SLionel Sambuc #if !defined(__minix) /* LSC: No sigqueueinfo on Minix. */ 102*84d9c625SLionel Sambuc #ifdef __SOFTFP__ 103*84d9c625SLionel Sambuc excepts &= fpgetsticky(); 104*84d9c625SLionel Sambuc 105*84d9c625SLionel Sambuc if (excepts) { 106*84d9c625SLionel Sambuc siginfo_t info; 107*84d9c625SLionel Sambuc memset(&info, 0, sizeof info); 108*84d9c625SLionel Sambuc info.si_signo = SIGFPE; 109*84d9c625SLionel Sambuc info.si_pid = getpid(); 110*84d9c625SLionel Sambuc info.si_uid = geteuid(); 111*84d9c625SLionel Sambuc if (excepts & FE_UNDERFLOW) 112*84d9c625SLionel Sambuc info.si_code = FPE_FLTUND; 113*84d9c625SLionel Sambuc else if (excepts & FE_OVERFLOW) 114*84d9c625SLionel Sambuc info.si_code = FPE_FLTOVF; 115*84d9c625SLionel Sambuc else if (excepts & FE_DIVBYZERO) 116*84d9c625SLionel Sambuc info.si_code = FPE_FLTDIV; 117*84d9c625SLionel Sambuc else if (excepts & FE_INVALID) 118*84d9c625SLionel Sambuc info.si_code = FPE_FLTINV; 119*84d9c625SLionel Sambuc else if (excepts & FE_INEXACT) 120*84d9c625SLionel Sambuc info.si_code = FPE_FLTRES; 121*84d9c625SLionel Sambuc sigqueueinfo(getpid(), &info); 122*84d9c625SLionel Sambuc } 123*84d9c625SLionel Sambuc #else 124*84d9c625SLionel Sambuc int fpscr = armreg_fpscr_read(); 125*84d9c625SLionel Sambuc fpscr = (fpscr & ~VFP_FPSCR_ESUM) | __SHIFTIN(excepts, VFP_FPSCR_ESUM); 126*84d9c625SLionel Sambuc armreg_fpscr_write(fpscr); 127*84d9c625SLionel Sambuc #endif 128*84d9c625SLionel Sambuc #endif /* !defined(__minix) */ 129*84d9c625SLionel Sambuc return 0; 130*84d9c625SLionel Sambuc } 131*84d9c625SLionel Sambuc 132*84d9c625SLionel Sambuc /* 133*84d9c625SLionel Sambuc * The fesetexceptflag() function shall attempt to set the floating-point 134*84d9c625SLionel Sambuc * status flags indicated by the argument excepts to the states stored in the 135*84d9c625SLionel Sambuc * object pointed to by flagp. The value pointed to by flagp shall have been 136*84d9c625SLionel Sambuc * set by a previous call to fegetexceptflag() whose second argument 137*84d9c625SLionel Sambuc * represented at least those floating-point exceptions represented by the 138*84d9c625SLionel Sambuc * argument excepts. This function does not raise floating-point exceptions, 139*84d9c625SLionel Sambuc * but only sets the state of the flags. 140*84d9c625SLionel Sambuc */ 141*84d9c625SLionel Sambuc int 142*84d9c625SLionel Sambuc fesetexceptflag(const fexcept_t *flagp, int excepts) 143*84d9c625SLionel Sambuc { 144*84d9c625SLionel Sambuc #ifndef lint 145*84d9c625SLionel Sambuc _DIAGASSERT((except & ~FE_EXCEPT_ALL) == 0); 146*84d9c625SLionel Sambuc #endif 147*84d9c625SLionel Sambuc #ifdef __SOFTFP__ 148*84d9c625SLionel Sambuc fpsetsticky((fpgetsticky() & ~excepts) | (excepts & *flagp)); 149*84d9c625SLionel Sambuc #else 150*84d9c625SLionel Sambuc int fpscr = armreg_fpscr_read(); 151*84d9c625SLionel Sambuc fpscr &= ~__SHIFTIN(excepts, VFP_FPSCR_CSUM); 152*84d9c625SLionel Sambuc fpscr |= __SHIFTIN((*flagp & excepts), VFP_FPSCR_CSUM); 153*84d9c625SLionel Sambuc armreg_fpscr_write(fpscr); 154*84d9c625SLionel Sambuc #endif 155*84d9c625SLionel Sambuc return 0; 156*84d9c625SLionel Sambuc } 157*84d9c625SLionel Sambuc 158*84d9c625SLionel Sambuc /* 159*84d9c625SLionel Sambuc * The fetestexcept() function shall determine which of a specified subset of 160*84d9c625SLionel Sambuc * the floating-point exception flags are currently set. The excepts argument 161*84d9c625SLionel Sambuc * specifies the floating-point status flags to be queried. 162*84d9c625SLionel Sambuc */ 163*84d9c625SLionel Sambuc int 164*84d9c625SLionel Sambuc fetestexcept(int excepts) 165*84d9c625SLionel Sambuc { 166*84d9c625SLionel Sambuc _DIAGASSERT((except & ~FE_EXCEPT_ALL) == 0); 167*84d9c625SLionel Sambuc #ifdef __SOFTFP__ 168*84d9c625SLionel Sambuc return fpgetsticky() & excepts; 169*84d9c625SLionel Sambuc #else 170*84d9c625SLionel Sambuc return __SHIFTOUT(armreg_fpscr_read(), VFP_FPSCR_CSUM) & excepts; 171*84d9c625SLionel Sambuc #endif 172*84d9c625SLionel Sambuc } 173*84d9c625SLionel Sambuc 174*84d9c625SLionel Sambuc /* 175*84d9c625SLionel Sambuc * The fegetround() function shall get the current rounding direction. 176*84d9c625SLionel Sambuc */ 177*84d9c625SLionel Sambuc int 178*84d9c625SLionel Sambuc fegetround(void) 179*84d9c625SLionel Sambuc { 180*84d9c625SLionel Sambuc #ifdef __SOFTFP__ 181*84d9c625SLionel Sambuc return fpgetround(); 182*84d9c625SLionel Sambuc #else 183*84d9c625SLionel Sambuc return __SHIFTOUT(armreg_fpscr_read(), VFP_FPSCR_RMODE); 184*84d9c625SLionel Sambuc #endif 185*84d9c625SLionel Sambuc } 186*84d9c625SLionel Sambuc 187*84d9c625SLionel Sambuc /* 188*84d9c625SLionel Sambuc * The fesetround() function shall establish the rounding direction represented 189*84d9c625SLionel Sambuc * by its argument round. If the argument is not equal to the value of a 190*84d9c625SLionel Sambuc * rounding direction macro, the rounding direction is not changed. 191*84d9c625SLionel Sambuc */ 192*84d9c625SLionel Sambuc int 193*84d9c625SLionel Sambuc fesetround(int round) 194*84d9c625SLionel Sambuc { 195*84d9c625SLionel Sambuc #ifndef lint 196*84d9c625SLionel Sambuc _DIAGASSERT(!(round & ~__SHIFTOUT(VFP_FPSCR_RMODE, VFP_FPSCR_RMODE))); 197*84d9c625SLionel Sambuc #endif 198*84d9c625SLionel Sambuc #ifdef __SOFTFP__ 199*84d9c625SLionel Sambuc (void)fpsetround(round); 200*84d9c625SLionel Sambuc #else 201*84d9c625SLionel Sambuc int fpscr = armreg_fpscr_read() & ~VFP_FPSCR_RMODE; 202*84d9c625SLionel Sambuc fpscr |= __SHIFTIN(round, VFP_FPSCR_RMODE); 203*84d9c625SLionel Sambuc armreg_fpscr_write(fpscr); 204*84d9c625SLionel Sambuc #endif 205*84d9c625SLionel Sambuc return 0; 206*84d9c625SLionel Sambuc } 207*84d9c625SLionel Sambuc 208*84d9c625SLionel Sambuc /* 209*84d9c625SLionel Sambuc * The fegetenv() function shall attempt to store the current floating-point 210*84d9c625SLionel Sambuc * environment in the object pointed to by envp. 211*84d9c625SLionel Sambuc */ 212*84d9c625SLionel Sambuc int 213*84d9c625SLionel Sambuc fegetenv(fenv_t *envp) 214*84d9c625SLionel Sambuc { 215*84d9c625SLionel Sambuc #ifdef __SOFTFP__ 216*84d9c625SLionel Sambuc *envp = __SHIFTIN(fpgetround(), VFP_FPSCR_RMODE) 217*84d9c625SLionel Sambuc | __SHIFTIN(fpgetmask(), VFP_FPSCR_ESUM) 218*84d9c625SLionel Sambuc | __SHIFTIN(fpgetsticky(), VFP_FPSCR_CSUM); 219*84d9c625SLionel Sambuc #else 220*84d9c625SLionel Sambuc *envp = armreg_fpscr_read(); 221*84d9c625SLionel Sambuc #endif 222*84d9c625SLionel Sambuc return 0; 223*84d9c625SLionel Sambuc } 224*84d9c625SLionel Sambuc 225*84d9c625SLionel Sambuc /* 226*84d9c625SLionel Sambuc * The feholdexcept() function shall save the current floating-point 227*84d9c625SLionel Sambuc * environment in the object pointed to by envp, clear the floating-point 228*84d9c625SLionel Sambuc * status flags, and then install a non-stop (continue on floating-point 229*84d9c625SLionel Sambuc * exceptions) mode, if available, for all floating-point exceptions. 230*84d9c625SLionel Sambuc */ 231*84d9c625SLionel Sambuc int 232*84d9c625SLionel Sambuc feholdexcept(fenv_t *envp) 233*84d9c625SLionel Sambuc { 234*84d9c625SLionel Sambuc #ifdef __SOFTFP__ 235*84d9c625SLionel Sambuc *envp = __SHIFTIN(fpgetround(), VFP_FPSCR_RMODE) 236*84d9c625SLionel Sambuc | __SHIFTIN(fpgetmask(), VFP_FPSCR_ESUM) 237*84d9c625SLionel Sambuc | __SHIFTIN(fpgetsticky(), VFP_FPSCR_CSUM); 238*84d9c625SLionel Sambuc fpsetmask(0); 239*84d9c625SLionel Sambuc fpsetsticky(0); 240*84d9c625SLionel Sambuc #else 241*84d9c625SLionel Sambuc *envp = armreg_fpscr_read(); 242*84d9c625SLionel Sambuc armreg_fpscr_write((*envp) & ~(VFP_FPSCR_ESUM|VFP_FPSCR_CSUM)); 243*84d9c625SLionel Sambuc #endif 244*84d9c625SLionel Sambuc return 0; 245*84d9c625SLionel Sambuc } 246*84d9c625SLionel Sambuc 247*84d9c625SLionel Sambuc /* 248*84d9c625SLionel Sambuc * The fesetenv() function shall attempt to establish the floating-point 249*84d9c625SLionel Sambuc * environment represented by the object pointed to by envp. The fesetenv() 250*84d9c625SLionel Sambuc * function does not raise floating-point exceptions, but only installs the 251*84d9c625SLionel Sambuc * state of the floating-point status flags represented through its argument. 252*84d9c625SLionel Sambuc */ 253*84d9c625SLionel Sambuc int 254*84d9c625SLionel Sambuc fesetenv(const fenv_t *envp) 255*84d9c625SLionel Sambuc { 256*84d9c625SLionel Sambuc #ifdef __SOFTFP__ 257*84d9c625SLionel Sambuc (void)fpsetround(__SHIFTIN(*envp, VFP_FPSCR_RMODE)); 258*84d9c625SLionel Sambuc (void)fpsetmask(__SHIFTOUT(*envp, VFP_FPSCR_ESUM)); 259*84d9c625SLionel Sambuc (void)fpsetsticky(__SHIFTOUT(*envp, VFP_FPSCR_CSUM)); 260*84d9c625SLionel Sambuc #else 261*84d9c625SLionel Sambuc armreg_fpscr_write(*envp); 262*84d9c625SLionel Sambuc #endif 263*84d9c625SLionel Sambuc return 0; 264*84d9c625SLionel Sambuc } 265*84d9c625SLionel Sambuc 266*84d9c625SLionel Sambuc /* 267*84d9c625SLionel Sambuc * The feupdateenv() function shall attempt to save the currently raised 268*84d9c625SLionel Sambuc * floating-point exceptions in its automatic storage, attempt to install the 269*84d9c625SLionel Sambuc * floating-point environment represented by the object pointed to by envp, 270*84d9c625SLionel Sambuc * and then attempt to raise the saved floating-point exceptions. 271*84d9c625SLionel Sambuc */ 272*84d9c625SLionel Sambuc int 273*84d9c625SLionel Sambuc feupdateenv(const fenv_t *envp) 274*84d9c625SLionel Sambuc { 275*84d9c625SLionel Sambuc #ifndef lint 276*84d9c625SLionel Sambuc _DIAGASSERT(envp != NULL); 277*84d9c625SLionel Sambuc #endif 278*84d9c625SLionel Sambuc #ifdef __SOFTFP__ 279*84d9c625SLionel Sambuc (void)fpsetround(__SHIFTIN(*envp, VFP_FPSCR_RMODE)); 280*84d9c625SLionel Sambuc (void)fpsetmask(fpgetmask() | __SHIFTOUT(*envp, VFP_FPSCR_ESUM)); 281*84d9c625SLionel Sambuc (void)fpsetsticky(fpgetsticky() | __SHIFTOUT(*envp, VFP_FPSCR_CSUM)); 282*84d9c625SLionel Sambuc #else 283*84d9c625SLionel Sambuc int fpscr = armreg_fpscr_read() & ~(VFP_FPSCR_ESUM|VFP_FPSCR_CSUM); 284*84d9c625SLionel Sambuc fpscr |= *envp; 285*84d9c625SLionel Sambuc armreg_fpscr_write(fpscr); 286*84d9c625SLionel Sambuc #endif 287*84d9c625SLionel Sambuc 288*84d9c625SLionel Sambuc /* Success */ 289*84d9c625SLionel Sambuc return 0; 290*84d9c625SLionel Sambuc } 291