1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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 * $FreeBSD$
29 */
30
31#ifndef	_FENV_H_
32#define	_FENV_H_
33
34#include <sys/_types.h>
35
36#ifndef	__fenv_static
37#define	__fenv_static	static
38#endif
39
40typedef	__uint32_t	fenv_t;
41typedef	__uint32_t	fexcept_t;
42
43/* Exception flags */
44#define	FE_INVALID	0x0001
45#define	FE_DIVBYZERO	0x0002
46#define	FE_OVERFLOW	0x0004
47#define	FE_UNDERFLOW	0x0008
48#define	FE_INEXACT	0x0010
49#ifdef __ARM_PCS_VFP
50#define	FE_DENORMAL	0x0080
51#define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
52			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW | FE_DENORMAL)
53#else
54#define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
55			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
56#endif
57
58/* Rounding modes */
59#define	VFP_FE_TONEAREST	0x00000000
60#define	VFP_FE_UPWARD		0x00400000
61#define	VFP_FE_DOWNWARD		0x00800000
62#define	VFP_FE_TOWARDZERO	0x00c00000
63
64#ifdef __ARM_PCS_VFP
65#define	FE_TONEAREST	VFP_FE_TONEAREST
66#define	FE_UPWARD	VFP_FE_UPWARD
67#define	FE_DOWNWARD	VFP_FE_DOWNWARD
68#define	FE_TOWARDZERO	VFP_FE_TOWARDZERO
69#else
70#define	FE_TONEAREST	0x0000
71#define	FE_TOWARDZERO	0x0001
72#define	FE_UPWARD	0x0002
73#define	FE_DOWNWARD	0x0003
74#endif
75#define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
76			 FE_UPWARD | FE_TOWARDZERO)
77__BEGIN_DECLS
78
79/* Default floating-point environment */
80extern const fenv_t	__fe_dfl_env;
81#define	FE_DFL_ENV	(&__fe_dfl_env)
82
83/* We need to be able to map status flag positions to mask flag positions */
84#ifndef __ARM_PCS_VFP
85#define	_FPUSW_SHIFT	16
86#define	_ENABLE_MASK	(FE_ALL_EXCEPT << _FPUSW_SHIFT)
87#endif
88
89#ifndef __ARM_PCS_VFP
90
91int feclearexcept(int __excepts);
92int fegetexceptflag(fexcept_t *__flagp, int __excepts);
93int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
94int feraiseexcept(int __excepts);
95int fetestexcept(int __excepts);
96int fegetround(void);
97int fesetround(int __round);
98int fegetenv(fenv_t *__envp);
99int feholdexcept(fenv_t *__envp);
100int fesetenv(const fenv_t *__envp);
101int feupdateenv(const fenv_t *__envp);
102#if __BSD_VISIBLE
103int feenableexcept(int __mask);
104int fedisableexcept(int __mask);
105int fegetexcept(void);
106#endif
107
108#else	/* __ARM_PCS_VFP */
109
110#define	vmrs_fpscr(__r)	__asm __volatile("vmrs %0, fpscr" : "=&r"(__r))
111#define	vmsr_fpscr(__r)	__asm __volatile("vmsr fpscr, %0" : : "r"(__r))
112
113#define _FPU_MASK_SHIFT	8
114
115__fenv_static inline int
116feclearexcept(int __excepts)
117{
118	fexcept_t __fpsr;
119
120	vmrs_fpscr(__fpsr);
121	__fpsr &= ~__excepts;
122	vmsr_fpscr(__fpsr);
123	return (0);
124}
125
126__fenv_static inline int
127fegetexceptflag(fexcept_t *__flagp, int __excepts)
128{
129	fexcept_t __fpsr;
130
131	vmrs_fpscr(__fpsr);
132	*__flagp = __fpsr & __excepts;
133	return (0);
134}
135
136__fenv_static inline int
137fesetexceptflag(const fexcept_t *__flagp, int __excepts)
138{
139	fexcept_t __fpsr;
140
141	vmrs_fpscr(__fpsr);
142	__fpsr &= ~__excepts;
143	__fpsr |= *__flagp & __excepts;
144	vmsr_fpscr(__fpsr);
145	return (0);
146}
147
148__fenv_static inline int
149feraiseexcept(int __excepts)
150{
151	fexcept_t __ex = __excepts;
152
153	fesetexceptflag(&__ex, __excepts);	/* XXX */
154	return (0);
155}
156
157__fenv_static inline int
158fetestexcept(int __excepts)
159{
160	fexcept_t __fpsr;
161
162	vmrs_fpscr(__fpsr);
163	return (__fpsr & __excepts);
164}
165
166__fenv_static inline int
167fegetround(void)
168{
169	fenv_t __fpsr;
170
171	vmrs_fpscr(__fpsr);
172	return (__fpsr & _ROUND_MASK);
173}
174
175__fenv_static inline int
176fesetround(int __round)
177{
178	fenv_t __fpsr;
179
180	vmrs_fpscr(__fpsr);
181	__fpsr &= ~(_ROUND_MASK);
182	__fpsr |= __round;
183	vmsr_fpscr(__fpsr);
184	return (0);
185}
186
187__fenv_static inline int
188fegetenv(fenv_t *__envp)
189{
190
191	vmrs_fpscr(*__envp);
192	return (0);
193}
194
195__fenv_static inline int
196feholdexcept(fenv_t *__envp)
197{
198	fenv_t __env;
199
200	vmrs_fpscr(__env);
201	*__envp = __env;
202	__env &= ~(FE_ALL_EXCEPT);
203	vmsr_fpscr(__env);
204	return (0);
205}
206
207__fenv_static inline int
208fesetenv(const fenv_t *__envp)
209{
210
211	vmsr_fpscr(*__envp);
212	return (0);
213}
214
215__fenv_static inline int
216feupdateenv(const fenv_t *__envp)
217{
218	fexcept_t __fpsr;
219
220	vmrs_fpscr(__fpsr);
221	vmsr_fpscr(*__envp);
222	feraiseexcept(__fpsr & FE_ALL_EXCEPT);
223	return (0);
224}
225
226#if __BSD_VISIBLE
227
228/* We currently provide no external definitions of the functions below. */
229
230__fenv_static inline int
231feenableexcept(int __mask)
232{
233	fenv_t __old_fpsr, __new_fpsr;
234
235	vmrs_fpscr(__old_fpsr);
236	__new_fpsr = __old_fpsr |
237	    ((__mask & FE_ALL_EXCEPT) << _FPU_MASK_SHIFT);
238	vmsr_fpscr(__new_fpsr);
239	return ((__old_fpsr >> _FPU_MASK_SHIFT) & FE_ALL_EXCEPT);
240}
241
242__fenv_static inline int
243fedisableexcept(int __mask)
244{
245	fenv_t __old_fpsr, __new_fpsr;
246
247	vmrs_fpscr(__old_fpsr);
248	__new_fpsr = __old_fpsr &
249	    ~((__mask & FE_ALL_EXCEPT) << _FPU_MASK_SHIFT);
250	vmsr_fpscr(__new_fpsr);
251	return ((__old_fpsr >> _FPU_MASK_SHIFT) & FE_ALL_EXCEPT);
252}
253
254__fenv_static inline int
255fegetexcept(void)
256{
257	fenv_t __fpsr;
258
259	vmrs_fpscr(__fpsr);
260	return (__fpsr & FE_ALL_EXCEPT);
261}
262
263#endif /* __BSD_VISIBLE */
264
265#endif	/* __ARM_PCS_VFP */
266
267__END_DECLS
268
269#endif	/* !_FENV_H_ */
270