1 # https://github.com/antonblanchard/microwatt/blob/master/countzero.vhdl
2 from nmigen
import Memory
, Module
, Signal
, Cat
, Elaboratable
3 from nmigen
.hdl
.rec
import Record
, Layout
4 from nmigen
.cli
import main
8 return Cat(a
.any(), b
.any(), c
.any(), d
.any())
11 class IntermediateResult(Record
):
12 def __init__(self
, name
=None):
13 layout
= (('v16', 15),
17 Record
.__init
__(self
, Layout(layout
), name
=name
)
20 class ZeroCounter(Elaboratable
):
22 self
.rs_i
= Signal(64, reset_less
=True)
23 self
.count_right_i
= Signal(1, reset_less
=True)
24 self
.is_32bit_i
= Signal(1, reset_less
=True)
25 self
.result_o
= Signal(64, reset_less
=True)
28 return [self
.rs_i
, self
.count_right_i
, self
.is_32bit_i
, self
.result_o
]
30 def elaborate(self
, platform
):
33 # TODO: replace this with m.submodule.pe1 = PriorityEncoder(4)
34 # m.submodule.pe2 = PriorityEncoder(4)
35 # m.submodule.pe3 = PriorityEncoder(4)
37 # and where right will assign input to v and !right will assign v[::-1]
38 # so as to reverse the order of the input bits.
40 def encoder(v
, right
):
42 Return the index of the leftmost or rightmost 1 in a set of 4 bits.
43 Assumes v is not "0000"; if it is, return (right ? "11" : "00").
45 ret
= Signal(2, reset_less
=True)
66 r
= IntermediateResult()
67 r_in
= IntermediateResult()
69 m
.d
.comb
+= r
.eq(r_in
) # make the module entirely combinatorial for now
71 v
= IntermediateResult()
72 y
= Signal(4, reset_less
=True)
73 z
= Signal(4, reset_less
=True)
74 sel
= Signal(6, reset_less
=True)
75 v4
= Signal(4, reset_less
=True)
77 # Test 4 groups of 16 bits each.
78 # The top 2 groups are considered to be zero in 32-bit mode.
79 m
.d
.comb
+= z
.eq(or4(self
.rs_i
[0:16], self
.rs_i
[16:32],
80 self
.rs_i
[32:48], self
.rs_i
[48:64]))
81 with m
.If(self
.is_32bit_i
):
82 m
.d
.comb
+= v
.sel_hi
[1].eq(0)
83 with m
.If(self
.count_right_i
):
84 m
.d
.comb
+= v
.sel_hi
[0].eq(~z
[0])
86 m
.d
.comb
+= v
.sel_hi
[0].eq(z
[1])
88 m
.d
.comb
+= v
.sel_hi
.eq(encoder(z
, self
.count_right_i
))
90 # Select the leftmost/rightmost non-zero group of 16 bits
91 with m
.Switch(v
.sel_hi
):
93 m
.d
.comb
+= v
.v16
.eq(self
.rs_i
[0:16])
95 m
.d
.comb
+= v
.v16
.eq(self
.rs_i
[16:32])
97 m
.d
.comb
+= v
.v16
.eq(self
.rs_i
[32:48])
99 m
.d
.comb
+= v
.v16
.eq(self
.rs_i
[48:64])
101 # Latch this and do the rest in the next cycle, for the sake of timing
102 m
.d
.comb
+= v
.is_32bit
.eq(self
.is_32bit_i
)
103 m
.d
.comb
+= v
.count_right
.eq(self
.count_right_i
)
104 m
.d
.comb
+= r_in
.eq(v
)
105 m
.d
.comb
+= sel
[4:6].eq(r
.sel_hi
)
107 # Test 4 groups of 4 bits
108 m
.d
.comb
+= y
.eq(or4(r
.v16
[0:4], r
.v16
[4:8],
109 r
.v16
[8:12], r
.v16
[12:16]))
110 m
.d
.comb
+= sel
[2:4].eq(encoder(y
, r
.count_right
))
112 # Select the leftmost/rightmost non-zero group of 4 bits
113 with m
.Switch(sel
[2:4]):
115 m
.d
.comb
+= v4
.eq(r
.v16
[0:4])
117 m
.d
.comb
+= v4
.eq(r
.v16
[4:8])
119 m
.d
.comb
+= v4
.eq(r
.v16
[8:12])
121 m
.d
.comb
+= v4
.eq(r
.v16
[12:16])
123 m
.d
.comb
+= sel
[0:2].eq(encoder(v4
, r
.count_right
))
125 # sel is now the index of the leftmost/rightmost 1 bit in rs
128 # operand is zero, return 32 for 32-bit, else 64
129 m
.d
.comb
+= o
[5:7].eq(Cat(r
.is_32bit
, ~r
.is_32bit
))
130 with m
.Elif(r
.count_right
):
131 # return (63 - sel), trimmed to 5 bits in 32-bit mode
132 m
.d
.comb
+= o
.eq(Cat(~sel
[0:5], ~
(sel
[5] | r
.is_32bit
)))
134 m
.d
.comb
+= o
.eq(sel
)