whitespace
[ieee754fpu.git] / src / ieee754 / part_cmp / eq_gt_ge.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 "comparison" class, directly equivalent
8 to Signal.__eq__ except SIMD-partitionable
9
10 See:
11
12 * http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/eq
13 * http://bugs.libre-riscv.org/show_bug.cgi?id=132
14 """
15
16 from nmigen import Signal, Module, Elaboratable, Cat, C, Mux, Repl
17 from nmigen.cli import main
18
19 from ieee754.part_mul_add.partpoints import PartitionPoints
20 from ieee754.part_cmp.experiments.gt_combiner import GTCombiner
21
22
23 class PartitionedEqGtGe(Elaboratable):
24
25 # Expansion of the partitioned equals module to handle Greater
26 # Than and Greater than or Equal to. The function being evaluated
27 # is selected by the opcode signal, where:
28 # opcode 0x00 - EQ
29 # opcode 0x01 - GT
30 # opcode 0x02 - GE
31 def __init__(self, width, partition_points):
32 """Create a ``PartitionedEq`` operator
33 """
34 self.width = width
35 self.a = Signal(width, reset_less=True)
36 self.b = Signal(width, reset_less=True)
37 self.opcode = Signal(2)
38 self.partition_points = PartitionPoints(partition_points)
39 self.mwidth = len(self.partition_points)+1
40 self.output = Signal(self.mwidth, reset_less=True)
41 if not self.partition_points.fits_in_width(width):
42 raise ValueError("partition_points doesn't fit in width")
43
44 def elaborate(self, platform):
45 m = Module()
46 comb = m.d.comb
47 m.submodules.gtc = gtc = GTCombiner(self.mwidth)
48
49 # make a series of "eqs" and "gts", splitting a and b into partition chunks
50 eqs = Signal(self.mwidth, reset_less=True)
51 eql = []
52 gts = Signal(self.mwidth, reset_less=True)
53 gtl = []
54
55 keys = list(self.partition_points.keys()) + [self.width]
56 start = 0
57 for i in range(len(keys)):
58 end = keys[i]
59 eql.append(self.a[start:end] == self.b[start:end])
60 gtl.append(self.a[start:end] > self.b[start:end])
61 start = end # for next time round loop
62 comb += eqs.eq(Cat(*eql))
63 comb += gts.eq(Cat(*gtl))
64
65 # Signal to control the constant injected into the partition next to a closed gate
66 aux_input = Signal()
67 # Signal to enable or disable the gt input for the gt partition combiner
68 gt_en = Signal()
69
70 with m.Switch(self.opcode):
71 with m.Case(0b00): # equals
72 comb += aux_input.eq(1)
73 comb += gt_en.eq(0)
74 with m.Case(0b01): # greater than
75 comb += aux_input.eq(0)
76 comb += gt_en.eq(1)
77 with m.Case(0b10): # greater than or equal to
78 comb += aux_input.eq(1)
79 comb += gt_en.eq(1)
80
81 comb += gtc.gates.eq(self.partition_points.as_sig())
82 comb += gtc.eqs.eq(eqs)
83 comb += gtc.gts.eq(gts)
84 comb += gtc.aux_input.eq(aux_input)
85 comb += gtc.gt_en.eq(gt_en)
86 comb += self.output.eq(gtc.outputs)
87
88
89 return m