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