add SVSHAPE class, starting to add to ISACaller
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 5 Jul 2021 14:53:18 +0000 (15:53 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 5 Jul 2021 14:53:18 +0000 (15:53 +0100)
src/openpower/decoder/isa/caller.py
src/openpower/decoder/isa/remapyield.py [new file with mode: 0644]
src/openpower/decoder/isa/svshape.py [new file with mode: 0644]
src/openpower/decoder/selectable_int.py
src/openpower/sv/svp64.py

index b870ebe7bd860845926f136abedcc4f93928c8e3..f7561a78349e2cf3f851632397edd69847a37a70 100644 (file)
@@ -35,6 +35,7 @@ from openpower.decoder.power_svp64 import SVP64RM, decode_extra
 
 from openpower.decoder.isa.radixmmu import RADIX
 from openpower.decoder.isa.mem import Mem, swap_order, MemException
+from openpower.decoder.isa.svshape import SVSHAPE
 
 from openpower.util import log
 
diff --git a/src/openpower/decoder/isa/remapyield.py b/src/openpower/decoder/isa/remapyield.py
new file mode 100644 (file)
index 0000000..a18cfd7
--- /dev/null
@@ -0,0 +1,94 @@
+# a "yield" version of the REMAP algorithm. a little easier to read
+# than the Finite State Machine version
+
+# python "yield" can be iterated. use this to make it clear how
+# the indices are generated by using natural-looking nested loops
+def iterate_indices(SVSHAPE):
+    # get indices to iterate over, in the required order
+    xd = SVSHAPE.lims[0]
+    yd = SVSHAPE.lims[1]
+    zd = SVSHAPE.lims[2]
+    # create lists of indices to iterate over in each dimension
+    x_r = list(range(xd))
+    y_r = list(range(yd))
+    z_r = list(range(zd))
+    # invert the indices if needed
+    if SVSHAPE.invxyz[0]: x_r.reverse()
+    if SVSHAPE.invxyz[1]: y_r.reverse()
+    if SVSHAPE.invxyz[2]: z_r.reverse()
+    # start an infinite (wrapping) loop
+    while True:
+        for z in z_r:   # loop over 1st order dimension
+            for y in y_r:       # loop over 2nd order dimension
+                for x in x_r:           # loop over 3rd order dimension
+                    # ok work out which order to construct things in.
+                    # start by creating a list of tuples of the dimension
+                    # and its limit
+                    vals = [(SVSHAPE.lims[0], x, "x"),
+                            (SVSHAPE.lims[1], y, "y"),
+                            (SVSHAPE.lims[2], z, "z")
+                           ]
+                    # now select those by order.  this allows us to
+                    # create schedules for [z][x], [x][y], or [y][z]
+                    # for matrix multiply.
+                    vals = [vals[SVSHAPE.order[0]],
+                            vals[SVSHAPE.order[1]],
+                            vals[SVSHAPE.order[2]]
+                           ]
+                    # some of the dimensions can be "skipped".  the order
+                    # was actually selected above on all 3 dimensions,
+                    # e.g. [z][x][y] or [y][z][x].  "skip" allows one of
+                    # those to be knocked out
+                    if SVSHAPE.skip == 0b00:
+                        select = 0b111
+                    elif SVSHAPE.skip == 0b11:
+                        select = 0b011
+                    elif SVSHAPE.skip == 0b01:
+                        select = 0b110
+                    elif SVSHAPE.skip == 0b10:
+                        select = 0b101
+                    else:
+                        select = 0b111
+                    result = 0
+                    mult = 1
+                    # ok now we can construct the result, using bits of
+                    # "order" to say which ones get stacked on
+                    for i in range(3):
+                        lim, idx, dbg = vals[i]
+                        if select & (1<<i):
+                            #print ("select %d %s" % (i, dbg))
+                            idx *= mult   # shifts up by previous dimension(s)
+                            result += idx # adds on this dimension
+                            mult *= lim   # for the next dimension
+
+                    yield result + SVSHAPE.offset
+
+def demo():
+    # set the dimension sizes here
+    xdim = 3
+    ydim = 2
+    zdim = 1
+
+    # set total (can repeat, e.g. VL=x*y*z*4)
+    VL = xdim * ydim * zdim
+
+    # set up an SVSHAPE
+    class SVSHAPE:
+        pass
+    SVSHAPE0 = SVSHAPE()
+    SVSHAPE0.lims = [xdim, ydim, zdim]
+    SVSHAPE0.order = [1,0,2]  # experiment with different permutations, here
+    SVSHAPE0.mode = 0b00
+    SVSHAPE0.skip = 0b00
+    SVSHAPE0.offset = 0       # experiment with different offset, here
+    SVSHAPE0.invxyz = [0,0,0] # inversion if desired
+
+    # enumerate over the iterator function, getting new indices
+    for idx, new_idx in enumerate(iterate_indices(SVSHAPE0)):
+        if idx >= VL:
+            break
+        print ("%d->%d" % (idx, new_idx))
+
+# run the demo
+if __name__ == '__main__':
+    demo()
diff --git a/src/openpower/decoder/isa/svshape.py b/src/openpower/decoder/isa/svshape.py
new file mode 100644 (file)
index 0000000..139b540
--- /dev/null
@@ -0,0 +1,101 @@
+from openpower.decoder.isa.remapyield import iterate_indices
+from openpower.decoder.selectable_int import (FieldSelectableInt, SelectableInt,
+                                        selectconcat)
+from openpower.sv.svp64 import SVP64REMAP
+import os
+
+class SVSHAPE(SelectableInt):
+    def __init__(self, value):
+        SelectableInt.__init__(self, value, 32)
+        offs = 0
+        # set up sub-fields from Record layout
+        self.fsi = {}
+        for field, width in SVP64REMAP.layout:
+            v = FieldSelectableInt(self, tuple(range(offs, offs+width)))
+            self.fsi[field] = v
+            offs += width
+
+    @property
+    def order(self):
+        permute = self.fsi['permute'].asint(msb0=True)
+        return SVP64REMAP.order(permute)
+
+    @order.setter
+    def order(self, value):
+        rorder = SVP64REMAP.rorder(value)
+        self.fsi['permute'].eq(rorder)
+
+    @property
+    def xdimsz(self):
+        return self.fsi['xdimsz'].asint(msb0=True)
+
+    @xdimsz.setter
+    def xdimsz(self, value):
+        self.fsi['xdimsz'].eq(value)
+
+    @property
+    def ydimsz(self):
+        return self.fsi['ydimsz'].asint(msb0=True)
+
+    @ydimsz.setter
+    def ydimsz(self, value):
+        self.fsi['ydimsz'].eq(value)
+
+    @property
+    def zdimsz(self):
+        return self.fsi['zdimsz'].asint(msb0=True)
+
+    @zdimsz.setter
+    def zdimsz(self, value):
+        self.fsi['zdimsz'].eq(value)
+
+    @property
+    def lims(self):
+        return [self.xdimsz, self.ydimsz, self.zdimsz]
+
+    @lims.setter
+    def lims(self, value):
+        self.xdimsz = value[0]
+        self.ydimsz = value[1]
+        self.zdimsz = value[2]
+        
+    @property
+    def mode(self):
+        return self.fsi['mode'].asint(msb0=True)
+
+    @mode.setter
+    def mode(self, value):
+        self.fsi['mode'].eq(value)
+
+    @property
+    def offset(self):
+        return self.fsi['offset'].asint(msb0=True)
+
+    @offset.setter
+    def offset(self, value):
+        self.fsi['offset'].eq(value)
+
+    def get_iterator(self):
+        return iterate_indices(self)
+
+
+if __name__ == '__main__':
+    os.environ['SILENCELOG'] = "1"
+    xdim = 3
+    ydim = 2
+    zdim = 1
+    SVSHAPE0 = SVSHAPE(0)
+    SVSHAPE0.lims = [xdim, ydim, zdim]
+    SVSHAPE0.order = [1,0,2]  # experiment with different permutations, here
+    SVSHAPE0.mode = 0b00
+    SVSHAPE0.skip = 0b00
+    SVSHAPE0.offset = 0       # experiment with different offset, here
+    SVSHAPE0.invxyz = [0,0,0] # inversion if desired
+
+    VL = xdim * ydim * zdim
+
+    for idx, new_idx in enumerate(SVSHAPE0.get_iterator()):
+        if idx >= VL:
+            break
+        print ("%d->%d" % (idx, new_idx))
+
index a3e2974c3d498ee407e25c082d12fb1cdf51190a..5e2c0fe8b38e77160486d69f37bb1c5257048510 100644 (file)
@@ -31,7 +31,13 @@ class FieldSelectableInt:
         self.br = br  # map of indices.
 
     def eq(self, b):
-        if isinstance(b, SelectableInt):
+        if isinstance(b, int):
+            # convert integer to same SelectableInt of same bitlength as range
+            blen = len(self.br)
+            b = SelectableInt(b, blen)
+            for i in range(b.bits):
+                self[i] = b[i]
+        elif isinstance(b, SelectableInt):
             for i in range(b.bits):
                 self[i] = b[i]
         else:
index e9ba29b12272b28120e64610962d8f54eed2464b..cdf7a85e6e182b826ac458e90dd4c4475ea2130b 100644 (file)
@@ -40,9 +40,28 @@ class SVP64Rec(Record):
                 self.subvl, self.extra, self.mode]
 
 
