1 /* $OpenBSD: fenv.c,v 1.4 2020/07/09 22:13:29 kettenis Exp $ */ 2 /*- 3 * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/lib/msun/aarch64/fenv.h 280857 2015-03-30 16:42:08Z emaste $ 28 */ 29 30 #include <fenv.h> 31 #include <machine/ieeefp.h> 32 33 /* We need to be able to map status flag positions to mask flag positions */ 34 #define _FPUSW_SHIFT 8 35 #define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT) 36 37 #define __mrs_fpcr(r) __asm __volatile("mrs %x0, fpcr" : "=r" (r)) 38 #define __msr_fpcr(r) __asm __volatile("msr fpcr, %x0" : : "r" (r)) 39 40 #define __mrs_fpsr(r) __asm __volatile("mrs %x0, fpsr" : "=r" (r)) 41 #define __msr_fpsr(r) __asm __volatile("msr fpsr, %x0" : : "r" (r)) 42 43 /* 44 * The following constant represents the default floating-point environment 45 * (that is, the one installed at program startup) and has type pointer to 46 * const-qualified fenv_t. 47 * 48 * It can be used as an argument to the functions within the <fenv.h> header 49 * that manage the floating-point environment, namely fesetenv() and 50 * feupdateenv(). 51 */ 52 fenv_t __fe_dfl_env = 0; 53 54 /* 55 * The feclearexcept() function clears the supported floating-point exceptions 56 * represented by `excepts'. 57 */ 58 int 59 feclearexcept(int excepts) 60 { 61 fexcept_t r; 62 63 excepts &= FE_ALL_EXCEPT; 64 __mrs_fpsr(r); 65 r &= ~excepts; 66 __msr_fpsr(r); 67 return (0); 68 } 69 DEF_STD(feclearexcept); 70 71 /* 72 * The fegetexceptflag() function stores an implementation-defined 73 * representation of the states of the floating-point status flags indicated by 74 * the argument excepts in the object pointed to by the argument flagp. 75 */ 76 int 77 fegetexceptflag(fexcept_t *flagp, int excepts) 78 { 79 fexcept_t r; 80 81 excepts &= FE_ALL_EXCEPT; 82 __mrs_fpsr(r); 83 *flagp = r & excepts; 84 return (0); 85 } 86 87 /* 88 * The feraiseexcept() function raises the supported floating-point exceptions 89 * represented by the argument `excepts'. 90 */ 91 int 92 feraiseexcept(int excepts) 93 { 94 fexcept_t r; 95 96 excepts &= FE_ALL_EXCEPT; 97 __mrs_fpsr(r); 98 r |= excepts; 99 __msr_fpsr(r); 100 return (0); 101 } 102 DEF_STD(feraiseexcept); 103 104 /* 105 * This function sets the floating-point status flags indicated by the argument 106 * `excepts' to the states stored in the object pointed to by `flagp'. It does 107 * NOT raise any floating-point exceptions, but only sets the state of the flags. 108 */ 109 int 110 fesetexceptflag(const fexcept_t *flagp, int excepts) 111 { 112 fexcept_t r; 113 114 excepts &= FE_ALL_EXCEPT; 115 __mrs_fpsr(r); 116 r &= ~excepts; 117 r |= *flagp & excepts; 118 __msr_fpsr(r); 119 return (0); 120 } 121 DEF_STD(fesetexceptflag); 122 123 /* 124 * The fetestexcept() function determines which of a specified subset of the 125 * floating-point exception flags are currently set. The `excepts' argument 126 * specifies the floating-point status flags to be queried. 127 */ 128 int 129 fetestexcept(int excepts) 130 { 131 fexcept_t r; 132 133 excepts &= FE_ALL_EXCEPT; 134 __mrs_fpsr(r); 135 return (r & excepts); 136 } 137 DEF_STD(fetestexcept); 138 139 /* 140 * The fegetround() function gets the current rounding direction. 141 */ 142 int 143 fegetround(void) 144 { 145 fenv_t r; 146 147 __mrs_fpcr(r); 148 return ((r >> _ROUND_SHIFT) & _ROUND_MASK); 149 } 150 DEF_STD(fegetround); 151 152 /* 153 * The fesetround() function establishes the rounding direction represented by 154 * its argument `round'. If the argument is not equal to the value of a rounding 155 * direction macro, the rounding direction is not changed. 156 */ 157 int 158 fesetround(int round) 159 { 160 fenv_t r; 161 162 if (round & ~_ROUND_MASK) 163 return (-1); 164 __mrs_fpcr(r); 165 r &= ~(_ROUND_MASK << _ROUND_SHIFT); 166 r |= round << _ROUND_SHIFT; 167 __msr_fpcr(r); 168 return (0); 169 } 170 DEF_STD(fesetround); 171 172 /* 173 * The fegetenv() function attempts to store the current floating-point 174 * environment in the object pointed to by envp. 175 */ 176 int 177 fegetenv(fenv_t *envp) 178 { 179 fenv_t r; 180 181 __mrs_fpcr(r); 182 *envp = r; 183 184 __mrs_fpsr(r); 185 *envp |= (r << 32); 186 187 return (0); 188 } 189 DEF_STD(fegetenv); 190 191 /* 192 * The feholdexcept() function saves the current floating-point environment 193 * in the object pointed to by envp, clears the floating-point status flags, and 194 * then installs a non-stop (continue on floating-point exceptions) mode, if 195 * available, for all floating-point exceptions. 196 */ 197 int 198 feholdexcept(fenv_t *envp) 199 { 200 fenv_t r; 201 202 __mrs_fpcr(r); 203 *envp = r; 204 r &= ~_ENABLE_MASK; 205 __msr_fpcr(r); 206 207 __mrs_fpsr(r); 208 *envp |= (r << 32); 209 r &= ~FE_ALL_EXCEPT; 210 __msr_fpsr(r); 211 return (0); 212 } 213 DEF_STD(feholdexcept); 214 215 /* 216 * The fesetenv() function attempts to establish the floating-point environment 217 * represented by the object pointed to by envp. The argument `envp' points 218 * to an object set by a call to fegetenv() or feholdexcept(), or equal a 219 * floating-point environment macro. The fesetenv() function does not raise 220 * floating-point exceptions, but only installs the state of the floating-point 221 * status flags represented through its argument. 222 */ 223 int 224 fesetenv(const fenv_t *envp) 225 { 226 227 __msr_fpcr(*envp & 0xffffffff); 228 __msr_fpsr(*envp >> 32); 229 return (0); 230 } 231 DEF_STD(fesetenv); 232 233 /* 234 * The feupdateenv() function saves the currently raised floating-point 235 * exceptions in its automatic storage, installs the floating-point environment 236 * represented by the object pointed to by `envp', and then raises the saved 237 * floating-point exceptions. The argument `envp' shall point to an object set 238 * by a call to feholdexcept() or fegetenv(), or equal a floating-point 239 * environment macro. 240 */ 241 int 242 feupdateenv(const fenv_t *envp) 243 { 244 fexcept_t r; 245 246 __mrs_fpsr(r); 247 fesetenv(envp); 248 feraiseexcept(r & FE_ALL_EXCEPT); 249 return (0); 250 } 251 DEF_STD(feupdateenv); 252 253 /* 254 * The following functions are extentions to the standard 255 */ 256 int 257 feenableexcept(int mask) 258 { 259 return -1; 260 } 261 262 int 263 fedisableexcept(int mask) 264 { 265 return 0; 266 } 267 268 int 269 fegetexcept(void) 270 { 271 return 0; 272 } 273