xref: /netbsd-src/lib/libm/arch/arm/fenv.c (revision 0dcaa3783b9b222f97f1e1ea4eab2127f644225b)
1bc08020cSmatt /*-
2bc08020cSmatt  * Copyright (c) 2013 The NetBSD Foundation, Inc.
3bc08020cSmatt  * All rights reserved.
4bc08020cSmatt  *
5bc08020cSmatt  * This code is derived from software contributed to The NetBSD Foundation
6bc08020cSmatt  * by Matt Thomas of 3am Software Foundry.
7bc08020cSmatt  *
8bc08020cSmatt  * Redistribution and use in source and binary forms, with or without
9bc08020cSmatt  * modification, are permitted provided that the following conditions
10bc08020cSmatt  * are met:
11bc08020cSmatt  * 1. Redistributions of source code must retain the above copyright
12bc08020cSmatt  *    notice, this list of conditions and the following disclaimer.
13bc08020cSmatt  * 2. Redistributions in binary form must reproduce the above copyright
14bc08020cSmatt  *    notice, this list of conditions and the following disclaimer in the
15bc08020cSmatt  *    documentation and/or other materials provided with the distribution.
16bc08020cSmatt  *
17bc08020cSmatt  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18bc08020cSmatt  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19bc08020cSmatt  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20bc08020cSmatt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21bc08020cSmatt  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22bc08020cSmatt  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23bc08020cSmatt  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24bc08020cSmatt  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25bc08020cSmatt  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26bc08020cSmatt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27bc08020cSmatt  * POSSIBILITY OF SUCH DAMAGE.
28bc08020cSmatt  */
29bc08020cSmatt 
30bc08020cSmatt #include <sys/cdefs.h>
31*0dcaa378Smartin __RCSID("$NetBSD: fenv.c,v 1.9 2017/05/08 09:25:03 martin Exp $");
329bce3244Smartin 
339bce3244Smartin #include "namespace.h"
34bc08020cSmatt 
35bc08020cSmatt #include <sys/types.h>
36bc08020cSmatt #include <assert.h>
37bc08020cSmatt #include <fenv.h>
38bc08020cSmatt #include <string.h>
39bc08020cSmatt #include <unistd.h>
40194fd467Smatt #include <inttypes.h>
41bc08020cSmatt 
42bc08020cSmatt #ifdef __SOFTFP__
437e30e943Schs #error This fenv implementation is only for hardfloat.
44bc08020cSmatt #endif
45bc08020cSmatt 
46*0dcaa378Smartin #ifdef __weak_alias
47*0dcaa378Smartin __weak_alias(feclearexcept,_feclearexcept)
48*0dcaa378Smartin __weak_alias(fedisableexcept,_fedisableexcept)
49*0dcaa378Smartin __weak_alias(feenableexcept,_feenableexcept)
50*0dcaa378Smartin __weak_alias(fegetenv,_fegetenv)
51*0dcaa378Smartin __weak_alias(fegetexcept,_fegetexcept)
52*0dcaa378Smartin __weak_alias(fegetexceptflag,_fegetexceptflag)
53*0dcaa378Smartin __weak_alias(fegetround,_fegetround)
54*0dcaa378Smartin __weak_alias(feholdexcept,_feholdexcept)
55*0dcaa378Smartin __weak_alias(feraiseexcept,_feraiseexcept)
56*0dcaa378Smartin __weak_alias(fesetenv,_fesetenv)
57*0dcaa378Smartin __weak_alias(fesetexceptflag,_fesetexceptflag)
58*0dcaa378Smartin __weak_alias(fesetround,_fesetround)
59*0dcaa378Smartin __weak_alias(fetestexcept,_fetestexcept)
60*0dcaa378Smartin __weak_alias(feupdateenv,_feupdateenv)
61*0dcaa378Smartin #endif
62*0dcaa378Smartin 
637e30e943Schs #include <arm/armreg.h>
64bc08020cSmatt #include <arm/vfpreg.h>
65bc08020cSmatt 
66bc08020cSmatt const fenv_t __fe_dfl_env = VFP_FPSCR_FZ|VFP_FPSCR_DN|VFP_FPSCR_RN;
67bc08020cSmatt 
68bc08020cSmatt /*
69bc08020cSmatt  * The feclearexcept() function shall attempt to clear the supported
70bc08020cSmatt  * floating-point exceptions represented by excepts.
71bc08020cSmatt  */
72bc08020cSmatt int
feclearexcept(int excepts)73bc08020cSmatt feclearexcept(int excepts)
74bc08020cSmatt {
75194fd467Smatt #ifndef lint
76b137db75Smartin 	_DIAGASSERT((except & ~FE_ALL_EXCEPT) == 0);
77194fd467Smatt #endif
78bc08020cSmatt 	int tmp = armreg_fpscr_read() & ~__SHIFTIN(excepts, VFP_FPSCR_CSUM);
79bc08020cSmatt 	armreg_fpscr_write(tmp);
808f0edf9eSmatt 	return 0;
81bc08020cSmatt }
82bc08020cSmatt 
83bc08020cSmatt /*
84bc08020cSmatt  * The fegetexceptflag() function shall attempt to store an
85bc08020cSmatt  * implementation-defined representation of the states of the floating-point
86bc08020cSmatt  * status flags indicated by the argument excepts in the object pointed to by
87bc08020cSmatt  * the argument flagp.
88bc08020cSmatt  */
89bc08020cSmatt int
fegetexceptflag(fexcept_t * flagp,int excepts)90bc08020cSmatt fegetexceptflag(fexcept_t *flagp, int excepts)
91bc08020cSmatt {
927e30e943Schs 
93b137db75Smartin 	_DIAGASSERT((except & ~FE_ALL_EXCEPT) == 0);
94bc08020cSmatt 	*flagp = __SHIFTOUT(armreg_fpscr_read(), VFP_FPSCR_CSUM) & excepts;
95bc08020cSmatt 	return 0;
96bc08020cSmatt }
97bc08020cSmatt 
98bc08020cSmatt /*
99bc08020cSmatt  * The feraiseexcept() function shall attempt to raise the supported
100bc08020cSmatt  * floating-point exceptions represented by the argument excepts. The order
101bc08020cSmatt  * in which these floating-point exceptions are raised is unspecified.
102bc08020cSmatt  */
103bc08020cSmatt int
feraiseexcept(int excepts)104bc08020cSmatt feraiseexcept(int excepts)
105bc08020cSmatt {
106194fd467Smatt #ifndef lint
107b137db75Smartin 	_DIAGASSERT((except & ~FE_ALL_EXCEPT) == 0);
108194fd467Smatt #endif
109194fd467Smatt 	int fpscr = armreg_fpscr_read();
1107e30e943Schs 	fpscr |= __SHIFTIN(excepts, VFP_FPSCR_CSUM);
111bc08020cSmatt 	armreg_fpscr_write(fpscr);
112bc08020cSmatt 	return 0;
113bc08020cSmatt }
114bc08020cSmatt 
115bc08020cSmatt /*
116bc08020cSmatt  * The fesetexceptflag() function shall attempt to set the floating-point
117bc08020cSmatt  * status flags indicated by the argument excepts to the states stored in the
118bc08020cSmatt  * object pointed to by flagp. The value pointed to by flagp shall have been
119bc08020cSmatt  * set by a previous call to fegetexceptflag() whose second argument
120bc08020cSmatt  * represented at least those floating-point exceptions represented by the
121bc08020cSmatt  * argument excepts. This function does not raise floating-point exceptions,
122bc08020cSmatt  * but only sets the state of the flags.
123bc08020cSmatt  */
124bc08020cSmatt int
fesetexceptflag(const fexcept_t * flagp,int excepts)125bc08020cSmatt fesetexceptflag(const fexcept_t *flagp, int excepts)
126bc08020cSmatt {
127194fd467Smatt #ifndef lint
128b137db75Smartin 	_DIAGASSERT((except & ~FE_ALL_EXCEPT) == 0);
129194fd467Smatt #endif
130bc08020cSmatt 	int fpscr = armreg_fpscr_read();
131bc08020cSmatt 	fpscr &= ~__SHIFTIN(excepts, VFP_FPSCR_CSUM);
132bc08020cSmatt 	fpscr |= __SHIFTIN((*flagp & excepts), VFP_FPSCR_CSUM);
133bc08020cSmatt 	armreg_fpscr_write(fpscr);
134bc08020cSmatt 	return 0;
135bc08020cSmatt }
136bc08020cSmatt 
137b137db75Smartin int
feenableexcept(int excepts)138b137db75Smartin feenableexcept(int excepts)
139b137db75Smartin {
140b137db75Smartin #ifndef lint
141b137db75Smartin 	_DIAGASSERT((except & ~FE_ALL_EXCEPT) == 0);
142b137db75Smartin #endif
143b137db75Smartin 	int fpscr = armreg_fpscr_read();
144f5c779f5Smartin 	armreg_fpscr_write(fpscr | __SHIFTIN((excepts), VFP_FPSCR_ESUM));
145f5c779f5Smartin 	return __SHIFTOUT(fpscr, VFP_FPSCR_ESUM) & FE_ALL_EXCEPT;
146b137db75Smartin }
147b137db75Smartin 
148b137db75Smartin int
fedisableexcept(int excepts)149b137db75Smartin fedisableexcept(int excepts)
150b137db75Smartin {
151b137db75Smartin #ifndef lint
152b137db75Smartin 	_DIAGASSERT((except & ~FE_ALL_EXCEPT) == 0);
153b137db75Smartin #endif
154b137db75Smartin 	int fpscr = armreg_fpscr_read();
155f5c779f5Smartin 	armreg_fpscr_write(fpscr & ~__SHIFTIN((excepts), VFP_FPSCR_ESUM));
156f5c779f5Smartin 	return __SHIFTOUT(fpscr, VFP_FPSCR_ESUM) & FE_ALL_EXCEPT;
157b137db75Smartin }
158b137db75Smartin 
159bc08020cSmatt /*
160bc08020cSmatt  * The fetestexcept() function shall determine which of a specified subset of
161bc08020cSmatt  * the floating-point exception flags are currently set. The excepts argument
162bc08020cSmatt  * specifies the floating-point status flags to be queried.
163bc08020cSmatt  */
164bc08020cSmatt int
fetestexcept(int excepts)165bc08020cSmatt fetestexcept(int excepts)
166bc08020cSmatt {
167b137db75Smartin 	_DIAGASSERT((except & ~FE_ALL_EXCEPT) == 0);
168bc08020cSmatt 	return __SHIFTOUT(armreg_fpscr_read(), VFP_FPSCR_CSUM) & excepts;
169bc08020cSmatt }
170bc08020cSmatt 
171b137db75Smartin int
fegetexcept(void)172b137db75Smartin fegetexcept(void)
173b137db75Smartin {
174f5c779f5Smartin 	return __SHIFTOUT(armreg_fpscr_read(), VFP_FPSCR_ESUM);
175b137db75Smartin }
176b137db75Smartin 
177bc08020cSmatt /*
178bc08020cSmatt  * The fegetround() function shall get the current rounding direction.
179bc08020cSmatt  */
180bc08020cSmatt int
fegetround(void)181bc08020cSmatt fegetround(void)
182bc08020cSmatt {
183bc08020cSmatt 	return __SHIFTOUT(armreg_fpscr_read(), VFP_FPSCR_RMODE);
184bc08020cSmatt }
185bc08020cSmatt 
186bc08020cSmatt /*
187bc08020cSmatt  * The fesetround() function shall establish the rounding direction represented
188bc08020cSmatt  * by its argument round. If the argument is not equal to the value of a
189bc08020cSmatt  * rounding direction macro, the rounding direction is not changed.
190bc08020cSmatt  */
191bc08020cSmatt int
fesetround(int round)192bc08020cSmatt fesetround(int round)
193bc08020cSmatt {
194194fd467Smatt #ifndef lint
195bc08020cSmatt 	_DIAGASSERT(!(round & ~__SHIFTOUT(VFP_FPSCR_RMODE, VFP_FPSCR_RMODE)));
196194fd467Smatt #endif
197bc08020cSmatt 	int fpscr = armreg_fpscr_read() & ~VFP_FPSCR_RMODE;
198bc08020cSmatt 	fpscr |= __SHIFTIN(round, VFP_FPSCR_RMODE);
199bc08020cSmatt 	armreg_fpscr_write(fpscr);
200bc08020cSmatt 	return 0;
201bc08020cSmatt }
202bc08020cSmatt 
203bc08020cSmatt /*
204bc08020cSmatt  * The fegetenv() function shall attempt to store the current floating-point
205bc08020cSmatt  * environment in the object pointed to by envp.
206bc08020cSmatt  */
207bc08020cSmatt int
fegetenv(fenv_t * envp)208bc08020cSmatt fegetenv(fenv_t *envp)
209bc08020cSmatt {
2107e30e943Schs 
211bc08020cSmatt 	*envp = armreg_fpscr_read();
212bc08020cSmatt 	return 0;
213bc08020cSmatt }
214bc08020cSmatt 
215bc08020cSmatt /*
216bc08020cSmatt  * The feholdexcept() function shall save the current floating-point
217bc08020cSmatt  * environment in the object pointed to by envp, clear the floating-point
218bc08020cSmatt  * status flags, and then install a non-stop (continue on floating-point
219bc08020cSmatt  * exceptions) mode, if available, for all floating-point exceptions.
220bc08020cSmatt  */
221bc08020cSmatt int
feholdexcept(fenv_t * envp)222bc08020cSmatt feholdexcept(fenv_t *envp)
223bc08020cSmatt {
2247e30e943Schs 
225bc08020cSmatt 	*envp = armreg_fpscr_read();
226bc08020cSmatt 	armreg_fpscr_write((*envp) & ~(VFP_FPSCR_ESUM|VFP_FPSCR_CSUM));
227bc08020cSmatt 	return 0;
228bc08020cSmatt }
229bc08020cSmatt 
230bc08020cSmatt /*
231bc08020cSmatt  * The fesetenv() function shall attempt to establish the floating-point
232bc08020cSmatt  * environment represented by the object pointed to by envp. The fesetenv()
233bc08020cSmatt  * function does not raise floating-point exceptions, but only installs the
234bc08020cSmatt  * state of the floating-point status flags represented through its argument.
235bc08020cSmatt  */
236bc08020cSmatt int
fesetenv(const fenv_t * envp)237bc08020cSmatt fesetenv(const fenv_t *envp)
238bc08020cSmatt {
2397e30e943Schs 
240bc08020cSmatt 	armreg_fpscr_write(*envp);
241bc08020cSmatt 	return 0;
242bc08020cSmatt }
243bc08020cSmatt 
244bc08020cSmatt /*
245bc08020cSmatt  * The feupdateenv() function shall attempt to save the currently raised
246bc08020cSmatt  * floating-point exceptions in its automatic storage, attempt to install the
247bc08020cSmatt  * floating-point environment represented by the object pointed to by envp,
248bc08020cSmatt  * and then attempt to raise the saved floating-point exceptions.
249bc08020cSmatt  */
250bc08020cSmatt int
feupdateenv(const fenv_t * envp)251bc08020cSmatt feupdateenv(const fenv_t *envp)
252bc08020cSmatt {
253194fd467Smatt #ifndef lint
254bc08020cSmatt 	_DIAGASSERT(envp != NULL);
255194fd467Smatt #endif
2567e30e943Schs 	int fpscr = armreg_fpscr_read();
2577e30e943Schs 	fpscr &= ~(VFP_FPSCR_ESUM|VFP_FPSCR_RMODE);
258bc08020cSmatt 	fpscr |= *envp;
259bc08020cSmatt 	armreg_fpscr_write(fpscr);
260bc08020cSmatt 
261bc08020cSmatt 	/* Success */
262bc08020cSmatt 	return 0;
263bc08020cSmatt }
264