1 # need to ripple the starting LSB of each partition up through the
2 # rest of the partition. a Mux on the partition gate therefore selects
3 # either the current "thing" being propagated, or, if the gate is set open,
4 # will select the current bit from the input.
6 # this is actually a useful function, it's one of "set before first" or
7 # "set after first" from vector predication processing.
9 from nmigen
import Signal
, Module
, Elaboratable
, Mux
, Cat
10 from nmigen
.cli
import main
13 class RippleLSB(Elaboratable
):
16 based on a partition mask, the LSB is "rippled" (duplicated)
17 up to the beginning of the next partition.
19 def __init__(self
, width
):
21 self
.results_in
= Signal(width
, reset_less
=True)
22 self
.gates
= Signal(width
-1, reset_less
=True)
23 self
.output
= Signal(width
, reset_less
=True)
25 def elaborate(self
, platform
):
30 current_result
= self
.results_in
[0]
31 comb
+= self
.output
[0].eq(current_result
)
33 for i
in range(width
-1):
34 cur
= Mux(self
.gates
[i
], self
.results_in
[i
+1], self
.output
[i
])
35 comb
+= self
.output
[i
+1].eq(cur
)
40 class MoveMSBDown(Elaboratable
):
43 based on a partition mask, moves the MSB down to the LSB position.
44 only the MSB is relevant, other bits are ignored. works by first
45 rippling the MSB across the entire partition (TODO: split that out
46 into its own useful module), then ANDs the (new) LSB with the
47 partition mask to isolate it.
49 def __init__(self
, width
):
51 self
.results_in
= Signal(width
, reset_less
=True)
52 self
.gates
= Signal(width
-1, reset_less
=True)
53 self
.output
= Signal(width
, reset_less
=True)
55 def elaborate(self
, platform
):
59 intermed
= Signal(width
, reset_less
=True)
61 # first propagate MSB down until the nearest partition gate
62 comb
+= intermed
[-1].eq(self
.results_in
[-1]) # start at MSB
63 for i
in range(width
-2, -1, -1):
64 cur
= Mux(self
.gates
[i
], self
.results_in
[i
], intermed
[i
+1])
65 comb
+= intermed
[i
].eq(cur
)
67 # now only select those bits where the mask starts
68 out
= [intermed
[0]] # LSB of first part always set
69 for i
in range(width
-1): # length of partition gates
70 out
.append(self
.gates
[i
] & intermed
[i
+1])
71 comb
+= self
.output
.eq(Cat(*out
))
76 if __name__
== "__main__":
77 # python3 ieee754/part_cmp/ripple.py generate -t il > ripple.il
78 # then check with yosys "read_ilang ripple.il; show top"
79 alu
= MoveMSBDown(width
=4)
80 main(alu
, ports
=[alu
.results_in
, alu
.gates
, alu
.output
])