add more tests; they all pass
authorJacob Lifshay <programmerjake@gmail.com>
Wed, 10 Jul 2019 12:19:10 +0000 (05:19 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Wed, 10 Jul 2019 12:19:10 +0000 (05:19 -0700)
src/ieee754/div_rem_sqrt_rsqrt/test_core.py

index a9a3d29fed42cfe5d37665b1346dbf1dfc4e8925..88b61326820c7e812013ee11ae1d40284cff74a6 100755 (executable)
@@ -31,6 +31,8 @@ def get_core_op(alg_op):
 
 
 class TestCaseData:
+    __test__ = False  # make pytest ignore class
+
     def __init__(self,
                  dividend,
                  divisor_radicand,
@@ -90,25 +92,74 @@ def generate_test_case(core_config, dividend, divisor_radicand, alg_op):
                        core_config)
 
 
+def shifted_ints(total_bits, int_bits):
+    """ Generate a sequence like a generalized binary version of A037124.
+
+        See https://oeis.org/A037124
+
+        Generates the sequence of all non-negative integers ``n`` in ascending
+        order with no repeats where ``n < (1 << total_bits) and n == (v << i)``
+        where ``i`` is a non-negative integer and ``v`` is a non-negative
+        integer less than ``1 << int_bits``.
+    """
+    n = 0
+    while n < (1 << total_bits):
+        yield n
+        if n < (1 << int_bits):
+            n += 1
+        else:
+            n += 1 << (n.bit_length() - int_bits)
+
+
+def partitioned_ints(bit_width):
+    """ Get ints with all 1s on one side and 0s on the other. """
+    for i in range(bit_width):
+        yield (-1 << i) & ((1 << bit_width) - 1)
+        yield (1 << (i + 1)) - 1
+
+
+class TestShiftedInts(unittest.TestCase):
+    def test(self):
+        expected = [0x000,
+                    0x001,
+                    0x002, 0x003,
+                    0x004, 0x005, 0x006, 0x007,
+                    0x008, 0x009, 0x00A, 0x00B, 0x00C, 0x00D, 0x00E, 0x00F,
+                    0x010, 0x012, 0x014, 0x016, 0x018, 0x01A, 0x01C, 0x01E,
+                    0x020, 0x024, 0x028, 0x02C, 0x030, 0x034, 0x038, 0x03C,
+                    0x040, 0x048, 0x050, 0x058, 0x060, 0x068, 0x070, 0x078,
+                    0x080, 0x090, 0x0A0, 0x0B0, 0x0C0, 0x0D0, 0x0E0, 0x0F0,
+                    0x100, 0x120, 0x140, 0x160, 0x180, 0x1A0, 0x1C0, 0x1E0,
+                    0x200, 0x240, 0x280, 0x2C0, 0x300, 0x340, 0x380, 0x3C0,
+                    0x400, 0x480, 0x500, 0x580, 0x600, 0x680, 0x700, 0x780,
+                    0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00, 0xF00]
+        self.assertEqual(list(shifted_ints(12, 4)), expected)
+
+
 def get_test_cases(core_config,
                    dividends=None,
                    divisors=None,
                    radicands=None):
     if dividends is None:
-        dividends = range(1 << (core_config.bit_width
-                                + core_config.fract_width))
+        dividend_width = core_config.bit_width + core_config.fract_width
+        dividends = [*shifted_ints(dividend_width,
+                                   max(3, core_config.log2_radix)),
+                     *partitioned_ints(dividend_width)]
     else:
         assert isinstance(dividends, list)
     if divisors is None:
-        divisors = range(1 << core_config.bit_width)
+        divisors = [*shifted_ints(core_config.bit_width,
+                                  max(3, core_config.log2_radix)),
+                    *partitioned_ints(core_config.bit_width)]
     else:
         assert isinstance(divisors, list)
     if radicands is None:
-        radicands = range(1 << core_config.bit_width)
+        radicands = [*shifted_ints(core_config.bit_width, 5),
+                     *partitioned_ints(core_config.bit_width)]
     else:
         assert isinstance(radicands, list)
 
-    for alg_op in Operation:
+    for alg_op in reversed(Operation):  # put UDivRem at end
         if alg_op is Operation.UDivRem:
             for dividend in dividends:
                 for divisor in divisors:
@@ -160,27 +211,18 @@ class DivPipeCoreTestPipeline(Elaboratable):
 
 
 class TestDivPipeCore(unittest.TestCase):
-    def handle_case(self,
-                    core_config,
-                    dividends=None,
-                    divisors=None,
-                    radicands=None,
-                    sync=True):
-        if dividends is not None:
-            dividends = list(dividends)
-        if divisors is not None:
-            divisors = list(divisors)
-        if radicands is not None:
-            radicands = list(radicands)
-
-        def gen_test_cases():
-            yield from get_test_cases(core_config,
-                                      dividends,
-                                      divisors,
-                                      radicands)
-        base_name = f"div_pipe_core_bit_width_{core_config.bit_width}"
+    def handle_config(self,
+                      core_config,
+                      test_cases=None,
+                      sync=True):
+        if test_cases is None:
+            test_cases = get_test_cases(core_config)
+        test_cases = list(test_cases)
+        base_name = f"test_div_pipe_core_bit_width_{core_config.bit_width}"
         base_name += f"_fract_width_{core_config.fract_width}"
         base_name += f"_radix_{1 << core_config.log2_radix}"
+        if not sync:
+            base_name += "_comb"
         with self.subTest(part="synthesize"):
             dut = DivPipeCoreTestPipeline(core_config, sync)
             vl = rtlil.convert(dut, ports=[*dut.i, *dut.o])
@@ -192,7 +234,7 @@ class TestDivPipeCore(unittest.TestCase):
                        gtkw_file=open(f"{base_name}.gtkw", "w"),
                        traces=[*dut.traces()]) as sim:
             def generate_process():