+options = {0b000: (0,1,2),
+           0b001: (0,2,1),
+           0b010: (1,0,2),
+           0b011: (1,2,0),
+           0b100: (2,0,1),
+           0b101: (2,1,0)}
+roptions = {}
+for k, v in options.items():
+    roptions[v] = k
+
 # in nMigen, Record begins at the LSB and fills upwards
 # however in OpenPOWER, numbering is MSB0.  sigh.
 class SVP64REMAP(Record):
+    layout=[("mode"    , 2),
+            ("skip"    , 2),
+            ("offset"  , 4),
+            ("invxyz"  , 3),
+            ("permute" , 3),
+            ("zdimsz"  , 6),
+            ("ydimsz"  , 6),
+            ("xdimsz"  , 6)]
+
     """SVP64 SHAPE (REMAP) Record.
 
     https://libre-soc.org/openpower/sv/remap/
@@ -59,24 +78,16 @@ class SVP64REMAP(Record):
     | MODE       | `30:31`    | Selects Mode: Matrix, FFT, DCT         |
     """
     def __init__(self, name=None):
-        Record.__init__(self, layout=[("mode"    , 2),
-                                      ("skip"    , 2),
-                                      ("offset"  , 4),
-                                      ("invxyz"  , 3),
-                                      ("permute" , 3),
-                                      ("zdimsz"  , 6),
-                                      ("ydimsz"  , 6),
-                                      ("xdimsz"  , 6)], name=name)
-
-    def order(self, permute):
-        options = {0b000: [0,1,2],
-                   0b001: [0,2,1],
-                   0b010: [1,0,2],
-                   0b011: [1,2,0],
-                   0b100: [2,0,1],
-                   0b101: [2,1,0]}
+        Record.__init__(self, layout=self.layout, name=name)
+
+    @staticmethod
+    def order(permute):
         return options[permute]
 
+    @staticmethod
+    def rorder(order):
+        return roptions[tuple(order)]
+
     def ports(self):
         return [self.mode, self.skip, self.offset, self.invxyz, self.permute,
                 self.zdimsz, self.ydimsz, self.xdimsz]