master
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__ */