1 /* $NetBSD: fenv.c,v 1.1 2014/09/19 17:36:25 matt 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.1 2014/09/19 17:36:25 matt Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/sysctl.h> 37 #include <assert.h> 38 #include <fenv.h> 39 #include <stddef.h> 40 #include <string.h> 41 42 #include <riscv/sysreg.h> 43 44 /* 45 * The following constant represents the default floating-point environment 46 * (that is, the one installed at program startup) and has type pointer to 47 * const-qualified fenv_t. 48 * 49 * It can be used as an argument to the functions within the <fenv.h> header 50 * that manage the floating-point environment, namely fesetenv() and 51 * feupdateenv(). 52 */ 53 fenv_t __fe_dfl_env = __SHIFTIN(FCSR_FRM_RNE, FCSR_FRM); 54 55 /* 56 * The feclearexcept() function clears the supported floating-point exceptions 57 * represented by `excepts'. 58 */ 59 int 60 feclearexcept(int excepts) 61 { 62 _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); 63 64 int fflags = riscvreg_fcsr_read_fflags(); 65 66 fflags &= ~(excepts & FE_ALL_EXCEPT); 67 68 riscvreg_fcsr_write_fflags(fflags); 69 70 /* Success */ 71 return (0); 72 } 73 74 /* 75 * The fegetexceptflag() function stores an implementation-defined 76 * representation of the states of the floating-point status flags indicated by 77 * the argument excepts in the object pointed to by the argument flagp. 78 */ 79 int 80 fegetexceptflag(fexcept_t *flagp, int excepts) 81 { 82 _DIAGASSERT(flagp != NULL); 83 _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); 84 85 *flagp = riscvreg_fcsr_read_fflags() & excepts; 86 87 /* Success */ 88 return (0); 89 } 90 91 /* 92 * The feraiseexcept() function raises the supported floating-point exceptions 93 * represented by the argument `excepts'. 94 * 95 * The standard explicitly allows us to execute an instruction that has the 96 * exception as a side effect, but we choose to manipulate the status register 97 * directly. 98 * 99 * The validation of input is being deferred to fesetexceptflag(). 100 */ 101 int 102 feraiseexcept(int excepts) 103 { 104 fexcept_t ex = 0; 105 106 _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); 107 108 excepts &= FE_ALL_EXCEPT; 109 fesetexceptflag(&ex, excepts); 110 /* XXX exception magic XXX */ 111 112 /* Success */ 113 return (0); 114 } 115 116 /* 117 * This function sets the floating-point status flags indicated by the argument 118 * `excepts' to the states stored in the object pointed to by `flagp'. It does 119 * NOT raise any floating-point exceptions, but only sets the state of the flags. 120 */ 121 int 122 fesetexceptflag(const fexcept_t *flagp, int excepts) 123 { 124 _DIAGASSERT(flagp != NULL); 125 _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); 126 127 excepts &= FE_ALL_EXCEPT; 128 129 int fflags = riscvreg_fcsr_read_fflags(); 130 131 fflags = (fflags & ~excepts) | (*flagp & excepts); 132 133 riscvreg_fcsr_write_fflags(fflags); 134 135 /* Success */ 136 return (0); 137 } 138 139 /* 140 * The fetestexcept() function determines which of a specified subset of the 141 * floating-point exception flags are currently set. The `excepts' argument 142 * specifies the floating-point status flags to be queried. 143 */ 144 int 145 fetestexcept(int excepts) 146 { 147 _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); 148 149 return riscvreg_fcsr_read_fflags() & excepts & FE_ALL_EXCEPT; 150 } 151 152 int 153 fegetround(void) 154 { 155 return riscvreg_fcsr_read_frm(); 156 } 157 158 /* 159 * The fesetround() function shall establish the rounding direction represented 160 * by its argument round. If the argument is not equal to the value of a 161 * rounding direction macro, the rounding direction is not changed. 162 */ 163 int 164 fesetround(int round) 165 { 166 if ((unsigned int)round > FCSR_FRM_RMM) { 167 /* Failure */ 168 return (-1); 169 } 170 171 riscvreg_fcsr_write_frm(round); 172 173 /* Success */ 174 return (0); 175 } 176 177 /* 178 * The fegetenv() function attempts to store the current floating-point 179 * environment in the object pointed to by envp. 180 */ 181 int 182 fegetenv(fenv_t *envp) 183 { 184 _DIAGASSERT(envp != NULL); 185 186 *envp = riscvreg_fcsr_read(); 187 188 /* Success */ 189 return (0); 190 } 191 192 /* 193 * The feholdexcept() function saves the current floating-point environment in 194 * the object pointed to by envp, clears the floating-point status flags, and 195 * then installs a non-stop (continue on floating-point exceptions) mode, if 196 * available, for all floating-point exceptions. 197 */ 198 int 199 feholdexcept(fenv_t *envp) 200 { 201 _DIAGASSERT(envp != NULL); 202 203 *envp = riscvreg_fcsr_read(); 204 205 riscvreg_fcsr_write_fflags(0); 206 207 /* Success */ 208 return (0); 209 } 210 211 /* 212 * The fesetenv() function attempts to establish the floating-point environment 213 * represented by the object pointed to by envp. The argument `envp' points 214 * to an object set by a call to fegetenv() or feholdexcept(), or equal a 215 * floating-point environment macro. The fesetenv() function does not raise 216 * floating-point exceptions, but only installs the state of the floating-point 217 * status flags represented through its argument. 218 */ 219 int 220 fesetenv(const fenv_t *envp) 221 { 222 223 _DIAGASSERT(envp != NULL); 224 225 fenv_t env = *envp; 226 227 if ((env & ~(FCSR_FRM|FCSR_FFLAGS) 228 || __SHIFTOUT(env, FCSR_FRM) > FCSR_FRM_RMM)) { 229 return -1; 230 } 231 232 riscvreg_fcsr_write(env); 233 234 /* Success */ 235 return (0); 236 } 237 238 /* 239 * The feupdateenv() function saves the currently raised floating-point 240 * exceptions in its automatic storage, installs the floating-point environment 241 * represented by the object pointed to by `envp', and then raises the saved 242 * floating-point exceptions. The argument `envp' shall point to an object set 243 * by a call to feholdexcept() or fegetenv(), or equal a floating-point 244 * environment macro. 245 */ 246 int 247 feupdateenv(const fenv_t *envp) 248 { 249 _DIAGASSERT(envp != NULL); 250 251 int fflags = riscvreg_fcsr_read_fflags(); 252 253 fesetenv(envp); 254 feraiseexcept(fflags); 255 256 /* Success */ 257 return (0); 258 } 259 260 /* 261 * The following functions are extentions to the standard 262 */ 263 int 264 feenableexcept(int nmask) 265 { 266 return 0; 267 } 268 269 int 270 fedisableexcept(int nmask) 271 { 272 return 0; 273 } 274 275 int 276 fegetexcept(void) 277 { 278 return 0; 279 } 280