NEORV32 - Software Framework Documentation
Loading...
Searching...
No Matches
neorv32_zfinx_extension_intrinsics.h
1// #################################################################################################
2// # << NEORV32 - Intrinsics + Emulation Functions for the RISC-V "Zfinx" CPU extension >> #
3// # ********************************************************************************************* #
4// # The intrinsics provided by this library allow to use the hardware floating-point unit of the #
5// # RISC-V Zfinx CPU extension without the need for Zfinx support by the compiler / toolchain. #
6// # ********************************************************************************************* #
7// # BSD 3-Clause License #
8// # #
9// # Copyright (c) 2022, Stephan Nolting. All rights reserved. #
10// # #
11// # Redistribution and use in source and binary forms, with or without modification, are #
12// # permitted provided that the following conditions are met: #
13// # #
14// # 1. Redistributions of source code must retain the above copyright notice, this list of #
15// # conditions and the following disclaimer. #
16// # #
17// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of #
18// # conditions and the following disclaimer in the documentation and/or other materials #
19// # provided with the distribution. #
20// # #
21// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to #
22// # endorse or promote products derived from this software without specific prior written #
23// # permission. #
24// # #
25// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS #
26// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF #
27// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE #
28// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #
29// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
30// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED #
31// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING #
32// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED #
33// # OF THE POSSIBILITY OF SUCH DAMAGE. #
34// # ********************************************************************************************* #
35// # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
36// #################################################################################################
37
38
39/**********************************************************************/
52#ifndef neorv32_zfinx_extension_intrinsics_h
53#define neorv32_zfinx_extension_intrinsics_h
54
55#define __USE_GNU
56
57#include <fenv.h>
58//#pragma STDC FENV_ACCESS ON
59
60#define _GNU_SOURCE
61
62#include <float.h>
63#include <math.h>
64
65
66/**********************************************************************/
69#if defined __riscv_f || (__riscv_flen == 32)
70 #error Application programs using the Zfinx intrinsic library have to be compiled WITHOUT the <F> MARCH ISA attribute!
71#endif
72
73
74/**********************************************************************/
77typedef union
78{
79 uint32_t binary_value;
82
83
84// ################################################################################################
85// Helper functions
86// ################################################################################################
87
88/**********************************************************************/
96float subnormal_flush(float tmp) {
97
98 float res = tmp;
99
100 // flush to zero if subnormal
101 if (fpclassify(tmp) == FP_SUBNORMAL) {
102 if (signbit(tmp) != 0) {
103 res = -0.0f;
104 }
105 else {
106 res = +0.0f;
107 }
108 }
109
110 return res;
111}
112
113
114// ################################################################################################
115// Exception access
116// ################################################################################################
117
118/**********************************************************************/
123uint32_t get_hw_exceptions(void) {
124
125 uint32_t res = neorv32_cpu_csr_read(CSR_FFLAGS);
126
127 neorv32_cpu_csr_write(CSR_FFLAGS, 0); // clear status word
128
129 return res;
130}
131
132
133/**********************************************************************/
140uint32_t get_sw_exceptions(void) {
141
142 const uint32_t FP_EXC_NV_C = 1 << 0; // invalid operation
143 const uint32_t FP_EXC_DZ_C = 1 << 1; // divide by zero
144 const uint32_t FP_EXC_OF_C = 1 << 2; // overflow
145 const uint32_t FP_EXC_UF_C = 1 << 3; // underflow
146 const uint32_t FP_EXC_NX_C = 1 << 4; // inexact
147
148 int fpeRaised = fetestexcept(FE_ALL_EXCEPT);
149
150 uint32_t res = 0;
151
152 if (fpeRaised & FE_INVALID) { res |= FP_EXC_NV_C; }
153 if (fpeRaised & FE_DIVBYZERO) { res |= FP_EXC_DZ_C; }
154 if (fpeRaised & FE_OVERFLOW) { res |= FP_EXC_OF_C; }
155 if (fpeRaised & FE_UNDERFLOW) { res |= FP_EXC_UF_C; }
156 if (fpeRaised & FE_INEXACT) { res |= FP_EXC_NX_C; }
157
158 feclearexcept(FE_ALL_EXCEPT);
159
160 return res;
161}
162
163
164// ################################################################################################
165// "Intrinsics"
166// ################################################################################################
167
168/**********************************************************************/
175inline float __attribute__ ((always_inline)) riscv_intrinsic_fadds(float rs1, float rs2) {
176
177 float_conv_t opa, opb, res;
178 opa.float_value = rs1;
179 opb.float_value = rs2;
180
181 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0000000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
182 return res.float_value;
183}
184
185
186/**********************************************************************/
193inline float __attribute__ ((always_inline)) riscv_intrinsic_fsubs(float rs1, float rs2) {
194
195 float_conv_t opa, opb, res;
196 opa.float_value = rs1;
197 opb.float_value = rs2;
198
199 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0000100, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
200 return res.float_value;
201}
202
203
204/**********************************************************************/
211inline float __attribute__ ((always_inline)) riscv_intrinsic_fmuls(float rs1, float rs2) {
212
213 float_conv_t opa, opb, res;
214 opa.float_value = rs1;
215 opb.float_value = rs2;
216
217 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0001000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
218 return res.float_value;
219}
220
221
222/**********************************************************************/
229inline float __attribute__ ((always_inline)) riscv_intrinsic_fmins(float rs1, float rs2) {
230
231 float_conv_t opa, opb, res;
232 opa.float_value = rs1;
233 opb.float_value = rs2;
234
235 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010100, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
236 return res.float_value;
237}
238
239
240/**********************************************************************/
247inline float __attribute__ ((always_inline)) riscv_intrinsic_fmaxs(float rs1, float rs2) {
248
249 float_conv_t opa, opb, res;
250 opa.float_value = rs1;
251 opb.float_value = rs2;
252
253 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010100, opb.binary_value, opa.binary_value, 0b001, 0b1010011);
254 return res.float_value;
255}
256
257
258/**********************************************************************/
264inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fcvt_wus(float rs1) {
265
266 float_conv_t opa;
267 opa.float_value = rs1;
268
269 return CUSTOM_INSTR_R2_TYPE(0b1100000, 0b00001, opa.binary_value, 0b000, 0b1010011);
270}
271
272
273/**********************************************************************/
279inline int32_t __attribute__ ((always_inline)) riscv_intrinsic_fcvt_ws(float rs1) {
280
281 float_conv_t opa;
282 opa.float_value = rs1;
283
284 return (int32_t)CUSTOM_INSTR_R2_TYPE(0b1100000, 0b00000, opa.binary_value, 0b000, 0b1010011);
285}
286
287
288/**********************************************************************/
294inline float __attribute__ ((always_inline)) riscv_intrinsic_fcvt_swu(uint32_t rs1) {
295
296 float_conv_t res;
297
298 res.binary_value = CUSTOM_INSTR_R2_TYPE(0b1101000, 0b00001, rs1, 0b000, 0b1010011);
299 return res.float_value;
300}
301
302
303/**********************************************************************/
309inline float __attribute__ ((always_inline)) riscv_intrinsic_fcvt_sw(int32_t rs1) {
310
311 float_conv_t res;
312
313 res.binary_value = CUSTOM_INSTR_R2_TYPE(0b1101000, 0b00000, rs1, 0b000, 0b1010011);
314 return res.float_value;
315}
316
317
318/**********************************************************************/
325inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_feqs(float rs1, float rs2) {
326
327 float_conv_t opa, opb;
328 opa.float_value = rs1;
329 opb.float_value = rs2;
330
331 return CUSTOM_INSTR_R3_TYPE(0b1010000, opb.binary_value, opa.binary_value, 0b010, 0b1010011);
332}
333
334
335/**********************************************************************/
342inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_flts(float rs1, float rs2) {
343
344 float_conv_t opa, opb;
345 opa.float_value = rs1;
346 opb.float_value = rs2;
347
348 return CUSTOM_INSTR_R3_TYPE(0b1010000, opb.binary_value, opa.binary_value, 0b001, 0b1010011);
349}
350
351
352/**********************************************************************/
359inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fles(float rs1, float rs2) {
360
361 float_conv_t opa, opb;
362 opa.float_value = rs1;
363 opb.float_value = rs2;
364
365 return CUSTOM_INSTR_R3_TYPE(0b1010000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
366}
367
368
369/**********************************************************************/
376inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjs(float rs1, float rs2) {
377
378 float_conv_t opa, opb, res;
379 opa.float_value = rs1;
380 opb.float_value = rs2;
381
382 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
383 return res.float_value;
384}
385
386
387/**********************************************************************/
394inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjns(float rs1, float rs2) {
395
396 float_conv_t opa, opb, res;
397 opa.float_value = rs1;
398 opb.float_value = rs2;
399
400 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010000, opb.binary_value, opa.binary_value, 0b001, 0b1010011);
401 return res.float_value;
402}
403
404
405/**********************************************************************/
412inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjxs(float rs1, float rs2) {
413
414 float_conv_t opa, opb, res;
415 opa.float_value = rs1;
416 opb.float_value = rs2;
417
418 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010000, opb.binary_value, opa.binary_value, 0b010, 0b1010011);
419 return res.float_value;
420}
421
422
423/**********************************************************************/
429inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fclasss(float rs1) {
430
431 float_conv_t opa;
432 opa.float_value = rs1;
433
434 return CUSTOM_INSTR_R2_TYPE(0b1110000, 0b00000, opa.binary_value, 0b001, 0b1010011);
435}
436
437
438// ################################################################################################
439// !!! UNSUPPORTED instructions !!!
440// ################################################################################################
441
442/**********************************************************************/
451inline float __attribute__ ((always_inline)) riscv_intrinsic_fdivs(float rs1, float rs2) {
452
453 float_conv_t opa, opb, res;
454 opa.float_value = rs1;
455 opb.float_value = rs2;
456
457 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0001100, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
458 return res.float_value;
459}
460
461
462/**********************************************************************/
470inline float __attribute__ ((always_inline)) riscv_intrinsic_fsqrts(float rs1) {
471
472 float_conv_t opa, res;
473 opa.float_value = rs1;
474
475 res.binary_value = CUSTOM_INSTR_R2_TYPE(0b0101100, 0b00000, opa.binary_value, 0b000, 0b1010011);
476 return res.float_value;
477}
478
479
480/**********************************************************************/
490inline float __attribute__ ((always_inline)) riscv_intrinsic_fmadds(float rs1, float rs2, float rs3) {
491
492 float_conv_t opa, opb, opc, res;
493 opa.float_value = rs1;
494 opb.float_value = rs2;
495 opc.float_value = rs3;
496
497 res.binary_value = CUSTOM_INSTR_R4_TYPE(opc.binary_value, opb.binary_value, opa.binary_value, 0b000, 0b1000011);
498 return res.float_value;
499}
500
501
502/**********************************************************************/
512inline float __attribute__ ((always_inline)) riscv_intrinsic_fmsubs(float rs1, float rs2, float rs3) {
513
514 float_conv_t opa, opb, opc, res;
515 opa.float_value = rs1;
516 opb.float_value = rs2;
517 opc.float_value = rs3;
518
519 res.binary_value = CUSTOM_INSTR_R4_TYPE(opc.binary_value, opb.binary_value, opa.binary_value, 0b000, 0b1000111);
520 return res.float_value;
521}
522
523
524/**********************************************************************/
534inline float __attribute__ ((always_inline)) riscv_intrinsic_fnmsubs(float rs1, float rs2, float rs3) {
535
536 float_conv_t opa, opb, opc, res;
537 opa.float_value = rs1;
538 opb.float_value = rs2;
539 opc.float_value = rs3;
540
541 res.binary_value = CUSTOM_INSTR_R4_TYPE(opc.binary_value, opb.binary_value, opa.binary_value, 0b000, 0b1001011);
542 return res.float_value;
543}
544
545
546/**********************************************************************/
556inline float __attribute__ ((always_inline)) riscv_intrinsic_fnmadds(float rs1, float rs2, float rs3) {
557
558 float_conv_t opa, opb, opc, res;
559 opa.float_value = rs1;
560 opb.float_value = rs2;
561 opc.float_value = rs3;
562
563 res.binary_value = CUSTOM_INSTR_R4_TYPE(opc.binary_value, opb.binary_value, opa.binary_value, 0b000, 0b1001111);
564 return res.float_value;
565}
566
567
568// ################################################################################################
569// Emulation functions
570// ################################################################################################
571
572/**********************************************************************/
579float __attribute__ ((noinline)) riscv_emulate_fadds(float rs1, float rs2) {
580
581 float opa = subnormal_flush(rs1);
582 float opb = subnormal_flush(rs2);
583
584 float res = opa + opb;
585
586 // make NAN canonical
587 if (fpclassify(res) == FP_NAN) {
588 res = NAN;
589 }
590
591 return subnormal_flush(res);
592}
593
594
595/**********************************************************************/
602float __attribute__ ((noinline)) riscv_emulate_fsubs(float rs1, float rs2) {
603
604 float opa = subnormal_flush(rs1);
605 float opb = subnormal_flush(rs2);
606
607 float res = opa - opb;
608
609 // make NAN canonical
610 if (fpclassify(res) == FP_NAN) {
611 res = NAN;
612 }
613
614 return subnormal_flush(res);
615}
616
617
618/**********************************************************************/
625float __attribute__ ((noinline)) riscv_emulate_fmuls(float rs1, float rs2) {
626
627 float opa = subnormal_flush(rs1);
628 float opb = subnormal_flush(rs2);
629
630 float res = opa * opb;
631 return subnormal_flush(res);
632}
633
634
635/**********************************************************************/
642float __attribute__ ((noinline)) riscv_emulate_fmins(float rs1, float rs2) {
643
644 float opa = subnormal_flush(rs1);
645 float opb = subnormal_flush(rs2);
646
647 union {
648 uint32_t binary_value;
649 float float_value;
650 } tmp_a, tmp_b;
651
652 if ((fpclassify(opa) == FP_NAN) && (fpclassify(opb) == FP_NAN)) {
653 return nanf("");
654 }
655
656 if (fpclassify(opa) == FP_NAN) {
657 return opb;
658 }
659
660 if (fpclassify(opb) == FP_NAN) {
661 return opa;
662 }
663
664 // RISC-V spec: -0 < +0
665 tmp_a.float_value = opa;
666 tmp_b.float_value = opb;
667 if (((tmp_a.binary_value == 0x80000000) && (tmp_b.binary_value == 0x00000000)) ||
668 ((tmp_a.binary_value == 0x00000000) && (tmp_b.binary_value == 0x80000000))) {
669 return -0.0f;
670 }
671
672 return fmin(opa, opb);
673}
674
675
676/**********************************************************************/
683float __attribute__ ((noinline)) riscv_emulate_fmaxs(float rs1, float rs2) {
684
685 float opa = subnormal_flush(rs1);
686 float opb = subnormal_flush(rs2);
687
688 union {
689 uint32_t binary_value;
690 float float_value;
691 } tmp_a, tmp_b;
692
693
694 if ((fpclassify(opa) == FP_NAN) && (fpclassify(opb) == FP_NAN)) {
695 return nanf("");
696 }
697
698 if (fpclassify(opa) == FP_NAN) {
699 return opb;
700 }
701
702 if (fpclassify(opb) == FP_NAN) {
703 return opa;
704 }
705
706 // RISC-V spec: -0 < +0
707 tmp_a.float_value = opa;
708 tmp_b.float_value = opb;
709 if (((tmp_a.binary_value == 0x80000000) && (tmp_b.binary_value == 0x00000000)) ||
710 ((tmp_a.binary_value == 0x00000000) && (tmp_b.binary_value == 0x80000000))) {
711 return +0.0f;
712 }
713
714 return fmax(opa, opb);
715}
716
717
718/**********************************************************************/
724uint32_t __attribute__ ((noinline)) riscv_emulate_fcvt_wus(float rs1) {
725
726 float opa = subnormal_flush(rs1);
727
728 return (uint32_t)roundf(opa);
729}
730
731
732/**********************************************************************/
738int32_t __attribute__ ((noinline)) riscv_emulate_fcvt_ws(float rs1) {
739
740 float opa = subnormal_flush(rs1);
741
742 return (int32_t)roundf(opa);
743}
744
745
746/**********************************************************************/
752float __attribute__ ((noinline)) riscv_emulate_fcvt_swu(uint32_t rs1) {
753
754 return (float)rs1;
755}
756
757
758/**********************************************************************/
764float __attribute__ ((noinline)) riscv_emulate_fcvt_sw(int32_t rs1) {
765
766 return (float)rs1;
767}
768
769
770/**********************************************************************/
777uint32_t __attribute__ ((noinline)) riscv_emulate_feqs(float rs1, float rs2) {
778
779 float opa = subnormal_flush(rs1);
780 float opb = subnormal_flush(rs2);
781
782 if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
783 return 0;
784 }
785
786 if isless(opa, opb) {
787 return 0;
788 }
789 else if isgreater(opa, opb) {
790 return 0;
791 }
792 else {
793 return 1;
794 }
795}
796
797
798/**********************************************************************/
805uint32_t __attribute__ ((noinline)) riscv_emulate_flts(float rs1, float rs2) {
806
807 float opa = subnormal_flush(rs1);
808 float opb = subnormal_flush(rs2);
809
810 if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
811 return 0;
812 }
813
814 if isless(opa, opb) {
815 return 1;
816 }
817 else {
818 return 0;
819 }
820}
821
822
823/**********************************************************************/
830uint32_t __attribute__ ((noinline)) riscv_emulate_fles(float rs1, float rs2) {
831
832 float opa = subnormal_flush(rs1);
833 float opb = subnormal_flush(rs2);
834
835 if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
836 return 0;
837 }
838
839 if islessequal(opa, opb) {
840 return 1;
841 }
842 else {
843 return 0;
844 }
845}
846
847
848/**********************************************************************/
855float __attribute__ ((noinline)) riscv_emulate_fsgnjs(float rs1, float rs2) {
856
857 float opa = subnormal_flush(rs1);
858 float opb = subnormal_flush(rs2);
859
860 int sign_1 = (int)signbit(opa);
861 int sign_2 = (int)signbit(opb);
862 float res = 0;
863
864 if (sign_2 != 0) { // opb is negative
865 if (sign_1 == 0) {
866 res = -opa;
867 }
868 else {
869 res = opa;
870 }
871 }
872 else { // opb is positive
873 if (sign_1 == 0) {
874 res = opa;
875 }
876 else {
877 res = -opa;
878 }
879 }
880
881 return res;
882}
883
884
885/**********************************************************************/
892float __attribute__ ((noinline)) riscv_emulate_fsgnjns(float rs1, float rs2) {
893
894 float opa = subnormal_flush(rs1);
895 float opb = subnormal_flush(rs2);
896
897 int sign_1 = (int)signbit(opa);
898 int sign_2 = (int)signbit(opb);
899 float res = 0;
900
901 if (sign_2 != 0) { // opb is negative
902 if (sign_1 == 0) {
903 res = opa;
904 }
905 else {
906 res = -opa;
907 }
908 }
909 else { // opb is positive
910 if (sign_1 == 0) {
911 res = -opa;
912 }
913 else {
914 res = opa;
915 }
916 }
917
918 return res;
919}
920
921
922/**********************************************************************/
929float __attribute__ ((noinline)) riscv_emulate_fsgnjxs(float rs1, float rs2) {
930
931 float opa = subnormal_flush(rs1);
932 float opb = subnormal_flush(rs2);
933
934 int sign_1 = (int)signbit(opa);
935 int sign_2 = (int)signbit(opb);
936 float res = 0;
937
938 if (((sign_1 == 0) && (sign_2 != 0)) || ((sign_1 != 0) && (sign_2 == 0))) {
939 if (sign_1 == 0) {
940 res = -opa;
941 }
942 else {
943 res = opa;
944 }
945 }
946 else {
947 if (sign_1 == 0) {
948 res = opa;
949 }
950 else {
951 res = -opa;
952 }
953 }
954
955 return res;
956}
957
958
959/**********************************************************************/
965uint32_t __attribute__ ((noinline)) riscv_emulate_fclasss(float rs1) {
966
967 float opa = subnormal_flush(rs1);
968
969 union {
970 uint32_t binary_value;
971 float float_value;
972 } aux;
973
974 // RISC-V classify result layout
975 const uint32_t CLASS_NEG_INF = 1 << 0; // negative infinity
976 const uint32_t CLASS_NEG_NORM = 1 << 1; // negative normal number
977 const uint32_t CLASS_NEG_DENORM = 1 << 2; // negative subnormal number
978 const uint32_t CLASS_NEG_ZERO = 1 << 3; // negative zero
979 const uint32_t CLASS_POS_ZERO = 1 << 4; // positive zero
980 const uint32_t CLASS_POS_DENORM = 1 << 5; // positive subnormal number
981 const uint32_t CLASS_POS_NORM = 1 << 6; // positive normal number
982 const uint32_t CLASS_POS_INF = 1 << 7; // positive infinity
983 const uint32_t CLASS_SNAN = 1 << 8; // signaling NaN (sNaN)
984 const uint32_t CLASS_QNAN = 1 << 9; // quiet NaN (qNaN)
985
986 int tmp = fpclassify(opa);
987 int sgn = (int)signbit(opa);
988
989 uint32_t res = 0;
990
991 // infinity
992 if (tmp == FP_INFINITE) {
993 if (sgn) { res |= CLASS_NEG_INF; }
994 else { res |= CLASS_POS_INF; }
995 }
996
997 // zero
998 if (tmp == FP_ZERO) {
999 if (sgn) { res |= CLASS_NEG_ZERO; }
1000 else { res |= CLASS_POS_ZERO; }
1001 }
1002
1003 // normal
1004 if (tmp == FP_NORMAL) {
1005 if (sgn) { res |= CLASS_NEG_NORM; }
1006 else { res |= CLASS_POS_NORM; }
1007 }
1008
1009 // subnormal
1010 if (tmp == FP_SUBNORMAL) {
1011 if (sgn) { res |= CLASS_NEG_DENORM; }
1012 else { res |= CLASS_POS_DENORM; }
1013 }
1014
1015 // NaN
1016 if (tmp == FP_NAN) {
1017 aux.float_value = opa;
1018 if ((aux.binary_value >> 22) & 0b1) { // bit 22 (mantissa's MSB) is set -> canonical (quiet) NAN
1019 res |= CLASS_QNAN;
1020 }
1021 else {
1022 res |= CLASS_SNAN;
1023 }
1024 }
1025
1026 return res;
1027}
1028
1029
1030/**********************************************************************/
1037float __attribute__ ((noinline)) riscv_emulate_fdivs(float rs1, float rs2) {
1038
1039 float opa = subnormal_flush(rs1);
1040 float opb = subnormal_flush(rs2);
1041
1042 float res = opa / opb;
1043 return subnormal_flush(res);
1044}
1045
1046
1047/**********************************************************************/
1053float __attribute__ ((noinline)) riscv_emulate_fsqrts(float rs1) {
1054
1055 float opa = subnormal_flush(rs1);
1056
1057 float res = sqrtf(opa);
1058 return subnormal_flush(res);
1059}
1060
1061
1062/**********************************************************************/
1072float __attribute__ ((noinline)) riscv_emulate_fmadds(float rs1, float rs2, float rs3) {
1073
1074 float opa = subnormal_flush(rs1);
1075 float opb = subnormal_flush(rs2);
1076 float opc = subnormal_flush(rs3);
1077
1078 float res = (opa * opb) + opc;
1079 return subnormal_flush(res);
1080}
1081
1082
1083/**********************************************************************/
1091float __attribute__ ((noinline)) riscv_emulate_fmsubs(float rs1, float rs2, float rs3) {
1092
1093 float opa = subnormal_flush(rs1);
1094 float opb = subnormal_flush(rs2);
1095 float opc = subnormal_flush(rs3);
1096
1097 float res = (opa * opb) - opc;
1098 return subnormal_flush(res);
1099}
1100
1101
1102/**********************************************************************/
1110float __attribute__ ((noinline)) riscv_emulate_fnmsubs(float rs1, float rs2, float rs3) {
1111
1112 float opa = subnormal_flush(rs1);
1113 float opb = subnormal_flush(rs2);
1114 float opc = subnormal_flush(rs3);
1115
1116 float res = -(opa * opb) + opc;
1117 return subnormal_flush(res);
1118}
1119
1120
1121/**********************************************************************/
1129float __attribute__ ((noinline)) riscv_emulate_fnmadds(float rs1, float rs2, float rs3) {
1130
1131 float opa = subnormal_flush(rs1);
1132 float opb = subnormal_flush(rs2);
1133 float opc = subnormal_flush(rs3);
1134
1135 float res = -(opa * opb) - opc;
1136 return subnormal_flush(res);
1137}
1138
1139
1140#endif // neorv32_zfinx_extension_intrinsics_h
1141
uint32_t neorv32_cpu_csr_read(const int csr_id)
Definition neorv32_cpu.h:400
void neorv32_cpu_csr_write(const int csr_id, uint32_t data)
Definition neorv32_cpu.h:416
@ CSR_FFLAGS
Definition neorv32_cpu_csr.h:50
Definition neorv32_zfinx_extension_intrinsics.h:78
uint32_t binary_value
Definition neorv32_zfinx_extension_intrinsics.h:79
float float_value
Definition neorv32_zfinx_extension_intrinsics.h:80