/* $NetBSD: fenv.c,v 1.2 2017/03/22 23:11:08 chs Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Matt Thomas of 3am Software Foundry. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __RCSID("$NetBSD: fenv.c,v 1.2 2017/03/22 23:11:08 chs Exp $"); #include "namespace.h" #include #include #include #include #include #include #include #ifdef __weak_alias __weak_alias(feclearexcept,_feclearexcept) __weak_alias(fedisableexcept,_fedisableexcept) __weak_alias(feenableexcept,_feenableexcept) __weak_alias(fegetenv,_fegetenv) __weak_alias(fegetexcept,_fegetexcept) __weak_alias(fegetexceptflag,_fegetexceptflag) __weak_alias(fegetround,_fegetround) __weak_alias(feholdexcept,_feholdexcept) __weak_alias(feraiseexcept,_feraiseexcept) __weak_alias(fesetenv,_fesetenv) __weak_alias(fesetexceptflag,_fesetexceptflag) __weak_alias(fesetround,_fesetround) __weak_alias(fetestexcept,_fetestexcept) __weak_alias(feupdateenv,_feupdateenv) #endif /* * The following constant represents the default floating-point environment * (that is, the one installed at program startup) and has type pointer to * const-qualified fenv_t. * * It can be used as an argument to the functions within the header * that manage the floating-point environment, namely fesetenv() and * feupdateenv(). */ const fenv_t __fe_dfl_env = __SHIFTIN(FCSR_FRM_RNE, FCSR_FRM); /* * The feclearexcept() function clears the supported floating-point exceptions * represented by `excepts'. */ int feclearexcept(int excepts) { _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); int fflags = riscvreg_fcsr_read_fflags(); fflags &= ~(excepts & FE_ALL_EXCEPT); riscvreg_fcsr_write_fflags(fflags); /* Success */ return (0); } /* * The fegetexceptflag() function stores an implementation-defined * representation of the states of the floating-point status flags indicated by * the argument excepts in the object pointed to by the argument flagp. */ int fegetexceptflag(fexcept_t *flagp, int excepts) { _DIAGASSERT(flagp != NULL); _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); *flagp = riscvreg_fcsr_read_fflags() & excepts; /* Success */ return (0); } /* * The feraiseexcept() function raises the supported floating-point exceptions * represented by the argument `excepts'. * * The standard explicitly allows us to execute an instruction that has the * exception as a side effect, but we choose to manipulate the status register * directly. * * The validation of input is being deferred to fesetexceptflag(). */ int feraiseexcept(int excepts) { fexcept_t ex = 0; _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); excepts &= FE_ALL_EXCEPT; fesetexceptflag(&ex, excepts); /* XXX exception magic XXX */ /* Success */ return (0); } /* * This function sets the floating-point status flags indicated by the argument * `excepts' to the states stored in the object pointed to by `flagp'. It does * NOT raise any floating-point exceptions, but only sets the state of the flags. */ int fesetexceptflag(const fexcept_t *flagp, int excepts) { _DIAGASSERT(flagp != NULL); _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); excepts &= FE_ALL_EXCEPT; int fflags = riscvreg_fcsr_read_fflags(); fflags = (fflags & ~excepts) | (*flagp & excepts); riscvreg_fcsr_write_fflags(fflags); /* Success */ return (0); } /* * The fetestexcept() function determines which of a specified subset of the * floating-point exception flags are currently set. The `excepts' argument * specifies the floating-point status flags to be queried. */ int fetestexcept(int excepts) { _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); return riscvreg_fcsr_read_fflags() & excepts & FE_ALL_EXCEPT; } int fegetround(void) { return riscvreg_fcsr_read_frm(); } /* * The fesetround() function shall establish the rounding direction represented * by its argument round. If the argument is not equal to the value of a * rounding direction macro, the rounding direction is not changed. */ int fesetround(int round) { if ((unsigned int)round > FCSR_FRM_RMM) { /* Failure */ return (-1); } riscvreg_fcsr_write_frm(round); /* Success */ return (0); } /* * The fegetenv() function attempts to store the current floating-point * environment in the object pointed to by envp. */ int fegetenv(fenv_t *envp) { _DIAGASSERT(envp != NULL); *envp = riscvreg_fcsr_read(); /* Success */ return (0); } /* * The feholdexcept() function saves the current floating-point environment in * the object pointed to by envp, clears the floating-point status flags, and * then installs a non-stop (continue on floating-point exceptions) mode, if * available, for all floating-point exceptions. */ int feholdexcept(fenv_t *envp) { _DIAGASSERT(envp != NULL); *envp = riscvreg_fcsr_read(); riscvreg_fcsr_write_fflags(0); /* Success */ return (0); } /* * The fesetenv() function attempts to establish the floating-point environment * represented by the object pointed to by envp. The argument `envp' points * to an object set by a call to fegetenv() or feholdexcept(), or equal a * floating-point environment macro. The fesetenv() function does not raise * floating-point exceptions, but only installs the state of the floating-point * status flags represented through its argument. */ int fesetenv(const fenv_t *envp) { _DIAGASSERT(envp != NULL); fenv_t env = *envp; if ((env & ~(FCSR_FRM|FCSR_FFLAGS) || __SHIFTOUT(env, FCSR_FRM) > FCSR_FRM_RMM)) { return -1; } riscvreg_fcsr_write(env); /* Success */ return (0); } /* * The feupdateenv() function saves the currently raised floating-point * exceptions in its automatic storage, installs the floating-point environment * represented by the object pointed to by `envp', and then raises the saved * floating-point exceptions. The argument `envp' shall point to an object set * by a call to feholdexcept() or fegetenv(), or equal a floating-point * environment macro. */ int feupdateenv(const fenv_t *envp) { _DIAGASSERT(envp != NULL); int fflags = riscvreg_fcsr_read_fflags(); fesetenv(envp); feraiseexcept(fflags); /* Success */ return (0); } /* * The following functions are extentions to the standard */ int feenableexcept(int nmask) { return 0; } int fedisableexcept(int nmask) { return 0; } int fegetexcept(void) { return 0; }