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