Home | History | Annotate | Line # | Download | only in riscv
      1 /* $NetBSD: fenv.c,v 1.5 2024/05/17 02:11:07 riastradh Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2014 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Matt Thomas of 3am Software Foundry.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __RCSID("$NetBSD: fenv.c,v 1.5 2024/05/17 02:11:07 riastradh Exp $");
     34 
     35 #include "namespace.h"
     36 
     37 #include <sys/param.h>
     38 #include <sys/sysctl.h>
     39 #include <assert.h>
     40 #include <fenv.h>
     41 #include <stddef.h>
     42 #include <string.h>
     43 
     44 #include <riscv/sysreg.h>
     45 
     46 #ifdef __weak_alias
     47 __weak_alias(feclearexcept,_feclearexcept)
     48 __weak_alias(fedisableexcept,_fedisableexcept)
     49 __weak_alias(feenableexcept,_feenableexcept)
     50 __weak_alias(fegetenv,_fegetenv)
     51 __weak_alias(fegetexcept,_fegetexcept)
     52 __weak_alias(fegetexceptflag,_fegetexceptflag)
     53 __weak_alias(fegetround,_fegetround)
     54 __weak_alias(feholdexcept,_feholdexcept)
     55 __weak_alias(feraiseexcept,_feraiseexcept)
     56 __weak_alias(fesetenv,_fesetenv)
     57 __weak_alias(fesetexceptflag,_fesetexceptflag)
     58 __weak_alias(fesetround,_fesetround)
     59 __weak_alias(fetestexcept,_fetestexcept)
     60 __weak_alias(feupdateenv,_feupdateenv)
     61 #endif
     62 
     63 /*
     64  * The following constant represents the default floating-point environment
     65  * (that is, the one installed at program startup) and has type pointer to
     66  * const-qualified fenv_t.
     67  *
     68  * It can be used as an argument to the functions within the <fenv.h> header
     69  * that manage the floating-point environment, namely fesetenv() and
     70  * feupdateenv().
     71  */
     72 const fenv_t __fe_dfl_env = __SHIFTIN(FCSR_FRM_RNE, FCSR_FRM);
     73 
     74 /*
     75  * The feclearexcept() function clears the supported floating-point exceptions
     76  * represented by `excepts'.
     77  */
     78 int
     79 feclearexcept(int excepts)
     80 {
     81 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
     82 
     83 	int fflags = fcsr_fflags_read();
     84 
     85 	fflags &= ~(excepts & FE_ALL_EXCEPT);
     86 
     87 	fcsr_fflags_write(fflags);
     88 
     89 	/* Success */
     90 	return 0;
     91 }
     92 
     93 /*
     94  * The fegetexceptflag() function stores an implementation-defined
     95  * representation of the states of the floating-point status flags indicated by
     96  * the argument excepts in the object pointed to by the argument flagp.
     97  */
     98 int
     99 fegetexceptflag(fexcept_t *flagp, int excepts)
    100 {
    101 	_DIAGASSERT(flagp != NULL);
    102 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
    103 
    104 	*flagp = fcsr_fflags_read() & excepts;
    105 
    106 	/* Success */
    107 	return 0;
    108 }
    109 
    110 /*
    111  * The feraiseexcept() function raises the supported floating-point exceptions
    112  * represented by the argument `excepts'.
    113  *
    114  * The standard explicitly allows us to execute an instruction that has the
    115  * exception as a side effect, but we choose to manipulate the status register
    116  * directly.
    117  */
    118 int
    119 feraiseexcept(int excepts)
    120 {
    121 
    122 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
    123 
    124 	excepts &= FE_ALL_EXCEPT;
    125 	fcsr_fflags_write(fcsr_fflags_read() | excepts);
    126 
    127 	/* Success */
    128 	return 0;
    129 }
    130 
    131 /*
    132  * This function sets the floating-point status flags indicated by the argument
    133  * `excepts' to the states stored in the object pointed to by `flagp'. It does
    134  * NOT raise any floating-point exceptions, but only sets the state of the flags.
    135  */
    136 int
    137 fesetexceptflag(const fexcept_t *flagp, int excepts)
    138 {
    139 	_DIAGASSERT(flagp != NULL);
    140 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
    141 
    142 	excepts &= FE_ALL_EXCEPT;
    143 
    144 	int fflags = fcsr_fflags_read();
    145 
    146 	fflags = (fflags & ~excepts) | (*flagp & excepts);
    147 
    148 	fcsr_fflags_write(fflags);
    149 
    150 	/* Success */
    151 	return 0;
    152 }
    153 
    154 /*
    155  * The fetestexcept() function determines which of a specified subset of the
    156  * floating-point exception flags are currently set. The `excepts' argument
    157  * specifies the floating-point status flags to be queried.
    158  */
    159 int
    160 fetestexcept(int excepts)
    161 {
    162 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
    163 
    164 	return fcsr_fflags_read() & excepts & FE_ALL_EXCEPT;
    165 }
    166 
    167 int
    168 fegetround(void)
    169 {
    170 	return fcsr_frm_read();
    171 }
    172 
    173 /*
    174  * The fesetround() function shall establish the rounding direction represented
    175  * by its argument round. If the argument is not equal to the value of a
    176  * rounding direction macro, the rounding direction is not changed.
    177  */
    178 int
    179 fesetround(int round)
    180 {
    181 	if ((unsigned int)round > FCSR_FRM_RMM) {
    182 		/* Failure */
    183 		return (-1);
    184 	}
    185 
    186 	fcsr_frm_write(round);
    187 
    188 	/* Success */
    189 	return 0;
    190 }
    191 
    192 /*
    193  * The fegetenv() function attempts to store the current floating-point
    194  * environment in the object pointed to by envp.
    195  */
    196 int
    197 fegetenv(fenv_t *envp)
    198 {
    199 	_DIAGASSERT(envp != NULL);
    200 
    201 	*envp = fcsr_read();
    202 
    203 	/* Success */
    204 	return 0;
    205 }
    206 
    207 /*
    208  * The feholdexcept() function saves the current floating-point environment in
    209  * the object pointed to by envp, clears the floating-point status flags, and
    210  * then installs a non-stop (continue on floating-point exceptions) mode, if
    211  * available, for all floating-point exceptions.
    212  */
    213 int
    214 feholdexcept(fenv_t *envp)
    215 {
    216 	_DIAGASSERT(envp != NULL);
    217 
    218 	*envp = fcsr_read();
    219 
    220 	fcsr_fflags_write(0);
    221 
    222 	/* Success */
    223 	return 0;
    224 }
    225 
    226 /*
    227  * The fesetenv() function attempts to establish the floating-point environment
    228  * represented by the object pointed to by envp. The argument `envp' points
    229  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
    230  * floating-point environment macro. The fesetenv() function does not raise
    231  * floating-point exceptions, but only installs the state of the floating-point
    232  * status flags represented through its argument.
    233  */
    234 int
    235 fesetenv(const fenv_t *envp)
    236 {
    237 
    238 	_DIAGASSERT(envp != NULL);
    239 
    240 	fenv_t env = *envp;
    241 
    242 	if ((env & ~(FCSR_FRM|FCSR_FFLAGS)
    243 	    || __SHIFTOUT(env, FCSR_FRM) > FCSR_FRM_RMM)) {
    244 		return -1;
    245 	}
    246 
    247 	fcsr_write(env);
    248 
    249 	/* Success */
    250 	return 0;
    251 }
    252 
    253 /*
    254  * The feupdateenv() function saves the currently raised floating-point
    255  * exceptions in its automatic storage, installs the floating-point environment
    256  * represented by the object pointed to by `envp', and then raises the saved
    257  * floating-point exceptions. The argument `envp' shall point to an object set
    258  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
    259  * environment macro.
    260  */
    261 int
    262 feupdateenv(const fenv_t *envp)
    263 {
    264 	_DIAGASSERT(envp != NULL);
    265 
    266 	int fflags = fcsr_fflags_read();
    267 
    268 	fesetenv(envp);
    269 	feraiseexcept(fflags);
    270 
    271 	/* Success */
    272 	return 0;
    273 }
    274 
    275 /*
    276  * The following functions are extensions to the standard
    277  */
    278 int
    279 feenableexcept(int nmask)
    280 {
    281 	return 0;
    282 }
    283 
    284 int
    285 fedisableexcept(int nmask)
    286 {
    287 	return 0;
    288 }
    289 
    290 int
    291 fegetexcept(void)
    292 {
    293 	return 0;
    294 }
    295