Use RipleLSB in PartitionedXOR, and invert outputs
[ieee754fpu.git] / src / ieee754 / part_bits / xor.py
1 # SPDX-License-Identifier: LGPL-2.1-or-later
2 # See Notices.txt for copyright information
3
4 """
5 Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
6
7 dynamically-partitionable "xor" class, directly equivalent
8 to Signal.xor() 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, Mux, Repl
17 from nmigen.cli import main
18 from nmutil.ripple import RippleLSB
19
20 from ieee754.part_mul_add.partpoints import PartitionPoints
21 from ieee754.part_cmp.experiments.eq_combiner import XORCombiner
22
23
24 class PartitionedXOR(Elaboratable):
25
26 def __init__(self, width, partition_points):
27 """Create a ``PartitionedXOR`` operator
28 """
29 self.width = width
30 self.a = Signal(width, reset_less=True)
31 self.partition_points = PartitionPoints(partition_points)
32 self.mwidth = len(self.partition_points)+1
33 self.output = Signal(self.mwidth, reset_less=True)
34 if not self.partition_points.fits_in_width(width):
35 raise ValueError("partition_points doesn't fit in width")
36
37 def elaborate(self, platform):
38 m = Module()
39 comb = m.d.comb
40 m.submodules.xorc = xorc = XORCombiner(self.mwidth)
41
42 # make a series of "xor", splitting a and b into partition chunks
43 xors = Signal(self.mwidth, reset_less=True)
44 xorl = []
45 keys = list(self.partition_points.keys()) + [self.width]
46 start = 0
47 for i in range(len(keys)):
48 end = keys[i]
49 xorl.append(self.a[start:end].xor())
50 start = end # for next time round loop
51 comb += xors.eq(Cat(*xorl))
52
53 # put the partial results through the combiner
54 comb += xorc.gates.eq(self.partition_points.as_sig())
55 comb += xorc.neqs.eq(xors)
56
57 m.submodules.ripple = ripple = RippleLSB(self.mwidth)
58 comb += ripple.results_in.eq(xorc.outputs)
59 comb += ripple.gates.eq(self.partition_points.as_sig())
60 comb += self.output.eq(~ripple.output)
61
62 return m