move unused partitioned comparison modules to experiments/
authorMichael Nolan <mtnolan2640@gmail.com>
Wed, 5 Feb 2020 15:54:24 +0000 (10:54 -0500)
committerMichael Nolan <mtnolan2640@gmail.com>
Wed, 5 Feb 2020 23:11:28 +0000 (18:11 -0500)
src/ieee754/part_cmp/equal.py [deleted file]
src/ieee754/part_cmp/equal_ortree.py [deleted file]
src/ieee754/part_cmp/experiments/equal.py [new file with mode: 0644]
src/ieee754/part_cmp/experiments/equal_ortree.py [new file with mode: 0644]
src/ieee754/part_cmp/experiments/formal/proof_equal.py [new file with mode: 0644]
src/ieee754/part_cmp/experiments/ge.py [new file with mode: 0644]
src/ieee754/part_cmp/formal/proof_equal.py [deleted file]
src/ieee754/part_cmp/ge.py [deleted file]

diff --git a/src/ieee754/part_cmp/equal.py b/src/ieee754/part_cmp/equal.py
deleted file mode 100644 (file)
index 21bd0e2..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-# SPDX-License-Identifier: LGPL-2.1-or-later
-# See Notices.txt for copyright information
-
-"""
-Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
-
-dynamically-partitionable "comparison" class, directly equivalent
-to Signal.__eq__ except SIMD-partitionable
-
-See:
-
-* http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/eq
-* http://bugs.libre-riscv.org/show_bug.cgi?id=132
-"""
-
-from nmigen import Signal, Module, Elaboratable, Cat, C, Mux, Repl
-from nmigen.cli import main
-
-from ieee754.part_mul_add.partpoints import PartitionPoints
-
-class PartitionedEq(Elaboratable):
-
-    def __init__(self, width, partition_points):
-        """Create a ``PartitionedEq`` operator
-        """
-        self.width = width
-        self.a = Signal(width, reset_less=True)
-        self.b = 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
-
-        # ok first thing to note, before reading this (read the wiki page
-        # first), according to boolean algebra, these two are equivalent:
-        # (~[~eq0, ~eq1, ~eq2].bool()) is the same as (eq0 AND eq1 AND eq2)
-        # where bool() is the *OR* of all bits in the list.
-        #
-        # given that ~eqN is neN (not equal), we first create a series
-        # of != comparisons on the partitions, then chain the relevant
-        # ones together depending on partition points, BOOL those together
-        # and invert the result.
-        #
-        # the outer loop is on the partition value.  the preparation phase
-        # (idx array) is to work out how and when the eqs (ne's) are to be
-        # chained together.  finally an inner loop - one per bit - grabs
-        # each chain, on a per-output-bit basis.
-        #
-        # the result is that for each partition-point permutation you get
-        # a different set of output results for each bit.  it's... messy
-        # but functional.
-
-        # prepare the output bits (name them for convenience)
-        eqsigs = []
-        for i in range(self.mwidth):
-            eqsig = Signal(name="eqsig%d"%i, reset_less=True)
-            eqsigs.append(eqsig)
-
-        # make a series of "not-eqs", splitting a and b into partition chunks
-        nes = Signal(self.mwidth, reset_less=True)
-        nel = []
-        keys = list(self.partition_points.keys()) + [self.width]
-        start = 0
-        for i in range(len(keys)):
-            end = keys[i]
-            nel.append(self.a[start:end] != self.b[start:end]) # see bool below
-            start = end # for next time round loop
-        comb += nes.eq(Cat(*nel))
-
-        # now, based on the partition points, create the (multi-)boolean result
-        # this is a terrible way to do it, it's very laborious.  however it
-        # will actually "work".  optimisations come later
-
-        # we want just the partition points, as a number
-        ppoints = Signal(self.mwidth-1)
-        comb += ppoints.eq(self.partition_points.as_sig())
-
-        with m.Switch(ppoints):
-            for pval in range(1<<(self.mwidth-1)): # for each partition point
-                # identify (find-first) transition points, and how
-                # long each partition is
-                start = 0
-                count = 1
-                idx = [0] * self.mwidth
-                for ipdx in range((self.mwidth-1)):
-                    if (pval & (1<<ipdx)):
-                        idx[start] = count
-                        start = ipdx + 1
-                        count = 1
-                    else:
-                        count += 1
-                idx[start] = count # update last point (or create it)
-
-                # now for each partition combination,
-                with m.Case(pval):
-                    #print (pval, bin(pval), idx)
-                    for i in range(self.mwidth):
-                        n = "andsig_%d_%d" % (pval, i)
-                        if not idx[start]:
-                            continue
-                        ands = nes[i:i+idx[start]]
-                        andsig = Signal(len(ands), name=n, reset_less=True)
-                        ands = ands.bool() # create an AND cascade
-                        #print ("ands", pval, i, ands)
-                        comb += andsig.eq(ands)
-                        comb += eqsigs[i].eq(~andsig) # here's the inversion
-
-        # assign cascade-SIMD-compares to output
-        comb += self.output.eq(Cat(*eqsigs))
-
-        return m
diff --git a/src/ieee754/part_cmp/equal_ortree.py b/src/ieee754/part_cmp/equal_ortree.py
deleted file mode 100644 (file)
index 470fb60..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-# SPDX-License-Identifier: LGPL-2.1-or-later
-# See Notices.txt for copyright information
-
-"""
-Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
-
-dynamically-partitionable "comparison" class, directly equivalent
-to Signal.__eq__ except SIMD-partitionable
-
-See:
-
-* http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/eq
-* http://bugs.libre-riscv.org/show_bug.cgi?id=132
-"""
-
-from nmigen import Signal, Module, Elaboratable, Cat, C, Mux, Repl
-from nmigen.cli import main
-
-from ieee754.part_mul_add.partpoints import PartitionPoints
-from ieee754.part_cmp.experiments.eq_combiner import EQCombiner
-
-
-class PartitionedEq(Elaboratable):
-
-    def __init__(self, width, partition_points):
-        """Create a ``PartitionedEq`` operator
-        """
-        self.width = width
-        self.a = Signal(width, reset_less=True)
-        self.b = 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.eqc = eqc = EQCombiner(self.mwidth)
-
-        # make a series of "not-eqs", splitting a and b into partition chunks
-        nes = Signal(self.mwidth, reset_less=True)
-        nel = []
-        keys = list(self.partition_points.keys()) + [self.width]
-        start = 0
-        for i in range(len(keys)):
-            end = keys[i]
-            nel.append(self.a[start:end] != self.b[start:end])
-            start = end # for next time round loop
-        comb += nes.eq(Cat(*nel))
-
-        comb += eqc.gates.eq(self.partition_points.as_sig())
-        comb += eqc.neqs.eq(nes)
-        comb += self.output.eq(eqc.outputs)
-        
-
-        return m
diff --git a/src/ieee754/part_cmp/experiments/equal.py b/src/ieee754/part_cmp/experiments/equal.py
new file mode 100644 (file)
index 0000000..21bd0e2
--- /dev/null
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# See Notices.txt for copyright information
+
+"""
+Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+
+dynamically-partitionable "comparison" class, directly equivalent
+to Signal.__eq__ except SIMD-partitionable
+
+See:
+
+* http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/eq
+* http://bugs.libre-riscv.org/show_bug.cgi?id=132
+"""
+
+from nmigen import Signal, Module, Elaboratable, Cat, C, Mux, Repl
+from nmigen.cli import main
+
+from ieee754.part_mul_add.partpoints import PartitionPoints
+
+class PartitionedEq(Elaboratable):
+
+    def __init__(self, width, partition_points):
+        """Create a ``PartitionedEq`` operator
+        """
+        self.width = width
+        self.a = Signal(width, reset_less=True)
+        self.b = 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
+
+        # ok first thing to note, before reading this (read the wiki page
+        # first), according to boolean algebra, these two are equivalent:
+        # (~[~eq0, ~eq1, ~eq2].bool()) is the same as (eq0 AND eq1 AND eq2)
+        # where bool() is the *OR* of all bits in the list.
+        #
+        # given that ~eqN is neN (not equal), we first create a series
+        # of != comparisons on the partitions, then chain the relevant
+        # ones together depending on partition points, BOOL those together
+        # and invert the result.
+        #
+        # the outer loop is on the partition value.  the preparation phase
+        # (idx array) is to work out how and when the eqs (ne's) are to be
+        # chained together.  finally an inner loop - one per bit - grabs
+        # each chain, on a per-output-bit basis.
+        #
+        # the result is that for each partition-point permutation you get
+        # a different set of output results for each bit.  it's... messy
+        # but functional.
+
+        # prepare the output bits (name them for convenience)
+        eqsigs = []
+        for i in range(self.mwidth):
+            eqsig = Signal(name="eqsig%d"%i, reset_less=True)
+            eqsigs.append(eqsig)
+
+        # make a series of "not-eqs", splitting a and b into partition chunks
+        nes = Signal(self.mwidth, reset_less=True)
+        nel = []
+        keys = list(self.partition_points.keys()) + [self.width]
+        start = 0
+        for i in range(len(keys)):
+            end = keys[i]
+            nel.append(self.a[start:end] != self.b[start:end]) # see bool below
+            start = end # for next time round loop
+        comb += nes.eq(Cat(*nel))
+
+        # now, based on the partition points, create the (multi-)boolean result
+        # this is a terrible way to do it, it's very laborious.  however it
+        # will actually "work".  optimisations come later
+
+        # we want just the partition points, as a number
+        ppoints = Signal(self.mwidth-1)
+        comb += ppoints.eq(self.partition_points.as_sig())
+
+        with m.Switch(ppoints):
+            for pval in range(1<<(self.mwidth-1)): # for each partition point
+                # identify (find-first) transition points, and how
+                # long each partition is
+                start = 0
+                count = 1
+                idx = [0] * self.mwidth
+                for ipdx in range((self.mwidth-1)):
+                    if (pval & (1<<ipdx)):
+                        idx[start] = count
+                        start = ipdx + 1
+                        count = 1
+                    else:
+                        count += 1
+                idx[start] = count # update last point (or create it)
+
+                # now for each partition combination,
+                with m.Case(pval):
+                    #print (pval, bin(pval), idx)
+                    for i in range(self.mwidth):
+                        n = "andsig_%d_%d" % (pval, i)
+                        if not idx[start]:
+                            continue
+                        ands = nes[i:i+idx[start]]
+                        andsig = Signal(len(ands), name=n, reset_less=True)
+                        ands = ands.bool() # create an AND cascade
+                        #print ("ands", pval, i, ands)
+                        comb += andsig.eq(ands)
+                        comb += eqsigs[i].eq(~andsig) # here's the inversion
+
+        # assign cascade-SIMD-compares to output
+        comb += self.output.eq(Cat(*eqsigs))
+
+        return m
diff --git a/src/ieee754/part_cmp/experiments/equal_ortree.py b/src/ieee754/part_cmp/experiments/equal_ortree.py
new file mode 100644 (file)
index 0000000..470fb60
--- /dev/null
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# See Notices.txt for copyright information
+
+"""
+Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+
+dynamically-partitionable "comparison" class, directly equivalent
+to Signal.__eq__ except SIMD-partitionable
+
+See:
+
+* http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/eq
+* http://bugs.libre-riscv.org/show_bug.cgi?id=132
+"""
+
+from nmigen import Signal, Module, Elaboratable, Cat, C, Mux, Repl
+from nmigen.cli import main
+
+from ieee754.part_mul_add.partpoints import PartitionPoints
+from ieee754.part_cmp.experiments.eq_combiner import EQCombiner
+
+
+class PartitionedEq(Elaboratable):
+
+    def __init__(self, width, partition_points):
+        """Create a ``PartitionedEq`` operator
+        """
+        self.width = width
+        self.a = Signal(width, reset_less=True)
+        self.b = 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.eqc = eqc = EQCombiner(self.mwidth)
+
+        # make a series of "not-eqs", splitting a and b into partition chunks
+        nes = Signal(self.mwidth, reset_less=True)
+        nel = []
+        keys = list(self.partition_points.keys()) + [self.width]
+        start = 0
+        for i in range(len(keys)):
+            end = keys[i]
+            nel.append(self.a[start:end] != self.b[start:end])
+            start = end # for next time round loop
+        comb += nes.eq(Cat(*nel))
+
+        comb += eqc.gates.eq(self.partition_points.as_sig())
+        comb += eqc.neqs.eq(nes)
+        comb += self.output.eq(eqc.outputs)
+        
+
+        return m
diff --git a/src/ieee754/part_cmp/experiments/formal/proof_equal.py b/src/ieee754/part_cmp/experiments/formal/proof_equal.py
new file mode 100644 (file)
index 0000000..441a4c7
--- /dev/null
@@ -0,0 +1,106 @@
+# Proof of correctness for partitioned equals module
+# Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
+
+from nmigen import Module, Signal, Elaboratable, Mux
+from nmigen.asserts import Assert, AnyConst, Assume
+from nmigen.test.utils import FHDLTestCase
+from nmigen.cli import rtlil
+
+from ieee754.part_mul_add.partpoints import PartitionPoints
+from ieee754.part_cmp.experiments.equal_ortree import PartitionedEq
+import unittest
+
+
+# This defines a module to drive the device under test and assert
+# properties about its outputs
+class EqualsDriver(Elaboratable):
+    def __init__(self):
+        # inputs and outputs
+        pass
+
+    def get_intervals(self, signal, points):
+        start = 0
+        interval = []
+        keys = list(points.keys()) + [signal.width]
+        for key in keys:
+            end = key
+            interval.append(signal[start:end])
+            start = end
+        return interval
+
+    def elaborate(self, platform):
+        m = Module()
+        comb = m.d.comb
+        width = 32
+        mwidth = 4
+
+        # setup the inputs and outputs of the DUT as anyconst
+        a = Signal(width)
+        b = Signal(width)
+        points = PartitionPoints()
+        gates = Signal(mwidth-1)
+        for i in range(mwidth-1):
+            points[i*4+4] = gates[i]
+        out = Signal(mwidth)
+
+        comb += [a.eq(AnyConst(width)),
+                 b.eq(AnyConst(width)),
+                 gates.eq(AnyConst(mwidth-1))]
+
+        m.submodules.dut = dut = PartitionedEq(width, points)
+
+        a_intervals = self.get_intervals(a, points)
+        b_intervals = self.get_intervals(b, points)
+
+        with m.Switch(gates):
+            with m.Case(0b000):
+                comb += Assert(out == (a == b))
+            with m.Case(0b001):
+                comb += Assert(out[1] == ((a_intervals[1] == b_intervals[1]) &
+                                          (a_intervals[2] == b_intervals[2]) &
+                                          (a_intervals[3] == b_intervals[3])))
+                comb += Assert(out[0] == (a_intervals[0] == b_intervals[0]))
+            with m.Case(0b010):
+                comb += Assert(out[2] == ((a_intervals[2] == b_intervals[2]) &
+                                          (a_intervals[3] == b_intervals[3])))
+                comb += Assert(out[0] == ((a_intervals[0] == b_intervals[0]) &
+                                          (a_intervals[1] == b_intervals[1])))
+            with m.Case(0b011):
+                comb += Assert(out[2] == ((a_intervals[2] == b_intervals[2]) &
+                                          (a_intervals[3] == b_intervals[3])))
+                comb += Assert(out[0] == (a_intervals[0] == b_intervals[0]))
+                comb += Assert(out[1] == (a_intervals[1] == b_intervals[1]))
+            with m.Case(0b100):
+                comb += Assert(out[0] == ((a_intervals[0] == b_intervals[0]) &
+                                          (a_intervals[1] == b_intervals[1]) &
+                                          (a_intervals[2] == b_intervals[2])))
+                comb += Assert(out[3] == (a_intervals[3] == b_intervals[3]))
+            with m.Case(0b101):
+                comb += Assert(out[1] == ((a_intervals[1] == b_intervals[1]) &
+                                          (a_intervals[2] == b_intervals[2])))
+                comb += Assert(out[3] == (a_intervals[3] == b_intervals[3]))
+                comb += Assert(out[0] == (a_intervals[0] == b_intervals[0]))
+            with m.Case(0b110):
+                comb += Assert(out[0] == ((a_intervals[0] == b_intervals[0]) &
+                                          (a_intervals[1] == b_intervals[1])))
+                comb += Assert(out[3] == (a_intervals[3] == b_intervals[3]))
+                comb += Assert(out[2] == (a_intervals[2] == b_intervals[2]))
+            with m.Case(0b111):
+                for i in range(mwidth-1):
+                    comb += Assert(out[i] == (a_intervals[i] == b_intervals[i]))
+
+
+
+        comb += [dut.a.eq(a),
+                 dut.b.eq(b),
+                 out.eq(dut.output)]
+        return m
+
+class PartitionedEqTestCase(FHDLTestCase):
+    def test_eq(self):
+        module = EqualsDriver()
+        self.assertFormal(module, mode="bmc", depth=4)
+
+if __name__ == "__main__":
+    unittest.main()
+
diff --git a/src/ieee754/part_cmp/experiments/ge.py b/src/ieee754/part_cmp/experiments/ge.py
new file mode 100644 (file)
index 0000000..8c3efb3
--- /dev/null
@@ -0,0 +1,117 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# See Notices.txt for copyright information
+
+"""
+Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+
+dynamically-partitionable "comparison" class, directly equivalent
+to Signal.__ge__ except SIMD-partitionable
+
+See:
+
+* http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/ge
+* http://bugs.libre-riscv.org/show_bug.cgi?id=132
+"""
+
+from nmigen import Signal, Module, Elaboratable, Cat, C, Mux, Repl
+from nmigen.cli import main
+
+from ieee754.part_mul_add.partpoints import PartitionPoints
+
+def create_ge(nes, les, start, count):
+    """create a greater-than-or-equal from partitioned eqs and greaterthans
+
+        this works by doing:  lt3 |
+                             (lt2 & eq3) |
+                             (lt1 & eq3 & eq2) |
+                             (lt0 & eq3 & eq2 & eq1)
+    """
+    res = []
+    for i in range(count-1):
+        ands = [les[start+count-1]] # always one, and it's the end one
+        res.append(les[start+i])
+
+
+class PartitionedGe(Elaboratable):
+
+    def __init__(self, width, partition_points):
+        """Create a ``PartitionedGe`` operator
+        """
+        self.width = width
+        self.a = Signal(width, reset_less=True)
+        self.b = 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
+
+        # see equal.py notes
+
+        # prepare the output bits (name them for convenience)
+        gtsigs = []
+        for i in range(self.mwidth):
+            gtsig = Signal(name="gtsig%d"%i, reset_less=True)
+            gtsigs.append(gtsig)
+
+        # make series of !eqs and !gts, splitting a and b into partition chunks
+        nes = Signal(self.mwidth, reset_less=True)
+        les = Signal(self.mwidth, reset_less=True)
+        nel = []
+        lel = []
+        keys = list(self.partition_points.keys()) + [self.width]
+        start = 0
+        for i in range(len(keys)):
+            end = keys[i]
+            nel.append(self.a[start:end] != self.b[start:end]) # see bool below
+            lel.append(self.a[start:end] <= self.b[start:end]) # see bool below
+            start = end # for next time round loop
+        comb += nes.eq(Cat(*nel))
+        comb += les.eq(Cat(*nel))
+
+        # now, based on the partition points, create the (multi-)boolean result
+        # this is a terrible way to do it, it's very laborious.  however it
+        # will actually "work".  optimisations come later
+
+        # we want just the partition points, as a number
+        ppoints = Signal(self.mwidth-1)
+        comb += ppoints.eq(self.partition_points.as_sig())
+
+        with m.Switch(ppoints):
+            for pval in range(1<<(self.mwidth-1)): # for each partition point
+                # identify (find-first) transition points, and how
+                # long each partition is
+                start = 0
+                count = 1
+                idx = [0] * self.mwidth
+                for ipdx in range((self.mwidth-1)):
+                    if (pval & (1<<ipdx)):
+                        idx[start] = count
+                        start = ipdx + 1
+                        count = 1
+                    else:
+                        count += 1
+                idx[start] = count # update last point (or create it)
+
+                # now for each partition combination,
+                with m.Case(pval):
+                    #print (pval, bin(pval), idx)
+                    for i in range(self.mwidth):
+                        n = "andsig_%d_%d" % (pval, i)
+                        if not idx[start]:
+                            continue
+                        ands = create_ge(nes, les, i, idx[start])
+                        andsig = Signal(len(ands), name=n, reset_less=True)
+                        ands = ands.bool() # create an AND cascade
+                        #print ("ands", pval, i, ands)
+                        comb += andsig.eq(ands)
+                        comb += gtsigs[i].eq(~andsig) # here's the inversion
+
+        # assign cascade-SIMD-compares to output
+        comb += self.output.eq(Cat(*gtsigs))
+
+        return m
diff --git a/src/ieee754/part_cmp/formal/proof_equal.py b/src/ieee754/part_cmp/formal/proof_equal.py
deleted file mode 100644 (file)
index 52c688b..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-# Proof of correctness for partitioned equals module
-# Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
-
-from nmigen import Module, Signal, Elaboratable, Mux
-from nmigen.asserts import Assert, AnyConst, Assume
-from nmigen.test.utils import FHDLTestCase
-from nmigen.cli import rtlil
-
-from ieee754.part_mul_add.partpoints import PartitionPoints
-from ieee754.part_cmp.equal_ortree import PartitionedEq
-import unittest
-
-
-# This defines a module to drive the device under test and assert
-# properties about its outputs
-class EqualsDriver(Elaboratable):
-    def __init__(self):
-        # inputs and outputs
-        pass
-
-    def get_intervals(self, signal, points):
-        start = 0
-        interval = []
-        keys = list(points.keys()) + [signal.width]
-        for key in keys:
-            end = key
-            interval.append(signal[start:end])
-            start = end
-        return interval
-
-    def elaborate(self, platform):
-        m = Module()
-        comb = m.d.comb
-        width = 32
-        mwidth = 4
-
-        # setup the inputs and outputs of the DUT as anyconst
-        a = Signal(width)
-        b = Signal(width)
-        points = PartitionPoints()
-        gates = Signal(mwidth-1)
-        for i in range(mwidth-1):
-            points[i*4+4] = gates[i]
-        out = Signal(mwidth)
-
-        comb += [a.eq(AnyConst(width)),
-                 b.eq(AnyConst(width)),
-                 gates.eq(AnyConst(mwidth-1))]
-
-        m.submodules.dut = dut = PartitionedEq(width, points)
-
-        a_intervals = self.get_intervals(a, points)
-        b_intervals = self.get_intervals(b, points)
-
-        with m.Switch(gates):
-            with m.Case(0b000):
-                comb += Assert(out == (a == b))
-            with m.Case(0b001):
-                comb += Assert(out[1] == ((a_intervals[1] == b_intervals[1]) &
-                                          (a_intervals[2] == b_intervals[2]) &
-                                          (a_intervals[3] == b_intervals[3])))
-                comb += Assert(out[0] == (a_intervals[0] == b_intervals[0]))
-            with m.Case(0b010):
-                comb += Assert(out[2] == ((a_intervals[2] == b_intervals[2]) &
-                                          (a_intervals[3] == b_intervals[3])))
-                comb += Assert(out[0] == ((a_intervals[0] == b_intervals[0]) &
-                                          (a_intervals[1] == b_intervals[1])))
-            with m.Case(0b011):
-                comb += Assert(out[2] == ((a_intervals[2] == b_intervals[2]) &
-                                          (a_intervals[3] == b_intervals[3])))
-                comb += Assert(out[0] == (a_intervals[0] == b_intervals[0]))
-                comb += Assert(out[1] == (a_intervals[1] == b_intervals[1]))
-            with m.Case(0b100):
-                comb += Assert(out[0] == ((a_intervals[0] == b_intervals[0]) &
-                                          (a_intervals[1] == b_intervals[1]) &
-                                          (a_intervals[2] == b_intervals[2])))
-                comb += Assert(out[3] == (a_intervals[3] == b_intervals[3]))
-            with m.Case(0b101):
-                comb += Assert(out[1] == ((a_intervals[1] == b_intervals[1]) &
-                                          (a_intervals[2] == b_intervals[2])))
-                comb += Assert(out[3] == (a_intervals[3] == b_intervals[3]))
-                comb += Assert(out[0] == (a_intervals[0] == b_intervals[0]))
-            with m.Case(0b110):
-                comb += Assert(out[0] == ((a_intervals[0] == b_intervals[0]) &
-                                          (a_intervals[1] == b_intervals[1])))
-                comb += Assert(out[3] == (a_intervals[3] == b_intervals[3]))
-                comb += Assert(out[2] == (a_intervals[2] == b_intervals[2]))
-            with m.Case(0b111):
-                for i in range(mwidth-1):
-                    comb += Assert(out[i] == (a_intervals[i] == b_intervals[i]))
-
-
-
-        comb += [dut.a.eq(a),
-                 dut.b.eq(b),
-                 out.eq(dut.output)]
-        return m
-
-class PartitionedEqTestCase(FHDLTestCase):
-    def test_eq(self):
-        module = EqualsDriver()
-        self.assertFormal(module, mode="bmc", depth=4)
-
-if __name__ == "__main__":
-    unittest.main()
-
diff --git a/src/ieee754/part_cmp/ge.py b/src/ieee754/part_cmp/ge.py
deleted file mode 100644 (file)
index 8c3efb3..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-# SPDX-License-Identifier: LGPL-2.1-or-later
-# See Notices.txt for copyright information
-
-"""
-Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
-
-dynamically-partitionable "comparison" class, directly equivalent
-to Signal.__ge__ except SIMD-partitionable
-
-See:
-
-* http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/ge
-* http://bugs.libre-riscv.org/show_bug.cgi?id=132
-"""
-
-from nmigen import Signal, Module, Elaboratable, Cat, C, Mux, Repl
-from nmigen.cli import main
-
-from ieee754.part_mul_add.partpoints import PartitionPoints
-
-def create_ge(nes, les, start, count):
-    """create a greater-than-or-equal from partitioned eqs and greaterthans
-
-        this works by doing:  lt3 |
-                             (lt2 & eq3) |
-                             (lt1 & eq3 & eq2) |
-                             (lt0 & eq3 & eq2 & eq1)
-    """
-    res = []
-    for i in range(count-1):
-        ands = [les[start+count-1]] # always one, and it's the end one
-        res.append(les[start+i])
-
-
-class PartitionedGe(Elaboratable):
-
-    def __init__(self, width, partition_points):
-        """Create a ``PartitionedGe`` operator
-        """
-        self.width = width
-        self.a = Signal(width, reset_less=True)
-        self.b = 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
-
-        # see equal.py notes
-
-        # prepare the output bits (name them for convenience)
-        gtsigs = []
-        for i in range(self.mwidth):
-            gtsig = Signal(name="gtsig%d"%i, reset_less=True)
-            gtsigs.append(gtsig)
-
-        # make series of !eqs and !gts, splitting a and b into partition chunks
-        nes = Signal(self.mwidth, reset_less=True)
-        les = Signal(self.mwidth, reset_less=True)
-        nel = []
-        lel = []
-        keys = list(self.partition_points.keys()) + [self.width]
-        start = 0
-        for i in range(len(keys)):
-            end = keys[i]
-            nel.append(self.a[start:end] != self.b[start:end]) # see bool below
-            lel.append(self.a[start:end] <= self.b[start:end]) # see bool below
-            start = end # for next time round loop
-        comb += nes.eq(Cat(*nel))
-        comb += les.eq(Cat(*nel))
-
-        # now, based on the partition points, create the (multi-)boolean result
-        # this is a terrible way to do it, it's very laborious.  however it
-        # will actually "work".  optimisations come later
-
-        # we want just the partition points, as a number
-        ppoints = Signal(self.mwidth-1)
-        comb += ppoints.eq(self.partition_points.as_sig())
-
-        with m.Switch(ppoints):
-            for pval in range(1<<(self.mwidth-1)): # for each partition point
-                # identify (find-first) transition points, and how
-                # long each partition is
-                start = 0
-                count = 1
-                idx = [0] * self.mwidth
-                for ipdx in range((self.mwidth-1)):
-                    if (pval & (1<<ipdx)):
-                        idx[start] = count
-                        start = ipdx + 1
-                        count = 1
-                    else:
-                        count += 1
-                idx[start] = count # update last point (or create it)
-
-                # now for each partition combination,
-                with m.Case(pval):
-                    #print (pval, bin(pval), idx)
-                    for i in range(self.mwidth):
-                        n = "andsig_%d_%d" % (pval, i)
-                        if not idx[start]:
-                            continue
-                        ands = create_ge(nes, les, i, idx[start])
-                        andsig = Signal(len(ands), name=n, reset_less=True)
-                        ands = ands.bool() # create an AND cascade
-                        #print ("ands", pval, i, ands)
-                        comb += andsig.eq(ands)
-                        comb += gtsigs[i].eq(~andsig) # here's the inversion
-
-        # assign cascade-SIMD-compares to output
-        comb += self.output.eq(Cat(*gtsigs))
-
-        return m