-                for test_case in gen_test_cases():
+                for test_case in test_cases:
                     yield Tick()
                     yield dut.i.dividend.eq(test_case.dividend)
                     yield dut.i.divisor_radicand.eq(test_case.divisor_radicand)
@@ -208,7 +250,7 @@ class TestDivPipeCore(unittest.TestCase):
                     yield
 
                 # now synched with generator
-                for test_case in gen_test_cases():
+                for test_case in test_cases:
                     yield Tick()
                     yield Delay(0.9e-6)
                     quotient_root = (yield dut.o.quotient_root)
@@ -222,19 +264,49 @@ class TestDivPipeCore(unittest.TestCase):
             sim.add_sync_process(check_process)
             sim.run()
 
-    def test_bit_width_8_fract_width_4_radix_2(self):
-        self.handle_case(DivPipeCoreConfig(bit_width=8,
-                                           fract_width=4,
-                                           log2_radix=1),
-                         dividends=[*range(1 << 8),
-                                    *range(1 << 8, 1 << 12, 1 << 4)],
-                         sync=False)
+    def test_bit_width_2_fract_width_1_radix_2_comb(self):
+        self.handle_config(DivPipeCoreConfig(bit_width=2,
+                                             fract_width=1,
+                                             log2_radix=1),
+                           sync=False)
 
     def test_bit_width_2_fract_width_1_radix_2(self):
-        self.handle_case(DivPipeCoreConfig(bit_width=2,
-                                           fract_width=1,
-                                           log2_radix=1),
-                         sync=False)
+        self.handle_config(DivPipeCoreConfig(bit_width=2,
+                                             fract_width=1,
+                                             log2_radix=1))
+
+    def test_bit_width_8_fract_width_4_radix_2_comb(self):
+        self.handle_config(DivPipeCoreConfig(bit_width=8,
+                                             fract_width=4,
+                                             log2_radix=1),
+                           sync=False)
+
+    def test_bit_width_8_fract_width_4_radix_2(self):
+        self.handle_config(DivPipeCoreConfig(bit_width=8,
+                                             fract_width=4,
+                                             log2_radix=1))
+
+    def test_bit_width_32_fract_width_24_radix_8_comb(self):
+        self.handle_config(DivPipeCoreConfig(bit_width=32,
+                                             fract_width=24,
+                                             log2_radix=3),
+                           sync=False)
+
+    def test_bit_width_32_fract_width_24_radix_8(self):
+        self.handle_config(DivPipeCoreConfig(bit_width=32,
+                                             fract_width=24,
+                                             log2_radix=3))
+
+    def test_bit_width_32_fract_width_28_radix_8_comb(self):
+        self.handle_config(DivPipeCoreConfig(bit_width=32,
+                                             fract_width=28,
+                                             log2_radix=3),
+                           sync=False)
+
+    def test_bit_width_32_fract_width_28_radix_8(self):
+        self.handle_config(DivPipeCoreConfig(bit_width=32,
+                                             fract_width=28,
+                                             log2_radix=3))
 
     # FIXME: add more test_* functions