1 /* $OpenBSD: fenv.c,v 1.2 2011/04/28 17:34:23 martynas Exp $ */ 2 3 /* 4 * Copyright (c) 2011 Martynas Venckus <martynas@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/cdefs.h> 20 21 #include <fenv.h> 22 23 /* 24 * The following constant represents the default floating-point environment 25 * (that is, the one installed at program startup) and has type pointer to 26 * const-qualified fenv_t. 27 * 28 * It can be used as an argument to the functions within the <fenv.h> header 29 * that manage the floating-point environment, namely fesetenv() and 30 * feupdateenv(). 31 */ 32 fenv_t __fe_dfl_env = 0; 33 34 /* 35 * The feclearexcept() function clears the supported floating-point exceptions 36 * represented by `excepts'. 37 */ 38 int 39 feclearexcept(int excepts) 40 { 41 unsigned int fcsr; 42 43 excepts &= FE_ALL_EXCEPT; 44 45 /* Store the current floating-point control and status register */ 46 __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (fcsr)); 47 48 /* Clear the requested floating-point exceptions */ 49 fcsr &= ~excepts; 50 51 /* Load the floating-point control and status register */ 52 __asm__ __volatile__ ("ctc1 %0, $31" : : "r" (fcsr)); 53 54 return (0); 55 } 56 57 /* 58 * The fegetexceptflag() function stores an implementation-defined 59 * representation of the states of the floating-point status flags indicated by 60 * the argument excepts in the object pointed to by the argument flagp. 61 */ 62 int 63 fegetexceptflag(fexcept_t *flagp, int excepts) 64 { 65 unsigned int fcsr; 66 67 excepts &= FE_ALL_EXCEPT; 68 69 /* Store the current floating-point control and status register */ 70 __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (fcsr)); 71 72 /* Store the results in flagp */ 73 *flagp = fcsr & excepts; 74 75 return (0); 76 } 77 78 /* 79 * The feraiseexcept() function raises the supported floating-point exceptions 80 * represented by the argument `excepts'. 81 */ 82 int 83 feraiseexcept(int excepts) 84 { 85 unsigned int fcsr; 86 87 excepts &= FE_ALL_EXCEPT; 88 89 /* Store the current floating-point control and status register */ 90 __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (fcsr)); 91 92 fcsr |= excepts | (excepts << 10); 93 94 /* Load the floating-point control and status register */ 95 __asm__ __volatile__ ("ctc1 %0, $31" : : "r" (fcsr)); 96 97 return (0); 98 } 99 100 /* 101 * This function sets the floating-point status flags indicated by the argument 102 * `excepts' to the states stored in the object pointed to by `flagp'. It does 103 * NOT raise any floating-point exceptions, but only sets the state of the flags. 104 */ 105 int 106 fesetexceptflag(const fexcept_t *flagp, int excepts) 107 { 108 unsigned int fcsr; 109 110 excepts &= FE_ALL_EXCEPT; 111 112 /* Store the current floating-point control and status register */ 113 __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (fcsr)); 114 115 /* Set the requested status flags */ 116 fcsr &= ~excepts; 117 fcsr |= *flagp & excepts; 118 119 /* Load the floating-point control and status register */ 120 __asm__ __volatile__ ("ctc1 %0, $31" : : "r" (fcsr)); 121 122 return (0); 123 } 124 125 /* 126 * The fetestexcept() function determines which of a specified subset of the 127 * floating-point exception flags are currently set. The `excepts' argument 128 * specifies the floating-point status flags to be queried. 129 */ 130 int 131 fetestexcept(int excepts) 132 { 133 unsigned int fcsr; 134 135 excepts &= FE_ALL_EXCEPT; 136 137 /* Store the current floating-point control and status register */ 138 __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (fcsr)); 139 140 return (fcsr & excepts); 141 } 142 143 /* 144 * The fegetround() function gets the current rounding direction. 145 */ 146 int 147 fegetround(void) 148 { 149 unsigned int fcsr; 150 151 /* Store the current floating-point control and status register */ 152 __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (fcsr)); 153 154 return (fcsr & _ROUND_MASK); 155 } 156 157 /* 158 * The fesetround() function establishes the rounding direction represented by 159 * its argument `round'. If the argument is not equal to the value of a rounding 160 * direction macro, the rounding direction is not changed. 161 */ 162 int 163 fesetround(int round) 164 { 165 unsigned int fcsr; 166 167 /* Check whether requested rounding direction is supported */ 168 if (round & ~_ROUND_MASK) 169 return (-1); 170 171 /* Store the current floating-point control and status register */ 172 __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (fcsr)); 173 174 /* Set the rounding direction */ 175 fcsr &= ~_ROUND_MASK; 176 fcsr |= round; 177 178 /* Load the floating-point control and status register */ 179 __asm__ __volatile__ ("ctc1 %0, $31" : : "r" (fcsr)); 180 181 return (0); 182 } 183 184 /* 185 * The fegetenv() function attempts to store the current floating-point 186 * environment in the object pointed to by envp. 187 */ 188 int 189 fegetenv(fenv_t *envp) 190 { 191 /* Store the current floating-point control and status register */ 192 __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (*envp)); 193 194 return (0); 195 } 196 197 /* 198 * The feholdexcept() function saves the current floating-point environment 199 * in the object pointed to by envp, clears the floating-point status flags, and 200 * then installs a non-stop (continue on floating-point exceptions) mode, if 201 * available, for all floating-point exceptions. 202 */ 203 int 204 feholdexcept(fenv_t *envp) 205 { 206 unsigned int fcsr; 207 208 /* Store the current floating-point control and status register */ 209 __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (*envp)); 210 211 /* Clear exception flags in FCSR */ 212 fcsr = *envp; 213 fcsr &= ~FE_ALL_EXCEPT; 214 215 /* Mask all exceptions */ 216 fcsr &= ~(FE_ALL_EXCEPT << _MASK_SHIFT); 217 __asm__ __volatile__ ("ctc1 %0, $31" : : "r" (fcsr)); 218 219 return (0); 220 } 221 222 /* 223 * The fesetenv() function attempts to establish the floating-point environment 224 * represented by the object pointed to by envp. The argument `envp' points 225 * to an object set by a call to fegetenv() or feholdexcept(), or equal a 226 * floating-point environment macro. The fesetenv() function does not raise 227 * floating-point exceptions, but only installs the state of the floating-point 228 * status flags represented through its argument. 229 */ 230 int 231 fesetenv(const fenv_t *envp) 232 { 233 /* Load the floating-point control and status register */ 234 __asm__ __volatile__ ("ctc1 %0, $31" : : "r" (*envp)); 235 236 return (0); 237 } 238 239 /* 240 * The feupdateenv() function saves the currently raised floating-point 241 * exceptions in its automatic storage, installs the floating-point environment 242 * represented by the object pointed to by `envp', and then raises the saved 243 * floating-point exceptions. The argument `envp' shall point to an object set 244 * by a call to feholdexcept() or fegetenv(), or equal a floating-point 245 * environment macro. 246 */ 247 int 248 feupdateenv(const fenv_t *envp) 249 { 250 unsigned int fcsr; 251 252 /* Store the current floating-point control and status register */ 253 __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (fcsr)); 254 255 /* Install new floating-point environment */ 256 fesetenv(envp); 257 258 /* Raise any previously accumulated exceptions */ 259 feraiseexcept(fcsr); 260 261 return (0); 262 } 263 264 /* 265 * The following functions are extentions to the standard 266 */ 267 int 268 feenableexcept(int mask) 269 { 270 unsigned int fcsr, omask; 271 272 mask &= FE_ALL_EXCEPT; 273 274 /* Store the current floating-point control and status register */ 275 __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (fcsr)); 276 277 omask = (fcsr >> _MASK_SHIFT) & FE_ALL_EXCEPT; 278 fcsr |= mask << _MASK_SHIFT; 279 280 /* Load the floating-point control and status register */ 281 __asm__ __volatile__ ("ctc1 %0, $31" : : "r" (fcsr)); 282 283 return (omask); 284 285 } 286 287 int 288 fedisableexcept(int mask) 289 { 290 unsigned int fcsr, omask; 291 292 mask &= FE_ALL_EXCEPT; 293 294 /* Store the current floating-point control and status register */ 295 __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (fcsr)); 296 297 omask = (fcsr >> _MASK_SHIFT) & FE_ALL_EXCEPT; 298 fcsr &= ~(mask << _MASK_SHIFT); 299 300 /* Load the floating-point control and status register */ 301 __asm__ __volatile__ ("ctc1 %0, $31" : : "r" (fcsr)); 302 303 return (omask); 304 } 305 306 int 307 fegetexcept(void) 308 { 309 unsigned int fcsr; 310 311 /* Store the current floating-point control and status register */ 312 __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (fcsr)); 313 314 return ((fcsr >> _MASK_SHIFT) & FE_ALL_EXCEPT); 315 } 316