Skip to content

Commit 7a87448

Browse files
authored
Merge pull request #334 from ShashankVM/main
Add 32-bit floating point functions and floating point addition operation
2 parents f91ce90 + 5776c64 commit 7a87448

File tree

4 files changed

+382
-5
lines changed

4 files changed

+382
-5
lines changed

arch/inst/F/fadd.s.yaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ access:
2626
vu: always
2727
data_independent_timing: true
2828
operation(): |
29-
30-
31-
29+
RoundingMode mode = rm_to_mode(X[rm], $encoding);
30+
X[fd] = f32_add(X[fs1], X[fs2], mode);
3231
3332
sail(): |
3433
{

arch/isa/fp.idl

Lines changed: 376 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)