1 /*
2 (c) Copyright 2017 Michael R. Neilly
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15
16 * Neither the names of the copyright holders nor the names of their
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /* This implementation is intended to comply with the following
35 * specification:
36 *
37 * http://pubs.opengroup.org/onlinepubs/009695399/functions/feclearexcept.html
38 * Referred to as 'feclearexcept.html below.
39 *
40 * "The feclearexcept() function shall attempt to clear the supported
41 * floating-point exceptions represented by excepts."
42 */
43
feclearexcept(int excepts)44 __declare_fenv_inline(int) feclearexcept(int excepts)
45 {
46
47 /* Mask excepts to be sure only supported flag bits are set */
48
49 excepts &= FE_ALL_EXCEPT;
50
51 /* Per "The RISC-V Instruction Set Manual: Volume I: User-Level ISA:
52 * Version 2.1":
53 *
54 * "The CSRRC (Atomic Read and Clear Bits in CSR) instruction reads
55 * the value of the CSR, zeroextends the value to XLEN bits, and
56 * writes it to integer register rd. The initial value in integer
57 * register rs1 is treated as a bit mask that specifies bit
58 * positions to be cleared in the CSR. Any bit that is high in rs1
59 * will cause the corresponding bit to be cleared in the CSR, if
60 * that CSR bit is writable. Other bits in the CSR are unaffected."
61 */
62
63 /* Clear the requested flags */
64
65 __asm__ volatile("csrrc zero, fflags, %0" : : "r"(excepts));
66
67 /* Per 'feclearexcept.html
68 * "If the argument is zero or if all the specified exceptions were
69 * successfully cleared, feclearexcept() shall return zero. Otherwise,
70 * it shall return a non-zero value."
71 */
72
73 return 0;
74 }
75
76 /* This implementation is intended to comply with the following
77 * specification:
78 *
79 * http://pubs.opengroup.org/onlinepubs/009695399/functions/fegetenv.html
80 * Referred to as 'fegetenv.html below.
81 *
82 * "The fegetenv() function shall attempt to store the current
83 * floating-point environment in the object pointed to by envp."
84 *
85 */
86
fegetenv(fenv_t * envp)87 __declare_fenv_inline(int) fegetenv(fenv_t *envp)
88 {
89
90 /* Get the current environment (FCSR) */
91
92 fenv_t fcsr;
93 __asm__ volatile("frcsr %0" : "=r"(fcsr));
94
95 /* Store FCSR in envp */
96
97 *envp = fcsr;
98
99 /* Per 'fegetenv.html:
100 *
101 * "If the representation was successfully stored, fegetenv() shall
102 * return zero. Otherwise, it shall return a non-zero value.
103 */
104
105 return 0;
106 }
107
108 /* This implementation is intended to comply with the following
109 * specification:
110 *
111 * http://pubs.opengroup.org/onlinepubs/009695399/functions/fegetexceptflag.html
112 * Referred to as 'fegetexceptflag.html below.
113 *
114 * "The fegetexceptflag() function shall attempt to store an
115 * implementation-defined representation of the states of the
116 * floating-point status flags indicated by the argument excepts in
117 * the object pointed to by the argument flagp."
118 */
119
fegetexceptflag(fexcept_t * flagp,int excepts)120 __declare_fenv_inline(int) fegetexceptflag(fexcept_t *flagp, int excepts)
121 {
122
123 /* Mask excepts to be sure only supported flag bits are set */
124
125 excepts &= FE_ALL_EXCEPT;
126
127 /* Get current exception flags */
128
129 fexcept_t flags;
130 __asm__ volatile("frflags %0" : "=r"(flags));
131
132 /* Return the requested flags in flagp */
133
134 *flagp = flags & excepts;
135
136 /* Per 'fegetexceptflag.html:
137 *
138 * "If the representation was successfully stored, fegetexceptflag()
139 * shall return zero. Otherwise, it shall return a non-zero
140 * value."
141 */
142
143 return 0;
144 }
145
146 /* This implementation is intended to comply with the following
147 * specification:
148 *
149 * http://pubs.opengroup.org/onlinepubs/009695399/functions/fegetround.html
150 * Referred to as 'fegetround.html below.
151 *
152 * "The fegetround() function shall get the current rounding direction."
153 */
154
fegetround(void)155 __declare_fenv_inline(int) fegetround(void)
156 {
157
158 /* Get current rounding mode */
159
160 fenv_t frm;
161 __asm__ volatile("frrm %0" : "=r"(frm));
162
163 /* Per 'fegetround.html:
164 *
165 * "The fegetround() function shall return the value of the rounding
166 * direction macro representing the current rounding direction or a
167 * negative value if there is no such rounding direction macro or
168 * the current rounding direction is not determinable."
169 */
170
171 /* Return the rounding mode */
172
173 return frm;
174
175 }
176
177 /* This implementation is intended to comply with the following
178 * specification:
179 *
180 * http://pubs.opengroup.org/onlinepubs/009695399/functions/feholdexcept.html
181 * Referred to as 'feholdexcept.html below.
182 *
183 * "The feholdexcept() function shall save the current floating-point
184 * environment in the object pointed to by envp, clear the
185 * floating-point status flags, and then install a non-stop (continue
186 * on floating-point exceptions) mode, if available, for all
187 * floating-point exceptions."
188 */
189
feholdexcept(fenv_t * envp)190 __declare_fenv_inline(int) feholdexcept(fenv_t *envp)
191 {
192
193 /* Store the current FP environment in envp*/
194
195 fenv_t fcsr;
196 __asm__ volatile("frcsr %0" : "=r"(fcsr));
197 *envp = fcsr;
198
199 /* Clear all flags */
200
201 __asm__ volatile("csrrc zero, fflags, %0" : : "r"(FE_ALL_EXCEPT));
202
203 /* RISC-V does not raise FP traps so it is always in a "non-stop" mode */
204
205 /* Per 'feholdexcept.html:
206 *
207 * "The feholdexcept() function shall return zero if and only if
208 * non-stop floating-point exception handling was successfully
209 * installed."
210 */
211
212 return 0;
213 }
214
215 /* This implementation is intended to comply with the following
216 * specification:
217 *
218 * http://pubs.opengroup.org/onlinepubs/009695399/functions/feraiseexcept.html
219 * Referred to as 'feraiseexcept.html below.
220 *
221 * "The feraiseexcept() function shall attempt to raise the supported
222 * floating-point exceptions represented by the excepts argument. The
223 * order in which these floating-point exceptions are raised is
224 * unspecified, except that if the excepts argument represents IEC
225 * 60559 valid coincident floating-point exceptions for atomic
226 * operations (namely overflow and inexact, or underflow and inexact),
227 * then overflow or underflow shall be raised before inexact. Whether
228 * the feraiseexcept() function additionally raises the inexact
229 * floating-point exception whenever it raises the overflow or
230 * underflow floating-point exception is implementation-defined."
231 */
232
feraiseexcept(int excepts)233 __declare_fenv_inline(int) feraiseexcept(int excepts)
234 {
235
236 /* Mask excepts to be sure only supported flag bits are set */
237
238 excepts &= FE_ALL_EXCEPT;
239
240 /* Set the requested exception flags */
241
242 __asm__ volatile("csrs fflags, %0" : : "r"(excepts));
243
244 /* Per 'feraiseexcept.html:
245 * "If the argument is zero or if all the specified exceptions were
246 * successfully raised, feraiseexcept() shall return
247 * zero. Otherwise, it shall return a non-zero value."
248 */
249
250 /* Per "The RISC-V Instruction Set Manual: Volume I: User-Level ISA:
251 * Version 2.1":
252 *
253 * "As allowed by the standard, we do not support traps on
254 * floating-point exceptions in the base ISA, but instead require
255 * explicit checks of the flags in software."
256 *
257 */
258
259 return 0;
260 }
261
fesetexcept(int excepts)262 __declare_fenv_inline(int) fesetexcept(int excepts)
263 {
264 return feraiseexcept(excepts);
265 }
266
267 /* This implementation is intended to comply with the following
268 * specification:
269 *
270 * http://pubs.opengroup.org/onlinepubs/009695399/functions/fegetenv.html
271 * Referred to as 'fegetenv.html below.
272 *
273 * "The fegetenv() function shall attempt to store the current
274 * floating-point environment in the object pointed to by envp.
275 *
276 * The fesetenv() function shall attempt to establish the
277 * floating-point environment represented by the object pointed to by
278 * envp. The argument envp shall point to an object set by a call to
279 * fegetenv() or feholdexcept(), or equal a floating-point environment
280 * macro. The fesetenv() function does not raise floating-point
281 * exceptions, but only installs the state of the floating-point
282 * status flags represented through its argument."
283 */
284
fesetenv(const fenv_t * envp)285 __declare_fenv_inline(int) fesetenv(const fenv_t *envp)
286 {
287
288 /* Set environment (FCSR) */
289
290 fenv_t fcsr = *envp;
291 __asm__ volatile("fscsr %0" : : "r"(fcsr));
292
293 /* Per 'fegetenv.html:
294 *
295 * "If the environment was successfully established, fesetenv()
296 * shall return zero. Otherwise, it shall return a non-zero value.
297 */
298
299 return 0;
300 }
301
302 /* This implementation is intended to comply with the following
303 * specification:
304 *
305 * http://pubs.opengroup.org/onlinepubs/009695399/functions/fesetexceptflag.html
306 * Referred to as 'fesetexceptflag.html below.
307 *
308 * "The fesetexceptflag() function shall attempt to set the
309 * floating-point status flags indicated by the argument excepts to
310 * the states stored in the object pointed to by flagp. The value
311 * pointed to by flagp shall have been set by a previous call to
312 * fegetexceptflag() whose second argument represented at least those
313 * floating-point exceptions represented by the argument excepts. This
314 * function does not raise floating-point exceptions, but only sets
315 * the state of the flags."
316 *
317 */
318
fesetexceptflag(const fexcept_t * flagp,int excepts)319 __declare_fenv_inline(int) fesetexceptflag(const fexcept_t *flagp, int excepts)
320 {
321
322 /* Mask excepts to be sure only supported flag bits are set */
323
324 excepts &= FE_ALL_EXCEPT;
325
326 /* Set the requested flags */
327
328 fexcept_t flags = *flagp & FE_ALL_EXCEPT;
329
330 /* Set new the flags */
331
332 __asm__ volatile("csrc fflags, %0" : : "r"(excepts));
333 __asm__ volatile("csrs fflags, %0" : : "r"(flags & excepts));
334
335 /* Per 'fesetexceptflag.html:
336 *
337 * "If the excepts argument is zero or if all the specified
338 * exceptions were successfully set, fesetexceptflag() shall return
339 * zero. Otherwise, it shall return a non-zero value."
340 */
341
342 return 0;
343 }
344
345 /* This implementation is intended to comply with the following
346 * specification:
347 *
348 * http://pubs.opengroup.org/onlinepubs/009695399/functions/fesetround.html
349 * Referred to as 'fegetenv.html below.
350 *
351 * "The fesetround() function shall establish the rounding direction
352 * represented by its argument round. If the argument is not equal to
353 * the value of a rounding direction macro, the rounding direction is
354 * not changed."
355 */
356
fesetround(int round)357 __declare_fenv_inline(int) fesetround(int round)
358 {
359
360 /* Mask round to be sure only valid rounding bits are set */
361
362 round &= FE_RMODE_MASK;
363
364 /* Set the rounding mode */
365
366 __asm__ volatile("fsrm %0" : : "r"(round));
367
368 /* Per 'fesetround.html:
369 *
370 * "The fesetround() function shall return a zero value if and only
371 * if the requested rounding direction was established."
372 */
373
374 return 0;
375 }
376
377 /* This implementation is intended to comply with the following
378 * specification:
379 *
380 * http://pubs.opengroup.org/onlinepubs/9699919799/functions/fetestexcept.html
381 *
382 * "The fetestexcept() function shall determine which of a specified
383 * subset of the floating-point exception flags are currently set. The
384 * excepts argument specifies the floating-point status flags to be
385 * queried."
386 */
387
fetestexcept(int excepts)388 __declare_fenv_inline(int) fetestexcept(int excepts)
389 {
390
391 /* Mask excepts to be sure only supported flag bits are set */
392
393 excepts &= FE_ALL_EXCEPT;
394
395 /* Read the current flags */
396
397 fexcept_t flags;
398 __asm__ volatile("frflags %0" : "=r"(flags));
399
400 /* "The fetestexcept() function shall return the value of the
401 * bitwise-inclusive OR of the floating-point exception macros
402 * corresponding to the currently set floating-point exceptions
403 * included in excepts."
404 */
405
406 return (flags & excepts);
407 }
408
409 /* This implementation is intended to comply with the following
410 * specification:
411 *
412 * http://pubs.opengroup.org/onlinepubs/9699919799/functions/feupdateenv.html
413 *
414 * "The feupdateenv() function shall attempt to save the currently
415 * raised floating-point exceptions in its automatic storage, attempt
416 * to install the floating-point environment represented by the object
417 * pointed to by envp, and then attempt to raise the saved
418 * floating-point exceptions. The argument envp shall point to an
419 * object set by a call to feholdexcept() or fegetenv(), or equal a
420 * floating-point environment macro."
421 */
422
feupdateenv(const fenv_t * envp)423 __declare_fenv_inline(int) feupdateenv(const fenv_t *envp)
424 {
425
426 /* Get current exception flags */
427
428 fexcept_t flags;
429 __asm__ volatile("frflags %0" : "=r"(flags));
430
431 /* Set the environment as requested */
432
433 fenv_t fcsr = *envp; /* Environment to install */
434 __asm__ volatile("fscsr %0" : : "r"(fcsr)); /* Install environment */
435
436 /* OR in the saved exception flags */
437
438 __asm__ volatile("csrs fflags, %0" : : "r"(flags));
439
440 /* "The feupdateenv() function shall return a zero value if and only
441 * if all the required actions were successfully carried out."
442 */
443
444 return 0;
445
446 }
447
feenableexcept(int excepts)448 __declare_fenv_inline(int) feenableexcept(int excepts)
449 {
450 return excepts == 0 ? 0 : -1;
451 }
452
fedisableexcept(int excepts)453 __declare_fenv_inline(int) fedisableexcept(int excepts)
454 {
455 (void) excepts;
456 return excepts == 0 ? 0 : -1;
457 }
458
fegetexcept(void)459 __declare_fenv_inline(int) fegetexcept(void)
460 {
461 return 0;
462 }
463