Begin adding dynamic shifter
authorMichael Nolan <mtnolan2640@gmail.com>
Wed, 12 Feb 2020 15:51:26 +0000 (10:51 -0500)
committerMichael Nolan <mtnolan2640@gmail.com>
Wed, 12 Feb 2020 15:51:44 +0000 (10:51 -0500)
src/ieee754/part_shift_scalar/part_shift_dynamic.py [new file with mode: 0644]
src/ieee754/part_shift_scalar/part_shift_scalar.py
src/ieee754/part_shift_scalar/test/test_shift_dynamic.py [new file with mode: 0644]

diff --git a/src/ieee754/part_shift_scalar/part_shift_dynamic.py b/src/ieee754/part_shift_scalar/part_shift_dynamic.py
new file mode 100644 (file)
index 0000000..d3bd0c0
--- /dev/null
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# See Notices.txt for copyright information
+
+"""
+Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
+
+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 = 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 i in range(len(keys)):
+                end = keys[i]
+                row.append(Signal(width - start))
+            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
+            for index in range(1<<(i-1)):
+                with m.Switch(gates[:i]):
+                    with m.Case(index):
+                        element = matrix[index][i]
+            print(keys[i-1])
+            intermed = Mux(gates[i-1], element, element | intermed[:keys[i-1]])
+            comb += out_intervals[i].eq(intermed)
+
+
+        return m
+
index 87908c5c5afc16de27530aae692c9398c7fd1ebe..21b8db82569c97e797301b8d4a7113d9d8124214 100644 (file)
@@ -2,11 +2,10 @@
 # See Notices.txt for copyright information
 
 """
-Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
 Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
 
-dynamically-partitionable "comparison" class, directly equivalent
-to Signal.__eq__, __gt__ and __ge__, except SIMD-partitionable
+dynamically partitionable shifter. Only the operand to be shifted can
+be partitioned, the amount to shift by *must* be a scalar
 
 See:
 
@@ -52,7 +51,7 @@ class PartitionedScalarShift(Elaboratable):
             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):
diff --git a/src/ieee754/part_shift_scalar/test/test_shift_dynamic.py b/src/ieee754/part_shift_scalar/test/test_shift_dynamic.py
new file mode 100644 (file)
index 0000000..5e89999
--- /dev/null
@@ -0,0 +1,66 @@
+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(0)
+                yield Delay(1e-6)
+                yield Settle()
+            yield gates.eq(1)
+            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()
+
+
+
+