from ieee754.part_ass.passign import PAssign
from ieee754.part_cat.pcat import PCat
from ieee754.part_repl.prepl import PRepl
+from ieee754.part.simd_scope import SimdScope
+from ieee754.part.layout_experiment import layout
from operator import or_, xor, and_, not_
from nmigen import (Signal, Const, Cat)
def blanklanes(self):
return 0
+
# this one would be an elwidth version
# see https://bugs.libre-soc.org/show_bug.cgi?id=713#c34
# it requires an "adapter" which is the layout() function
# function and this class then "understands" the relationship
# between elwidth and the PartitionPoints that were created
# by layout()
-
-
-class ElWidthPartType: # TODO decide name
+class ElwidPartType: # TODO decide name
def __init__(self, psig):
self.psig = psig
def get_mask(self):
- ppoints, pbits = layout()
- return ppoints.values() # i think
+ return list(self.psig._shape.partpoints.values()) # i think
def get_switch(self):
- return self.psig.elwidth
+ return self.psig.scope.elwid # switch on elwid: match get_cases()
def get_cases(self):
- ppoints, pbits = layout()
- return pbits
+ return self.psig._shape.bitp.keys() # all possible values of elwid
@property
def blanklanes(self):
- return 0 # TODO
+ return self.psig.shape.blankmask
+
+
+class SimdShape(Shape):
+ """a SIMD variant of Shape. supports:
+ * fixed overall width with variable (maxed-out) element lengths
+ * fixed element widths with overall size auto-determined
+ * both fixed overall width and fixed element widths
+
+ naming is preserved to be compatible with Shape().
+ """
+ def __init__(self, scope, width=None, # this is actually widths_at_elwid
+ signed=False,
+ fixed_width=None): # fixed overall width
+ widths_at_elwid = width
+ print ("SimdShape width", width, "fixed_width", fixed_width)
+ # this check is done inside layout but do it again here anyway
+ assert fixed_width != None or widths_at_elwid != None, \
+ "both width (widths_at_elwid) and fixed_width cannot be None"
+ (pp, bitp, lpoints, bmask, fixed_width, lane_shapes, part_wid) = \
+ layout(scope.elwid,
+ scope.vec_el_counts,
+ widths_at_elwid,
+ fixed_width)
+ self.partpoints = pp
+ self.bitp = bitp # binary values for partpoints at each elwidth
+ self.lpoints = lpoints # layout ranges
+ self.blankmask = bmask # blanking mask (partitions always padding)
+ self.partwid = part_wid # smallest alignment start point for elements
+
+ # pass through the calculated width to Shape() so that when/if
+ # objects using this Shape are downcast, they know exactly how to
+ # get *all* bits and need know absolutely nothing about SIMD at all
+ Shape.__init__(self, fixed_width, signed)
class SimdSignal(UserValue):
# XXX ################################################### XXX
# XXX Keep these functions in the same order as ast.Value XXX
# XXX ################################################### XXX
- def __init__(self, mask, *args, src_loc_at=0, **kwargs):
+ def __init__(self, mask, shape=None, *args,
+ src_loc_at=0, fixed_width=None, **kwargs):
super().__init__(src_loc_at=src_loc_at)
- self.sig = Signal(*args, **kwargs)
- width = len(self.sig) # get signal width
+ print ("SimdSignal shape", shape)
# create partition points
- if isinstance(mask, PartitionPoints):
- self.partpoints = mask
+ if isinstance(mask, SimdScope): # mask parameter is a SimdScope
+ self.scope = mask
+ self.ptype = ElwidPartType(self)
+ # adapt shape to a SimdShape
+ if not isinstance(shape, SimdShape):
+ shape = SimdShape(self.scope, shape, fixed_width=fixed_width)
+ self._shape = shape
+ self.sig = Signal(shape, *args, **kwargs)
+ # get partpoints from SimdShape
+ self.partpoints = shape.partpoints
else:
- self.partpoints = make_partition2(mask, width)
- self.ptype = PartType(self)
+ self.sig = Signal(shape, *args, **kwargs)
+ width = len(self.sig) # get signal width
+ if isinstance(mask, PartitionPoints):
+ self.partpoints = mask
+ else:
+ self.partpoints = make_partition2(mask, width)
+ self.ptype = PartType(self)
def set_module(self, m):
self.m = m
# nmigen-redirected constructs (Mux, Cat, Switch, Assign)
- # TODO, http://bugs.libre-riscv.org/show_bug.cgi?id=458
- # def __Part__(self, offset, width, stride=1, *, src_loc_at=0):
+ # TODO, http://bugs.libre-riscv.org/show_bug.cgi?id=716
+ #def __Part__(self, offset, width, stride=1, *, src_loc_at=0):
+ raise NotImplementedError("TODO: implement as "
+ "(self>>(offset*stride)[:width]")
+ # TODO, http://bugs.libre-riscv.org/show_bug.cgi?id=716
+ def __Slice__(self, start, stop, *, src_loc_at=0):
+ # NO. Swizzled shall NOT be deployed, it violates
+ # Project Development Practices
+ raise NotImplementedError("TODO: need PartitionedSlice")
def __Repl__(self, count, *, src_loc_at=0):
return PRepl(self.m, self, count, self.ptype)
def __Cat__(self, *args, src_loc_at=0):
+ print ("partsig cat", self, args)
+ # TODO: need SwizzledSimdValue-aware Cat
args = [self] + list(args)
for sig in args:
assert isinstance(sig, SimdSignal), \
return PMux(self.m, self.partpoints, self, val1, val2, self.ptype)
def __Assign__(self, val, *, src_loc_at=0):
- # print ("partsig ass", self, val)
+ print ("partsig assign", self, val)
+ # this is a truly awful hack, outlined here:
+ # https://bugs.libre-soc.org/show_bug.cgi?id=731#c13
+ # during the period between constructing Simd-aware sub-modules
+ # and the elaborate() being called on them there is a window of
+ # opportunity to indicate which of those submodules is LHS and
+ # which is RHS. manic laughter is permitted. *gibber*.
+ if hasattr(self, "_hack_submodule"):
+ self._hack_submodule.set_lhs_mode(True)
+ if hasattr(val, "_hack_submodule"):
+ val._hack_submodule.set_lhs_mode(False)
return PAssign(self.m, self, val, self.ptype)
# TODO, http://bugs.libre-riscv.org/show_bug.cgi?id=458
# def __getitem__(self, key):
def __new_sign(self, signed):
+ # XXX NO - SimdShape not Shape
+ print ("XXX requires SimdShape not Shape")
shape = Shape(len(self), signed=signed)
result = SimdSignal.like(self, shape=shape)
self.m.d.comb += result.sig.eq(self.sig)