had to add fixed_width parameter temporarily to confirm that the
[ieee754fpu.git] / src / ieee754 / part / partsig.py
index bc12d26e6805d2b87cb52caa972cd565517c061f..61b64e661e4ff1a3e3b2d8e3896c18be923947eb 100644 (file)
@@ -28,6 +28,8 @@ from ieee754.part_mux.part_mux import PMux
 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)
@@ -79,6 +81,7 @@ class PartType:  # TODO decide name
     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
@@ -86,47 +89,84 @@ class PartType:  # TODO decide name
 # 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 False: # isinstance(mask, SimdMode):
+        if isinstance(mask, SimdScope): # mask parameter is a SimdScope
+            self.scope = mask
             self.ptype = ElwidPartType(self)
-            # parse the args, get elwid from SimdMode,
-            # get module as well, call self.set_module(mask.module)
-            self.partpoints = ptype.make_layout_get_stuff(mask, *args, **kwargs)
-        if isinstance(mask, PartitionPoints):
-            self.partpoints = mask
+            # 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
@@ -423,6 +463,8 @@ class SimdSignal(UserValue):
     # 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)