add initial grev implementation
[nmutil.git] / src / nmutil / grev.py
1 # SPDX-License-Identifier: LGPL-3-or-later
2 # See Notices.txt for copyright information
3
4 from nmigen.hdl.ast import Signal
5 from nmigen.hdl.dsl import Module
6 from nmigen.hdl.ir import Elaboratable
7
8
9 class GRev(Elaboratable):
10 def __init__(self, log2_width):
11 assert isinstance(log2_width, int)
12 self.log2_width = log2_width
13 self.width = 1 << log2_width
14
15 self.input = Signal(self.width)
16 self.chunk_sizes = Signal(log2_width)
17
18 def step(i):
19 return Signal(self.width, name=f"step{i}")
20 self._steps = [step(i) for i in range(log2_width)]
21
22 self.output = Signal(self.width)
23
24 def elaborate(self, platform):
25 m = Module()
26 for i, step_o in enumerate(self._steps):
27 step_i = self.input if i == 0 else self._steps[i - 1]
28 chunk_size = 1 << i
29 with m.If(self.chunk_sizes[i]):
30 for j in range(self.width):
31 m.d.comb += step_o[j].eq(step_i[j ^ chunk_size])
32 with m.Else():
33 m.d.comb += step_o.eq(step_i)
34 m.d.comb += self.output.eq(self._steps[-1])
35 return m