1 # SPDX-License-Identifier: LGPL-3-or-later
2 from nmigen
import Module
, Signal
, Elaboratable
, Cat
, Repl
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
8 This work is funded through NLnet under Grant 2019-02-012
16 """count leading zeros."""
17 assert isinstance(width
, int) and 0 <= width
18 max_v
= (1 << width
) - 1
19 assert isinstance(v
, int) and 0 <= v
<= max_v
20 return max_v
.bit_length() - v
.bit_length()
23 class CLZ(Elaboratable
):
24 def __init__(self
, width
):
26 self
.sig_in
= Signal(width
, reset_less
=True)
27 out_width
= math
.ceil(math
.log2(width
+1))
28 self
.lz
= Signal(out_width
)
30 def generate_pairs(self
, m
):
33 for i
in range(0, self
.width
, 2):
35 pair
= Signal(1, name
="cnt_1_%d" % (i
/2))
36 comb
+= pair
.eq(~self
.sig_in
[i
])
37 pairs
.append((pair
, 1))
39 pair
= Signal(2, name
="pair%d" % i
)
40 comb
+= pair
.eq(self
.sig_in
[i
:i
+2])
42 pair_cnt
= Signal(2, name
="cnt_1_%d" % (i
/2))
45 comb
+= pair_cnt
.eq(2)
47 comb
+= pair_cnt
.eq(1)
49 comb
+= pair_cnt
.eq(0)
50 pairs
.append((pair_cnt
, 2)) # append pair, max_value
53 def combine_pairs(self
, m
, iteration
, pairs
):
57 for i
in range(0, length
, 2):
61 new_pair
= Signal(width
, name
="cnt_%d_%d" % (iteration
, i
))
62 comb
+= new_pair
.eq(Cat(right
, 0))
63 ret
.append((new_pair
, mv
))
67 width
= right
.width
+ 1
68 new_pair
= Signal(width
, name
="cnt_%d_%d" % (iteration
, i
))
70 with m
.If(left
[-1] == 1):
71 with m
.If(right
[-1] == 1):
72 comb
+= new_pair
.eq(Cat(Repl(0, width
-1), 1))
74 comb
+= new_pair
.eq(Cat(right
[0:-1], 0b01))
76 comb
+= new_pair
.eq(Cat(left
, 0))
78 with m
.If(left
== lv
):
79 comb
+= new_pair
.eq(right
+ left
)
81 comb
+= new_pair
.eq(left
)
83 ret
.append((new_pair
, lv
+rv
))
86 def elaborate(self
, platform
):
90 pairs
= self
.generate_pairs(m
)
93 pairs
= self
.combine_pairs(m
, i
, pairs
)
96 comb
+= self
.lz
.eq(pairs
[0][0])