From 61db0f95d7d92caccf72368992ad9bacfd0e6b81 Mon Sep 17 00:00:00 2001 From: Michael Nolan Date: Wed, 12 Feb 2020 10:51:26 -0500 Subject: [PATCH] Begin adding dynamic shifter --- .../part_shift_scalar/part_shift_dynamic.py | 83 +++++++++++++++++++ .../part_shift_scalar/part_shift_scalar.py | 7 +- .../test/test_shift_dynamic.py | 66 +++++++++++++++ 3 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 src/ieee754/part_shift_scalar/part_shift_dynamic.py create mode 100644 src/ieee754/part_shift_scalar/test/test_shift_dynamic.py 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 index 00000000..d3bd0c08 --- /dev/null +++ b/src/ieee754/part_shift_scalar/part_shift_dynamic.py @@ -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 +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 = 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 + diff --git a/src/ieee754/part_shift_scalar/part_shift_scalar.py b/src/ieee754/part_shift_scalar/part_shift_scalar.py index 87908c5c..21b8db82 100644 --- a/src/ieee754/part_shift_scalar/part_shift_scalar.py +++ b/src/ieee754/part_shift_scalar/part_shift_scalar.py @@ -2,11 +2,10 @@ # See Notices.txt for copyright information """ -Copyright (C) 2020 Luke Kenneth Casson Leighton Copyright (C) 2020 Michael Nolan -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 index 00000000..5e899992 --- /dev/null +++ b/src/ieee754/part_shift_scalar/test/test_shift_dynamic.py @@ -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() + + + + -- 2.30.2