Add rudimentary test for partitioned add with carry
[ieee754fpu.git] / src / ieee754 / part / test / test_partsig.py
index c9dfcb5216e608194ab4a835fc6ae407d2c32b1c..5e5f310b361ebb70fe015f2953cc779f84fc8e54 100644 (file)
@@ -10,6 +10,12 @@ from ieee754.part.partsig import PartitionedSignal
 from ieee754.part_mux.part_mux import PMux
 
 import unittest
+import itertools
+
+
+def perms(k):
+    return map(''.join, itertools.product('01', repeat=k))
+
 
 def create_ilang(dut, traces, test_name):
     vl = rtlil.convert(dut, ports=traces)
@@ -38,6 +44,8 @@ class TestAddMod(Elaboratable):
         self.le_output = Signal(len(partpoints)+1)
         self.mux_sel = Signal(len(partpoints)+1)
         self.mux_out = Signal(width)
+        self.carry_in = Signal(len(partpoints)+1)
+        self.carry_out = Signal(len(partpoints)+1)
 
     def elaborate(self, platform):
         m = Module()
@@ -49,7 +57,9 @@ class TestAddMod(Elaboratable):
         m.d.comb += self.gt_output.eq(self.a > self.b)
         m.d.comb += self.eq_output.eq(self.a == self.b)
         m.d.comb += self.ge_output.eq(self.a >= self.b)
-        m.d.comb += self.add_output.eq(self.a + self.b)
+        add_out, add_carry = self.a.addc(self.b, self.carry_in)
+        m.d.comb += self.add_output.eq(add_out)
+        m.d.comb += self.carry_out.eq(add_carry)
         ppts = self.partpoints
         m.d.comb += self.mux_out.eq(PMux(m, ppts, self.mux_sel, self.a, self.b))
 
@@ -70,7 +80,7 @@ class TestPartitionPoints(unittest.TestCase):
                                module.eq_output],
                               "part_sig_add")
         def async_process():
-            def test_add(msg_prefix, *mask_list):
+            def test_add(msg_prefix, carry, *mask_list):
                 for a, b in [(0x0000, 0x0000),
                              (0x1234, 0x1234),
                              (0xABCD, 0xABCD),
@@ -80,20 +90,27 @@ class TestPartitionPoints(unittest.TestCase):
                              (0x0000, 0xFFFF)]:
                     yield module.a.eq(a)
                     yield module.b.eq(b)
+                    carry_sig = 0xf if carry else 0
+                    yield module.carry_in.eq(carry_sig)
                     yield Delay(0.1e-6)
                     y = 0
-                    for mask in mask_list:
-                        y |= mask & ((a & mask) + (b & mask))
+                    for i, mask in enumerate(mask_list):
+                        lsb = mask & ~(mask-1) if carry else 0
+                        y |= mask & ((a & mask) + (b & mask) + lsb)
                     outval = (yield module.add_output)
+                    print(a, b, outval, carry)
                     msg = f"{msg_prefix}: 0x{a:X} + 0x{b:X}" + \
                         f" => 0x{y:X} != 0x{outval:X}"
                     self.assertEqual(y, outval, msg)
             yield part_mask.eq(0)
-            yield from test_add("16-bit", 0xFFFF)
+            yield from test_add("16-bit", 1, 0xFFFF)
+            yield from test_add("16-bit", 0, 0xFFFF)
             yield part_mask.eq(0b10)
-            yield from test_add("8-bit", 0xFF00, 0x00FF)
+            yield from test_add("8-bit", 0, 0xFF00, 0x00FF)
+            yield from test_add("8-bit", 1, 0xFF00, 0x00FF)
             yield part_mask.eq(0b1111)
-            yield from test_add("4-bit", 0xF000, 0x0F00, 0x00F0, 0x000F)
+            yield from test_add("4-bit", 0, 0xF000, 0x0F00, 0x00F0, 0x000F)
+            yield from test_add("4-bit", 1, 0xF000, 0x0F00, 0x00F0, 0x000F)
 
             def test_ne_fn(a, b, mask):
                 return (a & mask) != (b & mask)
@@ -165,17 +182,13 @@ class TestPartitionPoints(unittest.TestCase):
                                       0b1000, 0b0100, 0b0010, 0b0001)
 
             def test_muxop(msg_prefix, *maskbit_list):
-                for a, b, sel in [(0x0000, 0x0000, 0b0110),
-                             (0x1234, 0x1234, 0b1010),
-                             (0xABCD, 0xABCD, 0b1100),
-                             (0xFFFF, 0x0000, 0b0011),
-                             (0x0000, 0x0000, 0b1001),
-                             (0xFFFF, 0xFFFF, 0b1101),
-                             (0x0000, 0xFFFF, 0b1100)]:
-                    yield module.a.eq(a)
-                    yield module.b.eq(b)
-                    yield module.mux_sel.eq(sel)
-                    yield Delay(0.1e-6)
+                for a, b in [(0x0000, 0x0000),
+                             (0x1234, 0x1234),
+                             (0xABCD, 0xABCD),
+                             (0xFFFF, 0x0000),
+                             (0x0000, 0x0000),
+                             (0xFFFF, 0xFFFF),
+                             (0x0000, 0xFFFF)]:
                     # convert to mask_list
                     mask_list = []
                     for mb in maskbit_list:
@@ -184,19 +197,35 @@ class TestPartitionPoints(unittest.TestCase):
                             if mb & (1<<i):
                                 v |= 0xf << (i*4)
                         mask_list.append(v)
-                    y = 0
-                    # do the partitioned tests
-                    for i, mask in enumerate(mask_list):
-                        if (sel & mask):
-                            y |= (a & mask)
-                        else:
-                            y |= (b & mask)
-                    # check the result
-                    outval = (yield module.mux_out)
-                    msg = f"{msg_prefix}: mux 0x{a:X} == 0x{b:X}" + \
-                        f" => 0x{y:X} != 0x{outval:X}, masklist %s"
-                    #print ((msg % str(maskbit_list)).format(locals()))
-                    self.assertEqual(y, outval, msg % str(maskbit_list))
+
+                    # TODO: sel needs to go through permutations of mask_list
+                    for p in perms(len(mask_list)):
+
+                        sel = 0
+                        selmask = 0
+                        for i, v in enumerate(p):
+                            if v == '1':
+                                sel |= maskbit_list[i]
+                                selmask |= mask_list[i]
+
+                        yield module.a.eq(a)
+                        yield module.b.eq(b)
+                        yield module.mux_sel.eq(sel)
+                        yield Delay(0.1e-6)
+                        y = 0
+                        # do the partitioned tests
+                        for i, mask in enumerate(mask_list):
+                            if (selmask & mask):
+                                y |= (a & mask)
+                            else:
+                                y |= (b & mask)
+                        # check the result
+                        outval = (yield module.mux_out)
+                        msg = f"{msg_prefix}: mux " + \
+                            f"0x{sel:X} ? 0x{a:X} : 0x{b:X}" + \
+                            f" => 0x{y:X} != 0x{outval:X}, masklist %s"
+                        #print ((msg % str(maskbit_list)).format(locals()))
+                        self.assertEqual(y, outval, msg % str(maskbit_list))
 
             yield part_mask.eq(0)
             yield from test_muxop("16-bit", 0b1111)