From: Michael Nolan Date: Wed, 12 Feb 2020 16:43:56 +0000 (-0500) Subject: Rename part_shift_scalar/ to part_shift X-Git-Tag: ls180-24jan2020~188 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=96b2f62147a32de33d5ac3a834ca57198f259765;p=ieee754fpu.git Rename part_shift_scalar/ to part_shift --- diff --git a/src/ieee754/part_shift/formal/.gitignore b/src/ieee754/part_shift/formal/.gitignore new file mode 100644 index 00000000..37ad79e3 --- /dev/null +++ b/src/ieee754/part_shift/formal/.gitignore @@ -0,0 +1 @@ +proof_*/** diff --git a/src/ieee754/part_shift/formal/proof_shift_dynamic.py b/src/ieee754/part_shift/formal/proof_shift_dynamic.py new file mode 100644 index 00000000..ad9e6517 --- /dev/null +++ b/src/ieee754/part_shift/formal/proof_shift_dynamic.py @@ -0,0 +1,113 @@ +# Proof of correctness for partitioned dynamic shifter +# Copyright (C) 2020 Michael Nolan + +from nmigen import Module, Signal, Elaboratable, Mux, Cat +from nmigen.asserts import Assert, AnyConst, Assume +from nmigen.test.utils import FHDLTestCase +from nmigen.cli import rtlil + +from ieee754.part_mul_add.partpoints import PartitionPoints +from ieee754.part_shift.part_shift_dynamic import \ + PartitionedDynamicShift +import unittest + + +# This defines a module to drive the device under test and assert +# properties about its outputs +class ShifterDriver(Elaboratable): + def __init__(self): + # inputs and outputs + pass + + def get_intervals(self, signal, points): + start = 0 + interval = [] + keys = list(points.keys()) + [signal.width] + for key in keys: + end = key + interval.append(signal[start:end]) + start = end + return interval + + def elaborate(self, platform): + m = Module() + comb = m.d.comb + width = 24 + mwidth = 3 + + # setup the inputs and outputs of the DUT as anyconst + a = Signal(width) + b = Signal(width) + out = Signal(width) + points = PartitionPoints() + gates = Signal(mwidth-1) + step = int(width/mwidth) + for i in range(mwidth-1): + points[(i+1)*step] = gates[i] + print(points) + + comb += [a.eq(AnyConst(width)), + b.eq(AnyConst(width)), + gates.eq(AnyConst(mwidth-1))] + + m.submodules.dut = dut = PartitionedDynamicShift(width, points) + + a_intervals = self.get_intervals(a, points) + b_intervals = self.get_intervals(b, points) + out_intervals = self.get_intervals(out, points) + + comb += [dut.a.eq(a), + dut.b.eq(b), + out.eq(dut.output)] + + + with m.Switch(points.as_sig()): + with m.Case(0b00): + comb += Assume(b < 24) + comb += Assert(out == (a< + +from nmigen import Module, Signal, Elaboratable, Mux, Cat +from nmigen.asserts import Assert, AnyConst, Assume +from nmigen.test.utils import FHDLTestCase +from nmigen.cli import rtlil + +from ieee754.part_mul_add.partpoints import PartitionPoints +from ieee754.part_shift_scalar.part_shift_scalar import PartitionedScalarShift +import unittest + + +# This defines a module to drive the device under test and assert +# properties about its outputs +class ShifterDriver(Elaboratable): + def __init__(self): + # inputs and outputs + pass + + def get_intervals(self, signal, points): + start = 0 + interval = [] + keys = list(points.keys()) + [signal.width] + for key in keys: + end = key + interval.append(signal[start:end]) + start = end + return interval + + def elaborate(self, platform): + m = Module() + comb = m.d.comb + width = 24 + shifterwidth = 5 + mwidth = 3 + + # setup the inputs and outputs of the DUT as anyconst + data = Signal(width) + out = Signal(width) + shifter = Signal(shifterwidth) + points = PartitionPoints() + gates = Signal(mwidth-1) + step = int(width/mwidth) + for i in range(mwidth-1): + points[(i+1)*step] = gates[i] + print(points) + + comb += [data.eq(AnyConst(width)), + shifter.eq(AnyConst(shifterwidth)), + gates.eq(AnyConst(mwidth-1))] + + m.submodules.dut = dut = PartitionedScalarShift(width, points) + + data_intervals = self.get_intervals(data, points) + out_intervals = self.get_intervals(out, points) + + comb += [dut.data.eq(data), + dut.shifter.eq(shifter), + out.eq(dut.output)] + + expected = Signal(width) + comb += expected.eq(data << shifter) + + with m.Switch(points.as_sig()): + with m.Case(0b00): + comb += Assert(out[0:24] == (data[0:24] << shifter) & 0xffffff) + + with m.Case(0b01): + comb += Assert(out[0:8] == expected[0:8]) + comb += Assert(out[8:24] == (data[8:24] << shifter) & 0xffff) + + with m.Case(0b10): + comb += Assert(out[16:24] == (data[16:24] << shifter) & 0xff) + comb += Assert(out[0:16] == (data[0:16] << shifter) & 0xffff) + + with m.Case(0b11): + comb += Assert(out[0:8] == expected[0:8]) + comb += Assert(out[8:16] == (data[8:16] << shifter) & 0xff) + comb += Assert(out[16:24] == (data[16:24] << shifter) & 0xff) + return m + +class PartitionedScalarShiftTestCase(FHDLTestCase): + def test_shift(self): + module = ShifterDriver() + self.assertFormal(module, mode="bmc", depth=4) + +if __name__ == "__main__": + unittest.main() + diff --git a/src/ieee754/part_shift/part_shift_dynamic.py b/src/ieee754/part_shift/part_shift_dynamic.py new file mode 100644 index 00000000..a32e5bfd --- /dev/null +++ b/src/ieee754/part_shift/part_shift_dynamic.py @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# See Notices.txt for copyright information + +""" +Copyright (C) 2020 Luke Kenneth Casson Leighton +Copyright (C) 2020 Michael Nolan + +dynamically partitionable shifter. Unlike part_shift_scalar, both +operands can be partitioned + +See: + +* http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/shift/ +* http://bugs.libre-riscv.org/show_bug.cgi?id=173 +""" +from nmigen import Signal, Module, Elaboratable, Cat, Mux +from ieee754.part_mul_add.partpoints import PartitionPoints +import math + + +class PartitionedDynamicShift(Elaboratable): + def __init__(self, width, partition_points): + self.width = width + self.partition_points = PartitionPoints(partition_points) + + self.a = Signal(width) + self.b = Signal(width) + self.output = Signal(width) + + def elaborate(self, platform): + m = Module() + comb = m.d.comb + width = self.width + gates = Signal(self.partition_points.get_max_partition_count(width)-1) + comb += gates.eq(self.partition_points.as_sig()) + + matrix = [] + keys = list(self.partition_points.keys()) + [self.width] + start = 0 + + for i in range(len(keys)): + row = [] + start = 0 + for j in range(len(keys)): + end = keys[j] + row.append(Signal(width - start, + name="matrix[%d][%d]" % (i, j))) + matrix.append(row) + + a_intervals = [] + b_intervals = [] + out_intervals = [] + intervals = [] + start = 0 + for i in range(len(keys)): + end = keys[i] + a_intervals.append(self.a[start:end]) + b_intervals.append(self.b[start:end]) + out_intervals.append(self.output[start:end]) + intervals.append([start,end]) + start = end + + for i, b in enumerate(b_intervals): + start = 0 + for j, a in enumerate(a_intervals): + end = keys[i] + comb += matrix[i][j].eq(a << b) + start = end + + intermed = matrix[0][0] + comb += out_intervals[0].eq(intermed) + for i in range(1, len(out_intervals)): + index = gates[:i] # selects the 'i' least significant bits + # of gates + element = Signal(width, name="element%d" % i) + for index in range(1< + +dynamically partitionable shifter. Only the operand to be shifted can +be partitioned, the amount to shift by *must* be a scalar + +See: + +* http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/shift/ +* http://bugs.libre-riscv.org/show_bug.cgi?id=173 +""" +from nmigen import Signal, Module, Elaboratable, Cat, Mux +from ieee754.part_mul_add.partpoints import PartitionPoints +import math + + +class PartitionedScalarShift(Elaboratable): + def __init__(self, width, partition_points): + self.width = width + self.partition_points = PartitionPoints(partition_points) + + self.data = Signal(width) + self.shiftbits = math.ceil(math.log2(width)) + self.shifter = Signal(self.shiftbits) + self.output = Signal(width) + + def elaborate(self, platform): + m = Module() + comb = m.d.comb + width = self.width + shiftbits = self.shiftbits + shifted = Signal(self.data.width) + gates = self.partition_points.as_sig() + comb += shifted.eq(self.data << self.shifter) + + parts = [] + outputs = [] + shiftparts = [] + intervals = [] + keys = list(self.partition_points.keys()) + [self.width] + start = 0 + for i in range(len(keys)): + end = keys[i] + parts.append(self.data[start:end]) + outputs.append(self.output[start:end]) + intervals.append((start,end)) + + sp = Signal(width) + comb += sp[start:].eq(self.data[start:end] << self.shifter) + shiftparts.append(sp) + + start = end # for next time round loop + + for i, interval in enumerate(intervals): + start, end = interval + if i == 0: + intermed = shiftparts[i] + else: + intermed = shiftparts[i] | Mux(gates[i-1], 0, prev) + comb += outputs[i].eq(intermed[start:end]) + prev = intermed + + return m diff --git a/src/ieee754/part_shift/test/test_shift_dynamic.py b/src/ieee754/part_shift/test/test_shift_dynamic.py new file mode 100644 index 00000000..68579914 --- /dev/null +++ b/src/ieee754/part_shift/test/test_shift_dynamic.py @@ -0,0 +1,69 @@ +from nmigen import Module, Signal +from nmigen.back.pysim import Simulator, Delay, Settle +from nmigen.test.utils import FHDLTestCase +from ieee754.part_mul_add.partpoints import PartitionPoints + +from ieee754.part_shift.part_shift_dynamic import \ + PartitionedDynamicShift + +import unittest + +class DynamicShiftTestCase(FHDLTestCase): + def get_intervals(self, signal, points): + start = 0 + interval = [] + keys = list(points.keys()) + [signal.width] + for key in keys: + end = key + interval.append(signal[start:end]) + start = end + return interval + + def test_dynamic(self): + m = Module() + comb = m.d.comb + mwidth = 4 + width = 32 + step = int(width/mwidth) + gates = Signal(mwidth-1) + points = PartitionPoints() + for i in range(mwidth-1): + points[(i+1)*step] = gates[i] + a = Signal(width) + b = Signal(width) + output = Signal(width) + a_intervals = self.get_intervals(a, points) + b_intervals = self.get_intervals(b, points) + output_intervals = self.get_intervals(output, points) + + m.submodules.dut = dut = PartitionedDynamicShift(width, points) + comb += [dut.a.eq(a), + dut.b.eq(b), + output.eq(dut.output)] + + sim = Simulator(m) + def process(): + yield a.eq(0x01010101) + yield b.eq(0x04030201) + for i in range(1<<(mwidth-1)): + yield gates.eq(i) + yield Delay(1e-6) + yield Settle() + yield gates.eq(1) + yield Delay(1e-6) + yield Settle() + yield gates.eq(0) + yield Delay(1e-6) + yield Settle() + + + sim.add_process(process) + with sim.write_vcd("test.vcd", "test.gtkw", traces=[a,b,output]): + sim.run() + +if __name__ == "__main__": + unittest.main() + + + + diff --git a/src/ieee754/part_shift_scalar/formal/.gitignore b/src/ieee754/part_shift_scalar/formal/.gitignore deleted file mode 100644 index 37ad79e3..00000000 --- a/src/ieee754/part_shift_scalar/formal/.gitignore +++ /dev/null @@ -1 +0,0 @@ -proof_*/** diff --git a/src/ieee754/part_shift_scalar/formal/proof_shift_dynamic.py b/src/ieee754/part_shift_scalar/formal/proof_shift_dynamic.py deleted file mode 100644 index ea2cc745..00000000 --- a/src/ieee754/part_shift_scalar/formal/proof_shift_dynamic.py +++ /dev/null @@ -1,113 +0,0 @@ -# Proof of correctness for partitioned dynamic shifter -# Copyright (C) 2020 Michael Nolan - -from nmigen import Module, Signal, Elaboratable, Mux, Cat -from nmigen.asserts import Assert, AnyConst, Assume -from nmigen.test.utils import FHDLTestCase -from nmigen.cli import rtlil - -from ieee754.part_mul_add.partpoints import PartitionPoints -from ieee754.part_shift_scalar.part_shift_dynamic import \ - PartitionedDynamicShift -import unittest - - -# This defines a module to drive the device under test and assert -# properties about its outputs -class ShifterDriver(Elaboratable): - def __init__(self): - # inputs and outputs - pass - - def get_intervals(self, signal, points): - start = 0 - interval = [] - keys = list(points.keys()) + [signal.width] - for key in keys: - end = key - interval.append(signal[start:end]) - start = end - return interval - - def elaborate(self, platform): - m = Module() - comb = m.d.comb - width = 24 - mwidth = 3 - - # setup the inputs and outputs of the DUT as anyconst - a = Signal(width) - b = Signal(width) - out = Signal(width) - points = PartitionPoints() - gates = Signal(mwidth-1) - step = int(width/mwidth) - for i in range(mwidth-1): - points[(i+1)*step] = gates[i] - print(points) - - comb += [a.eq(AnyConst(width)), - b.eq(AnyConst(width)), - gates.eq(AnyConst(mwidth-1))] - - m.submodules.dut = dut = PartitionedDynamicShift(width, points) - - a_intervals = self.get_intervals(a, points) - b_intervals = self.get_intervals(b, points) - out_intervals = self.get_intervals(out, points) - - comb += [dut.a.eq(a), - dut.b.eq(b), - out.eq(dut.output)] - - - with m.Switch(points.as_sig()): - with m.Case(0b00): - comb += Assume(b < 24) - comb += Assert(out == (a< - -from nmigen import Module, Signal, Elaboratable, Mux, Cat -from nmigen.asserts import Assert, AnyConst, Assume -from nmigen.test.utils import FHDLTestCase -from nmigen.cli import rtlil - -from ieee754.part_mul_add.partpoints import PartitionPoints -from ieee754.part_shift_scalar.part_shift_scalar import PartitionedScalarShift -import unittest - - -# This defines a module to drive the device under test and assert -# properties about its outputs -class ShifterDriver(Elaboratable): - def __init__(self): - # inputs and outputs - pass - - def get_intervals(self, signal, points): - start = 0 - interval = [] - keys = list(points.keys()) + [signal.width] - for key in keys: - end = key - interval.append(signal[start:end]) - start = end - return interval - - def elaborate(self, platform): - m = Module() - comb = m.d.comb - width = 24 - shifterwidth = 5 - mwidth = 3 - - # setup the inputs and outputs of the DUT as anyconst - data = Signal(width) - out = Signal(width) - shifter = Signal(shifterwidth) - points = PartitionPoints() - gates = Signal(mwidth-1) - step = int(width/mwidth) - for i in range(mwidth-1): - points[(i+1)*step] = gates[i] - print(points) - - comb += [data.eq(AnyConst(width)), - shifter.eq(AnyConst(shifterwidth)), - gates.eq(AnyConst(mwidth-1))] - - m.submodules.dut = dut = PartitionedScalarShift(width, points) - - data_intervals = self.get_intervals(data, points) - out_intervals = self.get_intervals(out, points) - - comb += [dut.data.eq(data), - dut.shifter.eq(shifter), - out.eq(dut.output)] - - expected = Signal(width) - comb += expected.eq(data << shifter) - - with m.Switch(points.as_sig()): - with m.Case(0b00): - comb += Assert(out[0:24] == (data[0:24] << shifter) & 0xffffff) - - with m.Case(0b01): - comb += Assert(out[0:8] == expected[0:8]) - comb += Assert(out[8:24] == (data[8:24] << shifter) & 0xffff) - - with m.Case(0b10): - comb += Assert(out[16:24] == (data[16:24] << shifter) & 0xff) - comb += Assert(out[0:16] == (data[0:16] << shifter) & 0xffff) - - with m.Case(0b11): - comb += Assert(out[0:8] == expected[0:8]) - comb += Assert(out[8:16] == (data[8:16] << shifter) & 0xff) - comb += Assert(out[16:24] == (data[16:24] << shifter) & 0xff) - - return m - -class PartitionedScalarShiftTestCase(FHDLTestCase): - def test_shift(self): - module = ShifterDriver() - self.assertFormal(module, mode="bmc", depth=4) - -if __name__ == "__main__": - unittest.main() - diff --git a/src/ieee754/part_shift_scalar/part_shift_dynamic.py b/src/ieee754/part_shift_scalar/part_shift_dynamic.py deleted file mode 100644 index a32e5bfd..00000000 --- a/src/ieee754/part_shift_scalar/part_shift_dynamic.py +++ /dev/null @@ -1,91 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -# See Notices.txt for copyright information - -""" -Copyright (C) 2020 Luke Kenneth Casson Leighton -Copyright (C) 2020 Michael Nolan - -dynamically partitionable shifter. Unlike part_shift_scalar, both -operands can be partitioned - -See: - -* http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/shift/ -* http://bugs.libre-riscv.org/show_bug.cgi?id=173 -""" -from nmigen import Signal, Module, Elaboratable, Cat, Mux -from ieee754.part_mul_add.partpoints import PartitionPoints -import math - - -class PartitionedDynamicShift(Elaboratable): - def __init__(self, width, partition_points): - self.width = width - self.partition_points = PartitionPoints(partition_points) - - self.a = Signal(width) - self.b = Signal(width) - self.output = Signal(width) - - def elaborate(self, platform): - m = Module() - comb = m.d.comb - width = self.width - gates = Signal(self.partition_points.get_max_partition_count(width)-1) - comb += gates.eq(self.partition_points.as_sig()) - - matrix = [] - keys = list(self.partition_points.keys()) + [self.width] - start = 0 - - for i in range(len(keys)): - row = [] - start = 0 - for j in range(len(keys)): - end = keys[j] - row.append(Signal(width - start, - name="matrix[%d][%d]" % (i, j))) - matrix.append(row) - - a_intervals = [] - b_intervals = [] - out_intervals = [] - intervals = [] - start = 0 - for i in range(len(keys)): - end = keys[i] - a_intervals.append(self.a[start:end]) - b_intervals.append(self.b[start:end]) - out_intervals.append(self.output[start:end]) - intervals.append([start,end]) - start = end - - for i, b in enumerate(b_intervals): - start = 0 - for j, a in enumerate(a_intervals): - end = keys[i] - comb += matrix[i][j].eq(a << b) - start = end - - intermed = matrix[0][0] - comb += out_intervals[0].eq(intermed) - for i in range(1, len(out_intervals)): - index = gates[:i] # selects the 'i' least significant bits - # of gates - element = Signal(width, name="element%d" % i) - for index in range(1< - -dynamically partitionable shifter. Only the operand to be shifted can -be partitioned, the amount to shift by *must* be a scalar - -See: - -* http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/shift/ -* http://bugs.libre-riscv.org/show_bug.cgi?id=173 -""" -from nmigen import Signal, Module, Elaboratable, Cat, Mux -from ieee754.part_mul_add.partpoints import PartitionPoints -import math - - -class PartitionedScalarShift(Elaboratable): - def __init__(self, width, partition_points): - self.width = width - self.partition_points = PartitionPoints(partition_points) - - self.data = Signal(width) - self.shiftbits = math.ceil(math.log2(width)) - self.shifter = Signal(self.shiftbits) - self.output = Signal(width) - - def elaborate(self, platform): - m = Module() - comb = m.d.comb - width = self.width - shiftbits = self.shiftbits - shifted = Signal(self.data.width) - gates = self.partition_points.as_sig() - comb += shifted.eq(self.data << self.shifter) - - parts = [] - outputs = [] - shiftparts = [] - intervals = [] - keys = list(self.partition_points.keys()) + [self.width] - start = 0 - for i in range(len(keys)): - end = keys[i] - parts.append(self.data[start:end]) - outputs.append(self.output[start:end]) - intervals.append((start,end)) - - sp = Signal(width) - comb += sp[start:].eq(self.data[start:end] << self.shifter) - shiftparts.append(sp) - - start = end # for next time round loop - - for i, interval in enumerate(intervals): - start, end = interval - if i == 0: - intermed = shiftparts[i] - else: - intermed = shiftparts[i] | Mux(gates[i-1], 0, prev) - comb += outputs[i].eq(intermed[start:end]) - prev = intermed - - return m diff --git a/src/ieee754/part_shift_scalar/test/test_shift_dynamic.py b/src/ieee754/part_shift_scalar/test/test_shift_dynamic.py deleted file mode 100644 index ec60d7c6..00000000 --- a/src/ieee754/part_shift_scalar/test/test_shift_dynamic.py +++ /dev/null @@ -1,69 +0,0 @@ -from nmigen import Module, Signal -from nmigen.back.pysim import Simulator, Delay, Settle -from nmigen.test.utils import FHDLTestCase -from ieee754.part_mul_add.partpoints import PartitionPoints - -from ieee754.part_shift_scalar.part_shift_dynamic import \ - PartitionedDynamicShift - -import unittest - -class DynamicShiftTestCase(FHDLTestCase): - def get_intervals(self, signal, points): - start = 0 - interval = [] - keys = list(points.keys()) + [signal.width] - for key in keys: - end = key - interval.append(signal[start:end]) - start = end - return interval - - def test_dynamic(self): - m = Module() - comb = m.d.comb - mwidth = 4 - width = 32 - step = int(width/mwidth) - gates = Signal(mwidth-1) - points = PartitionPoints() - for i in range(mwidth-1): - points[(i+1)*step] = gates[i] - a = Signal(width) - b = Signal(width) - output = Signal(width) - a_intervals = self.get_intervals(a, points) - b_intervals = self.get_intervals(b, points) - output_intervals = self.get_intervals(output, points) - - m.submodules.dut = dut = PartitionedDynamicShift(width, points) - comb += [dut.a.eq(a), - dut.b.eq(b), - output.eq(dut.output)] - - sim = Simulator(m) - def process(): - yield a.eq(0x01010101) - yield b.eq(0x04030201) - for i in range(1<<(mwidth-1)): - yield gates.eq(i) - yield Delay(1e-6) - yield Settle() - yield gates.eq(1) - yield Delay(1e-6) - yield Settle() - yield gates.eq(0) - yield Delay(1e-6) - yield Settle() - - - sim.add_process(process) - with sim.write_vcd("test.vcd", "test.gtkw", traces=[a,b,output]): - sim.run() - -if __name__ == "__main__": - unittest.main() - - - -