1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
5 * Copyright (c) 2013 Andrew Turner <andrew@FreeBSD.ORG>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #define __fenv_static
31 #include "fenv.h"
32
33 #include <machine/acle-compat.h>
34
35 /* When SOFTFP_ABI is defined we are using the softfp ABI. */
36 #if defined(__VFP_FP__) && !defined(__ARM_PCS_VFP)
37 #define SOFTFP_ABI
38 #endif
39
40
41 #ifndef FENV_MANGLE
42 /*
43 * Hopefully the system ID byte is immutable, so it's valid to use
44 * this as a default environment.
45 */
46 const fenv_t __fe_dfl_env = 0;
47 #endif
48
49
50 /* If this is a non-mangled softfp version special processing is required */
51 #if defined(FENV_MANGLE) || !defined(SOFTFP_ABI)
52
53 /*
54 * The following macros map between the softfloat emulator's flags and
55 * the hardware's FPSR. The hardware this file was written for doesn't
56 * have rounding control bits, so we stick those in the system ID byte.
57 */
58 #ifndef __ARM_PCS_VFP
59 #define __set_env(env, flags, mask, rnd) env = ((flags) \
60 | (mask)<<_FPUSW_SHIFT \
61 | (rnd) << 24)
62 #define __env_flags(env) ((env) & FE_ALL_EXCEPT)
63 #define __env_mask(env) (((env) >> _FPUSW_SHIFT) \
64 & FE_ALL_EXCEPT)
65 #define __env_round(env) (((env) >> 24) & _ROUND_MASK)
66 #include "fenv-softfloat.h"
67 #endif
68
69 #ifdef __GNUC_GNU_INLINE__
70 #error "This file must be compiled with C99 'inline' semantics"
71 #endif
72
73 extern inline int feclearexcept(int __excepts);
74 extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts);
75 extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
76 extern inline int feraiseexcept(int __excepts);
77 extern inline int fetestexcept(int __excepts);
78 extern inline int fegetround(void);
79 extern inline int fesetround(int __round);
80 extern inline int fegetenv(fenv_t *__envp);
81 extern inline int feholdexcept(fenv_t *__envp);
82 extern inline int fesetenv(const fenv_t *__envp);
83 extern inline int feupdateenv(const fenv_t *__envp);
84 extern inline int feenableexcept(int __mask);
85 extern inline int fedisableexcept(int __mask);
86 extern inline int fegetexcept(void);
87
88 #else /* !FENV_MANGLE && SOFTFP_ABI */
89 /* Set by libc when the VFP unit is enabled */
90 extern int _libc_arm_fpu_present;
91
92 int __softfp_feclearexcept(int __excepts);
93 int __softfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
94 int __softfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
95 int __softfp_feraiseexcept(int __excepts);
96 int __softfp_fetestexcept(int __excepts);
97 int __softfp_fegetround(void);
98 int __softfp_fesetround(int __round);
99 int __softfp_fegetenv(fenv_t *__envp);
100 int __softfp_feholdexcept(fenv_t *__envp);
101 int __softfp_fesetenv(const fenv_t *__envp);
102 int __softfp_feupdateenv(const fenv_t *__envp);
103 int __softfp_feenableexcept(int __mask);
104 int __softfp_fedisableexcept(int __mask);
105 int __softfp_fegetexcept(void);
106
107 int __vfp_feclearexcept(int __excepts);
108 int __vfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
109 int __vfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
110 int __vfp_feraiseexcept(int __excepts);
111 int __vfp_fetestexcept(int __excepts);
112 int __vfp_fegetround(void);
113 int __vfp_fesetround(int __round);
114 int __vfp_fegetenv(fenv_t *__envp);
115 int __vfp_feholdexcept(fenv_t *__envp);
116 int __vfp_fesetenv(const fenv_t *__envp);
117 int __vfp_feupdateenv(const fenv_t *__envp);
118 int __vfp_feenableexcept(int __mask);
119 int __vfp_fedisableexcept(int __mask);
120 int __vfp_fegetexcept(void);
121
122 static int
__softfp_round_to_vfp(int round)123 __softfp_round_to_vfp(int round)
124 {
125
126 switch (round) {
127 case FE_TONEAREST:
128 default:
129 return VFP_FE_TONEAREST;
130 case FE_TOWARDZERO:
131 return VFP_FE_TOWARDZERO;
132 case FE_UPWARD:
133 return VFP_FE_UPWARD;
134 case FE_DOWNWARD:
135 return VFP_FE_DOWNWARD;
136 }
137 }
138
139 static int
__softfp_round_from_vfp(int round)140 __softfp_round_from_vfp(int round)
141 {
142
143 switch (round) {
144 case VFP_FE_TONEAREST:
145 default:
146 return FE_TONEAREST;
147 case VFP_FE_TOWARDZERO:
148 return FE_TOWARDZERO;
149 case VFP_FE_UPWARD:
150 return FE_UPWARD;
151 case VFP_FE_DOWNWARD:
152 return FE_DOWNWARD;
153 }
154 }
155
feclearexcept(int __excepts)156 int feclearexcept(int __excepts)
157 {
158
159 if (_libc_arm_fpu_present)
160 __vfp_feclearexcept(__excepts);
161 __softfp_feclearexcept(__excepts);
162
163 return (0);
164 }
165
fegetexceptflag(fexcept_t * __flagp,int __excepts)166 int fegetexceptflag(fexcept_t *__flagp, int __excepts)
167 {
168 fexcept_t __vfp_flagp;
169
170 __vfp_flagp = 0;
171 if (_libc_arm_fpu_present)
172 __vfp_fegetexceptflag(&__vfp_flagp, __excepts);
173 __softfp_fegetexceptflag(__flagp, __excepts);
174
175 *__flagp |= __vfp_flagp;
176
177 return (0);
178 }
179
fesetexceptflag(const fexcept_t * __flagp,int __excepts)180 int fesetexceptflag(const fexcept_t *__flagp, int __excepts)
181 {
182
183 if (_libc_arm_fpu_present)
184 __vfp_fesetexceptflag(__flagp, __excepts);
185 __softfp_fesetexceptflag(__flagp, __excepts);
186
187 return (0);
188 }
189
feraiseexcept(int __excepts)190 int feraiseexcept(int __excepts)
191 {
192
193 if (_libc_arm_fpu_present)
194 __vfp_feraiseexcept(__excepts);
195 __softfp_feraiseexcept(__excepts);
196
197 return (0);
198 }
199
fetestexcept(int __excepts)200 int fetestexcept(int __excepts)
201 {
202 int __got_excepts;
203
204 __got_excepts = 0;
205 if (_libc_arm_fpu_present)
206 __got_excepts = __vfp_fetestexcept(__excepts);
207 __got_excepts |= __softfp_fetestexcept(__excepts);
208
209 return (__got_excepts);
210 }
211
fegetround(void)212 int fegetround(void)
213 {
214
215 if (_libc_arm_fpu_present)
216 return __softfp_round_from_vfp(__vfp_fegetround());
217 return __softfp_fegetround();
218 }
219
fesetround(int __round)220 int fesetround(int __round)
221 {
222
223 if (_libc_arm_fpu_present)
224 __vfp_fesetround(__softfp_round_to_vfp(__round));
225 __softfp_fesetround(__round);
226
227 return (0);
228 }
229
fegetenv(fenv_t * __envp)230 int fegetenv(fenv_t *__envp)
231 {
232 fenv_t __vfp_envp;
233
234 __vfp_envp = 0;
235 if (_libc_arm_fpu_present)
236 __vfp_fegetenv(&__vfp_envp);
237 __softfp_fegetenv(__envp);
238 *__envp |= __vfp_envp;
239
240 return (0);
241 }
242
feholdexcept(fenv_t * __envp)243 int feholdexcept(fenv_t *__envp)
244 {
245 fenv_t __vfp_envp;
246
247 __vfp_envp = 0;
248 if (_libc_arm_fpu_present)
249 __vfp_feholdexcept(&__vfp_envp);
250 __softfp_feholdexcept(__envp);
251 *__envp |= __vfp_envp;
252
253 return (0);
254 }
255
fesetenv(const fenv_t * __envp)256 int fesetenv(const fenv_t *__envp)
257 {
258
259 if (_libc_arm_fpu_present)
260 __vfp_fesetenv(__envp);
261 __softfp_fesetenv(__envp);
262
263 return (0);
264 }
265
feupdateenv(const fenv_t * __envp)266 int feupdateenv(const fenv_t *__envp)
267 {
268
269 if (_libc_arm_fpu_present)
270 __vfp_feupdateenv(__envp);
271 __softfp_feupdateenv(__envp);
272
273 return (0);
274 }
275
feenableexcept(int __mask)276 int feenableexcept(int __mask)
277 {
278 int __unmasked;
279
280 __unmasked = 0;
281 if (_libc_arm_fpu_present)
282 __unmasked = __vfp_feenableexcept(__mask);
283 __unmasked |= __softfp_feenableexcept(__mask);
284
285 return (__unmasked);
286 }
287
fedisableexcept(int __mask)288 int fedisableexcept(int __mask)
289 {
290 int __unmasked;
291
292 __unmasked = 0;
293 if (_libc_arm_fpu_present)
294 __unmasked = __vfp_fedisableexcept(__mask);
295 __unmasked |= __softfp_fedisableexcept(__mask);
296
297 return (__unmasked);
298 }
299
fegetexcept(void)300 int fegetexcept(void)
301 {
302 int __unmasked;
303
304 __unmasked = 0;
305 if (_libc_arm_fpu_present)
306 __unmasked = __vfp_fegetexcept();
307 __unmasked |= __softfp_fegetexcept();
308
309 return (__unmasked);
310 }
311
312 #endif
313
314