1 /* $NetBSD: fenv.h,v 1.4 2024/10/30 15:56:12 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2016 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 _SH3_FENV_H_ 33 #define _SH3_FENV_H_ 34 35 #include <sys/featuretest.h> 36 #include <sys/stdint.h> 37 38 #include <sh3/float.h> 39 #include <sh3/fpreg.h> 40 41 #ifndef __fenv_static 42 #define __fenv_static static 43 #endif 44 45 /* Exception bits, from FPSCR */ 46 #define FE_INEXACT ((uint32_t)FPSCR_EXCEPTION_INEXACT >> 5) 47 #define FE_DIVBYZERO ((uint32_t)FPSCR_EXCEPTION_ZERODIV >> 5) 48 #define FE_UNDERFLOW ((uint32_t)FPSCR_EXCEPTION_UNDERFLOW >> 5) 49 #define FE_OVERFLOW ((uint32_t)FPSCR_EXCEPTION_OVERFLOW >> 5) 50 #define FE_INVALID ((uint32_t)FPSCR_EXCEPTION_INVALID >> 5) 51 52 #define FE_ALL_EXCEPT \ 53 (FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID) 54 55 /* Rounding modes, from FPSCR */ 56 #define FE_TONEAREST FPSCR_ROUND_NEAREST 57 #define FE_TOWARDZERO FPSCR_ROUND_ZERO 58 /* These two don't exist and are only defined for the benefit of softfloat */ 59 #define FE_DOWNWARD (FPSCR_ROUND_ZERO + 1) 60 #define FE_UPWARD (FPSCR_ROUND_ZERO + 2) 61 62 #define _ROUND_MASK \ 63 (FE_TONEAREST | FE_TOWARDZERO) 64 65 #ifdef __SH_FPU_ANY__ 66 67 typedef uint32_t fexcept_t; 68 69 typedef struct { 70 uint32_t __fpscr; 71 } fenv_t; 72 73 #define FE_DFL_ENV ((fenv_t *) -1) 74 75 #define __get_fpscr(__fpscr) \ 76 __asm__ __volatile__ ("sts fpscr,%0" : "=r" (__fpscr)) 77 #define __set_fpscr(__fpscr) \ 78 __asm__ __volatile__ ("lds %0,fpscr" : : "r" (__fpscr)) 79 80 __BEGIN_DECLS 81 82 __fenv_static inline int 83 feclearexcept(int __excepts) 84 { 85 fexcept_t __fpscr; 86 87 __excepts &= FE_ALL_EXCEPT; 88 89 __get_fpscr(__fpscr); 90 __fpscr &= ~__excepts; 91 __set_fpscr(__fpscr); 92 93 return 0; 94 } 95 96 __fenv_static inline int 97 fegetexceptflag(fexcept_t *__flagp, int __excepts) 98 { 99 fexcept_t __fpscr; 100 101 __get_fpscr(__fpscr); 102 103 *__flagp = __fpscr & __excepts & FE_ALL_EXCEPT; 104 105 return 0; 106 } 107 108 __fenv_static inline int 109 fesetexceptflag(const fexcept_t *__flagp, int __excepts) 110 { 111 fexcept_t __fpscr; 112 113 __get_fpscr(__fpscr); 114 115 __fpscr &= ~(__excepts & FE_ALL_EXCEPT); 116 __fpscr |= *__flagp & __excepts & FE_ALL_EXCEPT; 117 118 __set_fpscr(__fpscr); 119 120 return 0; 121 } 122 123 static inline void 124 __fmul(double a, double b) 125 { 126 #ifdef __sh4__ 127 __asm__ __volatile__ ("fmul %1, %0" : "+d" (a) : "d" (b)); 128 #endif 129 } 130 131 static inline void 132 __fdiv(double a, double b) { 133 #ifdef __sh4__ 134 __asm__ __volatile__ ("fdiv %1, %0" : "+d" (a) : "d" (b)); 135 #endif 136 } 137 138 __fenv_static inline int 139 feraiseexcept(int __excepts) 140 { 141 fexcept_t __fpscr; 142 143 if (__excepts & FE_INVALID) /* Inf * 0 */ 144 __fmul(__builtin_huge_val(), 0.0); 145 146 if (__excepts & FE_DIVBYZERO) /* 1.0 / 0 */ 147 __fdiv(1.0, 0.0); 148 149 if (__excepts & FE_OVERFLOW) /* MAX * MAX */ 150 __fmul(LDBL_MAX, LDBL_MAX); 151 152 if (__excepts & FE_UNDERFLOW) /* MIN / 10.0 */ 153 __fdiv(LDBL_MIN, 10.0); 154 155 if (__excepts & FE_INEXACT) /* 1 / 3 */ 156 __fdiv(1.0, 3.0); 157 158 __get_fpscr(__fpscr); 159 160 __fpscr |= __excepts & FE_ALL_EXCEPT; 161 162 __set_fpscr(__fpscr); 163 164 return 0; 165 } 166 167 __fenv_static inline int 168 fetestexcept(int __excepts) 169 { 170 fexcept_t __fpscr; 171 172 __get_fpscr(__fpscr); 173 174 return __fpscr & __excepts & FE_ALL_EXCEPT; 175 } 176 177 __fenv_static inline int 178 fegetround(void) 179 { 180 fexcept_t __fpscr; 181 182 __get_fpscr(__fpscr); 183 return __fpscr & _ROUND_MASK; 184 } 185 186 __fenv_static inline int 187 fesetround(int __round) 188 { 189 fexcept_t __fpscr; 190 191 if (__round & ~_ROUND_MASK) 192 return -1; 193 194 __get_fpscr(__fpscr); 195 196 __fpscr &= ~_ROUND_MASK; 197 __fpscr |= __round; 198 199 __set_fpscr(__fpscr); 200 201 return 0; 202 } 203 204 __fenv_static inline int 205 fegetenv(fenv_t *__envp) 206 { 207 fexcept_t __fpscr; 208 209 __get_fpscr(__fpscr); 210 __envp->__fpscr = __fpscr; 211 212 return 0; 213 } 214 215 __fenv_static inline int 216 feholdexcept(fenv_t *__envp) 217 { 218 fexcept_t __fpscr; 219 220 __get_fpscr(__fpscr); 221 __envp->__fpscr = __fpscr; 222 223 __fpscr &= ~FE_ALL_EXCEPT; 224 __fpscr &= ~(FE_ALL_EXCEPT << 5); 225 __set_fpscr(__fpscr); /* clear all */ 226 227 return 0; 228 } 229 230 __fenv_static inline int 231 fesetenv(const fenv_t *__envp) 232 { 233 if (__envp == FE_DFL_ENV) 234 __set_fpscr(FPSCR_DEFAULT); 235 else 236 __set_fpscr(__envp->__fpscr); 237 238 return 0; 239 } 240 241 __fenv_static inline int 242 feupdateenv(const fenv_t *__envp) 243 { 244 fexcept_t __fpscr; 245 246 __get_fpscr(__fpscr); 247 __fpscr &= FE_ALL_EXCEPT; 248 fesetenv(__envp); 249 feraiseexcept((int)__fpscr); 250 return 0; 251 } 252 253 #if defined(_NETBSD_SOURCE) || defined(_GNU_SOURCE) 254 255 /* We currently provide no external definitions of the functions below. */ 256 257 static inline int 258 feenableexcept(int __mask) 259 { 260 fexcept_t __fpscr, __oldmask; 261 262 __get_fpscr(__fpscr); 263 __oldmask = (__fpscr >> 5) & FE_ALL_EXCEPT; 264 __fpscr |= (__mask & FE_ALL_EXCEPT) << 5; 265 __set_fpscr(__fpscr); 266 267 return __oldmask; 268 } 269 270 static inline int 271 fedisableexcept(int __mask) 272 { 273 fexcept_t __fpscr, __oldmask; 274 275 __get_fpscr(__fpscr); 276 __oldmask = (__fpscr >> 5) & FE_ALL_EXCEPT; 277 __fpscr &= ~(__mask & FE_ALL_EXCEPT) << 5; 278 __set_fpscr(__fpscr); 279 280 return __oldmask; 281 } 282 283 static inline int 284 fegetexcept(void) 285 { 286 fexcept_t __fpscr; 287 288 __get_fpscr(__fpscr); 289 290 return (__fpscr >> 5) & FE_ALL_EXCEPT; 291 } 292 293 #endif /* _NETBSD_SOURCE || _GNU_SOURCE */ 294 295 __END_DECLS 296 297 #endif /* __SH_FPU_ANY__ */ 298 299 #endif /* _SH3_FENV_H_ */ 300