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
 27#ifdef __arm__
 28#include <arm/fenv.h>
 29#else /* __arm__ */
 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
 40/* The high 32 bits contain fpcr, low 32 contain fpsr. */
 41typedef	__uint64_t	fenv_t;
 42typedef	__uint64_t	fexcept_t;
 43
 44/* Exception flags */
 45#define	FE_INVALID	0x00000001
 46#define	FE_DIVBYZERO	0x00000002
 47#define	FE_OVERFLOW	0x00000004
 48#define	FE_UNDERFLOW	0x00000008
 49#define	FE_INEXACT	0x00000010
 50#define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
 51			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
 52
 53/*
 54 * Rounding modes
 55 *
 56 * We can't just use the hardware bit values here, because that would
 57 * make FE_UPWARD and FE_DOWNWARD negative, which is not allowed.
 58 */
 59#define	FE_TONEAREST	0x0
 60#define	FE_UPWARD	0x1
 61#define	FE_DOWNWARD	0x2
 62#define	FE_TOWARDZERO	0x3
 63#define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
 64			 FE_UPWARD | FE_TOWARDZERO)
 65#define	_ROUND_SHIFT	22
 66
 67__BEGIN_DECLS
 68
 69/* Default floating-point environment */
 70extern const fenv_t	__fe_dfl_env;
 71#define	FE_DFL_ENV	(&__fe_dfl_env)
 72
 73/* We need to be able to map status flag positions to mask flag positions */
 74#define _FPUSW_SHIFT	8
 75#define	_ENABLE_MASK	(FE_ALL_EXCEPT << _FPUSW_SHIFT)
 76
 77#define	__mrs_fpcr(__r)	__asm __volatile("mrs %0, fpcr" : "=r" (__r))
 78#define	__msr_fpcr(__r)	__asm __volatile("msr fpcr, %0" : : "r" (__r))
 79
 80#define	__mrs_fpsr(__r)	__asm __volatile("mrs %0, fpsr" : "=r" (__r))
 81#define	__msr_fpsr(__r)	__asm __volatile("msr fpsr, %0" : : "r" (__r))
 82
 83__fenv_static __inline int
 84feclearexcept(int __excepts)
 85{
 86	fexcept_t __r;
 87
 88	__mrs_fpsr(__r);
 89	__r &= ~__excepts;
 90	__msr_fpsr(__r);
 91	return (0);
 92}
 93
 94__fenv_static inline int
 95fegetexceptflag(fexcept_t *__flagp, int __excepts)
 96{
 97	fexcept_t __r;
 98
 99	__mrs_fpsr(__r);
100	*__flagp = __r & __excepts;
101	return (0);
102}
103
104__fenv_static inline int
105fesetexceptflag(const fexcept_t *__flagp, int __excepts)
106{
107	fexcept_t __r;
108
109	__mrs_fpsr(__r);
110	__r &= ~__excepts;
111	__r |= *__flagp & __excepts;
112	__msr_fpsr(__r);
113	return (0);
114}
115
116__fenv_static inline int
117feraiseexcept(int __excepts)
118{
119	fexcept_t __r;
120
121	__mrs_fpsr(__r);
122	__r |= __excepts;
123	__msr_fpsr(__r);
124	return (0);
125}
126
127__fenv_static inline int
128fetestexcept(int __excepts)
129{
130	fexcept_t __r;
131
132	__mrs_fpsr(__r);
133	return (__r & __excepts);
134}
135
136__fenv_static inline int
137fegetround(void)
138{
139	fenv_t __r;
140
141	__mrs_fpcr(__r);
142	return ((__r >> _ROUND_SHIFT) & _ROUND_MASK);
143}
144
145__fenv_static inline int
146fesetround(int __round)
147{
148	fenv_t __r;
149
150	if (__round & ~_ROUND_MASK)
151		return (-1);
152	__mrs_fpcr(__r);
153	__r &= ~(_ROUND_MASK << _ROUND_SHIFT);
154	__r |= __round << _ROUND_SHIFT;
155	__msr_fpcr(__r);
156	return (0);
157}
158
159__fenv_static inline int
160fegetenv(fenv_t *__envp)
161{
162	__uint64_t fpcr;
163	__uint64_t fpsr;
164
165	__mrs_fpcr(fpcr);
166	__mrs_fpsr(fpsr);
167	*__envp = fpsr | (fpcr << 32);
168
169	return (0);
170}
171
172__fenv_static inline int
173feholdexcept(fenv_t *__envp)
174{
175	fenv_t __r;
176
177	__mrs_fpcr(__r);
178	*__envp = __r << 32;
179	__r &= ~(_ENABLE_MASK);
180	__msr_fpcr(__r);
181
182	__mrs_fpsr(__r);
183	*__envp |= (__uint32_t)__r;
184	__r &= ~(_ENABLE_MASK);
185	__msr_fpsr(__r);
186	return (0);
187}
188
189__fenv_static inline int
190fesetenv(const fenv_t *__envp)
191{
192
193	__msr_fpcr((*__envp) >> 32);
194	__msr_fpsr((fenv_t)(__uint32_t)*__envp);
195	return (0);
196}
197
198__fenv_static inline int
199feupdateenv(const fenv_t *__envp)
200{
201	fexcept_t __r;
202
203	__mrs_fpsr(__r);
204	fesetenv(__envp);
205	feraiseexcept(__r & FE_ALL_EXCEPT);
206	return (0);
207}
208
209#if __BSD_VISIBLE
210
211/* We currently provide no external definitions of the functions below. */
212
213static inline int
214feenableexcept(int __mask)
215{
216	fenv_t __old_r, __new_r;
217
218	__mrs_fpcr(__old_r);
219	__new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
220	__msr_fpcr(__new_r);
221	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
222}
223
224static inline int
225fedisableexcept(int __mask)
226{
227	fenv_t __old_r, __new_r;
228
229	__mrs_fpcr(__old_r);
230	__new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
231	__msr_fpcr(__new_r);
232	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
233}
234
235static inline int
236fegetexcept(void)
237{
238	fenv_t __r;
239
240	__mrs_fpcr(__r);
241	return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT);
242}
243
244#endif /* __BSD_VISIBLE */
245
246__END_DECLS
247
248#endif	/* !_FENV_H_ */
249
250#endif /* __arm__ */