/* * Copyright (C) 2009 Android Open Source Project, All rights reserved. * Derived from "bionic/libm/arm/fenv.h" * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _FENV_H_ #define _FENV_H_ #include <stdio.h> #include <sys/types.h> typedef uint32_t fenv_t; typedef uint32_t fexcept_t; /* Exception flags */ #define FE_INVALID 0x0010 #define FE_DIVBYZERO 0x0008 #define FE_OVERFLOW 0x0004 #define FE_UNDERFLOW 0x0002 #define FE_INEXACT 0x0001 #define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) /* Rounding modes */ #define FE_TONEAREST 0x0000 #define FE_TOWARDZERO 0x0001 #define FE_UPWARD 0x0002 /* not supporetd */ #define FE_DOWNWARD 0x0003 /* not supporetd */ #define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ FE_UPWARD | FE_TOWARDZERO) /* bit shift for FPSCR mapping */ #define _FPUE_CAUSE_SHIFT 12 #define _FPUE_ENABLE_SHIFT 17 #define _FPUE_FLAG_SHIFT 2 /* bit shifters */ #define _FPUE_CAUSE(_EXCS) ((_EXCS) << _FPUE_CAUSE_SHIFT) #define _FPUE_ENABLE(_EXCS) ((_EXCS) << _FPUE_ENABLE_SHIFT) #define _FPUE_FLAG(_EXCS) ((_EXCS) << _FPUE_FLAG_SHIFT) #define _GET_FPUE_CAUSE(_FPUE) (((_FPUE) >> _FPUE_CAUSE_SHIFT) & FE_ALL_EXCEPT) #define _GET_FPUE_ENABLE(_FPUE) (((_FPUE) >> _FPUE_ENABLE_SHIFT)& FE_ALL_EXCEPT) #define _GET_FPUE_FLAG(_FPUE) (((_FPUE) >> _FPUE_FLAG_SHIFT) & FE_ALL_EXCEPT) /* FPSCR register accessors */ #ifdef __SH4_NOFPU__ #define __read_fpscr(_ptr) #define __write_fpscr(_val) #else #define __read_fpscr(_ptr) __asm __volatile("sts fpscr, %0" : "=r" (*(_ptr))) #define __write_fpscr(_val) __asm __volatile("lds %0, fpscr" : : "r" (_val)) #endif /* functions for libm */ static __inline int feclearexcept(int __excepts) { uint32_t __fpscr; __read_fpscr(&__fpscr); __fpscr &= ~_FPUE_FLAG(__excepts); __write_fpscr(__fpscr); return (0); } static __inline int fegetexceptflag(fexcept_t *__flagp, int __excepts) { uint32_t __fpscr; __read_fpscr(&__fpscr); *__flagp = _GET_FPUE_FLAG(__fpscr) & __excepts; return (0); } static __inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts) { uint32_t __fpscr; __read_fpscr(&__fpscr); __fpscr &= ~_FPUE_FLAG(__excepts); __fpscr |= ~_FPUE_FLAG(*__flagp & __excepts); __write_fpscr(__fpscr); return (0); } static __inline int feraiseexcept(int __excepts) { fexcept_t __ex = __excepts; fesetexceptflag(&__ex, __excepts); /* XXX */ return (0); } static __inline int fetestexcept(int __excepts) { fexcept_t __ex; fegetexceptflag(&__ex, __excepts); return (__ex); } static __inline int fegetround(void) { uint32_t __fpscr = 0; __read_fpscr(&__fpscr); return (__fpscr & _ROUND_MASK); } static __inline int fesetround(int __round) { uint32_t __fpscr = 0; if (__round == FE_UPWARD || __round == FE_DOWNWARD) { fprintf(stderr, "libm superh : " "upward/downward rounding not supporetd.\n"); return -1; } __read_fpscr(&__fpscr); __fpscr &= ~_ROUND_MASK; __fpscr |= (__round & _ROUND_MASK); __write_fpscr(__fpscr); return (0); } static __inline int fegetenv(fenv_t *__envp) { __read_fpscr(__envp); return (0); } static __inline int feholdexcept(fenv_t *__envp) { uint32_t __fpscr; __read_fpscr(&__fpscr); *__envp = __fpscr; __fpscr &= ~_FPUE_FLAG(FE_ALL_EXCEPT); __write_fpscr(__fpscr); return (0); } static __inline int fesetenv(const fenv_t *__envp) { __write_fpscr(*__envp); return (0); } static __inline int feupdateenv(const fenv_t *__envp) { uint32_t __fpscr; __read_fpscr(&__fpscr); __write_fpscr(*__envp); feraiseexcept(_GET_FPUE_FLAG(__fpscr)); return (0); } #if __BSD_VISIBLE static __inline int feenableexcept(int __mask) { uint32_t __old_fpscr, __new_fpscr; __read_fpscr(&__old_fpscr); __new_fpscr = __old_fpscr | _FPUE_ENABLE(__mask & FE_ALL_EXCEPT); __write_fpscr(__new_fpscr); return (_GET_FPUE_ENABLE(__old_fpscr)); } static __inline int fedisableexcept(int __mask) { uint32_t __old_fpscr, __new_fpscr; __read_fpscr(&__old_fpscr); __new_fpscr = __old_fpscr & ~(_FPUE_ENABLE(__mask & FE_ALL_EXCEPT)); __write_fpscr(__new_fpscr); return (_GET_FPUE_ENABLE(__old_fpscr)); } static __inline int fegetexcept(void) { uint32_t __fpscr; __read_fpscr(&__fpscr); return (_GET_FPUE_ENABLE(__fpscr)); } #endif /* __BSD_VISIBLE */ #endif /* _FENV_H_ */