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 int status = 1;
360
361 switch (round)
362 {
363 case FE_TONEAREST_MM:
364 /* Intentional fall-through */
365
366 case FE_UPWARD:
367 /* Intentional fall-through */
368
369 case FE_DOWNWARD:
370 /* Intentional fall-through */
371
372 case FE_TOWARDZERO:
373 /* Intentional fall-through */
374
375 case FE_TONEAREST:
376 /* Set the rounding mode */
377 __asm__ volatile("fsrm %0" : : "r"(round));
378
379 /* status 0 to indicate successful processing of rounding mode */
380 status = 0;
381 break;
382
383 default:
384 break;
385 }
386
387 /* Per 'fesetround.html:
388 *
389 * "The fesetround() function shall return a zero value if and only
390 * if the requested rounding direction was established."
391 */
392
393 return status;
394 }
395
396 /* This implementation is intended to comply with the following
397 * specification:
398 *
399 * http://pubs.opengroup.org/onlinepubs/9699919799/functions/fetestexcept.html
400 *
401 * "The fetestexcept() function shall determine which of a specified
402 * subset of the floating-point exception flags are currently set. The
403 * excepts argument specifies the floating-point status flags to be
404 * queried."
405 */
406
fetestexcept(int excepts)407 __declare_fenv_inline(int) fetestexcept(int excepts)
408 {
409
410 /* Mask excepts to be sure only supported flag bits are set */
411
412 excepts &= FE_ALL_EXCEPT;
413
414 /* Read the current flags */
415
416 fexcept_t flags;
417 __asm__ volatile("frflags %0" : "=r"(flags));
418
419 /* "The fetestexcept() function shall return the value of the
420 * bitwise-inclusive OR of the floating-point exception macros
421 * corresponding to the currently set floating-point exceptions
422 * included in excepts."
423 */
424
425 return (flags & excepts);
426 }
427
428 /* This implementation is intended to comply with the following
429 * specification:
430 *
431 * http://pubs.opengroup.org/onlinepubs/9699919799/functions/feupdateenv.html
432 *
433 * "The feupdateenv() function shall attempt to save the currently
434 * raised floating-point exceptions in its automatic storage, attempt
435 * to install the floating-point environment represented by the object
436 * pointed to by envp, and then attempt to raise the saved
437 * floating-point exceptions. The argument envp shall point to an
438 * object set by a call to feholdexcept() or fegetenv(), or equal a
439 * floating-point environment macro."
440 */
441
feupdateenv(const fenv_t * envp)442 __declare_fenv_inline(int) feupdateenv(const fenv_t *envp)
443 {
444
445 /* Get current exception flags */
446
447 fexcept_t flags;
448 __asm__ volatile("frflags %0" : "=r"(flags));
449
450 /* Set the environment as requested */
451
452 fenv_t fcsr = *envp; /* Environment to install */
453 __asm__ volatile("fscsr %0" : : "r"(fcsr)); /* Install environment */
454
455 /* OR in the saved exception flags */
456
457 __asm__ volatile("csrs fflags, %0" : : "r"(flags));
458
459 /* "The feupdateenv() function shall return a zero value if and only
460 * if all the required actions were successfully carried out."
461 */
462
463 return 0;
464
465 }
466
feenableexcept(int excepts)467 __declare_fenv_inline(int) feenableexcept(int excepts)
468 {
469 return excepts == 0 ? 0 : -1;
470 }
471
fedisableexcept(int excepts)472 __declare_fenv_inline(int) fedisableexcept(int excepts)
473 {
474 (void) excepts;
475 return excepts == 0 ? 0 : -1;
476 }
477
fegetexcept(void)478 __declare_fenv_inline(int) fegetexcept(void)
479 {
480 return 0;
481 }
482