add SPDX-License-Identifier comments rather than using License:
[nmutil.git] / src / nmutil / clz.py
1 # SPDX-License-Identifier: LGPL-3-or-later
2 from nmigen import Module, Signal, Elaboratable, Cat, Repl
3 import math
4 """ This module is much more efficient than PriorityEncoder
5 although it is functionally identical.
6 see https://bugs.libre-soc.org/show_bug.cgi?id=326
7
8 This work is funded through NLnet under Grant 2019-02-012
9
10 License: LGPLv3+
11
12 """
13
14
15 class CLZ(Elaboratable):
16 def __init__(self, width):
17 self.width = width
18 self.sig_in = Signal(width, reset_less=True)
19 out_width = math.ceil(math.log2(width+1))
20 self.lz = Signal(out_width)
21
22 def generate_pairs(self, m):
23 comb = m.d.comb
24 pairs = []
25 for i in range(0, self.width, 2):
26 if i+1 >= self.width:
27 pair = Signal(1, name="cnt_1_%d" % (i/2))
28 comb += pair.eq(~self.sig_in[i])
29 pairs.append((pair, 1))
30 else:
31 pair = Signal(2, name="pair%d" % i)
32 comb += pair.eq(self.sig_in[i:i+2])
33
34 pair_cnt = Signal(2, name="cnt_1_%d" % (i/2))
35 with m.Switch(pair):
36 with m.Case(0):
37 comb += pair_cnt.eq(2)
38 with m.Case(1):
39 comb += pair_cnt.eq(1)
40 with m.Default():
41 comb += pair_cnt.eq(0)
42 pairs.append((pair_cnt, 2)) # append pair, max_value
43 return pairs
44
45 def combine_pairs(self, m, iteration, pairs):
46 comb = m.d.comb
47 length = len(pairs)
48 ret = []
49 for i in range(0, length, 2):
50 if i+1 >= length:
51 right, mv = pairs[i]
52 width = right.width
53 new_pair = Signal(width, name="cnt_%d_%d" % (iteration, i))
54 comb += new_pair.eq(Cat(right, 0))
55 ret.append((new_pair, mv))
56 else:
57 left, lv = pairs[i+1]
58 right, rv = pairs[i]
59 width = right.width + 1
60 new_pair = Signal(width, name="cnt_%d_%d" % (iteration, i))
61 if rv == lv:
62 with m.If(left[-1] == 1):
63 with m.If(right[-1] == 1):
64 comb += new_pair.eq(Cat(Repl(0, width-1), 1))
65 with m.Else():
66 comb += new_pair.eq(Cat(right[0:-1], 0b01))
67 with m.Else():
68 comb += new_pair.eq(Cat(left, 0))
69 else:
70 with m.If(left == lv):
71 comb += new_pair.eq(right + left)
72 with m.Else():
73 comb += new_pair.eq(left)
74
75 ret.append((new_pair, lv+rv))
76 return ret
77
78 def elaborate(self, platform):
79 m = Module()
80 comb = m.d.comb
81
82 pairs = self.generate_pairs(m)
83 i = 2
84 while len(pairs) > 1:
85 pairs = self.combine_pairs(m, i, pairs)
86 i += 1
87
88 comb += self.lz.eq(pairs[0][0])
89
90 return m