add initial grev implementation
authorJacob Lifshay <programmerjake@gmail.com>
Fri, 10 Dec 2021 23:42:11 +0000 (15:42 -0800)
committerJacob Lifshay <programmerjake@gmail.com>
Fri, 10 Dec 2021 23:42:11 +0000 (15:42 -0800)
src/nmutil/grev.py [new file with mode: 0644]

diff --git a/src/nmutil/grev.py b/src/nmutil/grev.py
new file mode 100644 (file)
index 0000000..390b43e
--- /dev/null
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: LGPL-3-or-later
+# See Notices.txt for copyright information
+
+from nmigen.hdl.ast import Signal
+from nmigen.hdl.dsl import Module
+from nmigen.hdl.ir import Elaboratable
+
+
+class GRev(Elaboratable):
+    def __init__(self, log2_width):
+        assert isinstance(log2_width, int)
+        self.log2_width = log2_width
+        self.width = 1 << log2_width
+
+        self.input = Signal(self.width)
+        self.chunk_sizes = Signal(log2_width)
+
+        def step(i):
+            return Signal(self.width, name=f"step{i}")
+        self._steps = [step(i) for i in range(log2_width)]
+
+        self.output = Signal(self.width)
+
+    def elaborate(self, platform):
+        m = Module()
+        for i, step_o in enumerate(self._steps):
+            step_i = self.input if i == 0 else self._steps[i - 1]
+            chunk_size = 1 << i
+            with m.If(self.chunk_sizes[i]):
+                for j in range(self.width):
+                    m.d.comb += step_o[j].eq(step_i[j ^ chunk_size])
+            with m.Else():
+                m.d.comb += step_o.eq(step_i)
+        m.d.comb += self.output.eq(self._steps[-1])
+        return m