add regressions and corner cases
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 8 Jul 2019 06:38:31 +0000 (07:38 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 8 Jul 2019 06:38:31 +0000 (07:38 +0100)
src/ieee754/fpadd/test/add_data32.py
src/ieee754/fpadd/test/test_fpadd_pipe_32.py [new file with mode: 0644]
src/ieee754/fpcommon/test/case_gen.py [new file with mode: 0644]
src/ieee754/fpcommon/test/fpmux.py
src/ieee754/fpcommon/test/unit_test_single.py

index e50afdadcdab07e8619902248641ce064f885c8e..d7836365a4afd2910f1bcff6ebb47cf2c40e68bf 100644 (file)
@@ -42,7 +42,7 @@ def regressions():
     yield  0x4E5693A4, 0x42500000
     yield  0x42500000, 0x4E5693A4
 
-    yield 0x08000000, 0xff8000010
+    yield 0x08000000, 0xff800001
     yield 0x22cb525a, 0xadd79efa
     yield 0x40000000, 0xC0000000
     yield 0x83e73d5c, 0x1c800000
diff --git a/src/ieee754/fpadd/test/test_fpadd_pipe_32.py b/src/ieee754/fpadd/test/test_fpadd_pipe_32.py
new file mode 100644 (file)
index 0000000..d6cbd59
--- /dev/null
@@ -0,0 +1,31 @@
+""" test of FPADDMuxInOut
+"""
+
+from ieee754.fpadd.pipeline import (FPADDMuxInOut,)
+from ieee754.fpcommon.test.fpmux import runfp, repeat
+from ieee754.fpcommon.test.case_gen import get_corner_cases
+from ieee754.fpcommon.test import unit_test_single
+from ieee754.fpadd.test.add_data32 import regressions
+
+from sfpy import Float32
+from operator import add
+
+def test_pipe_fp32_cornercases():
+    dut = FPADDMuxInOut(32, 4)
+    vals = repeat(dut.num_rows, get_corner_cases(unit_test_single))
+    runfp(dut, 32, "test_fpadd_pipe_fp32_cornercases", Float32, add, vals=vals)
+
+def test_pipe_fp32_regressions():
+    dut = FPADDMuxInOut(32, 4)
+    vals = repeat(dut.num_rows, regressions())
+    runfp(dut, 32, "test_fpadd_pipe_fp32_regressions", Float32, add, vals=vals)
+
+def test_pipe_fp32_rand():
+    dut = FPADDMuxInOut(32, 4)
+    runfp(dut, 32, "test_fpadd_pipe_fp32_rand", Float32, add)
+
+if __name__ == '__main__':
+    test_pipe_fp32_rand()
+    test_pipe_fp32_regressions()
+    test_pipe_fp32_cornercases()
+
diff --git a/src/ieee754/fpcommon/test/case_gen.py b/src/ieee754/fpcommon/test/case_gen.py
new file mode 100644 (file)
index 0000000..0d7aa9b
--- /dev/null
@@ -0,0 +1,79 @@
+from random import randint
+from random import seed
+
+import sys
+from sfpy import Float32
+
+corner_cases = [0x80000000, 0x00000000, 0x7f800000, 0xff800000,
+                0x7fc00000, 0xffc00000]
+
+def get_corner_cases(mod):
+    #corner cases
+    from itertools import permutations
+    corner_cases = [mod.zero(1), mod.zero(0),
+                    mod.inf(1), mod.inf(0),
+                    mod.nan(1), mod.nan(0)]
+    stimulus_a = [i[0] for i in permutations(corner_cases, 2)]
+    stimulus_b = [i[1] for i in permutations(corner_cases, 2)]
+    return zip(stimulus_a, stimulus_b)
+
+
+def run_fpunit_2(dut, stimulus_a, stimulus_b, op, get_case_fn):
+    yield from run_fpunit(dut, stimulus_a, stimulus_b, op, get_case_fn)
+    yield from run_fpunit(dut, stimulus_b, stimulus_a, op, get_case_fn)
+
+def run_cases(dut, count, op, fixed_num, maxcount, get_case_fn):
+    if isinstance(fixed_num, int):
+        stimulus_a = [fixed_num for i in range(maxcount)]
+        report = hex(fixed_num)
+    else:
+        stimulus_a = fixed_num
+        report = "random"
+
+    stimulus_b = [randint(0, 1<<32) for i in range(maxcount)]
+    yield from run_fpunit_2(dut, stimulus_a, stimulus_b, op, get_case_fn)
+    count += len(stimulus_a)
+    print (count, "vectors passed 2^32", report)
+
+    # non-canonical NaNs.
+    stimulus_b = [set_exponent(randint(0, 1<<32), 128) \
+                        for i in range(maxcount)]
+    yield from run_fpunit_2(dut, stimulus_a, stimulus_b, op, get_case_fn)
+    count += len(stimulus_a)
+    print (count, "vectors passed Non-Canonical NaN", report)
+
+    # -127
+    stimulus_b = [set_exponent(randint(0, 1<<32), -127) \
+                        for i in range(maxcount)]
+    yield from run_fpunit_2(dut, stimulus_a, stimulus_b, op, get_case_fn)
+    count += len(stimulus_a)
+    print (count, "vectors passed exp=-127", report)
+
+    # nearly zero
+    stimulus_b = [set_exponent(randint(0, 1<<32), -126) \
+                        for i in range(maxcount)]
+    yield from run_fpunit_2(dut, stimulus_a, stimulus_b, op, get_case_fn)
+    count += len(stimulus_a)
+    print (count, "vectors passed exp=-126", report)
+
+    # nearly inf
+    stimulus_b = [set_exponent(randint(0, 1<<32), 127) \
+                        for i in range(maxcount)]
+    yield from run_fpunit_2(dut, stimulus_a, stimulus_b, op, get_case_fn)
+    count += len(stimulus_a)
+    print (count, "vectors passed exp=127", report)
+
+    return count
+
+def run_edge_cases(dut, count, op, get_case_fn, maxcount=10, num_loops=1000):
+    #edge cases
+    for testme in corner_cases:
+        count = yield from run_cases(dut, count, op, testme,
+                                     maxcount, get_case_fn)
+
+    for i in range(num_loops):
+        stimulus_a = [randint(0, 1<<32) for i in range(maxcount)]
+        count = yield from run_cases(dut, count, op, stimulus_a, 10,
+                                     get_case_fn)
+    return count
+
index 19967e583bfbe6e9c215a96066e62a6dcdbcae52..15441fe7ef6fd38a3f1c57d48e92a645f0f9e626 100644 (file)
@@ -30,6 +30,7 @@ class InputTest:
                     self.di[muxid][i] = (op1, )
                 else:
                     (op1, op2, ) = vals.pop(0)
+                    print ("test", hex(op1), hex(op2))
                     res = self.fpop(self.fpkls(op1), self.fpkls(op2))
                     self.di[muxid][i] = (op1, op2)
                 self.do[muxid].append(res.bits)
@@ -119,44 +120,56 @@ class InputTest:
         print ("recv ended", muxid)
 
 
-class InputTestRandom(InputTest):
-    def __init__(self, dut, width, fpkls, fpop, single_op=False, n_vals=10):
-        vals = []
-        for muxid in range(dut.num_rows):
-            for i in range(n_vals):
-                if single_op:
-                    op1 = randint(0, (1<<width)-1)
-                    #op1 = 0x40900000
-                    #op1 = 0x94607b66
-                    #op1 = 0x889cd8c
-                    #op1 = 0xe98646d7
-                    #op1 = 0x3340f2a7
-                    #op1 = 0xfff13f05
-                    #op1 = 0x453eb000
-                    #op1 = 0x3a05de50
-                    #op1 = 0xc27ff989
-                    #op1 = 0x41689000
-                    #op1 = 0xbbc0edec
-                    #op1 = 0x2EDBE6FF
-                    #op1 = 0x358637BD
-                    #op1 = 0x3340f2a7
-                    #op1 = 0x33D6BF95
-                    #op1 = 0x9885020648d8c0e8
-                    vals.append((op1,))
-                else:
-                    op1 = randint(0, (1<<width)-1)
-                    op2 = randint(0, (1<<width)-1)
-                    vals.append((op1, op2,))
+def create_random(num_rows, width, single_op=False, n_vals=10):
+    vals = []
+    for muxid in range(num_rows):
+        for i in range(n_vals):
+            if single_op:
+                op1 = randint(0, (1<<width)-1)
+                #op1 = 0x40900000
+                #op1 = 0x94607b66
+                #op1 = 0x889cd8c
+                #op1 = 0xe98646d7
+                #op1 = 0x3340f2a7
+                #op1 = 0xfff13f05
+                #op1 = 0x453eb000
+                #op1 = 0x3a05de50
+                #op1 = 0xc27ff989
+                #op1 = 0x41689000
+                #op1 = 0xbbc0edec
+                #op1 = 0x2EDBE6FF
+                #op1 = 0x358637BD
+                #op1 = 0x3340f2a7
+                #op1 = 0x33D6BF95
+                #op1 = 0x9885020648d8c0e8
+                vals.append((op1,))
+            else:
+                op1 = randint(0, (1<<width)-1)
+                op2 = randint(0, (1<<width)-1)
+                vals.append((op1, op2,))
+    return vals
 
-        InputTest.__init__(self, dut, width, fpkls, fpop, vals, single_op)
 
+def repeat(num_rows, vals):
+    """ bit of a hack: repeats the last value to create a list
+        that will be accepted by the muxer, all mux lists to be
+        of equal length
+    """
+    vals = list(vals)
+    n_to_repeat = len(vals) % num_rows
+    print (vals, vals[-1])
+    return vals + [vals[-1]] * n_to_repeat
 
-def runfp(dut, width, name, fpkls, fpop, single_op=False, n_vals=10):
+
+def runfp(dut, width, name, fpkls, fpop, single_op=False, n_vals=10, vals=None):
     vl = rtlil.convert(dut, ports=dut.ports())
     with open("%s.il" % name, "w") as f:
         f.write(vl)
 
-    test = InputTestRandom(dut, width, fpkls, fpop, single_op, n_vals)
+    if vals is None:
+        vals = create_random(dut.num_rows, width, single_op, n_vals)
+
+    test = InputTest(dut, width, fpkls, fpop, vals, single_op)
     run_simulation(dut, [test.rcv(1), test.rcv(0),
                          test.rcv(3), test.rcv(2),
                          test.send(0), test.send(1),
index 2c187d54f4d5853c2251d02f60ae55ddf3431155..601534aafedcde33c3cdd996c7d0b9dfb3804425 100644 (file)
@@ -36,14 +36,14 @@ def match(x, y):
         (x == y)
         )
 
-def create(s, e, x):
-    return (s<<31) | ((e+127) << 23) | m
+def create(s, e, m):
+    return set_exponent((s<<31) | m, e)
 
 def inf(s):
     return create(s, 128, 0)
 
 def nan(s):
-    return create(s, 128, 1<<23)
+    return create(s, 128, 1<<22)
 
 def zero(s):
     return s<<31