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
--- /dev/null
+# 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()
--- /dev/null
+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))
+
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:
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/
| 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]