1 /* $OpenBSD: fenv.c,v 1.4 2016/09/12 19:47:01 guenther 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/types.h> 20 #include <machine/sysarch.h> 21 22 #include <fenv.h> 23 24 /* 25 * Call sysarch(2) via its alias in the reserved namespace: 26 * _thread_sys_sysarch() 27 */ 28 typeof(sysarch) sysarch asm("_thread_sys_sysarch"); 29 30 31 /* 32 * The following constant represents the default floating-point environment 33 * (that is, the one installed at program startup) and has type pointer to 34 * const-qualified fenv_t. 35 * 36 * It can be used as an argument to the functions within the <fenv.h> header 37 * that manage the floating-point environment, namely fesetenv() and 38 * feupdateenv(). 39 */ 40 fenv_t __fe_dfl_env = { 41 0, 42 0, 43 FE_TONEAREST 44 }; 45 46 /* 47 * The feclearexcept() function clears the supported floating-point exceptions 48 * represented by `excepts'. 49 */ 50 int 51 feclearexcept(int excepts) 52 { 53 unsigned int fpsticky; 54 struct alpha_fp_except_args a; 55 56 excepts &= FE_ALL_EXCEPT; 57 58 /* Store the current floating-point sticky flags */ 59 fpsticky = sysarch(ALPHA_FPGETSTICKY, 0L); 60 61 /* Clear the requested floating-point exceptions */ 62 fpsticky &= ~excepts; 63 64 /* Load the floating-point sticky flags */ 65 a.mask = fpsticky; 66 sysarch(ALPHA_FPSETSTICKY, &a); 67 68 return (0); 69 } 70 DEF_STD(feclearexcept); 71 72 /* 73 * The fegetexceptflag() function stores an implementation-defined 74 * representation of the states of the floating-point status flags indicated by 75 * the argument excepts in the object pointed to by the argument flagp. 76 */ 77 int 78 fegetexceptflag(fexcept_t *flagp, int excepts) 79 { 80 unsigned int fpsticky; 81 82 excepts &= FE_ALL_EXCEPT; 83 84 /* Store the current floating-point sticky flags */ 85 fpsticky = sysarch(ALPHA_FPGETSTICKY, 0L); 86 87 /* Store the results in flagp */ 88 *flagp = fpsticky & excepts; 89 90 return (0); 91 } 92 93 /* 94 * The feraiseexcept() function raises the supported floating-point exceptions 95 * represented by the argument `excepts'. 96 */ 97 int 98 feraiseexcept(int excepts) 99 { 100 excepts &= FE_ALL_EXCEPT; 101 102 fesetexceptflag((fexcept_t *)&excepts, excepts); 103 104 return (0); 105 } 106 DEF_STD(feraiseexcept); 107 108 /* 109 * This function sets the floating-point status flags indicated by the argument 110 * `excepts' to the states stored in the object pointed to by `flagp'. It does 111 * NOT raise any floating-point exceptions, but only sets the state of the flags. 112 */ 113 int 114 fesetexceptflag(const fexcept_t *flagp, int excepts) 115 { 116 unsigned int fpsticky; 117 struct alpha_fp_except_args a; 118 119 excepts &= FE_ALL_EXCEPT; 120 121 /* Store the current floating-point sticky flags */ 122 fpsticky = sysarch(ALPHA_FPGETSTICKY, 0L); 123 124 /* Set the requested status flags */ 125 fpsticky &= ~excepts; 126 fpsticky |= *flagp & excepts; 127 128 /* Load the floating-point sticky flags */ 129 a.mask = fpsticky; 130 sysarch(ALPHA_FPSETSTICKY, &a); 131 132 return (0); 133 } 134 DEF_STD(fesetexceptflag); 135 136 /* 137 * The fetestexcept() function determines which of a specified subset of the 138 * floating-point exception flags are currently set. The `excepts' argument 139 * specifies the floating-point status flags to be queried. 140 */ 141 int 142 fetestexcept(int excepts) 143 { 144 unsigned int fpsticky; 145 146 excepts &= FE_ALL_EXCEPT; 147 148 /* Store the current floating-point sticky flags */ 149 fpsticky = sysarch(ALPHA_FPGETSTICKY, 0L); 150 151 return (fpsticky & excepts); 152 } 153 DEF_STD(fetestexcept); 154 155 /* 156 * The fegetround() function gets the current rounding direction. 157 */ 158 int 159 fegetround(void) 160 { 161 unsigned long fpcr; 162 163 /* Store the current floating-point control register */ 164 __asm__ volatile ("trapb"); 165 __asm__ volatile ("mf_fpcr %0" : "=f" (fpcr)); 166 __asm__ volatile ("trapb"); 167 168 return ((fpcr >> _ROUND_SHIFT) & _ROUND_MASK); 169 } 170 DEF_STD(fegetround); 171 172 /* 173 * The fesetround() function establishes the rounding direction represented by 174 * its argument `round'. If the argument is not equal to the value of a rounding 175 * direction macro, the rounding direction is not changed. 176 */ 177 int 178 fesetround(int round) 179 { 180 unsigned long fpcr; 181 182 /* Check whether requested rounding direction is supported */ 183 if (round & ~_ROUND_MASK) 184 return (-1); 185 186 /* Store the current floating-point control register */ 187 __asm__ volatile ("trapb"); 188 __asm__ volatile ("mf_fpcr %0" : "=f" (fpcr)); 189 __asm__ volatile ("trapb"); 190 191 /* Set the rounding direction */ 192 fpcr &= ~((unsigned long)_ROUND_MASK << _ROUND_SHIFT); 193 fpcr |= (unsigned long)round << _ROUND_SHIFT; 194 195 /* Load the floating-point control register */ 196 __asm__ volatile ("trapb"); 197 __asm__ volatile ("mt_fpcr %0" : : "f" (fpcr)); 198 __asm__ volatile ("trapb"); 199 200 return (0); 201 } 202 DEF_STD(fesetround); 203 204 /* 205 * The fegetenv() function attempts to store the current floating-point 206 * environment in the object pointed to by envp. 207 */ 208 int 209 fegetenv(fenv_t *envp) 210 { 211 unsigned long fpcr; 212 213 /* Store the current floating-point sticky flags */ 214 envp->__sticky = sysarch(ALPHA_FPGETSTICKY, 0L) & FE_ALL_EXCEPT; 215 216 /* Store the current floating-point masks */ 217 envp->__mask = sysarch(ALPHA_FPGETMASK, 0L) & FE_ALL_EXCEPT; 218 219 /* Store the current floating-point control register */ 220 __asm__ volatile ("trapb"); 221 __asm__ volatile ("mf_fpcr %0" : "=f" (fpcr)); 222 __asm__ volatile ("trapb"); 223 envp->__round = (fpcr >> _ROUND_SHIFT) & _ROUND_MASK; 224 225 return (0); 226 } 227 DEF_STD(fegetenv); 228 229 /* 230 * The feholdexcept() function saves the current floating-point environment 231 * in the object pointed to by envp, clears the floating-point status flags, and 232 * then installs a non-stop (continue on floating-point exceptions) mode, if 233 * available, for all floating-point exceptions. 234 */ 235 int 236 feholdexcept(fenv_t *envp) 237 { 238 struct alpha_fp_except_args a; 239 240 /* Store the current floating-point environment */ 241 fegetenv(envp); 242 243 /* Clear exception flags */ 244 a.mask = 0; 245 sysarch(ALPHA_FPSETSTICKY, &a); 246 247 /* Mask all exceptions */ 248 a.mask = 0; 249 sysarch(ALPHA_FPSETMASK, &a); 250 251 return (0); 252 } 253 DEF_STD(feholdexcept); 254 255 /* 256 * The fesetenv() function attempts to establish the floating-point environment 257 * represented by the object pointed to by envp. The argument `envp' points 258 * to an object set by a call to fegetenv() or feholdexcept(), or equal a 259 * floating-point environment macro. The fesetenv() function does not raise 260 * floating-point exceptions, but only installs the state of the floating-point 261 * status flags represented through its argument. 262 */ 263 int 264 fesetenv(const fenv_t *envp) 265 { 266 unsigned long fpcr; 267 struct alpha_fp_except_args a; 268 269 /* Load the floating-point sticky flags */ 270 a.mask = envp->__sticky & FE_ALL_EXCEPT; 271 sysarch(ALPHA_FPSETSTICKY, &a); 272 273 /* Load the floating-point masks */ 274 a.mask = envp->__mask & FE_ALL_EXCEPT; 275 sysarch(ALPHA_FPSETMASK, &a); 276 277 /* Store the current floating-point control register */ 278 __asm__ volatile ("trapb"); 279 __asm__ volatile ("mf_fpcr %0" : "=f" (fpcr)); 280 __asm__ volatile ("trapb"); 281 282 /* Set the requested flags */ 283 fpcr &= ~((unsigned long)_ROUND_MASK << _ROUND_SHIFT); 284 fpcr |= ((unsigned long)envp->__round & _ROUND_MASK) << _ROUND_SHIFT; 285 286 /* Load the floating-point control register */ 287 __asm__ volatile ("trapb"); 288 __asm__ volatile ("mt_fpcr %0" : : "f" (fpcr)); 289 __asm__ volatile ("trapb"); 290 291 return (0); 292 } 293 DEF_STD(fesetenv); 294 295 /* 296 * The feupdateenv() function saves the currently raised floating-point 297 * exceptions in its automatic storage, installs the floating-point environment 298 * represented by the object pointed to by `envp', and then raises the saved 299 * floating-point exceptions. The argument `envp' shall point to an object set 300 * by a call to feholdexcept() or fegetenv(), or equal a floating-point 301 * environment macro. 302 */ 303 int 304 feupdateenv(const fenv_t *envp) 305 { 306 unsigned int fpsticky; 307 308 /* Store the current floating-point sticky flags */ 309 fpsticky = sysarch(ALPHA_FPGETSTICKY, 0L); 310 311 /* Install new floating-point environment */ 312 fesetenv(envp); 313 314 /* Raise any previously accumulated exceptions */ 315 feraiseexcept(fpsticky); 316 317 return (0); 318 } 319 DEF_STD(feupdateenv); 320 321 /* 322 * The following functions are extentions to the standard 323 */ 324 int 325 feenableexcept(int mask) 326 { 327 unsigned int fpmask, omask; 328 struct alpha_fp_except_args a; 329 330 mask &= FE_ALL_EXCEPT; 331 332 /* Store the current floating-point masks */ 333 fpmask = sysarch(ALPHA_FPGETMASK, 0L); 334 335 omask = fpmask & FE_ALL_EXCEPT; 336 fpmask |= mask; 337 338 /* Load the floating-point masks */ 339 a.mask = fpmask; 340 sysarch(ALPHA_FPSETMASK, &a); 341 342 return (omask); 343 344 } 345 346 int 347 fedisableexcept(int mask) 348 { 349 unsigned int fpmask, omask; 350 struct alpha_fp_except_args a; 351 352 mask &= FE_ALL_EXCEPT; 353 354 /* Store the current floating-point masks */ 355 fpmask = sysarch(ALPHA_FPGETMASK, 0L); 356 357 omask = fpmask & FE_ALL_EXCEPT; 358 fpmask &= ~mask; 359 360 /* Load the floating-point masks */ 361 a.mask = fpmask; 362 sysarch(ALPHA_FPSETMASK, &a); 363 364 return (omask); 365 } 366 367 int 368 fegetexcept(void) 369 { 370 unsigned int fpmask; 371 372 /* Store the current floating-point masks */ 373 fpmask = sysarch(ALPHA_FPGETMASK, 0L); 374 375 return (fpmask & FE_ALL_EXCEPT); 376 } 377