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