1130143Sdas/*-
2143708Sdas * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
3130143Sdas * All rights reserved.
4130143Sdas *
5130143Sdas * Redistribution and use in source and binary forms, with or without
6130143Sdas * modification, are permitted provided that the following conditions
7130143Sdas * are met:
8130143Sdas * 1. Redistributions of source code must retain the above copyright
9130143Sdas *    notice, this list of conditions and the following disclaimer.
10130143Sdas * 2. Redistributions in binary form must reproduce the above copyright
11130143Sdas *    notice, this list of conditions and the following disclaimer in the
12130143Sdas *    documentation and/or other materials provided with the distribution.
13130143Sdas *
14130143Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15130143Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16130143Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17130143Sdas * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18130143Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19130143Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20130143Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21130143Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22130143Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23130143Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24130143Sdas * SUCH DAMAGE.
25130143Sdas *
26130143Sdas * $FreeBSD$
27130143Sdas */
28130143Sdas
29130143Sdas#ifndef	_FENV_H_
30130143Sdas#define	_FENV_H_
31130143Sdas
32130143Sdas#include <sys/_types.h>
33130143Sdas
34130143Sdastypedef	__uint32_t	fenv_t;
35130143Sdastypedef	__uint32_t	fexcept_t;
36130143Sdas
37130143Sdas/* Exception flags */
38130143Sdas#define	FE_INVALID	0x0001
39130143Sdas#define	FE_DIVBYZERO	0x0002
40130143Sdas#define	FE_OVERFLOW	0x0004
41130143Sdas#define	FE_UNDERFLOW	0x0008
42130143Sdas#define	FE_INEXACT	0x0010
43130143Sdas#define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
44130143Sdas			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
45130143Sdas
46140689Scognet/* Rounding modes */
47140689Scognet#define	FE_TONEAREST	0x0000
48140689Scognet#define	FE_TOWARDZERO	0x0001
49140689Scognet#define	FE_UPWARD	0x0002
50140689Scognet#define	FE_DOWNWARD	0x0003
51140689Scognet#define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
52140689Scognet			 FE_UPWARD | FE_TOWARDZERO)
53130143Sdas__BEGIN_DECLS
54130143Sdas
55130143Sdas/* Default floating-point environment */
56130143Sdasextern const fenv_t	__fe_dfl_env;
57130143Sdas#define	FE_DFL_ENV	(&__fe_dfl_env)
58130143Sdas
59130143Sdas/* We need to be able to map status flag positions to mask flag positions */
60130143Sdas#define _FPUSW_SHIFT	16
61130143Sdas#define	_ENABLE_MASK	(FE_ALL_EXCEPT << _FPUSW_SHIFT)
62130143Sdas
63133174Scognet#ifdef	ARM_HARD_FLOAT
64140219Sdas#define	__rfs(__fpsr)	__asm __volatile("rfs %0" : "=r" (*(__fpsr)))
65133174Scognet#define	__wfs(__fpsr)	__asm __volatile("wfs %0" : : "r" (__fpsr))
66133174Scognet#else
67133174Scognet#define __rfs(__fpsr)
68133174Scognet#define __wfs(__fpsr)
69133174Scognet#endif
70130143Sdas
71130143Sdasstatic __inline int
72130143Sdasfeclearexcept(int __excepts)
73130143Sdas{
74130143Sdas	fexcept_t __fpsr;
75130143Sdas
76130143Sdas	__rfs(&__fpsr);
77130143Sdas	__fpsr &= ~__excepts;
78130143Sdas	__wfs(__fpsr);
79130143Sdas	return (0);
80130143Sdas}
81130143Sdas
82130143Sdasstatic __inline int
83130143Sdasfegetexceptflag(fexcept_t *__flagp, int __excepts)
84130143Sdas{
85130143Sdas	fexcept_t __fpsr;
86130143Sdas
87130143Sdas	__rfs(&__fpsr);
88130143Sdas	*__flagp = __fpsr & __excepts;
89130143Sdas	return (0);
90130143Sdas}
91130143Sdas
92130143Sdasstatic __inline int
93130143Sdasfesetexceptflag(const fexcept_t *__flagp, int __excepts)
94130143Sdas{
95130143Sdas	fexcept_t __fpsr;
96130143Sdas
97130143Sdas	__rfs(&__fpsr);
98130143Sdas	__fpsr &= ~__excepts;
99130143Sdas	__fpsr |= *__flagp & __excepts;
100130143Sdas	__wfs(__fpsr);
101130143Sdas	return (0);
102130143Sdas}
103130143Sdas
104130143Sdasstatic __inline int
105130143Sdasferaiseexcept(int __excepts)
106130143Sdas{
107130143Sdas	fexcept_t __ex = __excepts;
108130143Sdas
109130143Sdas	fesetexceptflag(&__ex, __excepts);	/* XXX */
110130143Sdas	return (0);
111130143Sdas}
112130143Sdas
113130143Sdasstatic __inline int
114130143Sdasfetestexcept(int __excepts)
115130143Sdas{
116130143Sdas	fexcept_t __fpsr;
117130143Sdas
118130143Sdas	__rfs(&__fpsr);
119130143Sdas	return (__fpsr & __excepts);
120130143Sdas}
121130143Sdas
122130143Sdasstatic __inline int
123130143Sdasfegetround(void)
124130143Sdas{
125130143Sdas
126130143Sdas	/*
127130143Sdas	 * Apparently, the rounding mode is specified as part of the
128130143Sdas	 * instruction format on ARM, so the dynamic rounding mode is
129130143Sdas	 * indeterminate.  Some FPUs may differ.
130130143Sdas	 */
131130143Sdas	return (-1);
132130143Sdas}
133130143Sdas
134130143Sdasstatic __inline int
135130143Sdasfesetround(int __round)
136130143Sdas{
137130143Sdas
138130143Sdas	return (-1);
139130143Sdas}
140130143Sdas
141130143Sdasstatic __inline int
142130143Sdasfegetenv(fenv_t *__envp)
143130143Sdas{
144130143Sdas
145130143Sdas	__rfs(__envp);
146130143Sdas	return (0);
147130143Sdas}
148130143Sdas
149130143Sdasstatic __inline int
150130143Sdasfeholdexcept(fenv_t *__envp)
151130143Sdas{
152130143Sdas	fenv_t __env;
153130143Sdas
154130143Sdas	__rfs(&__env);
155130143Sdas	*__envp = __env;
156130143Sdas	__env &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
157130143Sdas	__wfs(__env);
158130143Sdas	return (0);
159130143Sdas}
160130143Sdas
161130143Sdasstatic __inline int
162130143Sdasfesetenv(const fenv_t *__envp)
163130143Sdas{
164130143Sdas
165130143Sdas	__wfs(*__envp);
166130143Sdas	return (0);
167130143Sdas}
168130143Sdas
169130143Sdasstatic __inline int
170130143Sdasfeupdateenv(const fenv_t *__envp)
171130143Sdas{
172130143Sdas	fexcept_t __fpsr;
173130143Sdas
174130143Sdas	__rfs(&__fpsr);
175130143Sdas	__wfs(*__envp);
176130143Sdas	feraiseexcept(__fpsr & FE_ALL_EXCEPT);
177130143Sdas	return (0);
178130143Sdas}
179130143Sdas
180130143Sdas#if __BSD_VISIBLE
181130143Sdas
182130143Sdasstatic __inline int
183143708Sdasfeenableexcept(int __mask)
184130143Sdas{
185143708Sdas	fenv_t __old_fpsr, __new_fpsr;
186130143Sdas
187143708Sdas	__rfs(&__old_fpsr);
188143708Sdas	__new_fpsr = __old_fpsr | (__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT;
189143708Sdas	__wfs(__new_fpsr);
190143708Sdas	return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
191130143Sdas}
192130143Sdas
193130143Sdasstatic __inline int
194143708Sdasfedisableexcept(int __mask)
195130143Sdas{
196143708Sdas	fenv_t __old_fpsr, __new_fpsr;
197143708Sdas
198143708Sdas	__rfs(&__old_fpsr);
199143708Sdas	__new_fpsr = __old_fpsr & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
200143708Sdas	__wfs(__new_fpsr);
201143708Sdas	return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
202143708Sdas}
203143708Sdas
204143708Sdasstatic __inline int
205143708Sdasfegetexcept(void)
206143708Sdas{
207130143Sdas	fenv_t __fpsr;
208130143Sdas
209130143Sdas	__rfs(&__fpsr);
210130143Sdas	return ((__fpsr & _ENABLE_MASK) >> _FPUSW_SHIFT);
211130143Sdas}
212130143Sdas
213130143Sdas#endif /* __BSD_VISIBLE */
214130143Sdas
215130143Sdas__END_DECLS
216130143Sdas
217130143Sdas#endif	/* !_FENV_H_ */
218