add testing functions to FPFormat
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 27 Jul 2019 15:02:50 +0000 (16:02 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 27 Jul 2019 15:02:50 +0000 (16:02 +0100)
src/ieee754/fclass/pipeline.py
src/ieee754/fpcommon/fpbase.py
src/ieee754/fpcommon/test/unit_test_double.py

index 6b489b2873512dc01b034d9482a27579b5c304b9..89cdcd399e62e0843d0d0396c6e304c055095138 100644 (file)
@@ -93,7 +93,7 @@ class FPClassMod(Elaboratable):
                 m.d.comb += self.o.z.eq(1<<9) # | a quiet NaN
 
         # subnormal
-        with m.Elif(a1.exp_n126): 
+        with m.Elif(a1.exp_n126 & ~a1.m_zero):
             with m.If(a1.s):
                 m.d.comb += self.o.z.eq(1<<2) # | a negative subnormal number.
             with m.Else():
index 5f7df717e374719c0b8b1ec1c2eee13feda427f0..2413a365cd65942ae68d38b55c36955ecda970f6 100644 (file)
@@ -9,6 +9,7 @@ from functools import reduce
 
 from nmutil.singlepipe import PrevControl, NextControl
 from nmutil.pipeline import ObjectProxy
+import unittest
 import math
 
 
@@ -81,16 +82,78 @@ class FPFormat:
             retval += f", {self.has_sign}"
         return retval + ")"
 
+    def get_sign(self, x):
+        """ returns the sign of its input number, x (assumes number is signed)
+        """
+        return x >> (self.e_width + self.m_width)
+
+    def get_exponent(self, x):
+        """ returns the exponent of its input number, x
+        """
+        x = ((x >> self.m_width) & self.exponent_inf_nan)
+        return x - self.exponent_bias
+
+    def get_mantissa(self, x):
+        """ returns the mantissa of its input number, x
+        """
+        return x & self.mantissa_mask
+
+    def is_zero(self, x):
+        """ returns true if x is subnormal (exp at minimum
+        """
+        e_sub = self.exponent_denormal_zero - self.exponent_bias
+        print ("e_sub", e_sub)
+        return self.get_exponent(x) == e_sub and self.get_mantissa(x) == 0
+
+    def is_subnormal(self, x):
+        """ returns true if x is subnormal (exp at minimum
+        """
+        e_sub = self.exponent_denormal_zero - self.exponent_bias
+        print ("e_sub", e_sub)
+        return self.get_exponent(x) == e_sub and self.get_mantissa(x) != 0
+
+    def is_inf(self, x):
+        """ returns true if x is infinite
+        """
+        return (self.get_exponent(x) == self.emax and
+                self.get_mantissa(x) == 0)
+
+    def is_nan(self, x):
+        """ returns true if x is nan
+        """
+        highbit = 1<<self.m_width
+        return (self.get_exponent(x) == self.emax and
+                self.get_mantissa(x) != 0 and
+                self.get_mantissa(x) & highbit == 0)
+
+    def is_nan_signalling(self, x):
+        """ returns true if x is a signalling nan
+        """
+        highbit = 1<<self.m_width
+        return (self.get_exponent(x) == self.emax and
+                self.get_mantissa(x) & highbit != 0)
+
     @property
     def width(self):
         """ Get the total number of bits in the FP format. """
         return self.has_sign + self.e_width + self.m_width
 
+    @property
+    def mantissa_mask(self):
+        """ Get the value of the exponent field designating infinity/NaN. """
+        return (1 << self.m_width) - 1
+
     @property
     def exponent_inf_nan(self):
         """ Get the value of the exponent field designating infinity/NaN. """
         return (1 << self.e_width) - 1
 
+    @property
+    def emax(self):
+        """ get the maximum exponent (minus bias)
+        """
+        return self.exponent_inf_nan - self.exponent_bias
+
     @property
     def exponent_denormal_zero(self):
         """ Get the value of the exponent field designating denormal/zero. """
@@ -117,6 +180,88 @@ class FPFormat:
         return self.m_width - self.has_int_bit
 
 
+class TestFPFormat(unittest.TestCase):
+    """ very quick test for FPFormat
+    """
+
+    def test_fpformat_fp64(self):
+        f64 = FPFormat.standard(64)
+        from sfpy import Float64
+        x = Float64(1.0).bits
+        print (hex(x))
+
+        self.assertEqual(f64.get_exponent(x), 0)
+        x = Float64(2.0).bits
+        print (hex(x))
+        self.assertEqual(f64.get_exponent(x), 1)
+
+        x = Float64(1.5).bits
+        m = f64.get_mantissa(x)
+        print (hex(x), hex(m))
+        self.assertEqual(m, 0x8000000000000)
+
+        s = f64.get_sign(x)
+        print (hex(x), hex(s))
+        self.assertEqual(s, 0)
+
+        x = Float64(-1.5).bits
+        s = f64.get_sign(x)
+        print (hex(x), hex(s))
+        self.assertEqual(s, 1)
+
+    def test_fpformat_fp32(self):
+        f32 = FPFormat.standard(32)
+        from sfpy import Float32
+        x = Float32(1.0).bits
+        print (hex(x))
+
+        self.assertEqual(f32.get_exponent(x), 0)
+        x = Float32(2.0).bits
+        print (hex(x))
+        self.assertEqual(f32.get_exponent(x), 1)
+
+        x = Float32(1.5).bits
+        m = f32.get_mantissa(x)
+        print (hex(x), hex(m))
+        self.assertEqual(m, 0x400000)
+
+        # NaN test
+        x = Float32(-1.0).sqrt()
+        x = x.bits
+        i = f32.is_nan(x)
+        print (hex(x), "nan", f32.get_exponent(x), f32.emax,
+               f32.get_mantissa(x), i)
+        self.assertEqual(i, True)
+
+        # Inf test
+        x = Float32(1e36) * Float32(1e36) * Float32(1e36)
+        x = x.bits
+        i = f32.is_inf(x)
+        print (hex(x), "inf", f32.get_exponent(x), f32.emax,
+               f32.get_mantissa(x), i)
+        self.assertEqual(i, True)
+
+        # subnormal
+        x = Float32(1e-41)
+        x = x.bits
+        i = f32.is_subnormal(x)
+        print (hex(x), "sub", f32.get_exponent(x), f32.emax,
+               f32.get_mantissa(x), i)
+        self.assertEqual(i, True)
+
+        x = Float32(0.0)
+        x = x.bits
+        i = f32.is_subnormal(x)
+        print (hex(x), "sub", f32.get_exponent(x), f32.emax,
+               f32.get_mantissa(x), i)
+        self.assertEqual(i, False)
+
+        # zero
+        i = f32.is_zero(x)
+        print (hex(x), "zero", f32.get_exponent(x), f32.emax,
+               f32.get_mantissa(x), i)
+        self.assertEqual(i, True)
+
 class MultiShiftR:
 
     def __init__(self, width):
@@ -903,3 +1048,7 @@ class FPID:
     def idsync(self, m):
         if self.id_wid is not None:
             m.d.sync += self.out_mid.eq(self.in_mid)
+
+
+if __name__ == '__main__':
+    unittest.main()
index 07d712bf36689ca4a147b6ed840deacf4ff2b3ca..7581bd859f2042e34ce5d5565f1bc93704a14f44 100644 (file)
@@ -10,19 +10,19 @@ def get_mantissa(x):
     return x & 0x000fffffffffffff
 
 def get_exponent(x):
-    return ((x & 0x7ff0000000000000) >> 52) - 1023
+    return ((x & 0x7ff0000000000000) >> 52) - (max_e-1)
 
 def set_exponent(x, e):
-    return (x & ~0x7ff0000000000000) | ((e+1023) << 52)
+    return (x & ~0x7ff0000000000000) | ((e+(max_e-1)) << 52)
 
 def get_sign(x):
     return ((x & 0x8000000000000000) >> 63)
 
 def is_nan(x):
-    return get_exponent(x) == 1024 and get_mantissa(x) != 0
+    return get_exponent(x) == max_e and get_mantissa(x) != 0
 
 def is_inf(x):
-    return get_exponent(x) == 1024 and get_mantissa(x) == 0
+    return get_exponent(x) == max_e and get_mantissa(x) == 0
 
 def is_pos_inf(x):
     return is_inf(x) and not get_sign(x)