xref: /minix3/lib/libm/arch/riscv/fenv.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /* $NetBSD: fenv.c,v 1.1 2014/09/19 17:36:25 matt Exp $ */
2*0a6a1f1dSLionel Sambuc 
3*0a6a1f1dSLionel Sambuc /*-
4*0a6a1f1dSLionel Sambuc  * Copyright (c) 2014 The NetBSD Foundation, Inc.
5*0a6a1f1dSLionel Sambuc  * All rights reserved.
6*0a6a1f1dSLionel Sambuc  *
7*0a6a1f1dSLionel Sambuc  * This code is derived from software contributed to The NetBSD Foundation
8*0a6a1f1dSLionel Sambuc  * by Matt Thomas of 3am Software Foundry.
9*0a6a1f1dSLionel Sambuc  *
10*0a6a1f1dSLionel Sambuc  * Redistribution and use in source and binary forms, with or without
11*0a6a1f1dSLionel Sambuc  * modification, are permitted provided that the following conditions
12*0a6a1f1dSLionel Sambuc  * are met:
13*0a6a1f1dSLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
14*0a6a1f1dSLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
15*0a6a1f1dSLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
16*0a6a1f1dSLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
17*0a6a1f1dSLionel Sambuc  *    documentation and/or other materials provided with the distribution.
18*0a6a1f1dSLionel Sambuc  *
19*0a6a1f1dSLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*0a6a1f1dSLionel Sambuc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*0a6a1f1dSLionel Sambuc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*0a6a1f1dSLionel Sambuc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*0a6a1f1dSLionel Sambuc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*0a6a1f1dSLionel Sambuc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*0a6a1f1dSLionel Sambuc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*0a6a1f1dSLionel Sambuc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*0a6a1f1dSLionel Sambuc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*0a6a1f1dSLionel Sambuc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*0a6a1f1dSLionel Sambuc  * POSSIBILITY OF SUCH DAMAGE.
30*0a6a1f1dSLionel Sambuc  */
31*0a6a1f1dSLionel Sambuc 
32*0a6a1f1dSLionel Sambuc #include <sys/cdefs.h>
33*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: fenv.c,v 1.1 2014/09/19 17:36:25 matt Exp $");
34*0a6a1f1dSLionel Sambuc 
35*0a6a1f1dSLionel Sambuc #include <sys/param.h>
36*0a6a1f1dSLionel Sambuc #include <sys/sysctl.h>
37*0a6a1f1dSLionel Sambuc #include <assert.h>
38*0a6a1f1dSLionel Sambuc #include <fenv.h>
39*0a6a1f1dSLionel Sambuc #include <stddef.h>
40*0a6a1f1dSLionel Sambuc #include <string.h>
41*0a6a1f1dSLionel Sambuc 
42*0a6a1f1dSLionel Sambuc #include <riscv/sysreg.h>
43*0a6a1f1dSLionel Sambuc 
44*0a6a1f1dSLionel Sambuc /*
45*0a6a1f1dSLionel Sambuc  * The following constant represents the default floating-point environment
46*0a6a1f1dSLionel Sambuc  * (that is, the one installed at program startup) and has type pointer to
47*0a6a1f1dSLionel Sambuc  * const-qualified fenv_t.
48*0a6a1f1dSLionel Sambuc  *
49*0a6a1f1dSLionel Sambuc  * It can be used as an argument to the functions within the <fenv.h> header
50*0a6a1f1dSLionel Sambuc  * that manage the floating-point environment, namely fesetenv() and
51*0a6a1f1dSLionel Sambuc  * feupdateenv().
52*0a6a1f1dSLionel Sambuc  */
53*0a6a1f1dSLionel Sambuc fenv_t __fe_dfl_env = __SHIFTIN(FCSR_FRM_RNE, FCSR_FRM);
54*0a6a1f1dSLionel Sambuc 
55*0a6a1f1dSLionel Sambuc /*
56*0a6a1f1dSLionel Sambuc  * The feclearexcept() function clears the supported floating-point exceptions
57*0a6a1f1dSLionel Sambuc  * represented by `excepts'.
58*0a6a1f1dSLionel Sambuc  */
59*0a6a1f1dSLionel Sambuc int
feclearexcept(int excepts)60*0a6a1f1dSLionel Sambuc feclearexcept(int excepts)
61*0a6a1f1dSLionel Sambuc {
62*0a6a1f1dSLionel Sambuc 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
63*0a6a1f1dSLionel Sambuc 
64*0a6a1f1dSLionel Sambuc 	int fflags = riscvreg_fcsr_read_fflags();
65*0a6a1f1dSLionel Sambuc 
66*0a6a1f1dSLionel Sambuc 	fflags &= ~(excepts & FE_ALL_EXCEPT);
67*0a6a1f1dSLionel Sambuc 
68*0a6a1f1dSLionel Sambuc 	riscvreg_fcsr_write_fflags(fflags);
69*0a6a1f1dSLionel Sambuc 
70*0a6a1f1dSLionel Sambuc 	/* Success */
71*0a6a1f1dSLionel Sambuc 	return (0);
72*0a6a1f1dSLionel Sambuc }
73*0a6a1f1dSLionel Sambuc 
74*0a6a1f1dSLionel Sambuc /*
75*0a6a1f1dSLionel Sambuc  * The fegetexceptflag() function stores an implementation-defined
76*0a6a1f1dSLionel Sambuc  * representation of the states of the floating-point status flags indicated by
77*0a6a1f1dSLionel Sambuc  * the argument excepts in the object pointed to by the argument flagp.
78*0a6a1f1dSLionel Sambuc  */
79*0a6a1f1dSLionel Sambuc int
fegetexceptflag(fexcept_t * flagp,int excepts)80*0a6a1f1dSLionel Sambuc fegetexceptflag(fexcept_t *flagp, int excepts)
81*0a6a1f1dSLionel Sambuc {
82*0a6a1f1dSLionel Sambuc 	_DIAGASSERT(flagp != NULL);
83*0a6a1f1dSLionel Sambuc 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
84*0a6a1f1dSLionel Sambuc 
85*0a6a1f1dSLionel Sambuc 	*flagp = riscvreg_fcsr_read_fflags() & excepts;
86*0a6a1f1dSLionel Sambuc 
87*0a6a1f1dSLionel Sambuc 	/* Success */
88*0a6a1f1dSLionel Sambuc 	return (0);
89*0a6a1f1dSLionel Sambuc }
90*0a6a1f1dSLionel Sambuc 
91*0a6a1f1dSLionel Sambuc /*
92*0a6a1f1dSLionel Sambuc  * The feraiseexcept() function raises the supported floating-point exceptions
93*0a6a1f1dSLionel Sambuc  * represented by the argument `excepts'.
94*0a6a1f1dSLionel Sambuc  *
95*0a6a1f1dSLionel Sambuc  * The standard explicitly allows us to execute an instruction that has the
96*0a6a1f1dSLionel Sambuc  * exception as a side effect, but we choose to manipulate the status register
97*0a6a1f1dSLionel Sambuc  * directly.
98*0a6a1f1dSLionel Sambuc  *
99*0a6a1f1dSLionel Sambuc  * The validation of input is being deferred to fesetexceptflag().
100*0a6a1f1dSLionel Sambuc  */
101*0a6a1f1dSLionel Sambuc int
feraiseexcept(int excepts)102*0a6a1f1dSLionel Sambuc feraiseexcept(int excepts)
103*0a6a1f1dSLionel Sambuc {
104*0a6a1f1dSLionel Sambuc 	fexcept_t ex = 0;
105*0a6a1f1dSLionel Sambuc 
106*0a6a1f1dSLionel Sambuc 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
107*0a6a1f1dSLionel Sambuc 
108*0a6a1f1dSLionel Sambuc 	excepts &= FE_ALL_EXCEPT;
109*0a6a1f1dSLionel Sambuc 	fesetexceptflag(&ex, excepts);
110*0a6a1f1dSLionel Sambuc 	/* XXX exception magic XXX */
111*0a6a1f1dSLionel Sambuc 
112*0a6a1f1dSLionel Sambuc 	/* Success */
113*0a6a1f1dSLionel Sambuc 	return (0);
114*0a6a1f1dSLionel Sambuc }
115*0a6a1f1dSLionel Sambuc 
116*0a6a1f1dSLionel Sambuc /*
117*0a6a1f1dSLionel Sambuc  * This function sets the floating-point status flags indicated by the argument
118*0a6a1f1dSLionel Sambuc  * `excepts' to the states stored in the object pointed to by `flagp'. It does
119*0a6a1f1dSLionel Sambuc  * NOT raise any floating-point exceptions, but only sets the state of the flags.
120*0a6a1f1dSLionel Sambuc  */
121*0a6a1f1dSLionel Sambuc int
fesetexceptflag(const fexcept_t * flagp,int excepts)122*0a6a1f1dSLionel Sambuc fesetexceptflag(const fexcept_t *flagp, int excepts)
123*0a6a1f1dSLionel Sambuc {
124*0a6a1f1dSLionel Sambuc 	_DIAGASSERT(flagp != NULL);
125*0a6a1f1dSLionel Sambuc 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
126*0a6a1f1dSLionel Sambuc 
127*0a6a1f1dSLionel Sambuc 	excepts &= FE_ALL_EXCEPT;
128*0a6a1f1dSLionel Sambuc 
129*0a6a1f1dSLionel Sambuc 	int fflags = riscvreg_fcsr_read_fflags();
130*0a6a1f1dSLionel Sambuc 
131*0a6a1f1dSLionel Sambuc 	fflags = (fflags & ~excepts) | (*flagp & excepts);
132*0a6a1f1dSLionel Sambuc 
133*0a6a1f1dSLionel Sambuc 	riscvreg_fcsr_write_fflags(fflags);
134*0a6a1f1dSLionel Sambuc 
135*0a6a1f1dSLionel Sambuc 	/* Success */
136*0a6a1f1dSLionel Sambuc 	return (0);
137*0a6a1f1dSLionel Sambuc }
138*0a6a1f1dSLionel Sambuc 
139*0a6a1f1dSLionel Sambuc /*
140*0a6a1f1dSLionel Sambuc  * The fetestexcept() function determines which of a specified subset of the
141*0a6a1f1dSLionel Sambuc  * floating-point exception flags are currently set. The `excepts' argument
142*0a6a1f1dSLionel Sambuc  * specifies the floating-point status flags to be queried.
143*0a6a1f1dSLionel Sambuc  */
144*0a6a1f1dSLionel Sambuc int
fetestexcept(int excepts)145*0a6a1f1dSLionel Sambuc fetestexcept(int excepts)
146*0a6a1f1dSLionel Sambuc {
147*0a6a1f1dSLionel Sambuc 	_DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
148*0a6a1f1dSLionel Sambuc 
149*0a6a1f1dSLionel Sambuc 	return riscvreg_fcsr_read_fflags() & excepts & FE_ALL_EXCEPT;
150*0a6a1f1dSLionel Sambuc }
151*0a6a1f1dSLionel Sambuc 
152*0a6a1f1dSLionel Sambuc int
fegetround(void)153*0a6a1f1dSLionel Sambuc fegetround(void)
154*0a6a1f1dSLionel Sambuc {
155*0a6a1f1dSLionel Sambuc 	return riscvreg_fcsr_read_frm();
156*0a6a1f1dSLionel Sambuc }
157*0a6a1f1dSLionel Sambuc 
158*0a6a1f1dSLionel Sambuc /*
159*0a6a1f1dSLionel Sambuc  * The fesetround() function shall establish the rounding direction represented
160*0a6a1f1dSLionel Sambuc  * by its argument round. If the argument is not equal to the value of a
161*0a6a1f1dSLionel Sambuc  * rounding direction macro, the rounding direction is not changed.
162*0a6a1f1dSLionel Sambuc  */
163*0a6a1f1dSLionel Sambuc int
fesetround(int round)164*0a6a1f1dSLionel Sambuc fesetround(int round)
165*0a6a1f1dSLionel Sambuc {
166*0a6a1f1dSLionel Sambuc 	if ((unsigned int)round > FCSR_FRM_RMM) {
167*0a6a1f1dSLionel Sambuc 		/* Failure */
168*0a6a1f1dSLionel Sambuc 		return (-1);
169*0a6a1f1dSLionel Sambuc 	}
170*0a6a1f1dSLionel Sambuc 
171*0a6a1f1dSLionel Sambuc 	riscvreg_fcsr_write_frm(round);
172*0a6a1f1dSLionel Sambuc 
173*0a6a1f1dSLionel Sambuc 	/* Success */
174*0a6a1f1dSLionel Sambuc 	return (0);
175*0a6a1f1dSLionel Sambuc }
176*0a6a1f1dSLionel Sambuc 
177*0a6a1f1dSLionel Sambuc /*
178*0a6a1f1dSLionel Sambuc  * The fegetenv() function attempts to store the current floating-point
179*0a6a1f1dSLionel Sambuc  * environment in the object pointed to by envp.
180*0a6a1f1dSLionel Sambuc  */
181*0a6a1f1dSLionel Sambuc int
fegetenv(fenv_t * envp)182*0a6a1f1dSLionel Sambuc fegetenv(fenv_t *envp)
183*0a6a1f1dSLionel Sambuc {
184*0a6a1f1dSLionel Sambuc 	_DIAGASSERT(envp != NULL);
185*0a6a1f1dSLionel Sambuc 
186*0a6a1f1dSLionel Sambuc 	*envp = riscvreg_fcsr_read();
187*0a6a1f1dSLionel Sambuc 
188*0a6a1f1dSLionel Sambuc 	/* Success */
189*0a6a1f1dSLionel Sambuc 	return (0);
190*0a6a1f1dSLionel Sambuc }
191*0a6a1f1dSLionel Sambuc 
192*0a6a1f1dSLionel Sambuc /*
193*0a6a1f1dSLionel Sambuc  * The feholdexcept() function saves the current floating-point environment in
194*0a6a1f1dSLionel Sambuc  * the object pointed to by envp, clears the floating-point status flags, and
195*0a6a1f1dSLionel Sambuc  * then installs a non-stop (continue on floating-point exceptions) mode, if
196*0a6a1f1dSLionel Sambuc  * available, for all floating-point exceptions.
197*0a6a1f1dSLionel Sambuc  */
198*0a6a1f1dSLionel Sambuc int
feholdexcept(fenv_t * envp)199*0a6a1f1dSLionel Sambuc feholdexcept(fenv_t *envp)
200*0a6a1f1dSLionel Sambuc {
201*0a6a1f1dSLionel Sambuc 	_DIAGASSERT(envp != NULL);
202*0a6a1f1dSLionel Sambuc 
203*0a6a1f1dSLionel Sambuc 	*envp = riscvreg_fcsr_read();
204*0a6a1f1dSLionel Sambuc 
205*0a6a1f1dSLionel Sambuc 	riscvreg_fcsr_write_fflags(0);
206*0a6a1f1dSLionel Sambuc 
207*0a6a1f1dSLionel Sambuc 	/* Success */
208*0a6a1f1dSLionel Sambuc 	return (0);
209*0a6a1f1dSLionel Sambuc }
210*0a6a1f1dSLionel Sambuc 
211*0a6a1f1dSLionel Sambuc /*
212*0a6a1f1dSLionel Sambuc  * The fesetenv() function attempts to establish the floating-point environment
213*0a6a1f1dSLionel Sambuc  * represented by the object pointed to by envp. The argument `envp' points
214*0a6a1f1dSLionel Sambuc  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
215*0a6a1f1dSLionel Sambuc  * floating-point environment macro. The fesetenv() function does not raise
216*0a6a1f1dSLionel Sambuc  * floating-point exceptions, but only installs the state of the floating-point
217*0a6a1f1dSLionel Sambuc  * status flags represented through its argument.
218*0a6a1f1dSLionel Sambuc  */
219*0a6a1f1dSLionel Sambuc int
fesetenv(const fenv_t * envp)220*0a6a1f1dSLionel Sambuc fesetenv(const fenv_t *envp)
221*0a6a1f1dSLionel Sambuc {
222*0a6a1f1dSLionel Sambuc 
223*0a6a1f1dSLionel Sambuc 	_DIAGASSERT(envp != NULL);
224*0a6a1f1dSLionel Sambuc 
225*0a6a1f1dSLionel Sambuc 	fenv_t env = *envp;
226*0a6a1f1dSLionel Sambuc 
227*0a6a1f1dSLionel Sambuc 	if ((env & ~(FCSR_FRM|FCSR_FFLAGS)
228*0a6a1f1dSLionel Sambuc 	    || __SHIFTOUT(env, FCSR_FRM) > FCSR_FRM_RMM)) {
229*0a6a1f1dSLionel Sambuc 		return -1;
230*0a6a1f1dSLionel Sambuc 	}
231*0a6a1f1dSLionel Sambuc 
232*0a6a1f1dSLionel Sambuc 	riscvreg_fcsr_write(env);
233*0a6a1f1dSLionel Sambuc 
234*0a6a1f1dSLionel Sambuc 	/* Success */
235*0a6a1f1dSLionel Sambuc 	return (0);
236*0a6a1f1dSLionel Sambuc }
237*0a6a1f1dSLionel Sambuc 
238*0a6a1f1dSLionel Sambuc /*
239*0a6a1f1dSLionel Sambuc  * The feupdateenv() function saves the currently raised floating-point
240*0a6a1f1dSLionel Sambuc  * exceptions in its automatic storage, installs the floating-point environment
241*0a6a1f1dSLionel Sambuc  * represented by the object pointed to by `envp', and then raises the saved
242*0a6a1f1dSLionel Sambuc  * floating-point exceptions. The argument `envp' shall point to an object set
243*0a6a1f1dSLionel Sambuc  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
244*0a6a1f1dSLionel Sambuc  * environment macro.
245*0a6a1f1dSLionel Sambuc  */
246*0a6a1f1dSLionel Sambuc int
feupdateenv(const fenv_t * envp)247*0a6a1f1dSLionel Sambuc feupdateenv(const fenv_t *envp)
248*0a6a1f1dSLionel Sambuc {
249*0a6a1f1dSLionel Sambuc 	_DIAGASSERT(envp != NULL);
250*0a6a1f1dSLionel Sambuc 
251*0a6a1f1dSLionel Sambuc 	int fflags = riscvreg_fcsr_read_fflags();
252*0a6a1f1dSLionel Sambuc 
253*0a6a1f1dSLionel Sambuc 	fesetenv(envp);
254*0a6a1f1dSLionel Sambuc 	feraiseexcept(fflags);
255*0a6a1f1dSLionel Sambuc 
256*0a6a1f1dSLionel Sambuc 	/* Success */
257*0a6a1f1dSLionel Sambuc 	return (0);
258*0a6a1f1dSLionel Sambuc }
259*0a6a1f1dSLionel Sambuc 
260*0a6a1f1dSLionel Sambuc /*
261*0a6a1f1dSLionel Sambuc  * The following functions are extentions to the standard
262*0a6a1f1dSLionel Sambuc  */
263*0a6a1f1dSLionel Sambuc int
feenableexcept(int nmask)264*0a6a1f1dSLionel Sambuc feenableexcept(int nmask)
265*0a6a1f1dSLionel Sambuc {
266*0a6a1f1dSLionel Sambuc 	return 0;
267*0a6a1f1dSLionel Sambuc }
268*0a6a1f1dSLionel Sambuc 
269*0a6a1f1dSLionel Sambuc int
fedisableexcept(int nmask)270*0a6a1f1dSLionel Sambuc fedisableexcept(int nmask)
271*0a6a1f1dSLionel Sambuc {
272*0a6a1f1dSLionel Sambuc 	return 0;
273*0a6a1f1dSLionel Sambuc }
274*0a6a1f1dSLionel Sambuc 
275*0a6a1f1dSLionel Sambuc int
fegetexcept(void)276*0a6a1f1dSLionel Sambuc fegetexcept(void)
277*0a6a1f1dSLionel Sambuc {
278*0a6a1f1dSLionel Sambuc 	return 0;
279*0a6a1f1dSLionel Sambuc }
280