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 #if __ARM_ARCH >= 6
36 #define FENV_ARMv6
37 #endif
38
39 /* When SOFTFP_ABI is defined we are using the softfp ABI. */
40 #if defined(__VFP_FP__) && !defined(__ARM_PCS_VFP)
41 #define SOFTFP_ABI
42 #endif
43
44
45 #ifndef FENV_MANGLE
46 /*
47 * Hopefully the system ID byte is immutable, so it's valid to use
48 * this as a default environment.
49 */
50 const fenv_t __fe_dfl_env = 0;
51 #endif
52
53
54 /* If this is a non-mangled softfp version special processing is required */
55 #if defined(FENV_MANGLE) || !defined(SOFTFP_ABI) || !defined(FENV_ARMv6)
56
57 /*
58 * The following macros map between the softfloat emulator's flags and
59 * the hardware's FPSR. The hardware this file was written for doesn't
60 * have rounding control bits, so we stick those in the system ID byte.
61 */
62 #ifndef __ARM_PCS_VFP
63 #define __set_env(env, flags, mask, rnd) env = ((flags) \
64 | (mask)<<_FPUSW_SHIFT \
65 | (rnd) << 24)
66 #define __env_flags(env) ((env) & FE_ALL_EXCEPT)
67 #define __env_mask(env) (((env) >> _FPUSW_SHIFT) \
68 & FE_ALL_EXCEPT)
69 #define __env_round(env) (((env) >> 24) & _ROUND_MASK)
70 #include "fenv-softfloat.h"
71 #endif
72
73 #ifdef __GNUC_GNU_INLINE__
74 #error "This file must be compiled with C99 'inline' semantics"
75 #endif
76
77 extern inline int feclearexcept(int __excepts);
78 extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts);
79 extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
80 extern inline int feraiseexcept(int __excepts);
81 extern inline int fetestexcept(int __excepts);
82 extern inline int fegetround(void);
83 extern inline int fesetround(int __round);
84 extern inline int fegetenv(fenv_t *__envp);
85 extern inline int feholdexcept(fenv_t *__envp);
86 extern inline int fesetenv(const fenv_t *__envp);
87 extern inline int feupdateenv(const fenv_t *__envp);
88 extern inline int feenableexcept(int __mask);
89 extern inline int fedisableexcept(int __mask);
90 extern inline int fegetexcept(void);
91
92 #else /* !FENV_MANGLE && SOFTFP_ABI */
93 /* Set by libc when the VFP unit is enabled */
94 extern int _libc_arm_fpu_present;
95
96 int __softfp_feclearexcept(int __excepts);
97 int __softfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
98 int __softfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
99 int __softfp_feraiseexcept(int __excepts);
100 int __softfp_fetestexcept(int __excepts);
101 int __softfp_fegetround(void);
102 int __softfp_fesetround(int __round);
103 int __softfp_fegetenv(fenv_t *__envp);
104 int __softfp_feholdexcept(fenv_t *__envp);
105 int __softfp_fesetenv(const fenv_t *__envp);
106 int __softfp_feupdateenv(const fenv_t *__envp);
107 int __softfp_feenableexcept(int __mask);
108 int __softfp_fedisableexcept(int __mask);
109 int __softfp_fegetexcept(void);
110
111 int __vfp_feclearexcept(int __excepts);
112 int __vfp_fegetexceptflag(fexcept_t *__flagp, int __excepts);
113 int __vfp_fesetexceptflag(const fexcept_t *__flagp, int __excepts);
114 int __vfp_feraiseexcept(int __excepts);
115 int __vfp_fetestexcept(int __excepts);
116 int __vfp_fegetround(void);
117 int __vfp_fesetround(int __round);
118 int __vfp_fegetenv(fenv_t *__envp);
119 int __vfp_feholdexcept(fenv_t *__envp);
120 int __vfp_fesetenv(const fenv_t *__envp);
121 int __vfp_feupdateenv(const fenv_t *__envp);
122 int __vfp_feenableexcept(int __mask);
123 int __vfp_fedisableexcept(int __mask);
124 int __vfp_fegetexcept(void);
125
126 static int
__softfp_round_to_vfp(int round)127 __softfp_round_to_vfp(int round)
128 {
129
130 switch (round) {
131 case FE_TONEAREST:
132 default:
133 return VFP_FE_TONEAREST;
134 case FE_TOWARDZERO:
135 return VFP_FE_TOWARDZERO;
136 case FE_UPWARD:
137 return VFP_FE_UPWARD;
138 case FE_DOWNWARD:
139 return VFP_FE_DOWNWARD;
140 }
141 }
142
143 static int
__softfp_round_from_vfp(int round)144 __softfp_round_from_vfp(int round)
145 {
146
147 switch (round) {
148 case VFP_FE_TONEAREST:
149 default:
150 return FE_TONEAREST;
151 case VFP_FE_TOWARDZERO:
152 return FE_TOWARDZERO;
153 case VFP_FE_UPWARD:
154 return FE_UPWARD;
155 case VFP_FE_DOWNWARD:
156 return FE_DOWNWARD;
157 }
158 }
159
feclearexcept(int __excepts)160 int feclearexcept(int __excepts)
161 {
162
163 if (_libc_arm_fpu_present)
164 __vfp_feclearexcept(__excepts);
165 __softfp_feclearexcept(__excepts);
166
167 return (0);
168 }
169
fegetexceptflag(fexcept_t * __flagp,int __excepts)170 int fegetexceptflag(fexcept_t *__flagp, int __excepts)
171 {
172 fexcept_t __vfp_flagp;
173
174 __vfp_flagp = 0;
175 if (_libc_arm_fpu_present)
176 __vfp_fegetexceptflag(&__vfp_flagp, __excepts);
177 __softfp_fegetexceptflag(__flagp, __excepts);
178
179 *__flagp |= __vfp_flagp;
180
181 return (0);
182 }
183
fesetexceptflag(const fexcept_t * __flagp,int __excepts)184 int fesetexceptflag(const fexcept_t *__flagp, int __excepts)
185 {
186
187 if (_libc_arm_fpu_present)
188 __vfp_fesetexceptflag(__flagp, __excepts);
189 __softfp_fesetexceptflag(__flagp, __excepts);
190
191 return (0);
192 }
193
feraiseexcept(int __excepts)194 int feraiseexcept(int __excepts)
195 {
196
197 if (_libc_arm_fpu_present)
198 __vfp_feraiseexcept(__excepts);
199 __softfp_feraiseexcept(__excepts);
200
201 return (0);
202 }
203
fetestexcept(int __excepts)204 int fetestexcept(int __excepts)
205 {
206 int __got_excepts;
207
208 __got_excepts = 0;
209 if (_libc_arm_fpu_present)
210 __got_excepts = __vfp_fetestexcept(__excepts);
211 __got_excepts |= __softfp_fetestexcept(__excepts);
212
213 return (__got_excepts);
214 }
215
fegetround(void)216 int fegetround(void)
217 {
218
219 if (_libc_arm_fpu_present)
220 return __softfp_round_from_vfp(__vfp_fegetround());
221 return __softfp_fegetround();
222 }
223
fesetround(int __round)224 int fesetround(int __round)
225 {
226
227 if (_libc_arm_fpu_present)
228 __vfp_fesetround(__softfp_round_to_vfp(__round));
229 __softfp_fesetround(__round);
230
231 return (0);
232 }
233
fegetenv(fenv_t * __envp)234 int fegetenv(fenv_t *__envp)
235 {
236 fenv_t __vfp_envp;
237
238 __vfp_envp = 0;
239 if (_libc_arm_fpu_present)
240 __vfp_fegetenv(&__vfp_envp);
241 __softfp_fegetenv(__envp);
242 *__envp |= __vfp_envp;
243
244 return (0);
245 }
246
feholdexcept(fenv_t * __envp)247 int feholdexcept(fenv_t *__envp)
248 {
249 fenv_t __vfp_envp;
250
251 __vfp_envp = 0;
252 if (_libc_arm_fpu_present)
253 __vfp_feholdexcept(&__vfp_envp);
254 __softfp_feholdexcept(__envp);
255 *__envp |= __vfp_envp;
256
257 return (0);
258 }
259
fesetenv(const fenv_t * __envp)260 int fesetenv(const fenv_t *__envp)
261 {
262
263 if (_libc_arm_fpu_present)
264 __vfp_fesetenv(__envp);
265 __softfp_fesetenv(__envp);
266
267 return (0);
268 }
269
feupdateenv(const fenv_t * __envp)270 int feupdateenv(const fenv_t *__envp)
271 {
272
273 if (_libc_arm_fpu_present)
274 __vfp_feupdateenv(__envp);
275 __softfp_feupdateenv(__envp);
276
277 return (0);
278 }
279
feenableexcept(int __mask)280 int feenableexcept(int __mask)
281 {
282 int __unmasked;
283
284 __unmasked = 0;
285 if (_libc_arm_fpu_present)
286 __unmasked = __vfp_feenableexcept(__mask);
287 __unmasked |= __softfp_feenableexcept(__mask);
288
289 return (__unmasked);
290 }
291
fedisableexcept(int __mask)292 int fedisableexcept(int __mask)
293 {
294 int __unmasked;
295
296 __unmasked = 0;
297 if (_libc_arm_fpu_present)
298 __unmasked = __vfp_fedisableexcept(__mask);
299 __unmasked |= __softfp_fedisableexcept(__mask);
300
301 return (__unmasked);
302 }
303
fegetexcept(void)304 int fegetexcept(void)
305 {
306 int __unmasked;
307
308 __unmasked = 0;
309 if (_libc_arm_fpu_present)
310 __unmasked = __vfp_fegetexcept();
311 __unmasked |= __softfp_fegetexcept();
312
313 return (__unmasked);
314 }
315
316 #endif
317
318