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