1 /* $NetBSD: fenv.c,v 1.4 2023/05/07 12:41:47 skrll 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.4 2023/05/07 12:41:47 skrll 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 * The validation of input is being deferred to fesetexceptflag(). 119 */ 120 int 121 feraiseexcept(int excepts) 122 { 123 fexcept_t ex = 0; 124 125 _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); 126 127 excepts &= FE_ALL_EXCEPT; 128 fesetexceptflag(&ex, excepts); 129 /* XXX exception magic XXX */ 130 131 /* Success */ 132 return 0; 133 } 134 135 /* 136 * This function sets the floating-point status flags indicated by the argument 137 * `excepts' to the states stored in the object pointed to by `flagp'. It does 138 * NOT raise any floating-point exceptions, but only sets the state of the flags. 139 */ 140 int 141 fesetexceptflag(const fexcept_t *flagp, int excepts) 142 { 143 _DIAGASSERT(flagp != NULL); 144 _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); 145 146 excepts &= FE_ALL_EXCEPT; 147 148 int fflags = fcsr_fflags_read(); 149 150 fflags = (fflags & ~excepts) | (*flagp & excepts); 151 152 fcsr_fflags_write(fflags); 153 154 /* Success */ 155 return 0; 156 } 157 158 /* 159 * The fetestexcept() function determines which of a specified subset of the 160 * floating-point exception flags are currently set. The `excepts' argument 161 * specifies the floating-point status flags to be queried. 162 */ 163 int 164 fetestexcept(int excepts) 165 { 166 _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); 167 168 return fcsr_fflags_read() & excepts & FE_ALL_EXCEPT; 169 } 170 171 int 172 fegetround(void) 173 { 174 return fcsr_frm_read(); 175 } 176 177 /* 178 * The fesetround() function shall establish the rounding direction represented 179 * by its argument round. If the argument is not equal to the value of a 180 * rounding direction macro, the rounding direction is not changed. 181 */ 182 int 183 fesetround(int round) 184 { 185 if ((unsigned int)round > FCSR_FRM_RMM) { 186 /* Failure */ 187 return (-1); 188 } 189 190 fcsr_frm_write(round); 191 192 /* Success */ 193 return 0; 194 } 195 196 /* 197 * The fegetenv() function attempts to store the current floating-point 198 * environment in the object pointed to by envp. 199 */ 200 int 201 fegetenv(fenv_t *envp) 202 { 203 _DIAGASSERT(envp != NULL); 204 205 *envp = fcsr_read(); 206 207 /* Success */ 208 return 0; 209 } 210 211 /* 212 * The feholdexcept() function saves the current floating-point environment in 213 * the object pointed to by envp, clears the floating-point status flags, and 214 * then installs a non-stop (continue on floating-point exceptions) mode, if 215 * available, for all floating-point exceptions. 216 */ 217 int 218 feholdexcept(fenv_t *envp) 219 { 220 _DIAGASSERT(envp != NULL); 221 222 *envp = fcsr_read(); 223 224 fcsr_fflags_write(0); 225 226 /* Success */ 227 return 0; 228 } 229 230 /* 231 * The fesetenv() function attempts to establish the floating-point environment 232 * represented by the object pointed to by envp. The argument `envp' points 233 * to an object set by a call to fegetenv() or feholdexcept(), or equal a 234 * floating-point environment macro. The fesetenv() function does not raise 235 * floating-point exceptions, but only installs the state of the floating-point 236 * status flags represented through its argument. 237 */ 238 int 239 fesetenv(const fenv_t *envp) 240 { 241 242 _DIAGASSERT(envp != NULL); 243 244 fenv_t env = *envp; 245 246 if ((env & ~(FCSR_FRM|FCSR_FFLAGS) 247 || __SHIFTOUT(env, FCSR_FRM) > FCSR_FRM_RMM)) { 248 return -1; 249 } 250 251 fcsr_write(env); 252 253 /* Success */ 254 return 0; 255 } 256 257 /* 258 * The feupdateenv() function saves the currently raised floating-point 259 * exceptions in its automatic storage, installs the floating-point environment 260 * represented by the object pointed to by `envp', and then raises the saved 261 * floating-point exceptions. The argument `envp' shall point to an object set 262 * by a call to feholdexcept() or fegetenv(), or equal a floating-point 263 * environment macro. 264 */ 265 int 266 feupdateenv(const fenv_t *envp) 267 { 268 _DIAGASSERT(envp != NULL); 269 270 int fflags = fcsr_fflags_read(); 271 272 fesetenv(envp); 273 feraiseexcept(fflags); 274 275 /* Success */ 276 return 0; 277 } 278 279 /* 280 * The following functions are extensions to the standard 281 */ 282 int 283 feenableexcept(int nmask) 284 { 285 return 0; 286 } 287 288 int 289 fedisableexcept(int nmask) 290 { 291 return 0; 292 } 293 294 int 295 fegetexcept(void) 296 { 297 return 0; 298 } 299