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