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