Home | History | Annotate | Line # | Download | only in include
      1 /*	$NetBSD: fenv.h,v 1.10 2024/10/30 15:56:11 riastradh Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2015 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 _M68K_FENV_H_
     33 #define _M68K_FENV_H_
     34 
     35 #include <sys/featuretest.h>
     36 #include <sys/stdint.h>
     37 
     38 #include <m68k/float.h>
     39 #include <m68k/fpreg.h>
     40 
     41 /* Exception bits, from FPSR */
     42 #define	FE_INEXACT	FPSR_AINEX
     43 #define	FE_DIVBYZERO	FPSR_ADZ
     44 #define	FE_UNDERFLOW	FPSR_AUNFL
     45 #define	FE_OVERFLOW	FPSR_AOVFL
     46 #define	FE_INVALID	FPSR_AIOP
     47 
     48 #define FE_ALL_EXCEPT \
     49     (FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID)
     50 
     51 /* Rounding modes, from FPCR */
     52 #define FE_TONEAREST	FPCR_NEAR
     53 #define	FE_TOWARDZERO	FPCR_ZERO
     54 #define	FE_DOWNWARD	FPCR_MINF
     55 #define	FE_UPWARD	FPCR_PINF
     56 
     57 #define _ROUND_MASK	\
     58     (FE_TONEAREST | FE_TOWARDZERO | FE_DOWNWARD | FE_UPWARD)
     59 
     60 #if defined(__HAVE_68881__)
     61 
     62 #ifndef __fenv_static
     63 #define __fenv_static   static
     64 #endif
     65 
     66 typedef uint32_t fexcept_t;
     67 
     68 /* same layout as fmovem */
     69 typedef struct {
     70 	uint32_t fpcr;
     71 	uint32_t fpsr;
     72 	uint32_t fppc;
     73 } fenv_t;
     74 
     75 #define FE_DFL_ENV	((fenv_t *) -1)
     76 
     77 #define __get_fpcr(__fpcr) \
     78     __asm__ __volatile__ ("fmove%.l %!,%0" : "=dm" (__fpcr))
     79 #define __set_fpcr(__fpcr) \
     80     __asm__ __volatile__ ("fmove%.l %0,%!" : : "dm" (__fpcr))
     81 
     82 #define __get_fpsr(__fpsr) \
     83     __asm__ __volatile__ ("fmove%.l %/fpsr,%0" : "=dm" (__fpsr))
     84 #define __set_fpsr(__fpsr) \
     85     __asm__ __volatile__ ("fmove%.l %0,%/fpsr" : : "dm" (__fpsr))
     86 
     87 #define __fmul(__s, __t, __d) \
     88     do { \
     89 	    __t d = __d; \
     90 	    __asm__ __volatile__ ("fmul" __s "; fnop" : "=f" (d) : "0" (d)); \
     91     } while (/*CONSTCOND*/0)
     92 
     93 #define __fdiv(__s, __t, __d) \
     94     do { \
     95 	    __t d = __d; \
     96 	    __asm__ __volatile__ ("fdiv" __s "; fnop" : "=f" (d) : "0" (d)); \
     97     } while (/*CONSTCOND*/0)
     98 
     99 #define __fetox(__s, __t, __d) \
    100     do { \
    101 	    __t d = __d; \
    102 	    __asm__ __volatile__ ("fetox" __s "; fnop" : "=f" (d) : "0" (d)); \
    103     } while (/*CONSTCOND*/0)
    104 
    105 #define __fgetenv(__envp) \
    106     __asm__ __volatile__ ("fmovem%.l %/fpcr/%/fpsr/%/fpiar,%0" : "=m" (__envp))
    107 
    108 #define __fsetenv(__envp) \
    109     __asm__ __volatile__ ("fmovem%.l %0,%/fpcr/%/fpsr/%/fpiar" : : "m" (__envp))
    110 
    111 __BEGIN_DECLS
    112 
    113 #if __GNUC_PREREQ__(8, 0)
    114 #pragma GCC diagnostic push
    115 #pragma GCC diagnostic ignored "-Wshadow"
    116 #endif
    117 
    118 __fenv_static inline int
    119 feclearexcept(int __excepts)
    120 {
    121 	fexcept_t __fpsr;
    122 
    123 	__excepts &= FE_ALL_EXCEPT;
    124 
    125 	__get_fpsr(__fpsr);
    126 	__fpsr &= ~__excepts;
    127 	__set_fpsr(__fpsr);
    128 
    129 	return 0;
    130 }
    131 
    132 __fenv_static inline int
    133 fegetexceptflag(fexcept_t *__flagp, int __excepts)
    134 {
    135 	fexcept_t __fpsr;
    136 
    137 	__get_fpsr(__fpsr);
    138 
    139 	*__flagp = __fpsr & __excepts & FE_ALL_EXCEPT;
    140 
    141 	return 0;
    142 }
    143 
    144 __fenv_static inline int
    145 fesetexceptflag(const fexcept_t *__flagp, int __excepts)
    146 {
    147 	fexcept_t __fpsr;
    148 
    149 	__get_fpsr(__fpsr);
    150 
    151 	__fpsr &= ~(__excepts & FE_ALL_EXCEPT);
    152 	__fpsr |= *__flagp & __excepts & FE_ALL_EXCEPT;
    153 
    154 	__set_fpsr(__fpsr);
    155 
    156 	return 0;
    157 }
    158 
    159 __fenv_static inline int
    160 feraiseexcept(int __excepts)
    161 {
    162 	if (__excepts & FE_INVALID)	/* Inf * 0 */
    163 		__fmul("%.s %#0r0,%0", double, __builtin_huge_val());
    164 
    165 	if (__excepts & FE_DIVBYZERO)	/* 1.0 / 0 */
    166 		__fdiv("%.s %#0r0,%0", double, 1.0);
    167 
    168 	if (__excepts & FE_OVERFLOW)	/* MAX * MAX */
    169 		__fmul("%.x %0,%0", long double, LDBL_MAX);
    170 
    171 	if (__excepts & FE_UNDERFLOW)	/* e ^ -MAX */
    172 		__fetox("%.x %0", long double, -LDBL_MAX);
    173 
    174 	if (__excepts & FE_INEXACT)	/* 1 / 3 */
    175 		__fdiv("%.s %#0r3,%0", long double, 1.0);
    176 
    177 	return 0;
    178 }
    179 
    180 __fenv_static inline int
    181 fetestexcept(int __excepts)
    182 {
    183 	fexcept_t __fpsr;
    184 
    185 	__get_fpsr(__fpsr);
    186 
    187 	return __fpsr & __excepts & FE_ALL_EXCEPT;
    188 }
    189 
    190 __fenv_static inline int
    191 fegetround(void)
    192 {
    193 	fexcept_t __fpcr;
    194 
    195 	__get_fpcr(__fpcr);
    196 	return __fpcr & _ROUND_MASK;
    197 }
    198 
    199 __fenv_static inline int
    200 fesetround(int __round)
    201 {
    202 	fexcept_t __fpcr;
    203 
    204 	if (__round & ~_ROUND_MASK)
    205 		return -1;
    206 
    207 	__get_fpcr(__fpcr);
    208 
    209 	__fpcr &= ~_ROUND_MASK;
    210 	__fpcr |= __round;
    211 
    212 	__set_fpcr(__fpcr);
    213 
    214 	return 0;
    215 }
    216 
    217 __fenv_static inline int
    218 fegetenv(fenv_t *__envp)
    219 {
    220 	__fgetenv(*__envp);
    221 
    222 	return 0;
    223 }
    224 
    225 __fenv_static inline int
    226 feholdexcept(fenv_t *__envp)
    227 {
    228 	fexcept_t __fpcr, __fpsr;
    229 
    230 	__fgetenv(*__envp);
    231 	__fpsr = __envp->fpsr & ~FE_ALL_EXCEPT;
    232 	__set_fpsr(__fpsr);	/* clear all */
    233 	__fpcr = __envp->fpcr & ~(FE_ALL_EXCEPT << 6);
    234 	__set_fpcr(__fpcr);	/* set non/stop */
    235 
    236 	return 0;
    237 }
    238 
    239 __fenv_static inline int
    240 fesetenv(const fenv_t *__envp)
    241 {
    242 	fenv_t __tenv;
    243 
    244 	__fgetenv(__tenv);
    245 
    246 	if (__envp == FE_DFL_ENV) {
    247 		__tenv.fpcr |=
    248 		    __envp->fpcr & ((FE_ALL_EXCEPT << 6) | FE_UPWARD);
    249 		__tenv.fpsr |= __envp->fpsr & FE_ALL_EXCEPT;
    250 	}
    251 
    252 	__fsetenv(__tenv);
    253 
    254 	return 0;
    255 }
    256 
    257 __fenv_static inline int
    258 feupdateenv(const fenv_t *__envp)
    259 {
    260 	fexcept_t __fpsr;
    261 
    262 	__get_fpsr(__fpsr);
    263 	__fpsr &= FE_ALL_EXCEPT;
    264 	fesetenv(__envp);
    265 	feraiseexcept((int)__fpsr);
    266 	return 0;
    267 }
    268 
    269 #if __GNUC_PREREQ__(8, 0)
    270 #pragma GCC diagnostic pop
    271 #endif
    272 
    273 #if defined(_NETBSD_SOURCE) || defined(_GNU_SOURCE)
    274 
    275 __fenv_static inline int
    276 feenableexcept(int __mask)
    277 {
    278 	fexcept_t __fpcr, __oldmask;
    279 
    280 	__get_fpcr(__fpcr);
    281 	__oldmask = (__fpcr >> 6) & FE_ALL_EXCEPT;
    282 	__fpcr |= (__mask & FE_ALL_EXCEPT) << 6;
    283 	__set_fpcr(__fpcr);
    284 
    285 	return __oldmask;
    286 }
    287 
    288 __fenv_static inline int
    289 fedisableexcept(int __mask)
    290 {
    291 	fexcept_t __fpcr, __oldmask;
    292 
    293 	__get_fpcr(__fpcr);
    294 	__oldmask = (__fpcr >> 6) & FE_ALL_EXCEPT;
    295 	__fpcr &= ~((__mask & FE_ALL_EXCEPT) << 6);
    296 	__set_fpcr(__fpcr);
    297 
    298 	return __oldmask;
    299 }
    300 
    301 __fenv_static inline int
    302 fegetexcept(void)
    303 {
    304 	fexcept_t __fpcr;
    305 
    306 	__get_fpcr(__fpcr);
    307 
    308 	return (__fpcr >> 6) & FE_ALL_EXCEPT;
    309 }
    310 
    311 #endif /* _NETBSD_SOURCE || _GNU_SOURCE */
    312 
    313 __END_DECLS
    314 
    315 #endif /* __HAVE_68881__ */
    316 
    317 #endif /* _M68K_FENV_H_ */
    318