NEORV32 Software Framework Documentation
The NEORV32 RISC-V Processor
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/**********************************************************************/
51
52#ifndef neorv32_zfinx_extension_intrinsics_h
53#define neorv32_zfinx_extension_intrinsics_h
54
55#define __USE_GNU
56
57#define _GNU_SOURCE
58
59#include <float.h>
60#include <fenv.h>
61#include <math.h>
62
63
64/**********************************************************************/
67#if defined __riscv_f || (__riscv_flen == 32)
68 #error Application programs using the Zfinx intrinsic library have to be compiled WITHOUT the <F> MARCH ISA attribute!
69#endif
70
71
72/**********************************************************************/
75typedef union
76{
77 uint32_t binary_value;
80
81
82// ################################################################################################
83// Helper functions
84// ################################################################################################
85
86/**********************************************************************/
94float subnormal_flush(float tmp) {
95
96 float res = tmp;
97
98 // flush to zero if subnormal
99 if (fpclassify(tmp) == FP_SUBNORMAL) {
100 if (signbit(tmp) != 0) {
101 res = -0.0f;
102 }
103 else {
104 res = +0.0f;
105 }
106 }
107
108 return res;
109}
110
111
112// ################################################################################################
113// Exception access
114// ################################################################################################
115
116/**********************************************************************/
121uint32_t get_hw_exceptions(void) {
122
123 uint32_t res = neorv32_cpu_csr_read(CSR_FFLAGS);
124
125 neorv32_cpu_csr_write(CSR_FFLAGS, 0); // clear status word
126
127 return res;
128}
129
130
131// ################################################################################################
132// "Intrinsics"
133// ################################################################################################
134
135/**********************************************************************/
142inline float __attribute__ ((always_inline)) riscv_intrinsic_fadds(float rs1, float rs2) {
143
144 float_conv_t opa, opb, res;
145 opa.float_value = rs1;
146 opb.float_value = rs2;
147
148 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0000000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
149 return res.float_value;
150}
151
152
153/**********************************************************************/
160inline float __attribute__ ((always_inline)) riscv_intrinsic_fsubs(float rs1, float rs2) {
161
162 float_conv_t opa, opb, res;
163 opa.float_value = rs1;
164 opb.float_value = rs2;
165
166 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0000100, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
167 return res.float_value;
168}
169
170
171/**********************************************************************/
178inline float __attribute__ ((always_inline)) riscv_intrinsic_fmuls(float rs1, float rs2) {
179
180 float_conv_t opa, opb, res;
181 opa.float_value = rs1;
182 opb.float_value = rs2;
183
184 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0001000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
185 return res.float_value;
186}
187
188
189/**********************************************************************/
196inline float __attribute__ ((always_inline)) riscv_intrinsic_fmins(float rs1, float rs2) {
197
198 float_conv_t opa, opb, res;
199 opa.float_value = rs1;
200 opb.float_value = rs2;
201
202 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010100, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
203 return res.float_value;
204}
205
206
207/**********************************************************************/
214inline float __attribute__ ((always_inline)) riscv_intrinsic_fmaxs(float rs1, float rs2) {
215
216 float_conv_t opa, opb, res;
217 opa.float_value = rs1;
218 opb.float_value = rs2;
219
220 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010100, opb.binary_value, opa.binary_value, 0b001, 0b1010011);
221 return res.float_value;
222}
223
224
225/**********************************************************************/
231inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fcvt_wus(float rs1) {
232
233 float_conv_t opa;
234 opa.float_value = rs1;
235
236 return CUSTOM_INSTR_R2_TYPE(0b1100000, 0b00001, opa.binary_value, 0b000, 0b1010011);
237}
238
239
240/**********************************************************************/
246inline int32_t __attribute__ ((always_inline)) riscv_intrinsic_fcvt_ws(float rs1) {
247
248 float_conv_t opa;
249 opa.float_value = rs1;
250
251 return (int32_t)CUSTOM_INSTR_R2_TYPE(0b1100000, 0b00000, opa.binary_value, 0b000, 0b1010011);
252}
253
254
255/**********************************************************************/
261inline float __attribute__ ((always_inline)) riscv_intrinsic_fcvt_swu(uint32_t rs1) {
262
263 float_conv_t res;
264
265 res.binary_value = CUSTOM_INSTR_R2_TYPE(0b1101000, 0b00001, rs1, 0b000, 0b1010011);
266 return res.float_value;
267}
268
269
270/**********************************************************************/
276inline float __attribute__ ((always_inline)) riscv_intrinsic_fcvt_sw(int32_t rs1) {
277
278 float_conv_t res;
279
280 res.binary_value = CUSTOM_INSTR_R2_TYPE(0b1101000, 0b00000, rs1, 0b000, 0b1010011);
281 return res.float_value;
282}
283
284
285/**********************************************************************/
292inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_feqs(float rs1, float rs2) {
293
294 float_conv_t opa, opb;
295 opa.float_value = rs1;
296 opb.float_value = rs2;
297
298 return CUSTOM_INSTR_R3_TYPE(0b1010000, opb.binary_value, opa.binary_value, 0b010, 0b1010011);
299}
300
301
302/**********************************************************************/
309inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_flts(float rs1, float rs2) {
310
311 float_conv_t opa, opb;
312 opa.float_value = rs1;
313 opb.float_value = rs2;
314
315 return CUSTOM_INSTR_R3_TYPE(0b1010000, opb.binary_value, opa.binary_value, 0b001, 0b1010011);
316}
317
318
319/**********************************************************************/
326inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fles(float rs1, float rs2) {
327
328 float_conv_t opa, opb;
329 opa.float_value = rs1;
330 opb.float_value = rs2;
331
332 return CUSTOM_INSTR_R3_TYPE(0b1010000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
333}
334
335
336/**********************************************************************/
343inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjs(float rs1, float rs2) {
344
345 float_conv_t opa, opb, res;
346 opa.float_value = rs1;
347 opb.float_value = rs2;
348
349 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
350 return res.float_value;
351}
352
353
354/**********************************************************************/
361inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjns(float rs1, float rs2) {
362
363 float_conv_t opa, opb, res;
364 opa.float_value = rs1;
365 opb.float_value = rs2;
366
367 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010000, opb.binary_value, opa.binary_value, 0b001, 0b1010011);
368 return res.float_value;
369}
370
371
372/**********************************************************************/
379inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjxs(float rs1, float rs2) {
380
381 float_conv_t opa, opb, res;
382 opa.float_value = rs1;
383 opb.float_value = rs2;
384
385 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010000, opb.binary_value, opa.binary_value, 0b010, 0b1010011);
386 return res.float_value;
387}
388
389
390/**********************************************************************/
396inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fclasss(float rs1) {
397
398 float_conv_t opa;
399 opa.float_value = rs1;
400
401 return CUSTOM_INSTR_R2_TYPE(0b1110000, 0b00000, opa.binary_value, 0b001, 0b1010011);
402}
403
404
405// ################################################################################################
406// !!! UNSUPPORTED instructions !!!
407// ################################################################################################
408
409/**********************************************************************/
418inline float __attribute__ ((always_inline)) riscv_intrinsic_fdivs(float rs1, float rs2) {
419
420 float_conv_t opa, opb, res;
421 opa.float_value = rs1;
422 opb.float_value = rs2;
423
424 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0001100, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
425 return res.float_value;
426}
427
428
429/**********************************************************************/
437inline float __attribute__ ((always_inline)) riscv_intrinsic_fsqrts(float rs1) {
438
439 float_conv_t opa, res;
440 opa.float_value = rs1;
441
442 res.binary_value = CUSTOM_INSTR_R2_TYPE(0b0101100, 0b00000, opa.binary_value, 0b000, 0b1010011);
443 return res.float_value;
444}
445
446
447/**********************************************************************/
457inline float __attribute__ ((always_inline)) riscv_intrinsic_fmadds(float rs1, float rs2, float rs3) {
458
459 float_conv_t opa, opb, opc, res;
460 opa.float_value = rs1;
461 opb.float_value = rs2;
462 opc.float_value = rs3;
463
464 res.binary_value = CUSTOM_INSTR_R4_TYPE(opc.binary_value, opb.binary_value, opa.binary_value, 0b000, 0b1000011);
465 return res.float_value;
466}
467
468
469/**********************************************************************/
479inline float __attribute__ ((always_inline)) riscv_intrinsic_fmsubs(float rs1, float rs2, float rs3) {
480
481 float_conv_t opa, opb, opc, res;
482 opa.float_value = rs1;
483 opb.float_value = rs2;
484 opc.float_value = rs3;
485
486 res.binary_value = CUSTOM_INSTR_R4_TYPE(opc.binary_value, opb.binary_value, opa.binary_value, 0b000, 0b1000111);
487 return res.float_value;
488}
489
490
491/**********************************************************************/
501inline float __attribute__ ((always_inline)) riscv_intrinsic_fnmsubs(float rs1, float rs2, float rs3) {
502
503 float_conv_t opa, opb, opc, res;
504 opa.float_value = rs1;
505 opb.float_value = rs2;
506 opc.float_value = rs3;
507
508 res.binary_value = CUSTOM_INSTR_R4_TYPE(opc.binary_value, opb.binary_value, opa.binary_value, 0b000, 0b1001011);
509 return res.float_value;
510}
511
512
513/**********************************************************************/
523inline float __attribute__ ((always_inline)) riscv_intrinsic_fnmadds(float rs1, float rs2, float rs3) {
524
525 float_conv_t opa, opb, opc, res;
526 opa.float_value = rs1;
527 opb.float_value = rs2;
528 opc.float_value = rs3;
529
530 res.binary_value = CUSTOM_INSTR_R4_TYPE(opc.binary_value, opb.binary_value, opa.binary_value, 0b000, 0b1001111);
531 return res.float_value;
532}
533
534
535// ################################################################################################
536// Emulation functions
537// ################################################################################################
538
539/**********************************************************************/
546float __attribute__ ((noinline)) riscv_emulate_fadds(float rs1, float rs2) {
547
548 float opa = subnormal_flush(rs1);
549 float opb = subnormal_flush(rs2);
550
551 float res = opa + opb;
552
553 // make NAN canonical
554 if (fpclassify(res) == FP_NAN) {
555 res = NAN;
556 }
557
558 return subnormal_flush(res);
559}
560
561
562/**********************************************************************/
569float __attribute__ ((noinline)) riscv_emulate_fsubs(float rs1, float rs2) {
570
571 float opa = subnormal_flush(rs1);
572 float opb = subnormal_flush(rs2);
573
574 float res = opa - opb;
575
576 // make NAN canonical
577 if (fpclassify(res) == FP_NAN) {
578 res = NAN;
579 }
580
581 return subnormal_flush(res);
582}
583
584
585/**********************************************************************/
592float __attribute__ ((noinline)) riscv_emulate_fmuls(float rs1, float rs2) {
593
594 float opa = subnormal_flush(rs1);
595 float opb = subnormal_flush(rs2);
596
597 float res = opa * opb;
598 return subnormal_flush(res);
599}
600
601
602/**********************************************************************/
609float __attribute__ ((noinline)) riscv_emulate_fmins(float rs1, float rs2) {
610
611 float opa = subnormal_flush(rs1);
612 float opb = subnormal_flush(rs2);
613
614 union {
615 uint32_t binary_value;
616 float float_value;
617 } tmp_a, tmp_b;
618
619 if ((fpclassify(opa) == FP_NAN) && (fpclassify(opb) == FP_NAN)) {
620 return nanf("");
621 }
622
623 if (fpclassify(opa) == FP_NAN) {
624 return opb;
625 }
626
627 if (fpclassify(opb) == FP_NAN) {
628 return opa;
629 }
630
631 // RISC-V spec: -0 < +0
632 tmp_a.float_value = opa;
633 tmp_b.float_value = opb;
634 if (((tmp_a.binary_value == 0x80000000) && (tmp_b.binary_value == 0x00000000)) ||
635 ((tmp_a.binary_value == 0x00000000) && (tmp_b.binary_value == 0x80000000))) {
636 return -0.0f;
637 }
638
639 return fmin(opa, opb);
640}
641
642
643/**********************************************************************/
650float __attribute__ ((noinline)) riscv_emulate_fmaxs(float rs1, float rs2) {
651
652 float opa = subnormal_flush(rs1);
653 float opb = subnormal_flush(rs2);
654
655 union {
656 uint32_t binary_value;
657 float float_value;
658 } tmp_a, tmp_b;
659
660
661 if ((fpclassify(opa) == FP_NAN) && (fpclassify(opb) == FP_NAN)) {
662 return nanf("");
663 }
664
665 if (fpclassify(opa) == FP_NAN) {
666 return opb;
667 }
668
669 if (fpclassify(opb) == FP_NAN) {
670 return opa;
671 }
672
673 // RISC-V spec: -0 < +0
674 tmp_a.float_value = opa;
675 tmp_b.float_value = opb;
676 if (((tmp_a.binary_value == 0x80000000) && (tmp_b.binary_value == 0x00000000)) ||
677 ((tmp_a.binary_value == 0x00000000) && (tmp_b.binary_value == 0x80000000))) {
678 return +0.0f;
679 }
680
681 return fmax(opa, opb);
682}
683
684
685/**********************************************************************/
691uint32_t __attribute__ ((noinline)) riscv_emulate_fcvt_wus(float rs1) {
692
693 float opa = subnormal_flush(rs1);
694
695 return (uint32_t)roundf(opa);
696}
697
698
699/**********************************************************************/
705int32_t __attribute__ ((noinline)) riscv_emulate_fcvt_ws(float rs1) {
706
707 float opa = subnormal_flush(rs1);
708
709 return (int32_t)roundf(opa);
710}
711
712
713/**********************************************************************/
719float __attribute__ ((noinline)) riscv_emulate_fcvt_swu(uint32_t rs1) {
720
721 return (float)rs1;
722}
723
724
725/**********************************************************************/
731float __attribute__ ((noinline)) riscv_emulate_fcvt_sw(int32_t rs1) {
732
733 return (float)rs1;
734}
735
736
737/**********************************************************************/
744uint32_t __attribute__ ((noinline)) riscv_emulate_feqs(float rs1, float rs2) {
745
746 float opa = subnormal_flush(rs1);
747 float opb = subnormal_flush(rs2);
748
749 if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
750 return 0;
751 }
752
753 if isless(opa, opb) {
754 return 0;
755 }
756 else if isgreater(opa, opb) {
757 return 0;
758 }
759 else {
760 return 1;
761 }
762}
763
764
765/**********************************************************************/
772uint32_t __attribute__ ((noinline)) riscv_emulate_flts(float rs1, float rs2) {
773
774 float opa = subnormal_flush(rs1);
775 float opb = subnormal_flush(rs2);
776
777 if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
778 return 0;
779 }
780
781 if isless(opa, opb) {
782 return 1;
783 }
784 else {
785 return 0;
786 }
787}
788
789
790/**********************************************************************/
797uint32_t __attribute__ ((noinline)) riscv_emulate_fles(float rs1, float rs2) {
798
799 float opa = subnormal_flush(rs1);
800 float opb = subnormal_flush(rs2);
801
802 if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
803 return 0;
804 }
805
806 if islessequal(opa, opb) {
807 return 1;
808 }
809 else {
810 return 0;
811 }
812}
813
814
815/**********************************************************************/
822float __attribute__ ((noinline)) riscv_emulate_fsgnjs(float rs1, float rs2) {
823
824 float opa = subnormal_flush(rs1);
825 float opb = subnormal_flush(rs2);
826
827 int sign_1 = (int)signbit(opa);
828 int sign_2 = (int)signbit(opb);
829 float res = 0;
830
831 if (sign_2 != 0) { // opb is negative
832 if (sign_1 == 0) {
833 res = -opa;
834 }
835 else {
836 res = opa;
837 }
838 }
839 else { // opb is positive
840 if (sign_1 == 0) {
841 res = opa;
842 }
843 else {
844 res = -opa;
845 }
846 }
847
848 return res;
849}
850
851
852/**********************************************************************/
859float __attribute__ ((noinline)) riscv_emulate_fsgnjns(float rs1, float rs2) {
860
861 float opa = subnormal_flush(rs1);
862 float opb = subnormal_flush(rs2);
863
864 int sign_1 = (int)signbit(opa);
865 int sign_2 = (int)signbit(opb);
866 float res = 0;
867
868 if (sign_2 != 0) { // opb is negative
869 if (sign_1 == 0) {
870 res = opa;
871 }
872 else {
873 res = -opa;
874 }
875 }
876 else { // opb is positive
877 if (sign_1 == 0) {
878 res = -opa;
879 }
880 else {
881 res = opa;
882 }
883 }
884
885 return res;
886}
887
888
889/**********************************************************************/
896float __attribute__ ((noinline)) riscv_emulate_fsgnjxs(float rs1, float rs2) {
897
898 float opa = subnormal_flush(rs1);
899 float opb = subnormal_flush(rs2);
900
901 int sign_1 = (int)signbit(opa);
902 int sign_2 = (int)signbit(opb);
903 float res = 0;
904
905 if (((sign_1 == 0) && (sign_2 != 0)) || ((sign_1 != 0) && (sign_2 == 0))) {
906 if (sign_1 == 0) {
907 res = -opa;
908 }
909 else {
910 res = opa;
911 }
912 }
913 else {
914 if (sign_1 == 0) {
915 res = opa;
916 }
917 else {
918 res = -opa;
919 }
920 }
921
922 return res;
923}
924
925
926/**********************************************************************/
932uint32_t __attribute__ ((noinline)) riscv_emulate_fclasss(float rs1) {
933
934 float opa = subnormal_flush(rs1);
935
936 union {
937 uint32_t binary_value;
938 float float_value;
939 } aux;
940
941 // RISC-V classify result layout
942 const uint32_t CLASS_NEG_INF = 1 << 0; // negative infinity
943 const uint32_t CLASS_NEG_NORM = 1 << 1; // negative normal number
944 const uint32_t CLASS_NEG_DENORM = 1 << 2; // negative subnormal number
945 const uint32_t CLASS_NEG_ZERO = 1 << 3; // negative zero
946 const uint32_t CLASS_POS_ZERO = 1 << 4; // positive zero
947 const uint32_t CLASS_POS_DENORM = 1 << 5; // positive subnormal number
948 const uint32_t CLASS_POS_NORM = 1 << 6; // positive normal number
949 const uint32_t CLASS_POS_INF = 1 << 7; // positive infinity
950 const uint32_t CLASS_SNAN = 1 << 8; // signaling NaN (sNaN)
951 const uint32_t CLASS_QNAN = 1 << 9; // quiet NaN (qNaN)
952
953 int tmp = fpclassify(opa);
954 int sgn = (int)signbit(opa);
955
956 uint32_t res = 0;
957
958 // infinity
959 if (tmp == FP_INFINITE) {
960 if (sgn) { res |= CLASS_NEG_INF; }
961 else { res |= CLASS_POS_INF; }
962 }
963
964 // zero
965 if (tmp == FP_ZERO) {
966 if (sgn) { res |= CLASS_NEG_ZERO; }
967 else { res |= CLASS_POS_ZERO; }
968 }
969
970 // normal
971 if (tmp == FP_NORMAL) {
972 if (sgn) { res |= CLASS_NEG_NORM; }
973 else { res |= CLASS_POS_NORM; }
974 }
975
976 // subnormal
977 if (tmp == FP_SUBNORMAL) {
978 if (sgn) { res |= CLASS_NEG_DENORM; }
979 else { res |= CLASS_POS_DENORM; }
980 }
981
982 // NaN
983 if (tmp == FP_NAN) {
984 aux.float_value = opa;
985 if ((aux.binary_value >> 22) & 0b1) { // bit 22 (mantissa's MSB) is set -> canonical (quiet) NAN
986 res |= CLASS_QNAN;
987 }
988 else {
989 res |= CLASS_SNAN;
990 }
991 }
992
993 return res;
994}
995
996
997/**********************************************************************/
1004float __attribute__ ((noinline)) riscv_emulate_fdivs(float rs1, float rs2) {
1005
1006 float opa = subnormal_flush(rs1);
1007 float opb = subnormal_flush(rs2);
1008
1009 float res = opa / opb;
1010 return subnormal_flush(res);
1011}
1012
1013
1014/**********************************************************************/
1020float __attribute__ ((noinline)) riscv_emulate_fsqrts(float rs1) {
1021
1022 float opa = subnormal_flush(rs1);
1023
1024 float res = sqrtf(opa);
1025 return subnormal_flush(res);
1026}
1027
1028
1029/**********************************************************************/
1039float __attribute__ ((noinline)) riscv_emulate_fmadds(float rs1, float rs2, float rs3) {
1040
1041 float opa = subnormal_flush(rs1);
1042 float opb = subnormal_flush(rs2);
1043 float opc = subnormal_flush(rs3);
1044
1045 float res = (opa * opb) + opc;
1046 return subnormal_flush(res);
1047}
1048
1049
1050/**********************************************************************/
1058float __attribute__ ((noinline)) riscv_emulate_fmsubs(float rs1, float rs2, float rs3) {
1059
1060 float opa = subnormal_flush(rs1);
1061 float opb = subnormal_flush(rs2);
1062 float opc = subnormal_flush(rs3);
1063
1064 float res = (opa * opb) - opc;
1065 return subnormal_flush(res);
1066}
1067
1068
1069/**********************************************************************/
1077float __attribute__ ((noinline)) riscv_emulate_fnmsubs(float rs1, float rs2, float rs3) {
1078
1079 float opa = subnormal_flush(rs1);
1080 float opb = subnormal_flush(rs2);
1081 float opc = subnormal_flush(rs3);
1082
1083 float res = -(opa * opb) + opc;
1084 return subnormal_flush(res);
1085}
1086
1087
1088/**********************************************************************/
1096float __attribute__ ((noinline)) riscv_emulate_fnmadds(float rs1, float rs2, float rs3) {
1097
1098 float opa = subnormal_flush(rs1);
1099 float opb = subnormal_flush(rs2);
1100 float opc = subnormal_flush(rs3);
1101
1102 float res = -(opa * opb) - opc;
1103 return subnormal_flush(res);
1104}
1105
1106
1107#endif // neorv32_zfinx_extension_intrinsics_h
1108
uint32_t neorv32_cpu_csr_read(const int csr_id)
Definition neorv32_cpu.h:172
void neorv32_cpu_csr_write(const int csr_id, uint32_t data)
Definition neorv32_cpu.h:186
@ CSR_FFLAGS
Definition neorv32_cpu_csr.h:25
Definition neorv32_zfinx_extension_intrinsics.h:76
uint32_t binary_value
Definition neorv32_zfinx_extension_intrinsics.h:77
float float_value
Definition neorv32_zfinx_extension_intrinsics.h:78