1/*-
2 * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: src/lib/msun/arm/fenv.h,v 1.5 2005/03/16 19:03:45 das Exp $
27 */
28
29#ifndef	_FENV_H_
30#define	_FENV_H_
31
32#include <sys/types.h>
33
34__BEGIN_DECLS
35
36typedef	uint32_t	fenv_t;
37typedef	uint32_t	fexcept_t;
38
39/* Exception flags */
40#define	FE_INVALID	0x0001
41#define	FE_DIVBYZERO	0x0002
42#define	FE_OVERFLOW	0x0004
43#define	FE_UNDERFLOW	0x0008
44#define	FE_INEXACT	0x0010
45#define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
46			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
47
48/* Rounding modes */
49#define	FE_TONEAREST	0x0000
50#define	FE_TOWARDZERO	0x0001
51#define	FE_UPWARD	0x0002
52#define	FE_DOWNWARD	0x0003
53#define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
54			 FE_UPWARD | FE_TOWARDZERO)
55
56/* Default floating-point environment */
57extern const fenv_t	__fe_dfl_env;
58#define	FE_DFL_ENV	(&__fe_dfl_env)
59
60/* We need to be able to map status flag positions to mask flag positions */
61#define _FPUSW_SHIFT	16
62#define	_ENABLE_MASK	(FE_ALL_EXCEPT << _FPUSW_SHIFT)
63
64#ifdef	ARM_HARD_FLOAT
65#define	__rfs(__fpsr)	__asm __volatile("rfs %0" : "=r" (*(__fpsr)))
66#define	__wfs(__fpsr)	__asm __volatile("wfs %0" : : "r" (__fpsr))
67#else
68#define __rfs(__fpsr)
69#define __wfs(__fpsr)
70#endif
71
72static __inline int
73feclearexcept(int __excepts)
74{
75	fexcept_t __fpsr;
76
77	__rfs(&__fpsr);
78	__fpsr &= ~__excepts;
79	__wfs(__fpsr);
80	return (0);
81}
82
83static __inline int
84fegetexceptflag(fexcept_t *__flagp, int __excepts)
85{
86	fexcept_t __fpsr;
87
88	__rfs(&__fpsr);
89	*__flagp = __fpsr & __excepts;
90	return (0);
91}
92
93static __inline int
94fesetexceptflag(const fexcept_t *__flagp, int __excepts)
95{
96	fexcept_t __fpsr;
97
98	__rfs(&__fpsr);
99	__fpsr &= ~__excepts;
100	__fpsr |= *__flagp & __excepts;
101	__wfs(__fpsr);
102	return (0);
103}
104
105static __inline int
106feraiseexcept(int __excepts)
107{
108	fexcept_t __ex = __excepts;
109
110	fesetexceptflag(&__ex, __excepts);	/* XXX */
111	return (0);
112}
113
114static __inline int
115fetestexcept(int __excepts)
116{
117	fexcept_t __fpsr;
118
119	__rfs(&__fpsr);
120	return (__fpsr & __excepts);
121}
122
123static __inline int
124fegetround(void)
125{
126
127	/*
128	 * Apparently, the rounding mode is specified as part of the
129	 * instruction format on ARM, so the dynamic rounding mode is
130	 * indeterminate.  Some FPUs may differ.
131	 */
132	return (-1);
133}
134
135static __inline int
136fesetround(int __round)
137{
138
139	return (-1);
140}
141
142static __inline int
143fegetenv(fenv_t *__envp)
144{
145
146	__rfs(__envp);
147	return (0);
148}
149
150static __inline int
151feholdexcept(fenv_t *__envp)
152{
153	fenv_t __env;
154
155	__rfs(&__env);
156	*__envp = __env;
157	__env &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
158	__wfs(__env);
159	return (0);
160}
161
162static __inline int
163fesetenv(const fenv_t *__envp)
164{
165
166	__wfs(*__envp);
167	return (0);
168}
169
170static __inline int
171feupdateenv(const fenv_t *__envp)
172{
173	fexcept_t __fpsr;
174
175	__rfs(&__fpsr);
176	__wfs(*__envp);
177	feraiseexcept(__fpsr & FE_ALL_EXCEPT);
178	return (0);
179}
180
181#if __BSD_VISIBLE
182
183static __inline int
184feenableexcept(int __mask)
185{
186	fenv_t __old_fpsr, __new_fpsr;
187
188	__rfs(&__old_fpsr);
189	__new_fpsr = __old_fpsr | (__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT;
190	__wfs(__new_fpsr);
191	return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
192}
193
194static __inline int
195fedisableexcept(int __mask)
196{
197	fenv_t __old_fpsr, __new_fpsr;
198
199	__rfs(&__old_fpsr);
200	__new_fpsr = __old_fpsr & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
201	__wfs(__new_fpsr);
202	return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
203}
204
205static __inline int
206fegetexcept(void)
207{
208	fenv_t __fpsr;
209
210	__rfs(&__fpsr);
211	return ((__fpsr & _ENABLE_MASK) >> _FPUSW_SHIFT);
212}
213
214#endif /* __BSD_VISIBLE */
215
216__END_DECLS
217
218#endif	/* !_FENV_H_ */
219