From: Luke Kenneth Casson Leighton Date: Fri, 1 May 2020 13:29:49 +0000 (+0100) Subject: add ripple.py to nmutil X-Git-Tag: 24jan2021_ls180~66 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=95d78ac315e282297096e013d3dc2d403b22723b;p=nmutil.git add ripple.py to nmutil --- diff --git a/src/nmutil/ripple.py b/src/nmutil/ripple.py new file mode 100644 index 0000000..0325120 --- /dev/null +++ b/src/nmutil/ripple.py @@ -0,0 +1,81 @@ +# need to ripple the starting LSB of each partition up through the +# rest of the partition. a Mux on the partition gate therefore selects +# either the current "thing" being propagated, or, if the gate is set open, +# will select the current bit from the input. +# +# this is actually a useful function, it's one of "set before first" or +# "set after first" from vector predication processing. + +from nmigen import Signal, Module, Elaboratable, Mux, Cat +from nmigen.cli import main + + +class RippleLSB(Elaboratable): + """RippleLSB + + based on a partition mask, the LSB is "rippled" (duplicated) + up to the beginning of the next partition. + """ + def __init__(self, width): + self.width = width + self.results_in = Signal(width, reset_less=True) + self.gates = Signal(width-1, reset_less=True) + self.output = Signal(width, reset_less=True) + + def elaborate(self, platform): + m = Module() + comb = m.d.comb + width = self.width + + current_result = self.results_in[0] + comb += self.output[0].eq(current_result) + + for i in range(width-1): + cur = Mux(self.gates[i], self.results_in[i+1], self.output[i]) + comb += self.output[i+1].eq(cur) + + return m + + +class MoveMSBDown(Elaboratable): + """MoveMSBDown + + based on a partition mask, moves the MSB down to the LSB position. + only the MSB is relevant, other bits are ignored. works by first + rippling the MSB across the entire partition (TODO: split that out + into its own useful module), then ANDs the (new) LSB with the + partition mask to isolate it. + """ + def __init__(self, width): + self.width = width + self.results_in = Signal(width, reset_less=True) + self.gates = Signal(width-1, reset_less=True) + self.output = Signal(width, reset_less=True) + + def elaborate(self, platform): + m = Module() + comb = m.d.comb + width = self.width + intermed = Signal(width, reset_less=True) + + # first propagate MSB down until the nearest partition gate + comb += intermed[-1].eq(self.results_in[-1]) # start at MSB + for i in range(width-2, -1, -1): + cur = Mux(self.gates[i], self.results_in[i], intermed[i+1]) + comb += intermed[i].eq(cur) + + # now only select those bits where the mask starts + out = [intermed[0]] # LSB of first part always set + for i in range(width-1): # length of partition gates + out.append(self.gates[i] & intermed[i+1]) + comb += self.output.eq(Cat(*out)) + + return m + + +if __name__ == "__main__": + # python3 ieee754/part_cmp/ripple.py generate -t il > ripple.il + # then check with yosys "read_ilang ripple.il; show top" + alu = MoveMSBDown(width=4) + main(alu, ports=[alu.results_in, alu.gates, alu.output]) +