[Libre-soc-bugs] [Bug 716] PartitionedSignal Slice and Part needed for __getitem__

bugzilla-daemon at libre-soc.org bugzilla-daemon at libre-soc.org
Sun Oct 24 20:24:55 BST 2021


https://bugs.libre-soc.org/show_bug.cgi?id=716

--- Comment #19 from Jacob Lifshay <programmerjake at gmail.com> ---
(In reply to Luke Kenneth Casson Leighton from comment #18)
> (In reply to Luke Kenneth Casson Leighton from comment #17)
> 
> > the answer is: an adapter submodule.
> > 
> > the exact details of how that works will emerge from
> > the examples, TBD.  i will write a couple now.
> 
> oo. err and um. that's interesting.  an add of a 3 bit
> sliced quantity with a 2 bit (element width=2bit) quantity
> requires sign (or zero) extension prior to partition
> expansion.
> 
> this is going to be interesting (translation: hairy)

The answer to all of those conversions is to have a SimdSignal.cast method that
handles conversion of an input nmigen Value or SimdSignal to the desired
SimdShape:
Full conversion implementation:
class SimdSignal(...):
    @staticmethod
    def cast(value, *, shape=None, scope):
        # scope injected by calling this method as
        # scope.Signal_cast(value, shape=shape), which is a
        # partial() of SimdSignal.cast
        if shape is not None:
            assert shape.scope is scope
        if isinstance(value, SimdSignal):
            assert value.shape().scope is scope
            if shape is None or shape == value.shape():
                return value
        # I'm assuming SwizzleKey is already replaced by SimdScope.
        # from_value handles splatting a scalar nmigen Value if needed.
        src = SwizzledSimdValue.from_value(scope, value)
        swizzles = {}
        for src_el, dst_el in zip(src.shape().elements(),
                                  shape.elements()):
            elwid = src_el.elwid
            # SimdShape always iterates elements in the same order across all
            # SimdShapes for a particular scope.
            assert elwid == dst_el.elwid
            if elwid not in swizzles:
                swizzles[elwid] = Swizzle.from_const(0, shape.width)
            # get bits for current src_el
            el = src.swizzles[elwid][src_el.slice]
            if src_el.shape.signed: # *src* determines sign/zero extension
                # truncate/sign-extend
                el = el.convert_s_to(dst_el.shape)
            else:
                # truncate/zero-extend
                el = el.convert_u_to(dst_el.shape)
            # assign converted bits to dest
            swizzles[elwid].bits[dst_rl.slice] = el.bits
        # oops, I forgot shape argument for __init__
        return SwizzledSimdValue(scope, swizzles, shape=shape)

now, all ops can use:
ops_input_arg = SimdSignal.cast(ops_input_arg, shape=desired_shape,
                                scope=scope)

e.g.:
    def __add__(self, other):
        l_shape = self.shape()
        scope = l_shape.scope
        # splat scalars to SimdSignal
        other = SimdSignal.cast(other, scope=scope)
        r_shape = other.shape()
        def get_el_shape(l, r):
            # let nmigen compute result element's shape
            return (Const(0, l) + Const(0, r)).shape()
        el_shapes = SimdMap.map(get_el_shape, l_shape.el_shapes,
                                r_shape.el_shapes)
        shape = SimdShape(el_shapes, scope=scope)
        # could have a SimdShape.map method letting us write:
        # shape = SimdShape.map(get_el_shape, l_shape, r_shape)

        # convert to result's shape
        lhs = SimdSignal.cast(self, shape=shape, scope=scope)
        rhs = SimdSignal.cast(other, shape=shape, scope=scope)

        # do add
        return lhs.add_op(lhs, rhs, carry=0)

-- 
You are receiving this mail because:
You are on the CC list for the bug.


More information about the libre-soc-bugs mailing list