From: lkcl Date: Sat, 15 Apr 2023 12:26:47 +0000 (+0100) Subject: (no commit message) X-Git-Tag: opf_rfc_ls009_v1~81 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=fb18ae2cfa46a22e1f1e9bda99dc303ac6a72bcd;p=libreriscv.git --- diff --git a/openpower/sv/rfc/ls009.mdwn b/openpower/sv/rfc/ls009.mdwn index 8ab6438c5..c3f41edf1 100644 --- a/openpower/sv/rfc/ls009.mdwn +++ b/openpower/sv/rfc/ls009.mdwn @@ -1566,4 +1566,107 @@ Add the following to Book I, 1.6.2 | SVM2 | I | # | 3.0B | svshape2 | REMAP shape instruction (2) | | SVI | I | # | 3.0B | svindex | REMAP General-purpose Indexing | +## REMAP 2D/3D Matrix pseudocode + +Written in python3 the following stand-alone executable source code is the Canonical +Specification for Matrix (2D/3D) REMAP. Vectors of "loopends" are returned when Rc=1 +in Vectors of CR Fields on `sv.svstep.`, or a single CR Field CR0 on +`svstep.` in Vertical-First Mode. The `SVSTATE.srcstep` or `SVSTATE.dststep` sequential +offset is put through this algorithm to determine the actual Element Offset. + +``` +# 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 + step = 0 # track src/dst step + while True: + for z in z_r: # loop over 1st order dimension + z_end = z == z_r[-1] + for y in y_r: # loop over 2nd order dimension + y_end = y == y_r[-1] + for x in x_r: # loop over 3rd order dimension + x_end = x == x_r[-1] + # 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]] + ] + # ok now we can construct the result, using bits of + # "order" to say which ones get stacked on + result = 0 + mult = 1 + for i in range(3): + lim, idx, dbg = vals[i] + # 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 == i+1: continue + #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 + + loopends = (x_end | + ((y_end and x_end)<<1) | + ((y_end and x_end and z_end)<<2)) + + if hasattr(SVSHAPE, "postprocess"): # for Indexed mode + result = SVSHAPE.postprocess(result, step) + yield result + SVSHAPE.offset, loopends + step += 1 + +def demo(): + # set the dimension sizes here + xdim = 3 + ydim = 2 + zdim = 4 + + # 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, end) in enumerate(iterate_indices(SVSHAPE0)): + if idx >= VL: + break + print ("%d->%d" % (idx, new_idx), "end", bin(end)[2:]) + +# run the demo +if __name__ == '__main__': + demo() +``` + [[!tag opf_rfc]]