1 /* $NetBSD: fenv.h,v 1.10 2024/10/30 15:56:11 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 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 #ifndef _M68K_FENV_H_ 33 #define _M68K_FENV_H_ 34 35 #include <sys/featuretest.h> 36 #include <sys/stdint.h> 37 38 #include <m68k/float.h> 39 #include <m68k/fpreg.h> 40 41 /* Exception bits, from FPSR */ 42 #define FE_INEXACT FPSR_AINEX 43 #define FE_DIVBYZERO FPSR_ADZ 44 #define FE_UNDERFLOW FPSR_AUNFL 45 #define FE_OVERFLOW FPSR_AOVFL 46 #define FE_INVALID FPSR_AIOP 47 48 #define FE_ALL_EXCEPT \ 49 (FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID) 50 51 /* Rounding modes, from FPCR */ 52 #define FE_TONEAREST FPCR_NEAR 53 #define FE_TOWARDZERO FPCR_ZERO 54 #define FE_DOWNWARD FPCR_MINF 55 #define FE_UPWARD FPCR_PINF 56 57 #define _ROUND_MASK \ 58 (FE_TONEAREST | FE_TOWARDZERO | FE_DOWNWARD | FE_UPWARD) 59 60 #if defined(__HAVE_68881__) 61 62 #ifndef __fenv_static 63 #define __fenv_static static 64 #endif 65 66 typedef uint32_t fexcept_t; 67 68 /* same layout as fmovem */ 69 typedef struct { 70 uint32_t fpcr; 71 uint32_t fpsr; 72 uint32_t fppc; 73 } fenv_t; 74 75 #define FE_DFL_ENV ((fenv_t *) -1) 76 77 #define __get_fpcr(__fpcr) \ 78 __asm__ __volatile__ ("fmove%.l %!,%0" : "=dm" (__fpcr)) 79 #define __set_fpcr(__fpcr) \ 80 __asm__ __volatile__ ("fmove%.l %0,%!" : : "dm" (__fpcr)) 81 82 #define __get_fpsr(__fpsr) \ 83 __asm__ __volatile__ ("fmove%.l %/fpsr,%0" : "=dm" (__fpsr)) 84 #define __set_fpsr(__fpsr) \ 85 __asm__ __volatile__ ("fmove%.l %0,%/fpsr" : : "dm" (__fpsr)) 86 87 #define __fmul(__s, __t, __d) \ 88 do { \ 89 __t d = __d; \ 90 __asm__ __volatile__ ("fmul" __s "; fnop" : "=f" (d) : "0" (d)); \ 91 } while (/*CONSTCOND*/0) 92 93 #define __fdiv(__s, __t, __d) \ 94 do { \ 95 __t d = __d; \ 96 __asm__ __volatile__ ("fdiv" __s "; fnop" : "=f" (d) : "0" (d)); \ 97 } while (/*CONSTCOND*/0) 98 99 #define __fetox(__s, __t, __d) \ 100 do { \ 101 __t d = __d; \ 102 __asm__ __volatile__ ("fetox" __s "; fnop" : "=f" (d) : "0" (d)); \ 103 } while (/*CONSTCOND*/0) 104 105 #define __fgetenv(__envp) \ 106 __asm__ __volatile__ ("fmovem%.l %/fpcr/%/fpsr/%/fpiar,%0" : "=m" (__envp)) 107 108 #define __fsetenv(__envp) \ 109 __asm__ __volatile__ ("fmovem%.l %0,%/fpcr/%/fpsr/%/fpiar" : : "m" (__envp)) 110 111 __BEGIN_DECLS 112 113 #if __GNUC_PREREQ__(8, 0) 114 #pragma GCC diagnostic push 115 #pragma GCC diagnostic ignored "-Wshadow" 116 #endif 117 118 __fenv_static inline int 119 feclearexcept(int __excepts) 120 { 121 fexcept_t __fpsr; 122 123 __excepts &= FE_ALL_EXCEPT; 124 125 __get_fpsr(__fpsr); 126 __fpsr &= ~__excepts; 127 __set_fpsr(__fpsr); 128 129 return 0; 130 } 131 132 __fenv_static inline int 133 fegetexceptflag(fexcept_t *__flagp, int __excepts) 134 { 135 fexcept_t __fpsr; 136 137 __get_fpsr(__fpsr); 138 139 *__flagp = __fpsr & __excepts & FE_ALL_EXCEPT; 140 141 return 0; 142 } 143 144 __fenv_static inline int 145 fesetexceptflag(const fexcept_t *__flagp, int __excepts) 146 { 147 fexcept_t __fpsr; 148 149 __get_fpsr(__fpsr); 150 151 __fpsr &= ~(__excepts & FE_ALL_EXCEPT); 152 __fpsr |= *__flagp & __excepts & FE_ALL_EXCEPT; 153 154 __set_fpsr(__fpsr); 155 156 return 0; 157 } 158 159 __fenv_static inline int 160 feraiseexcept(int __excepts) 161 { 162 if (__excepts & FE_INVALID) /* Inf * 0 */ 163 __fmul("%.s %#0r0,%0", double, __builtin_huge_val()); 164 165 if (__excepts & FE_DIVBYZERO) /* 1.0 / 0 */ 166 __fdiv("%.s %#0r0,%0", double, 1.0); 167 168 if (__excepts & FE_OVERFLOW) /* MAX * MAX */ 169 __fmul("%.x %0,%0", long double, LDBL_MAX); 170 171 if (__excepts & FE_UNDERFLOW) /* e ^ -MAX */ 172 __fetox("%.x %0", long double, -LDBL_MAX); 173 174 if (__excepts & FE_INEXACT) /* 1 / 3 */ 175 __fdiv("%.s %#0r3,%0", long double, 1.0); 176 177 return 0; 178 } 179 180 __fenv_static inline int 181 fetestexcept(int __excepts) 182 { 183 fexcept_t __fpsr; 184 185 __get_fpsr(__fpsr); 186 187 return __fpsr & __excepts & FE_ALL_EXCEPT; 188 } 189 190 __fenv_static inline int 191 fegetround(void) 192 { 193 fexcept_t __fpcr; 194 195 __get_fpcr(__fpcr); 196 return __fpcr & _ROUND_MASK; 197 } 198 199 __fenv_static inline int 200 fesetround(int __round) 201 { 202 fexcept_t __fpcr; 203 204 if (__round & ~_ROUND_MASK) 205 return -1; 206 207 __get_fpcr(__fpcr); 208 209 __fpcr &= ~_ROUND_MASK; 210 __fpcr |= __round; 211 212 __set_fpcr(__fpcr); 213 214 return 0; 215 } 216 217 __fenv_static inline int 218 fegetenv(fenv_t *__envp) 219 { 220 __fgetenv(*__envp); 221 222 return 0; 223 } 224 225 __fenv_static inline int 226 feholdexcept(fenv_t *__envp) 227 { 228 fexcept_t __fpcr, __fpsr; 229 230 __fgetenv(*__envp); 231 __fpsr = __envp->fpsr & ~FE_ALL_EXCEPT; 232 __set_fpsr(__fpsr); /* clear all */ 233 __fpcr = __envp->fpcr & ~(FE_ALL_EXCEPT << 6); 234 __set_fpcr(__fpcr); /* set non/stop */ 235 236 return 0; 237 } 238 239 __fenv_static inline int 240 fesetenv(const fenv_t *__envp) 241 { 242 fenv_t __tenv; 243 244 __fgetenv(__tenv); 245 246 if (__envp == FE_DFL_ENV) { 247 __tenv.fpcr |= 248 __envp->fpcr & ((FE_ALL_EXCEPT << 6) | FE_UPWARD); 249 __tenv.fpsr |= __envp->fpsr & FE_ALL_EXCEPT; 250 } 251 252 __fsetenv(__tenv); 253 254 return 0; 255 } 256 257 __fenv_static inline int 258 feupdateenv(const fenv_t *__envp) 259 { 260 fexcept_t __fpsr; 261 262 __get_fpsr(__fpsr); 263 __fpsr &= FE_ALL_EXCEPT; 264 fesetenv(__envp); 265 feraiseexcept((int)__fpsr); 266 return 0; 267 } 268 269 #if __GNUC_PREREQ__(8, 0) 270 #pragma GCC diagnostic pop 271 #endif 272 273 #if defined(_NETBSD_SOURCE) || defined(_GNU_SOURCE) 274 275 __fenv_static inline int 276 feenableexcept(int __mask) 277 { 278 fexcept_t __fpcr, __oldmask; 279 280 __get_fpcr(__fpcr); 281 __oldmask = (__fpcr >> 6) & FE_ALL_EXCEPT; 282 __fpcr |= (__mask & FE_ALL_EXCEPT) << 6; 283 __set_fpcr(__fpcr); 284 285 return __oldmask; 286 } 287 288 __fenv_static inline int 289 fedisableexcept(int __mask) 290 { 291 fexcept_t __fpcr, __oldmask; 292 293 __get_fpcr(__fpcr); 294 __oldmask = (__fpcr >> 6) & FE_ALL_EXCEPT; 295 __fpcr &= ~((__mask & FE_ALL_EXCEPT) << 6); 296 __set_fpcr(__fpcr); 297 298 return __oldmask; 299 } 300 301 __fenv_static inline int 302 fegetexcept(void) 303 { 304 fexcept_t __fpcr; 305 306 __get_fpcr(__fpcr); 307 308 return (__fpcr >> 6) & FE_ALL_EXCEPT; 309 } 310 311 #endif /* _NETBSD_SOURCE || _GNU_SOURCE */ 312 313 __END_DECLS 314 315 #endif /* __HAVE_68881__ */ 316 317 #endif /* _M68K_FENV_H_ */ 318