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 65typedef uint32_t fexcept_t; 66 67typedef 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 81feclearexcept(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 95fegetexceptflag(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 107fesetexceptflag(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 121static 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 129static 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 137feraiseexcept(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 166fetestexcept(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 176fegetround(void) 177{ 178 fexcept_t __fpscr; 179 180 __get_fpscr(__fpscr); 181 return __fpscr & _ROUND_MASK; 182} 183 184__fenv_static inline int 185fesetround(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 203fegetenv(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 214feholdexcept(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 229fesetenv(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 240feupdateenv(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 255static inline int 256feenableexcept(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 268static inline int 269fedisableexcept(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 281static inline int 282fegetexcept(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