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#ifdef __mips_soft_float
45#define	_FPUSW_SHIFT	16
46#define	FE_INVALID	0x0001
47#define	FE_DIVBYZERO	0x0002
48#define	FE_OVERFLOW	0x0004
49#define	FE_UNDERFLOW	0x0008
50#define	FE_INEXACT	0x0010
51#else
52#define	_FCSR_CAUSE_SHIFT	10
53#define	FE_INVALID	0x0040
54#define	FE_DIVBYZERO	0x0020
55#define	FE_OVERFLOW	0x0010
56#define	FE_UNDERFLOW	0x0008
57#define	FE_INEXACT	0x0004
58#endif
59#define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
60			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
61
62/* Rounding modes */
63#define	FE_TONEAREST	0x0000
64#define	FE_TOWARDZERO	0x0001
65#define	FE_UPWARD	0x0002
66#define	FE_DOWNWARD	0x0003
67#define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
68			 FE_UPWARD | FE_TOWARDZERO)
69__BEGIN_DECLS
70
71/* Default floating-point environment */
72extern const fenv_t	__fe_dfl_env;
73#define	FE_DFL_ENV	(&__fe_dfl_env)
74
75/* We need to be able to map status flag positions to mask flag positions */
76#define	_ENABLE_SHIFT	5
77#define	_ENABLE_MASK	(FE_ALL_EXCEPT << _ENABLE_SHIFT)
78
79#if !defined(__mips_soft_float) && !defined(__mips_hard_float)
80#error compiler didnt set soft/hard float macros
81#endif
82
83#ifndef	__mips_soft_float
84#define	__cfc1(__fcsr)	__asm __volatile("cfc1 %0, $31" : "=r" (__fcsr))
85#define	__ctc1(__fcsr)	__asm __volatile("ctc1 %0, $31" :: "r" (__fcsr))
86#endif
87
88#ifdef __mips_soft_float
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#else
101__fenv_static inline int
102feclearexcept(int __excepts)
103{
104	fexcept_t fcsr;
105
106	__excepts &= FE_ALL_EXCEPT;
107	__cfc1(fcsr);
108	fcsr &= ~(__excepts | (__excepts << _FCSR_CAUSE_SHIFT));
109	__ctc1(fcsr);
110
111	return (0);
112}
113
114__fenv_static inline int
115fegetexceptflag(fexcept_t *__flagp, int __excepts)
116{
117	fexcept_t fcsr;
118
119	__excepts &= FE_ALL_EXCEPT;
120	__cfc1(fcsr);
121	*__flagp = fcsr & __excepts;
122
123	return (0);
124}
125
126__fenv_static inline int
127fesetexceptflag(const fexcept_t *__flagp, int __excepts)
128{
129	fexcept_t fcsr;
130
131	__excepts &= FE_ALL_EXCEPT;
132	__cfc1(fcsr);
133	fcsr &= ~__excepts;
134	fcsr |= *__flagp & __excepts;
135	__ctc1(fcsr);
136
137	return (0);
138}
139
140__fenv_static inline int
141feraiseexcept(int __excepts)
142{
143	fexcept_t fcsr;
144
145	__excepts &= FE_ALL_EXCEPT;
146	__cfc1(fcsr);
147	fcsr |= __excepts | (__excepts << _FCSR_CAUSE_SHIFT);
148	__ctc1(fcsr);
149
150	return (0);
151}
152
153__fenv_static inline int
154fetestexcept(int __excepts)
155{
156	fexcept_t fcsr;
157
158	__excepts &= FE_ALL_EXCEPT;
159	__cfc1(fcsr);
160
161	return (fcsr & __excepts);
162}
163
164__fenv_static inline int
165fegetround(void)
166{
167	fexcept_t fcsr;
168
169	__cfc1(fcsr);
170
171	return (fcsr & _ROUND_MASK);
172}
173
174__fenv_static inline int
175fesetround(int __round)
176{
177	fexcept_t fcsr;
178
179	if (__round & ~_ROUND_MASK)
180		return (-1);
181
182	__cfc1(fcsr);
183	fcsr &= ~_ROUND_MASK;
184	fcsr |= __round;
185	__ctc1(fcsr);
186
187	return (0);
188}
189
190__fenv_static inline int
191fegetenv(fenv_t *__envp)
192{
193
194	__cfc1(*__envp);
195
196	return (0);
197}
198
199__fenv_static inline int
200feholdexcept(fenv_t *__envp)
201{
202	fexcept_t fcsr;
203
204	__cfc1(fcsr);
205	*__envp = fcsr;
206	fcsr &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
207	__ctc1(fcsr);
208
209	return (0);
210}
211
212__fenv_static inline int
213fesetenv(const fenv_t *__envp)
214{
215
216	__ctc1(*__envp);
217
218	return (0);
219}
220
221__fenv_static inline int
222feupdateenv(const fenv_t *__envp)
223{
224	fexcept_t fcsr;
225
226	__cfc1(fcsr);
227	fesetenv(__envp);
228	feraiseexcept(fcsr);
229
230	return (0);
231}
232#endif /* !__mips_soft_float */
233
234#if __BSD_VISIBLE
235
236/* We currently provide no external definitions of the functions below. */
237
238#ifdef __mips_soft_float
239int feenableexcept(int __mask);
240int fedisableexcept(int __mask);
241int fegetexcept(void);
242#else
243static inline int
244feenableexcept(int __mask)
245{
246	fenv_t __old_fcsr, __new_fcsr;
247
248	__cfc1(__old_fcsr);
249	__new_fcsr = __old_fcsr | (__mask & FE_ALL_EXCEPT) << _ENABLE_SHIFT;
250	__ctc1(__new_fcsr);
251
252	return ((__old_fcsr >> _ENABLE_SHIFT) & FE_ALL_EXCEPT);
253}
254
255static inline int
256fedisableexcept(int __mask)
257{
258	fenv_t __old_fcsr, __new_fcsr;
259
260	__cfc1(__old_fcsr);
261	__new_fcsr = __old_fcsr & ~((__mask & FE_ALL_EXCEPT) << _ENABLE_SHIFT);
262	__ctc1(__new_fcsr);
263
264	return ((__old_fcsr >> _ENABLE_SHIFT) & FE_ALL_EXCEPT);
265}
266
267static inline int
268fegetexcept(void)
269{
270	fexcept_t fcsr;
271
272	__cfc1(fcsr);
273
274	return ((fcsr & _ENABLE_MASK) >> _ENABLE_SHIFT);
275}
276
277#endif /* !__mips_soft_float */
278
279#endif /* __BSD_VISIBLE */
280
281__END_DECLS
282
283#endif	/* !_FENV_H_ */
284