NEORV32 - Software Framework Documentation
Loading...
Searching...
No Matches
neorv32_zfinx_extension_intrinsics.h
Go to the documentation of this file.
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) 2024, 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#define _GNU_SOURCE
57#include <float.h>
58#include <math.h>
59
60
61/**********************************************************************/
64#if defined __riscv_f || (__riscv_flen == 32)
65 #error Application programs using the Zfinx intrinsic library have to be compiled WITHOUT the <F> MARCH ISA attribute!
66#endif
67
68
69/**********************************************************************/
72typedef union
73{
74 uint32_t binary_value;
75 float float_value;
77
78
79// ################################################################################################
80// Helper functions
81// ################################################################################################
82
83/**********************************************************************/
91float subnormal_flush(float tmp) {
92
93 float res = tmp;
94
95 // flush to zero if subnormal
96 if (fpclassify(tmp) == FP_SUBNORMAL) {
97 if (signbit(tmp) != 0) {
98 res = -0.0f;
99 }
100 else {
101 res = +0.0f;
102 }
103 }
104
105 return res;
106}
107
108
109// ################################################################################################
110// "Intrinsics"
111// ################################################################################################
112
113/**********************************************************************/
120inline float __attribute__ ((always_inline)) riscv_intrinsic_fadds(float rs1, float rs2) {
121
122 float_conv_t opa, opb, res;
123 opa.float_value = rs1;
124 opb.float_value = rs2;
125
126 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0000000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
127 return res.float_value;
128}
129
130
131/**********************************************************************/
138inline float __attribute__ ((always_inline)) riscv_intrinsic_fsubs(float rs1, float rs2) {
139
140 float_conv_t opa, opb, res;
141 opa.float_value = rs1;
142 opb.float_value = rs2;
143
144 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0000100, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
145 return res.float_value;
146}
147
148
149/**********************************************************************/
156inline float __attribute__ ((always_inline)) riscv_intrinsic_fmuls(float rs1, float rs2) {
157
158 float_conv_t opa, opb, res;
159 opa.float_value = rs1;
160 opb.float_value = rs2;
161
162 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0001000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
163 return res.float_value;
164}
165
166
167/**********************************************************************/
174inline float __attribute__ ((always_inline)) riscv_intrinsic_fmins(float rs1, float rs2) {
175
176 float_conv_t opa, opb, res;
177 opa.float_value = rs1;
178 opb.float_value = rs2;
179
180 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010100, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
181 return res.float_value;
182}
183
184
185/**********************************************************************/
192inline float __attribute__ ((always_inline)) riscv_intrinsic_fmaxs(float rs1, float rs2) {
193
194 float_conv_t opa, opb, res;
195 opa.float_value = rs1;
196 opb.float_value = rs2;
197
198 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010100, opb.binary_value, opa.binary_value, 0b001, 0b1010011);
199 return res.float_value;
200}
201
202
203/**********************************************************************/
209inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fcvt_wus(float rs1) {
210
211 float_conv_t opa;
212 opa.float_value = rs1;
213
214 return CUSTOM_INSTR_R2_TYPE(0b1100000, 0b00001, opa.binary_value, 0b000, 0b1010011);
215}
216
217
218/**********************************************************************/
224inline int32_t __attribute__ ((always_inline)) riscv_intrinsic_fcvt_ws(float rs1) {
225
226 float_conv_t opa;
227 opa.float_value = rs1;
228
229 return (int32_t)CUSTOM_INSTR_R2_TYPE(0b1100000, 0b00000, opa.binary_value, 0b000, 0b1010011);
230}
231
232
233/**********************************************************************/
239inline float __attribute__ ((always_inline)) riscv_intrinsic_fcvt_swu(uint32_t rs1) {
240
241 float_conv_t res;
242
243 res.binary_value = CUSTOM_INSTR_R2_TYPE(0b1101000, 0b00001, rs1, 0b000, 0b1010011);
244 return res.float_value;
245}
246
247
248/**********************************************************************/
254inline float __attribute__ ((always_inline)) riscv_intrinsic_fcvt_sw(int32_t rs1) {
255
256 float_conv_t res;
257
258 res.binary_value = CUSTOM_INSTR_R2_TYPE(0b1101000, 0b00000, rs1, 0b000, 0b1010011);
259 return res.float_value;
260}
261
262
263/**********************************************************************/
270inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_feqs(float rs1, float rs2) {
271
272 float_conv_t opa, opb;
273 opa.float_value = rs1;
274 opb.float_value = rs2;
275
276 return CUSTOM_INSTR_R3_TYPE(0b1010000, opb.binary_value, opa.binary_value, 0b010, 0b1010011);
277}
278
279
280/**********************************************************************/
287inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_flts(float rs1, float rs2) {
288
289 float_conv_t opa, opb;
290 opa.float_value = rs1;
291 opb.float_value = rs2;
292
293 return CUSTOM_INSTR_R3_TYPE(0b1010000, opb.binary_value, opa.binary_value, 0b001, 0b1010011);
294}
295
296
297/**********************************************************************/
304inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fles(float rs1, float rs2) {
305
306 float_conv_t opa, opb;
307 opa.float_value = rs1;
308 opb.float_value = rs2;
309
310 return CUSTOM_INSTR_R3_TYPE(0b1010000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
311}
312
313
314/**********************************************************************/
321inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjs(float rs1, float rs2) {
322
323 float_conv_t opa, opb, res;
324 opa.float_value = rs1;
325 opb.float_value = rs2;
326
327 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
328 return res.float_value;
329}
330
331
332/**********************************************************************/
339inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjns(float rs1, float rs2) {
340
341 float_conv_t opa, opb, res;
342 opa.float_value = rs1;
343 opb.float_value = rs2;
344
345 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010000, opb.binary_value, opa.binary_value, 0b001, 0b1010011);
346 return res.float_value;
347}
348
349
350/**********************************************************************/
357inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjxs(float rs1, float rs2) {
358
359 float_conv_t opa, opb, res;
360 opa.float_value = rs1;
361 opb.float_value = rs2;
362
363 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0010000, opb.binary_value, opa.binary_value, 0b010, 0b1010011);
364 return res.float_value;
365}
366
367
368/**********************************************************************/
374inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fclasss(float rs1) {
375
376 float_conv_t opa;
377 opa.float_value = rs1;
378
379 return CUSTOM_INSTR_R2_TYPE(0b1110000, 0b00000, opa.binary_value, 0b001, 0b1010011);
380}
381
382
383// ################################################################################################
384// !!! UNSUPPORTED instructions !!!
385// ################################################################################################
386
387/**********************************************************************/
396inline float __attribute__ ((always_inline)) riscv_intrinsic_fdivs(float rs1, float rs2) {
397
398 float_conv_t opa, opb, res;
399 opa.float_value = rs1;
400 opb.float_value = rs2;
401
402 res.binary_value = CUSTOM_INSTR_R3_TYPE(0b0001100, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
403 return res.float_value;
404}
405
406
407/**********************************************************************/
415inline float __attribute__ ((always_inline)) riscv_intrinsic_fsqrts(float rs1) {
416
417 float_conv_t opa, res;
418 opa.float_value = rs1;
419
420 res.binary_value = CUSTOM_INSTR_R2_TYPE(0b0101100, 0b00000, opa.binary_value, 0b000, 0b1010011);
421 return res.float_value;
422}
423
424
425/**********************************************************************/
435inline float __attribute__ ((always_inline)) riscv_intrinsic_fmadds(float rs1, float rs2, float rs3) {
436
437 float_conv_t opa, opb, opc, res;
438 opa.float_value = rs1;
439 opb.float_value = rs2;
440 opc.float_value = rs3;
441
442 res.binary_value = CUSTOM_INSTR_R4_TYPE(opc.binary_value, opb.binary_value, opa.binary_value, 0b000, 0b1000011);
443 return res.float_value;
444}
445
446
447/**********************************************************************/
457inline float __attribute__ ((always_inline)) riscv_intrinsic_fmsubs(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, 0b1000111);
465 return res.float_value;
466}
467
468
469/**********************************************************************/
479inline float __attribute__ ((always_inline)) riscv_intrinsic_fnmsubs(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, 0b1001011);
487 return res.float_value;
488}
489
490
491/**********************************************************************/
501inline float __attribute__ ((always_inline)) riscv_intrinsic_fnmadds(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, 0b1001111);
509 return res.float_value;
510}
511
512
513// ################################################################################################
514// Emulation functions
515// ################################################################################################
516
517/**********************************************************************/
524float __attribute__ ((noinline)) riscv_emulate_fadds(float rs1, float rs2) {
525
526 float opa = subnormal_flush(rs1);
527 float opb = subnormal_flush(rs2);
528
529 float res = opa + opb;
530
531 // make NAN canonical
532 if (fpclassify(res) == FP_NAN) {
533 res = NAN;
534 }
535
536 return subnormal_flush(res);
537}
538
539
540/**********************************************************************/
547float __attribute__ ((noinline)) riscv_emulate_fsubs(float rs1, float rs2) {
548
549 float opa = subnormal_flush(rs1);
550 float opb = subnormal_flush(rs2);
551
552 float res = opa - opb;
553
554 // make NAN canonical
555 if (fpclassify(res) == FP_NAN) {
556 res = NAN;
557 }
558
559 return subnormal_flush(res);
560}
561
562
563/**********************************************************************/
570float __attribute__ ((noinline)) riscv_emulate_fmuls(float rs1, float rs2) {
571
572 float opa = subnormal_flush(rs1);
573 float opb = subnormal_flush(rs2);
574
575 float res = opa * opb;
576 return subnormal_flush(res);
577}
578
579
580/**********************************************************************/
587float __attribute__ ((noinline)) riscv_emulate_fmins(float rs1, float rs2) {
588
589 float opa = subnormal_flush(rs1);
590 float opb = subnormal_flush(rs2);
591
592 union {
593 uint32_t binary_value;
594 float float_value;
595 } tmp_a, tmp_b;
596
597 if ((fpclassify(opa) == FP_NAN) && (fpclassify(opb) == FP_NAN)) {
598 return nanf("");
599 }
600
601 if (fpclassify(opa) == FP_NAN) {
602 return opb;
603 }
604
605 if (fpclassify(opb) == FP_NAN) {
606 return opa;
607 }
608
609 // RISC-V spec: -0 < +0
610 tmp_a.float_value = opa;
611 tmp_b.float_value = opb;
612 if (((tmp_a.binary_value == 0x80000000) && (tmp_b.binary_value == 0x00000000)) ||
613 ((tmp_a.binary_value == 0x00000000) && (tmp_b.binary_value == 0x80000000))) {
614 return -0.0f;
615 }
616
617 return fmin(opa, opb);
618}
619
620
621/**********************************************************************/
628float __attribute__ ((noinline)) riscv_emulate_fmaxs(float rs1, float rs2) {
629
630 float opa = subnormal_flush(rs1);
631 float opb = subnormal_flush(rs2);
632
633 union {
634 uint32_t binary_value;
635 float float_value;
636 } tmp_a, tmp_b;
637
638
639 if ((fpclassify(opa) == FP_NAN) && (fpclassify(opb) == FP_NAN)) {
640 return nanf("");
641 }
642
643 if (fpclassify(opa) == FP_NAN) {
644 return opb;
645 }
646
647 if (fpclassify(opb) == FP_NAN) {
648 return opa;
649 }
650
651 // RISC-V spec: -0 < +0
652 tmp_a.float_value = opa;
653 tmp_b.float_value = opb;
654 if (((tmp_a.binary_value == 0x80000000) && (tmp_b.binary_value == 0x00000000)) ||
655 ((tmp_a.binary_value == 0x00000000) && (tmp_b.binary_value == 0x80000000))) {
656 return +0.0f;
657 }
658
659 return fmax(opa, opb);
660}
661
662
663/**********************************************************************/
669uint32_t __attribute__ ((noinline)) riscv_emulate_fcvt_wus(float rs1) {
670
671 float opa = subnormal_flush(rs1);
672
673 return (uint32_t)rint(opa);
674}
675
676
677/**********************************************************************/
683int32_t __attribute__ ((noinline)) riscv_emulate_fcvt_ws(float rs1) {
684
685 float opa = subnormal_flush(rs1);
686
687 return (int32_t)rint(opa);
688}
689
690
691/**********************************************************************/
697float __attribute__ ((noinline)) riscv_emulate_fcvt_swu(uint32_t rs1) {
698
699 return (float)rs1;
700}
701
702
703/**********************************************************************/
709float __attribute__ ((noinline)) riscv_emulate_fcvt_sw(int32_t rs1) {
710
711 return (float)rs1;
712}
713
714
715/**********************************************************************/
722uint32_t __attribute__ ((noinline)) riscv_emulate_feqs(float rs1, float rs2) {
723
724 float opa = subnormal_flush(rs1);
725 float opb = subnormal_flush(rs2);
726
727 if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
728 return 0;
729 }
730
731 if isless(opa, opb) {
732 return 0;
733 }
734 else if isgreater(opa, opb) {
735 return 0;
736 }
737 else {
738 return 1;
739 }
740}
741
742
743/**********************************************************************/
750uint32_t __attribute__ ((noinline)) riscv_emulate_flts(float rs1, float rs2) {
751
752 float opa = subnormal_flush(rs1);
753 float opb = subnormal_flush(rs2);
754
755 if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
756 return 0;
757 }
758
759 if isless(opa, opb) {
760 return 1;
761 }
762 else {
763 return 0;
764 }
765}
766
767
768/**********************************************************************/
775uint32_t __attribute__ ((noinline)) riscv_emulate_fles(float rs1, float rs2) {
776
777 float opa = subnormal_flush(rs1);
778 float opb = subnormal_flush(rs2);
779
780 if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
781 return 0;
782 }
783
784 if islessequal(opa, opb) {
785 return 1;
786 }
787 else {
788 return 0;
789 }
790}
791
792
793/**********************************************************************/
800float __attribute__ ((noinline)) riscv_emulate_fsgnjs(float rs1, float rs2) {
801
802 float opa = rs1;
803 float opb = rs2;
804
805 int sign_1 = (int)signbit(opa);
806 int sign_2 = (int)signbit(opb);
807 float res = 0;
808
809 if (sign_2 != 0) { // opb is negative
810 if (sign_1 == 0) {
811 res = -opa;
812 }
813 else {
814 res = opa;
815 }
816 }
817 else { // opb is positive
818 if (sign_1 == 0) {
819 res = opa;
820 }
821 else {
822 res = -opa;
823 }
824 }
825
826 return res;
827}
828
829
830/**********************************************************************/
837float __attribute__ ((noinline)) riscv_emulate_fsgnjns(float rs1, float rs2) {
838
839 float opa = rs1;
840 float opb = rs2;
841
842 int sign_1 = (int)signbit(opa);
843 int sign_2 = (int)signbit(opb);
844 float res = 0;
845
846 if (sign_2 != 0) { // opb is negative
847 if (sign_1 == 0) {
848 res = opa;
849 }
850 else {
851 res = -opa;
852 }
853 }
854 else { // opb is positive
855 if (sign_1 == 0) {
856 res = -opa;
857 }
858 else {
859 res = opa;
860 }
861 }
862
863 return res;
864}
865
866
867/**********************************************************************/
874float __attribute__ ((noinline)) riscv_emulate_fsgnjxs(float rs1, float rs2) {
875
876 float opa = rs1;
877 float opb = rs2;
878
879 int sign_1 = (int)signbit(opa);
880 int sign_2 = (int)signbit(opb);
881 float res = 0;
882
883 if (((sign_1 == 0) && (sign_2 != 0)) || ((sign_1 != 0) && (sign_2 == 0))) {
884 if (sign_1 == 0) {
885 res = -opa;
886 }
887 else {
888 res = opa;
889 }
890 }
891 else {
892 if (sign_1 == 0) {
893 res = opa;
894 }
895 else {
896 res = -opa;
897 }
898 }
899
900 return res;
901}
902
903
904/**********************************************************************/
910uint32_t __attribute__ ((noinline)) riscv_emulate_fclasss(float rs1) {
911
912 float opa = rs1;
913
914 union {
915 uint32_t binary_value;
916 float float_value;
917 } aux;
918
919 // RISC-V classify result layout
920 const uint32_t CLASS_NEG_INF = 1 << 0; // negative infinity
921 const uint32_t CLASS_NEG_NORM = 1 << 1; // negative normal number
922 const uint32_t CLASS_NEG_DENORM = 1 << 2; // negative subnormal number
923 const uint32_t CLASS_NEG_ZERO = 1 << 3; // negative zero
924 const uint32_t CLASS_POS_ZERO = 1 << 4; // positive zero
925 const uint32_t CLASS_POS_DENORM = 1 << 5; // positive subnormal number
926 const uint32_t CLASS_POS_NORM = 1 << 6; // positive normal number
927 const uint32_t CLASS_POS_INF = 1 << 7; // positive infinity
928 const uint32_t CLASS_SNAN = 1 << 8; // signaling NaN (sNaN)
929 const uint32_t CLASS_QNAN = 1 << 9; // quiet NaN (qNaN)
930
931 int tmp = fpclassify(opa);
932 int sgn = (int)signbit(opa);
933
934 uint32_t res = 0;
935
936 // infinity
937 if (tmp == FP_INFINITE) {
938 if (sgn) { res |= CLASS_NEG_INF; }
939 else { res |= CLASS_POS_INF; }
940 }
941
942 // zero
943 if (tmp == FP_ZERO) {
944 if (sgn) { res |= CLASS_NEG_ZERO; }
945 else { res |= CLASS_POS_ZERO; }
946 }
947
948 // normal
949 if (tmp == FP_NORMAL) {
950 if (sgn) { res |= CLASS_NEG_NORM; }
951 else { res |= CLASS_POS_NORM; }
952 }
953
954 // subnormal
955 if (tmp == FP_SUBNORMAL) {
956 if (sgn) { res |= CLASS_NEG_DENORM; }
957 else { res |= CLASS_POS_DENORM; }
958 }
959
960 // NaN
961 if (tmp == FP_NAN) {
962 aux.float_value = opa;
963 if ((aux.binary_value >> 22) & 0b1) { // bit 22 (mantissa's MSB) is set -> canonical (quiet) NAN
964 res |= CLASS_QNAN;
965 }
966 else {
967 res |= CLASS_SNAN;
968 }
969 }
970
971 return res;
972}
973
974
975/**********************************************************************/
982float __attribute__ ((noinline)) riscv_emulate_fdivs(float rs1, float rs2) {
983
984 float opa = subnormal_flush(rs1);
985 float opb = subnormal_flush(rs2);
986
987 float res = opa / opb;
988 return subnormal_flush(res);
989}
990
991
992/**********************************************************************/
998float __attribute__ ((noinline)) riscv_emulate_fsqrts(float rs1) {
999
1000 float opa = subnormal_flush(rs1);
1001
1002 float res = sqrtf(opa);
1003 return subnormal_flush(res);
1004}
1005
1006
1007/**********************************************************************/
1017float __attribute__ ((noinline)) riscv_emulate_fmadds(float rs1, float rs2, float rs3) {
1018
1019 float opa = subnormal_flush(rs1);
1020 float opb = subnormal_flush(rs2);
1021 float opc = subnormal_flush(rs3);
1022
1023 float res = (opa * opb) + opc;
1024 return subnormal_flush(res);
1025}
1026
1027
1028/**********************************************************************/
1036float __attribute__ ((noinline)) riscv_emulate_fmsubs(float rs1, float rs2, float rs3) {
1037
1038 float opa = subnormal_flush(rs1);
1039 float opb = subnormal_flush(rs2);
1040 float opc = subnormal_flush(rs3);
1041
1042 float res = (opa * opb) - opc;
1043 return subnormal_flush(res);
1044}
1045
1046
1047/**********************************************************************/
1055float __attribute__ ((noinline)) riscv_emulate_fnmsubs(float rs1, float rs2, float rs3) {
1056
1057 float opa = subnormal_flush(rs1);
1058 float opb = subnormal_flush(rs2);
1059 float opc = subnormal_flush(rs3);
1060
1061 float res = -(opa * opb) + opc;
1062 return subnormal_flush(res);
1063}
1064
1065
1066/**********************************************************************/
1074float __attribute__ ((noinline)) riscv_emulate_fnmadds(float rs1, float rs2, float rs3) {
1075
1076 float opa = subnormal_flush(rs1);
1077 float opb = subnormal_flush(rs2);
1078 float opc = subnormal_flush(rs3);
1079
1080 float res = -(opa * opb) - opc;
1081 return subnormal_flush(res);
1082}
1083
1084
1085#endif // neorv32_zfinx_extension_intrinsics_h
1086
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