split out logical ops into PartitionedBase
[ieee754fpu.git] / src / ieee754 / part_bits / base.py
1 # SPDX-License-Identifier: LGPL-2.1-or-later
2 # See Notices.txt for copyright information
3
4 """
5 Copyright (C) 2020,2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
6
7 dynamically-partitionable "sig" class, directly equivalent
8 to Signal.sig() except SIMD-partitionable
9
10 See:
11
12 * http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/logicops
13 * http://bugs.libre-riscv.org/show_bug.cgi?id=176
14 """
15
16 from nmigen import Signal, Module, Elaboratable, Cat, C
17 from nmigen.back.pysim import Simulator, Settle
18 from nmigen.cli import rtlil
19 from nmutil.ripple import RippleLSB
20
21 from ieee754.part_mul_add.partpoints import PartitionPoints
22 from ieee754.part_cmp.experiments.eq_combiner import EQCombiner
23
24
25 class PartitionedBase(Elaboratable):
26
27 def __init__(self, width, partition_points, CombinerKls, operator):
28 """Create a ``PartitionedBool`` operator
29 """
30 self.width = width
31 self.a = Signal(width, reset_less=True)
32 self.partition_points = PartitionPoints(partition_points)
33 self.mwidth = len(self.partition_points)+1
34 self.output = Signal(self.mwidth, reset_less=True)
35 self.combiner_kls = CombinerKls
36 self.operator = operator
37 if not self.partition_points.fits_in_width(width):
38 raise ValueError("partition_points doesn't fit in width")
39
40 def elaborate(self, platform):
41 m = Module()
42 comb = m.d.comb
43 m.submodules.sigc = sigc = self.combiner_kls(self.mwidth)
44
45 # make a series of "sig", splitting a and b into partition chunks
46 sigs = Signal(self.mwidth, reset_less=True)
47 sigl = []
48 keys = list(self.partition_points.keys()) + [self.width]
49 start = 0
50 for i in range(len(keys)):
51 end = keys[i]
52 part = self.a[start:end]
53 part = getattr(part, self.operator)()
54 sigl.append(part)
55 start = end # for next time round loop
56 comb += sigs.eq(Cat(*sigl))
57
58 # put the partial results through the combiner
59 comb += sigc.gates.eq(self.partition_points.as_sig())
60 comb += sigc.neqs.eq(sigs)
61
62 m.submodules.ripple = ripple = RippleLSB(self.mwidth)
63 comb += ripple.results_in.eq(sigc.outputs)
64 comb += ripple.gates.eq(self.partition_points.as_sig())
65 comb += self.output.eq(~ripple.output)
66
67 return m
68
69 def ports(self):
70 return [self.a, self.output]
71
72