1/*-
  2 * SPDX-License-Identifier: BSD-2-Clause
  3 *
  4 * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
  5 * All rights reserved.
  6 *
  7 * Redistribution and use in source and binary forms, with or without
  8 * modification, are permitted provided that the following conditions
  9 * are met:
 10 * 1. Redistributions of source code must retain the above copyright
 11 *    notice, this list of conditions and the following disclaimer.
 12 * 2. Redistributions in binary form must reproduce the above copyright
 13 *    notice, this list of conditions and the following disclaimer in the
 14 *    documentation and/or other materials provided with the distribution.
 15 *
 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 26 * SUCH DAMAGE.
 27 */
 28
 29#ifndef	_FENV_H_
 30#define	_FENV_H_
 31
 32#include <sys/_types.h>
 33
 34#ifndef	__fenv_static
 35#define	__fenv_static	static
 36#endif
 37
 38typedef	__uint32_t	fenv_t;
 39typedef	__uint32_t	fexcept_t;
 40
 41/* Exception flags */
 42#define	FE_INVALID	0x0001
 43#define	FE_DIVBYZERO	0x0002
 44#define	FE_OVERFLOW	0x0004
 45#define	FE_UNDERFLOW	0x0008
 46#define	FE_INEXACT	0x0010
 47#ifdef __ARM_PCS_VFP
 48#define	FE_DENORMAL	0x0080
 49#define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
 50			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW | FE_DENORMAL)
 51#else
 52#define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
 53			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
 54#endif
 55
 56/* Rounding modes */
 57#define	VFP_FE_TONEAREST	0x00000000
 58#define	VFP_FE_UPWARD		0x00400000
 59#define	VFP_FE_DOWNWARD		0x00800000
 60#define	VFP_FE_TOWARDZERO	0x00c00000
 61
 62#ifdef __ARM_PCS_VFP
 63#define	FE_TONEAREST	VFP_FE_TONEAREST
 64#define	FE_UPWARD	VFP_FE_UPWARD
 65#define	FE_DOWNWARD	VFP_FE_DOWNWARD
 66#define	FE_TOWARDZERO	VFP_FE_TOWARDZERO
 67#else
 68#define	FE_TONEAREST	0x0000
 69#define	FE_TOWARDZERO	0x0001
 70#define	FE_UPWARD	0x0002
 71#define	FE_DOWNWARD	0x0003
 72#endif
 73#define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
 74			 FE_UPWARD | FE_TOWARDZERO)
 75__BEGIN_DECLS
 76
 77/* Default floating-point environment */
 78extern const fenv_t	__fe_dfl_env;
 79#define	FE_DFL_ENV	(&__fe_dfl_env)
 80
 81/* We need to be able to map status flag positions to mask flag positions */
 82#ifndef __ARM_PCS_VFP
 83#define	_FPUSW_SHIFT	16
 84#define	_ENABLE_MASK	(FE_ALL_EXCEPT << _FPUSW_SHIFT)
 85#endif
 86
 87#ifndef __ARM_PCS_VFP
 88
 89int feclearexcept(int __excepts);
 90int fegetexceptflag(fexcept_t *__flagp, int __excepts);
 91int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
 92int feraiseexcept(int __excepts);
 93int fetestexcept(int __excepts);
 94int fegetround(void);
 95int fesetround(int __round);
 96int fegetenv(fenv_t *__envp);
 97int feholdexcept(fenv_t *__envp);
 98int fesetenv(const fenv_t *__envp);
 99int feupdateenv(const fenv_t *__envp);
