From: Luke Kenneth Casson Leighton Date: Mon, 5 Jul 2021 14:53:18 +0000 (+0100) Subject: add SVSHAPE class, starting to add to ISACaller X-Git-Tag: xlen-bcd~350 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=62cc4c906757fbbf4c0ead6befd0390253e70835;p=openpower-isa.git add SVSHAPE class, starting to add to ISACaller --- diff --git a/src/openpower/decoder/isa/caller.py b/src/openpower/decoder/isa/caller.py index b870ebe7..f7561a78 100644 --- a/src/openpower/decoder/isa/caller.py +++ b/src/openpower/decoder/isa/caller.py @@ -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 index 00000000..a18cfd7e --- /dev/null +++ b/src/openpower/decoder/isa/remapyield.py @@ -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<= 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 index 00000000..139b540d --- /dev/null +++ b/src/openpower/decoder/isa/svshape.py @@ -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)) + diff --git a/src/openpower/decoder/selectable_int.py b/src/openpower/decoder/selectable_int.py index a3e2974c..5e2c0fe8 100644 --- a/src/openpower/decoder/selectable_int.py +++ b/src/openpower/decoder/selectable_int.py @@ -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: diff --git a/src/openpower/sv/svp64.py b/src/openpower/sv/svp64.py index e9ba29b1..cdf7a85e 100644 --- a/src/openpower/sv/svp64.py +++ b/src/openpower/sv/svp64.py @@ -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]