From 241b958d034f486c069acdcdd757ce61990c03e7 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Fri, 1 Oct 2021 22:00:19 +0100 Subject: [PATCH] split out logical ops into PartitionedBase --- src/ieee754/part_bits/base.py | 72 +++++++++++++++++++++++++++++++++++ src/ieee754/part_bits/bool.py | 41 ++------------------ src/ieee754/part_bits/xor.py | 42 ++------------------ 3 files changed, 79 insertions(+), 76 deletions(-) create mode 100644 src/ieee754/part_bits/base.py diff --git a/src/ieee754/part_bits/base.py b/src/ieee754/part_bits/base.py new file mode 100644 index 00000000..c08b40db --- /dev/null +++ b/src/ieee754/part_bits/base.py @@ -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 + +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] + + diff --git a/src/ieee754/part_bits/bool.py b/src/ieee754/part_bits/bool.py index 6c9e2cb6..ab3a8c8a 100644 --- a/src/ieee754/part_bits/bool.py +++ b/src/ieee754/part_bits/bool.py @@ -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__": diff --git a/src/ieee754/part_bits/xor.py b/src/ieee754/part_bits/xor.py index 1c0110df..85129df0 100644 --- a/src/ieee754/part_bits/xor.py +++ b/src/ieee754/part_bits/xor.py @@ -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__": -- 2.30.2