split out logical ops into PartitionedBase
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 1 Oct 2021 21:00:19 +0000 (22:00 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 1 Oct 2021 21:00:19 +0000 (22:00 +0100)
src/ieee754/part_bits/base.py [new file with mode: 0644]
src/ieee754/part_bits/bool.py
src/ieee754/part_bits/xor.py

diff --git a/src/ieee754/part_bits/base.py b/src/ieee754/part_bits/base.py
new file mode 100644 (file)
index 0000000..c08b40d
--- /dev/null
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# See Notices.txt for copyright information
+
+"""
+Copyright (C) 2020,2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+
+dynamically-partitionable "sig" class, directly equivalent
+to Signal.sig() except SIMD-partitionable
+
+See:
+
+* http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/logicops
+* http://bugs.libre-riscv.org/show_bug.cgi?id=176
+"""
+
+from nmigen import Signal, Module, Elaboratable, Cat, C
+from nmigen.back.pysim import Simulator, Settle
+from nmigen.cli import rtlil
+from nmutil.ripple import RippleLSB
+
+from ieee754.part_mul_add.partpoints import PartitionPoints
+from ieee754.part_cmp.experiments.eq_combiner import EQCombiner
+
+
+class PartitionedBase(Elaboratable):
+
+    def __init__(self, width, partition_points, CombinerKls, operator):
+        """Create a ``PartitionedBool`` operator
+        """
+        self.width = width
+        self.a = Signal(width, reset_less=True)
+        self.partition_points = PartitionPoints(partition_points)
+        self.mwidth = len(self.partition_points)+1
+        self.output = Signal(self.mwidth, reset_less=True)
+        self.combiner_kls = CombinerKls
+        self.operator = operator
+        if not self.partition_points.fits_in_width(width):
+            raise ValueError("partition_points doesn't fit in width")
+
+    def elaborate(self, platform):
+        m = Module()
+        comb = m.d.comb
+        m.submodules.sigc = sigc = self.combiner_kls(self.mwidth)
+
+        # make a series of "sig", splitting a and b into partition chunks
+        sigs = Signal(self.mwidth, reset_less=True)
+        sigl = []
+        keys = list(self.partition_points.keys()) + [self.width]
+        start = 0
+        for i in range(len(keys)):
+            end = keys[i]
+            part = self.a[start:end]
+            part = getattr(part, self.operator)()
+            sigl.append(part)
+            start = end # for next time round loop
+        comb += sigs.eq(Cat(*sigl))
+
+        # put the partial results through the combiner
+        comb += sigc.gates.eq(self.partition_points.as_sig())
+        comb += sigc.neqs.eq(sigs)
+
+        m.submodules.ripple = ripple = RippleLSB(self.mwidth)
+        comb += ripple.results_in.eq(sigc.outputs)
+        comb += ripple.gates.eq(self.partition_points.as_sig())
+        comb += self.output.eq(~ripple.output)
+
+        return m
+
+    def ports(self):
+        return [self.a, self.output]
+
+
index 6c9e2cb6d9df763fdc61efba517b2c82e08f4fa1..ab3a8c8a2753e9821109941c422d23d4fec85e03 100644 (file)
@@ -20,50 +20,15 @@ from nmutil.ripple import RippleLSB
 
 from ieee754.part_mul_add.partpoints import PartitionPoints
 from ieee754.part_cmp.experiments.eq_combiner import EQCombiner
+from ieee754.part_bits.base import PartitionedBase
 
 
-class PartitionedBool(Elaboratable):
+class PartitionedBool(PartitionedBase):
 
     def __init__(self, width, partition_points):
         """Create a ``PartitionedBool`` operator
         """
-        self.width = width
-        self.a = Signal(width, reset_less=True)
-        self.partition_points = PartitionPoints(partition_points)
-        self.mwidth = len(self.partition_points)+1
-        self.output = Signal(self.mwidth, reset_less=True)
-        if not self.partition_points.fits_in_width(width):
-            raise ValueError("partition_points doesn't fit in width")
-
-    def elaborate(self, platform):
-        m = Module()
-        comb = m.d.comb
-        m.submodules.boolc = boolc = EQCombiner(self.mwidth)
-
-        # make a series of "bool", splitting a and b into partition chunks
-        bools = Signal(self.mwidth, reset_less=True)
-        booll = []
-        keys = list(self.partition_points.keys()) + [self.width]
-        start = 0
-        for i in range(len(keys)):
-            end = keys[i]
-            booll.append(self.a[start:end].bool())
-            start = end # for next time round loop
-        comb += bools.eq(Cat(*booll))
-
-        # put the partial results through the combiner
-        comb += boolc.gates.eq(self.partition_points.as_sig())
-        comb += boolc.neqs.eq(bools)
-
-        m.submodules.ripple = ripple = RippleLSB(self.mwidth)
-        comb += ripple.results_in.eq(boolc.outputs)
-        comb += ripple.gates.eq(self.partition_points.as_sig())
-        comb += self.output.eq(~ripple.output)
-
-        return m
-
-    def ports(self):
-        return [self.a, self.output]
+        super().__init__(width, partition_points, EQCombiner, "bool")
 
 
 if __name__ == "__main__":
index 1c0110df525908f26587f73ac1210e170422824e..85129df0896e83f539f346c1781269ca24543dd5 100644 (file)
@@ -20,50 +20,16 @@ from nmutil.ripple import RippleLSB
 
 from ieee754.part_mul_add.partpoints import PartitionPoints
 from ieee754.part_cmp.experiments.eq_combiner import XORCombiner
+from ieee754.part_bits.base import PartitionedBase
 
 
-class PartitionedXOR(Elaboratable):
+
+class PartitionedXOR(PartitionedBase):
 
     def __init__(self, width, partition_points):
         """Create a ``PartitionedXOR`` operator
         """
-        self.width = width
-        self.a = Signal(width, reset_less=True)
-        self.partition_points = PartitionPoints(partition_points)
-        self.mwidth = len(self.partition_points)+1
-        self.output = Signal(self.mwidth, reset_less=True)
-        if not self.partition_points.fits_in_width(width):
-            raise ValueError("partition_points doesn't fit in width")
-
-    def elaborate(self, platform):
-        m = Module()
-        comb = m.d.comb
-        m.submodules.xorc = xorc = XORCombiner(self.mwidth)
-
-        # make a series of "xor", splitting a and b into partition chunks
-        xors = Signal(self.mwidth, reset_less=True)
-        xorl = []
-        keys = list(self.partition_points.keys()) + [self.width]
-        start = 0
-        for i in range(len(keys)):
-            end = keys[i]
-            xorl.append(self.a[start:end].xor())
-            start = end # for next time round loop
-        comb += xors.eq(Cat(*xorl))
-
-        # put the partial results through the combiner
-        comb += xorc.gates.eq(self.partition_points.as_sig())
-        comb += xorc.neqs.eq(xors)
-
-        m.submodules.ripple = ripple = RippleLSB(self.mwidth)
-        comb += ripple.results_in.eq(xorc.outputs)
-        comb += ripple.gates.eq(self.partition_points.as_sig())
-        comb += self.output.eq(~ripple.output)
-
-        return m
-
-    def ports(self):
-        return [self.a, self.output]
+        super().__init__(width, partition_points, XORCombiner, "xor")
 
 
 if __name__ == "__main__":