1 # SPDX-License-Identifier: LGPL-2.1-or-later
2 # See Notices.txt for copyright information
5 Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
6 Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
8 dynamically-partitionable "comparison" class, directly equivalent
9 to Signal.__eq__, __gt__ and __ge__, except SIMD-partitionable
13 * http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/
14 * http://bugs.libre-riscv.org/show_bug.cgi?id=132
15 * http://bugs.libre-riscv.org/show_bug.cgi?id=171
18 from nmigen
import Signal
, Module
, Elaboratable
, Cat
, C
, Mux
, Repl
19 from nmigen
.back
.pysim
import Simulator
, Delay
, Settle
20 from nmigen
.cli
import main
, rtlil
22 from ieee754
.part_mul_add
.partpoints
import PartitionPoints
23 from ieee754
.part_cmp
.gt_combiner
import GTCombiner
24 from ieee754
.part_cmp
.reorder_results
import ReorderResults
25 from ieee754
.part_cmp
.ripple
import RippleLSB
28 class PartitionedEqGtGe(Elaboratable
):
33 # Expansion of the partitioned equals module to handle Greater
34 # Than and Greater than or Equal to. The function being evaluated
35 # is selected by the opcode signal, where:
39 def __init__(self
, width
, partition_points
):
40 """Create a ``PartitionedEq`` operator
43 self
.a
= Signal(width
, reset_less
=True)
44 self
.b
= Signal(width
, reset_less
=True)
45 self
.opcode
= Signal(2)
46 self
.partition_points
= PartitionPoints(partition_points
)
47 self
.mwidth
= len(self
.partition_points
)+1
48 self
.output
= Signal(self
.mwidth
, reset_less
=True)
49 assert self
.partition_points
.fits_in_width(width
), \
50 "partition_points doesn't fit in width"
52 def elaborate(self
, platform
):
55 m
.submodules
.gtc
= gtc
= GTCombiner(self
.mwidth
)
57 m
.submodules
.reorder
= reorder
= ReorderResults(self
.mwidth
)
59 # make a series of "eqs" and "gts", splitting a and b into
61 eqs
= Signal(self
.mwidth
, reset_less
=True)
63 gts
= Signal(self
.mwidth
, reset_less
=True)
66 keys
= list(self
.partition_points
.keys()) + [self
.width
]
68 for i
in range(len(keys
)):
70 eql
.append(self
.a
[start
:end
] == self
.b
[start
:end
])
71 gtl
.append(self
.a
[start
:end
] > self
.b
[start
:end
])
72 start
= end
# for next time round loop
73 comb
+= eqs
.eq(Cat(*eql
))
74 comb
+= gts
.eq(Cat(*gtl
))
76 # control the constant injected into the partition
77 # next to a closed gate
79 # enable or disable the gt input for the gt partition combiner
82 with m
.Switch(self
.opcode
):
83 with m
.Case(0b00): # equals
84 comb
+= aux_input
.eq(1)
86 with m
.Case(0b01): # greater than
87 comb
+= aux_input
.eq(0)
89 with m
.Case(0b10): # greater than or equal to
90 comb
+= aux_input
.eq(1)
93 results
= Signal(self
.mwidth
, reset_less
=True)
94 comb
+= gtc
.gates
.eq(self
.partition_points
.as_sig())
95 comb
+= gtc
.eqs
.eq(eqs
)
96 comb
+= gtc
.gts
.eq(gts
)
97 comb
+= gtc
.aux_input
.eq(aux_input
)
98 comb
+= gtc
.gt_en
.eq(gt_en
)
99 comb
+= results
.eq(gtc
.outputs
)
101 comb
+= reorder
.results_in
.eq(results
)
102 comb
+= reorder
.gates
.eq(self
.partition_points
.as_sig())
104 comb
+= self
.output
.eq(reorder
.output
)
109 return [self
.a
, self
.b
, self
.opcode
,
110 self
.partition_points
.as_sig(),
113 if __name__
== "__main__":
114 from ieee754
.part_mul_add
.partpoints
import make_partition
117 m
.submodules
.egg
= egg
= PartitionedEqGtGe(16, make_partition(mask
, 16))
123 yield egg
.a
.eq(0xf000)
125 yield egg
.opcode
.eq(0b00)
127 out
= yield egg
.output
128 print("out", bin(out
))
130 yield egg
.a
.eq(0x0000)
134 yield egg
.a
.eq(0x0000)
137 out
= yield egg
.output
138 print("out", bin(out
))
140 sim
.add_process(process
)
141 with sim
.write_vcd("eq_gt_ge.vcd", "eq_gt_ge.gtkw", traces
=egg
.ports()):