100#if __BSD_VISIBLE
101int feenableexcept(int __mask);
102int fedisableexcept(int __mask);
103int fegetexcept(void);
104#endif
105
106#else	/* __ARM_PCS_VFP */
107
108#define	vmrs_fpscr(__r)	__asm __volatile("vmrs %0, fpscr" : "=&r"(__r))
109#define	vmsr_fpscr(__r)	__asm __volatile("vmsr fpscr, %0" : : "r"(__r))
110
111#define _FPU_MASK_SHIFT	8
112
113__fenv_static inline int
114feclearexcept(int __excepts)
115{
116	fexcept_t __fpsr;
117
118	vmrs_fpscr(__fpsr);
119	__fpsr &= ~__excepts;
120	vmsr_fpscr(__fpsr);
121	return (0);
122}
123
124__fenv_static inline int
125fegetexceptflag(fexcept_t *__flagp, int __excepts)
126{
127	fexcept_t __fpsr;
128
129	vmrs_fpscr(__fpsr);
130	*__flagp = __fpsr & __excepts;
131	return (0);
132}
133
134__fenv_static inline int
135fesetexceptflag(const fexcept_t *__flagp, int __excepts)
136{
137	fexcept_t __fpsr;
138
139	vmrs_fpscr(__fpsr);
140	__fpsr &= ~__excepts;
141	__fpsr |= *__flagp & __excepts;
142	vmsr_fpscr(__fpsr);
143	return (0);
144}
145
146__fenv_static inline int
147feraiseexcept(int __excepts)
148{
149	fexcept_t __ex = __excepts;
150
151	fesetexceptflag(&__ex, __excepts);	/* XXX */
152	return (0);
153}
154
155__fenv_static inline int
156fetestexcept(int __excepts)
157{
158	fexcept_t __fpsr;
159
160	vmrs_fpscr(__fpsr);
161	return (__fpsr & __excepts);
162}
163
164__fenv_static inline int
165fegetround(void)
166{
167	fenv_t __fpsr;
168
169	vmrs_fpscr(__fpsr);
170	return (__fpsr & _ROUND_MASK);
171}
172
173__fenv_static inline int
174fesetround(int __round)
175{
176	fenv_t __fpsr;
177
178	vmrs_fpscr(__fpsr);
179	__fpsr &= ~(_ROUND_MASK);
180	__fpsr |= __round;
181	vmsr_fpscr(__fpsr);
182	return (0);
183}
184
185__fenv_static inline int
186fegetenv(fenv_t *__envp)
187{
188
189	vmrs_fpscr(*__envp);
190	return (0);
191}
192
193__fenv_static inline int
194feholdexcept(fenv_t *__envp)
195{
196	fenv_t __env;
197
198	vmrs_fpscr(__env);
199	*__envp = __env;
200	__env &= ~(FE_ALL_EXCEPT);
201	vmsr_fpscr(__env);
202	return (0);
203}
204
205__fenv_static inline int
206fesetenv(const fenv_t *__envp)
207{
208
209	vmsr_fpscr(*__envp);
210	return (0);
211}
212
213__fenv_static inline int
214feupdateenv(const fenv_t *__envp)
215{
216	fexcept_t __fpsr;
217
218	vmrs_fpscr(__fpsr);
219	vmsr_fpscr(*__envp);
220	feraiseexcept(__fpsr & FE_ALL_EXCEPT);
221	return (0);
222}
223
224#if __BSD_VISIBLE
225
226/* We currently provide no external definitions of the functions below. */
227
228__fenv_static inline int
229feenableexcept(int __mask)
230{
231	fenv_t __old_fpsr, __new_fpsr;
232
233	vmrs_fpscr(__old_fpsr);
234	__new_fpsr = __old_fpsr |
235	    ((__mask & FE_ALL_EXCEPT) << _FPU_MASK_SHIFT);
236	vmsr_fpscr(__new_fpsr);
237	return ((__old_fpsr >> _FPU_MASK_SHIFT) & FE_ALL_EXCEPT);
238}
239
240__fenv_static inline int
241fedisableexcept(int __mask)
242{
243	fenv_t __old_fpsr, __new_fpsr;
244
245	vmrs_fpscr(__old_fpsr);
246	__new_fpsr = __old_fpsr &
247	    ~((__mask & FE_ALL_EXCEPT) << _FPU_MASK_SHIFT);
248	vmsr_fpscr(__new_fpsr);
249	return ((__old_fpsr >> _FPU_MASK_SHIFT) & FE_ALL_EXCEPT);
250}
251
252__fenv_static inline int
253fegetexcept(void)
254{
255	fenv_t __fpsr;
256
257	vmrs_fpscr(__fpsr);
258	return (__fpsr & FE_ALL_EXCEPT);
259}
260
261#endif /* __BSD_VISIBLE */
262
263#endif	/* __ARM_PCS_VFP */
264
265__END_DECLS
266
267#endif	/* !_FENV_H_ */