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