@@ -485,3 +485,379 @@ function softfloat_normRoundPackToF32 {
485485 }
486486 }
487487}
488+
489+ function signF32UI {
490+ returns Bits<1>
491+ arguments
492+ Bits<32> a
493+ description {
494+ Extract sign-bit of a 32-bit floating point number
495+ }
496+ body {
497+ return a[31];
498+ }
499+ }
500+
501+ function expF32UI {
502+ returns Bits<8>
503+ arguments
504+ Bits<32> a
505+ description {
506+ Extract exponent of a 32-bit floating point number
507+ }
508+ body {
509+ return a[30:23];
510+ }
511+ }
512+
513+ function fracF32UI {
514+ returns Bits<23>
515+ arguments
516+ Bits<32> a
517+ description {
518+ Extract significand of a 32-bit floating point number
519+ }
520+ body {
521+ return a[22:0];
522+ }
523+ }
524+
525+ function returnNonSignalingNaN {
526+ returns U32
527+ arguments
528+ U32 a
529+ description {
530+ Returns a non-signalling NaN version of the floating-point number
531+ Does not modify the input
532+ }
533+ body {
534+ U32 a_copy = a;
535+ a_copy[22] = 1'b1;
536+ return a_copy;
537+ }
538+ }
539+
540+ function returnMag {
541+ returns U32
542+ arguments
543+ U32 a
544+ description {
545+ Returns magnitude of the given number
546+ Does not modify the input
547+ }
548+ body {
549+ U32 a_copy = a;
550+ # make sign bit zero
551+ a_copy[31] = 1'b0;
552+ return a_copy;
553+ }
554+ }
555+
556+ function returnLargerMag {
557+ returns U32
558+ arguments
559+ U32 a,
560+ U32 b
561+ description {
562+ Returns the larger number between a and b by magnitude
563+ If either number is signaling NaN then that is made quiet
564+ }
565+ body {
566+ U32 mag_a = returnMag(a);
567+ U32 mag_b = returnMag(b);
568+ U32 nonsig_a = returnNonSignalingNaN(a);
569+ U32 nonsig_b = returnNonSignalingNaN(b);
570+ if (mag_a < mag_b) {
571+ return nonsig_b;
572+ }
573+ if (mag_b < mag_a) {
574+ return nonsig_a;
575+ }
576+ return (nonsig_a < nonsig_b) ? nonsig_a : nonsig_b;
577+ }
578+ }
579+
580+ function softfloat_propagateNaNF32UI {
581+ returns U32
582+ arguments
583+ U32 a,
584+ U32 b
585+ description {
586+ Interpreting 'a' and 'b' as the bit patterns of two 32-bit floating-
587+ | point values, at least one of which is a NaN, returns the bit pattern of
588+ | the combined NaN result. If either 'a' or 'b' has the pattern of a
589+ | signaling NaN, the invalid exception is raised.
590+ }
591+ body {
592+ # check if a and b are signalling
593+ Boolean isSigNaN_a = is_sp_signaling_nan?(a);
594+ Boolean isSigNaN_b = is_sp_signaling_nan?(b);
595+
596+ # get non Signalling versions of a and b
597+ U32 nonsig_a = returnNonSignalingNaN(a);
598+ U32 nonsig_b = returnNonSignalingNaN(b);
599+
600+ if (isSigNaN_a || isSigNaN_b) {
601+ # raise invalid flag if either number is NaN
602+ set_fp_flag(FpFlag::NV);
603+ if ( isSigNaN_a ) {
604+ if ( isSigNaN_b ) {
605+ # if both numbers are NaN return larger magnitude and remove NaN signaling
606+ return returnLargerMag(a, b);
607+ }
608+ # if b is NaN return non signaling value of b
609+ return is_sp_nan?(b) ? nonsig_b : nonsig_a;
610+ } else {
611+ return is_sp_nan?(a) ? nonsig_a : nonsig_b;
612+ }
613+ }
614+
615+ }
616+ }
617+
618+ function softfloat_addMagsF32 {
619+ returns U32
620+ arguments
621+ U32 a,
622+ U32 b,
623+ RoundingMode mode
624+ description {
625+ Returns sum of the magnitudes of 2 floating point numbers
626+ }
627+ body {
628+
629+ # extract exponents and significands of a and b
630+ Bits<8> expA = expF32UI(a);
631+ Bits<23> sigA = fracF32UI(a);
632+ Bits<8> expB = expF32UI(b);
633+ Bits<23> sigB = fracF32UI(b);
634+
635+ # declare a variable to store significand of sum
636+ U32 sigZ;
637+ # declare a variable to store sum of the magnitudes of the 2 numbers
638+ U32 z;
639+ # declare a variable to store sign of sum
640+ Bits<1> signZ;
641+
642+ # declare a variable to store the exponent part of sum
643+ Bits<8> expZ;
644+
645+ # calculate difference of exponents
646+ Bits<8> expDiff = expA - expB;
647+
648+ if (expDiff == 8'd0) {
649+ if (expA == 8'd0) {
650+ z = a + b;
651+ return z; # if exponents of both numbers are zero, then return sum of both numbers
652+ }
653+
654+ # check if A is infinity or NaN
655+ if (expA == 8'hFF) {
656+ # A is NaN if significand is non-zero and exponent is 8'hFF
657+ if ((sigA != 8'd0) || (sigB != 8'd0)) {
658+ return softfloat_propagateNaNF32UI(a, b);
659+ }
660+ # return infinity if A is infinity
661+ return a;
662+ }
663+
664+ signZ = signF32UI(a);
665+ expZ = expA;
666+ sigZ = 32'h01000000 + sigA + sigB;
667+
668+ # check if significand is even and exponent is less than 8'FE
669+ if (((sigZ & 0x1) == 0) && (expZ < 8'hFE)) {
670+ # if significand is even, remove trailing zero
671+ sigZ = sigZ >> 1;
672+ # pack the sign, exponent and significand
673+ return (32'h0 + (signZ << 31) + (expZ << 23) + sigZ);
674+ }
675+
676+ sigZ = sigZ << 6;
677+ } else {
678+
679+ signZ = signF32UI(a);
680+
681+ U32 sigA_32 = 32'h0 + (sigA << 6);
682+ U32 sigB_32 = 32'h0 + (sigA << 6);
683+
684+ # check if B has a bigger exponent value than A
685+ if (expDiff < 0) {
686+ # check if B is infinity or NaN
687+ if (expB == 8'hFF) {
688+ # B is NaN if exponent is 8'hFF and significand is non-zero
689+ if (sigB != 0) {
690+ return softfloat_propagateNaNF32UI(a, b);
691+ }
692+ # return infinity with same sign as A
693+ return packToF32UI(signZ, 8'hFF, 23'h0);
694+ }
695+ expZ = expB;
696+
697+ sigA_32 = (expA == 0) ? 2*sigA_32 : (sigA_32 + 0x20000000);
698+ sigA_32 = softfloat_shiftRightJam32(sigA_32, (32'h0 - expDiff));
699+ } else {
700+ # check if A is infinity or NaN
701+ if (expA == 8'hFF) {
702+ # A is NaN if exponent is 8'hFF and significand is non-zero
703+ if (sigA != 0) {
704+ return softfloat_propagateNaNF32UI(a, b);
705+ }
706+ # return infinity with same sign as A
707+ return a;
708+ }
709+
710+ expZ = expA;
711+ sigB_32 = (expB == 0) ? 2*sigB_32 : (sigB_32 + 0x20000000);
712+ sigB_32 = softfloat_shiftRightJam32(sigB_32, (32'h0 + expDiff));
713+ }
714+
715+ U32 sigZ = 0x20000000 + sigA + sigB;
716+ if ( sigZ < 0x40000000 ) {
717+ expZ = expZ - 1;
718+ sigZ = sigZ << 1;
719+ }
720+ }
721+ return softfloat_roundPackToF32(signZ, expZ, sigZ[22:0], mode);
722+ }
723+ }
724+
725+ function softfloat_subMagsF32 {
726+ returns U32
727+ arguments
728+ U32 a,
729+ U32 b,
730+ RoundingMode mode
731+ description {
732+ Returns difference of the magnitudes of 2 floating point numbers
733+ }
734+ body {
735+
736+ # extract exponents and significands of a and b
737+ Bits<8> expA = expF32UI(a);
738+ Bits<23> sigA = fracF32UI(a);
739+ Bits<8> expB = expF32UI(b);
740+ Bits<23> sigB = fracF32UI(b);
741+
742+ # declare a variable to store significand of difference
743+ U32 sigZ;
744+ # declare a variable to store difference of the magnitudes of the 2 numbers
745+ U32 z;
746+ # declare a variable to store sign of difference
747+ Bits<1> signZ;
748+
749+ # declare a variable to store the exponent part of difference
750+ Bits<8> expZ;
751+
752+ # declare a variable to store the difference in significand
753+ U32 sigDiff;
754+
755+ # declare a sigX and sigY
756+ U32 sigX;
757+ U32 sigY;
758+
759+ # declare a U32 sigA and sigB
760+ U32 sigA_32;
761+ U32 sigB_32;
762+
763+ # declare a variable to store shift distance
764+ Bits<8> shiftDist;
765+
766+ # calculate difference of exponents
767+ Bits<8> expDiff = expA - expB;
768+
769+ if (expDiff == 8'd0) {
770+
771+ # check if A is infinity or NaN
772+ if (expA == 8'hFF) {
773+ # A is NaN if significand is non-zero and exponent is 8'hFF
774+ if ((sigA != 8'd0) || (sigB != 8'd0)) {
775+ return softfloat_propagateNaNF32UI(a, b);
776+ }
777+ # return infinity if A is infinity
778+ return a;
779+ }
780+
781+ sigDiff = sigA - sigB;
782+
783+ # check if no difference in significand
784+ if (sigDiff == 0) {
785+ # return -0 if rounding mode is round down, else return +0
786+ return packToF32UI(((mode == RoundingMode::RDN) ? 1 : 0),0,0);
787+ }
788+
789+ if (expA != 0) {
790+ expA = expA - 1;
791+ }
792+
793+ signZ = signF32UI(a);
794+
795+ # if difference is negative, change the sign of the result
796+ if (sigDiff < 0) {
797+ signZ = ~signZ;
798+ sigDiff = -32'sh1 * sigDiff;
799+ }
800+
801+ shiftDist = count_leading_zeros<32>(sigDiff) - 8;
802+ expZ = expA - shiftDist;
803+
804+ if (expZ < 0) {
805+ shiftDist = expA;
806+ expZ = 0;
807+ }
808+
809+ return packToF32UI(signZ, expZ, sigDiff << shiftDist);
810+
811+ } else {
812+ # when difference in exponents are not zero
813+ signZ = signF32UI(a);
814+ sigA_32 = 32'h0 + (sigA << 7);
815+ sigB_32 = 32'h0 + (sigB << 7);
816+ if (expDiff < 0) {
817+ signZ = ~signZ;
818+ if (expB == 0xFF) {
819+ if (sigB_32 != 0) {
820+ return softfloat_propagateNaNF32UI(a, b);
821+ }
822+ return packToF32UI(signZ, expB, 0);
823+ }
824+ expZ = expB - 1;
825+ sigX = sigB_32 | 0x40000000;
826+ sigY = sigA_32 + ((expA != 0) ? 0x40000000 : sigA_32);
827+ expDiff = - expDiff;
828+ } else {
829+ if (expA == 0xFF) {
830+ if (sigA_32 != 0) {
831+ return softfloat_propagateNaNF32UI(a, b);
832+ }
833+ return a;
834+ }
835+ expZ = expA - 1;
836+ sigX = sigA_32 | 0x40000000;
837+ sigY = sigB_32 + ((expB != 0) ? 0x40000000 : sigB_32);
838+ }
839+ return softfloat_normRoundPackToF32(signZ, expZ, sigX - softfloat_shiftRightJam32(sigY, expDiff), mode);
840+ }
841+ }
842+ }
843+
844+ function f32_add {
845+ returns U32
846+ arguments
847+ U32 a,
848+ U32 b,
849+ RoundingMode mode
850+ description {
851+ Returns sum of 2 floating point numbers
852+ }
853+ body {
854+ U32 a_xor_b = a ^ b;
855+ if (signF32UI(a_xor_b) == 1) {
856+ # subtract if signs are different
857+ return softfloat_subMagsF32(a,b,mode);
858+ } else {
859+ # add if signs are the same
860+ return softfloat_addMagsF32(a,b,mode);
861+ }
862+ }
863+ }
0 commit comments