add dct butterfly SVG autogenerator
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Tue, 10 Aug 2021 17:15:26 +0000 (18:15 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Tue, 10 Aug 2021 17:15:26 +0000 (18:15 +0100)
src/openpower/decoder/isa/dct_butterfly_svg.py [new file with mode: 0644]

diff --git a/src/openpower/decoder/isa/dct_butterfly_svg.py b/src/openpower/decoder/isa/dct_butterfly_svg.py
new file mode 100644 (file)
index 0000000..955f4b8
--- /dev/null
@@ -0,0 +1,459 @@
+#!/usr/bin/env python
+# SPDX: LGPLv3+
+# Program for generating DCT butterfly diagrams from yield REMAP schedules
+# avoids the need to mess about drawing diagrams by hand, getting them wrong,
+# introducing mistakes (common in academic published papers, sigh)
+
+from copy import deepcopy
+from collections import OrderedDict
+from math import pi
+import os
+import base64
+import math
+
+from openpower.decoder.isa.remap_dct_yield import (reverse_bits, halfrev2,
+                                        iterate_dct_inner_butterfly_indices,
+                                        iterate_dct_outer_butterfly_indices,
+                                        )
+
+cwd = os.path.split(os.path.abspath(__file__))[0]
+
+def linescale(l1, l2, scale):
+    diffx = l2[0] - l1[0]
+    diffy = l2[1] - l1[1]
+    return l1[0] - diffx*scale, l1[1] + diffy*scale
+
+def lineoffs(l2, scale):
+    return l2[0] - abs(scale), l2[1] + scale
+
+
+def create_idct(fname, n, redir=True):
+    """unsophisticated drawer of an SVG
+    """
+
+    try:
+        import svgwrite
+    except ImportError:
+        print ("WARNING, no SVG image, not producing image %s" % fname)
+        return
+
+    # Initialization
+    vec = range(n)
+    print ()
+    print ("transform2", n)
+    levels = n.bit_length() - 1
+
+    # set up dims
+    xdim = n
+
+    # reference (read/write) the in-place data in *reverse-bit-order*
+    ri = list(range(n))
+    ri = [ri[reverse_bits(i, levels)] for i in range(n)]
+
+    # pretend we LDed data in half-swapped *and* bit-reversed order as well
+    # TODO: merge these two
+    vec = [vec[ri[i]] for i in range(n)]
+    vec = halfrev2(vec, True)
+
+    width = 800
+    height = 600
+    scale = 15
+
+    dwg = svgwrite.Drawing(fname, profile='full',
+                           size=(width, height))
+
+    # outer QFP rect
+    dwg.add(dwg.rect((0, 0), (width, height),
+            fill='white',
+            stroke=svgwrite.rgb(0, 128, 0, '%'),
+            stroke_width=scale/5.0))
+
+    # x start layer
+    xstep = width / 10.0
+    x = xstep / 2
+    ystep = height/(n+1.0)
+    y = ystep
+
+    # start data
+    for i in range(n):
+        # flat lines
+        startline = (x-scale, y+i*ystep+scale/2)
+        dwg.add(dwg.text("%d" % vec[i],
+                         startline,
+                         fill='black'))
+
+    # set up an SVSHAPE
+    class SVSHAPE:
+        pass
+
+    # ####
+    # outer
+    # ####
+
+    # j schedule
+    SVSHAPE0 = SVSHAPE()
+    SVSHAPE0.lims = [xdim, 0b0000010, 0]
+    SVSHAPE0.submode2 = 0b11
+    SVSHAPE0.mode = 0b11
+    SVSHAPE0.skip = 0b00
+    SVSHAPE0.offset = 0       # experiment with different offset, here
+    SVSHAPE0.invxyz = [1,0,1] # inversion if desired
+    # j+halfstep schedule
+    SVSHAPE1 = SVSHAPE()
+    SVSHAPE1.lims = [xdim, 0b0000010, 0]
+    SVSHAPE1.mode = 0b11
+    SVSHAPE1.submode2 = 0b11
+    SVSHAPE1.skip = 0b01
+    SVSHAPE1.offset = 0       # experiment with different offset, here
+    SVSHAPE1.invxyz = [1,0,1] # inversion if desired
+
+    # enumerate over the iterator function, getting new indices
+    i0 = iterate_dct_outer_butterfly_indices(SVSHAPE0)
+    i1 = iterate_dct_outer_butterfly_indices(SVSHAPE1)
+    for k, ((jl, jle), (jh, jhe)) in enumerate(zip(i0, i1)):
+        print ("itersum    jr", jl, jh,
+                "end", bin(jle), bin(jhe))
+        if redir:
+            jl = vec[jl]
+            jh = vec[jh]
+        # jh to jl
+        startline = (x, y+jh*ystep)
+        endline = (x+xstep, y+jl*ystep)
+        dwg.add(dwg.line(startline,
+                         endline,
+                         stroke=svgwrite.rgb(255, 16, 16, '%'),
+                         stroke_width=scale/10.0))
+        # plus sign
+        dwg.add(dwg.text("+",
+                         lineoffs(endline, scale*0.9),
+                         fill='black'))
+        if (jle & 0b010):
+            for i in range(n):
+                # flat lines
+                startline = (x, y+i*ystep)
+                endline = (x+xstep, y+i*ystep)
+                dwg.add(dwg.line(startline,
+                                 endline,
+                                 stroke=svgwrite.rgb(16, 255, 16, '%'),
+                                 stroke_width=scale/15.0))
+            x += xstep * 1.2
+        if jle == 0b111: # all loops end
+            break
+
+    # break point
+    for i in range(n):
+        # flat lines
+        startline = (x, y+i*ystep)
+        endline = (x+xstep, y+i*ystep)
+        dwg.add(dwg.line(startline,
+                         endline,
+                         stroke=svgwrite.rgb(16, 255, 16, '%'),
+                         stroke_width=scale/15.0))
+    x += xstep * 0.2
+
+    ################
+    # INNER butterfly
+    ################
+
+    # j schedule
+    SVSHAPE0 = SVSHAPE()
+    SVSHAPE0.lims = [xdim, 0b000001, 0]
+    SVSHAPE0.mode = 0b11
+    SVSHAPE0.submode2 = 0b11
+    SVSHAPE0.skip = 0b00
+    SVSHAPE0.offset = 0       # experiment with different offset, here
+    SVSHAPE0.invxyz = [0,0,0] # inversion if desired
+    # j+halfstep schedule
+    SVSHAPE1 = SVSHAPE()
+    SVSHAPE1.lims = [xdim, 0b000001, 0]
+    SVSHAPE1.mode = 0b11
+    SVSHAPE1.submode2 = 0b11
+    SVSHAPE1.skip = 0b01
+    SVSHAPE1.offset = 0       # experiment with different offset, here
+    SVSHAPE1.invxyz = [0,0,0] # inversion if desired
+    # ci schedule
+    SVSHAPE2 = SVSHAPE()
+    SVSHAPE2.lims = [xdim, 0b000001, 0]
+    SVSHAPE2.mode = 0b11
+    SVSHAPE2.submode2 = 0b11
+    SVSHAPE2.skip = 0b10
+    SVSHAPE2.offset = 0       # experiment with different offset, here
+    SVSHAPE2.invxyz = [0,0,0] # inversion if desired
+    # size schedule
+    SVSHAPE3 = SVSHAPE()
+    SVSHAPE3.lims = [xdim, 0b000001, 0]
+    SVSHAPE3.mode = 0b11
+    SVSHAPE3.submode2 = 0b11
+    SVSHAPE3.skip = 0b11
+    SVSHAPE3.offset = 0       # experiment with different offset, here
+    SVSHAPE3.invxyz = [0,0,0] # inversion if desired
+
+    # enumerate over the iterator function, getting new indices
+    i0 = iterate_dct_inner_butterfly_indices(SVSHAPE0)
+    i1 = iterate_dct_inner_butterfly_indices(SVSHAPE1)
+    i2 = iterate_dct_inner_butterfly_indices(SVSHAPE2)
+    i3 = iterate_dct_inner_butterfly_indices(SVSHAPE3)
+    for k, ((jl, jle), (jh, jhe), (ci, cie), (size, sze)) in \
+                enumerate(zip(i0, i1, i2, i3)):
+        if redir:
+            jl = vec[jl]
+            jh = vec[jh]
+        print ("xform2", jl, jh, ci, size)
+        # jl to jh
+        startline = (x, y+jl*ystep)
+        endline = (x+xstep, y+jh*ystep)
+        dwg.add(dwg.line(startline,
+                         endline,
+                         stroke=svgwrite.rgb(255, 16, 16, '%'),
+                         stroke_width=scale/10.0))
+        # plus sign
+        dwg.add(dwg.text("+",
+                         lineoffs(endline, scale*0.9),
+                         fill='black'))
+        # jh to jl
+        startline = (x, y+jh*ystep)
+        endline = (x+xstep, y+jl*ystep)
+        dwg.add(dwg.line(startline,
+                         endline,
+                         stroke=svgwrite.rgb(255, 16, 16, '%'),
+                         stroke_width=scale/10.0))
+        # times sign
+        dwg.add(dwg.text("x",
+                         lineoffs(endline, scale*0.9),
+                         fill='black'))
+
+        if (jle & 0b010):
+            for i in range(n):
+                # flat lines
+                startline = (x, y+i*ystep)
+                endline = (x+xstep, y+i*ystep)
+                dwg.add(dwg.line(startline,
+                                 endline,
+                                 stroke=svgwrite.rgb(16, 255, 16, '%'),
+                                 stroke_width=scale/15.0))
+            x += xstep * 1.2
+        if jle == 0b111: # all loops end
+            break
+
+    print("transform2 result", vec)
+
+    dwg.save()
+
+
+def create_dct(fname, n, redir=True):
+    """unsophisticated drawer of an SVG
+    """
+
+    try:
+        import svgwrite
+    except ImportError:
+        print ("WARNING, no SVG image, not producing image %s" % fname)
+        return
+
+    # Initialization
+    vec = range(n)
+    print ()
+    print ("transform2", n)
+    levels = n.bit_length() - 1
+
+    # set up dims
+    xdim = n
+
+    # reference (read/write) the in-place data in *reverse-bit-order*
+    ri = list(range(n))
+    ri = [ri[reverse_bits(i, levels)] for i in range(n)]
+
+    # and pretend we LDed data in half-swapped *and* bit-reversed order as well
+    # TODO: merge these two
+    vec = halfrev2(vec, False)
+    vec = [vec[ri[i]] for i in range(n)]
+
+    width = 800
+    height = 600
+    scale = 15
+
+    dwg = svgwrite.Drawing(fname, profile='full',
+                           size=(width, height))
+
+    # outer QFP rect
+    dwg.add(dwg.rect((0, 0), (width, height),
+            fill='white',
+            stroke=svgwrite.rgb(0, 128, 0, '%'),
+            stroke_width=scale/5.0))
+
+    # set up an SVSHAPE
+    class SVSHAPE:
+        pass
+
+    ################
+    # INNER butterfly
+    ################
+
+    # j schedule
+    SVSHAPE0 = SVSHAPE()
+    SVSHAPE0.lims = [xdim, 0b000001, 0]
+    SVSHAPE0.mode = 0b01
+    SVSHAPE0.submode2 = 0b01
+    SVSHAPE0.skip = 0b00
+    SVSHAPE0.offset = 0       # experiment with different offset, here
+    SVSHAPE0.invxyz = [1,0,0] # inversion if desired
+    # j+halfstep schedule
+    SVSHAPE1 = SVSHAPE()
+    SVSHAPE1.lims = [xdim, 0b000001, 0]
+    SVSHAPE1.mode = 0b01
+    SVSHAPE1.submode2 = 0b01
+    SVSHAPE1.skip = 0b01
+    SVSHAPE1.offset = 0       # experiment with different offset, here
+    SVSHAPE1.invxyz = [1,0,0] # inversion if desired
+    # ci schedule
+    SVSHAPE2 = SVSHAPE()
+    SVSHAPE2.lims = [xdim, 0b000001, 0]
+    SVSHAPE2.mode = 0b01
+    SVSHAPE2.submode2 = 0b01
+    SVSHAPE2.skip = 0b10
+    SVSHAPE2.offset = 0       # experiment with different offset, here
+    SVSHAPE2.invxyz = [1,0,0] # inversion if desired
+    # size schedule
+    SVSHAPE3 = SVSHAPE()
+    SVSHAPE3.lims = [xdim, 0b000001, 0]
+    SVSHAPE3.mode = 0b01
+    SVSHAPE3.submode2 = 0b01
+    SVSHAPE3.skip = 0b11
+    SVSHAPE3.offset = 0       # experiment with different offset, here
+    SVSHAPE3.invxyz = [1,0,0] # inversion if desired
+
+    # x start layer
+    xstep = width / 10.0
+    x = xstep / 2
+    ystep = height/(n+1.0)
+    y = ystep
+
+    # start data
+    for i in range(n):
+        # flat lines
+        startline = (x-scale, y+i*ystep+scale/2)
+        dwg.add(dwg.text("%d" % vec[i],
+                         startline,
+                         fill='black'))
+
+    # enumerate over the iterator function, getting new indices
+    i0 = iterate_dct_inner_butterfly_indices(SVSHAPE0)
+    i1 = iterate_dct_inner_butterfly_indices(SVSHAPE1)
+    i2 = iterate_dct_inner_butterfly_indices(SVSHAPE2)
+    i3 = iterate_dct_inner_butterfly_indices(SVSHAPE3)
+    for k, ((jl, jle), (jh, jhe), (ci, cie), (size, sze)) in \
+                enumerate(zip(i0, i1, i2, i3)):
+        if redir:
+            jl = vec[jl]
+            jh = vec[jh]
+        print ("xform2", jl, jh, ci, size)
+        coeff = (math.cos((ci + 0.5) * math.pi / size) * 2.0)
+        # jl to jh
+        startline = (x, y+jl*ystep)
+        endline = (x+xstep, y+jh*ystep)
+        dwg.add(dwg.line(startline,
+                         endline,
+                         stroke=svgwrite.rgb(255, 16, 16, '%'),
+                         stroke_width=scale/10.0))
+        # plus sign
+        dwg.add(dwg.text("+",
+                         lineoffs(endline, scale*0.9),
+                         fill='black'))
+        # jh to jl
+        startline = (x, y+jh*ystep)
+        endline = (x+xstep, y+jl*ystep)
+        dwg.add(dwg.line(startline,
+                         endline,
+                         stroke=svgwrite.rgb(255, 16, 16, '%'),
+                         stroke_width=scale/10.0))
+        # times sign
+        dwg.add(dwg.text("x",
+                         lineoffs(endline, scale*0.9),
+                         fill='black'))
+
+        if (jle & 0b010):
+            for i in range(n):
+                # flat lines
+                startline = (x, y+i*ystep)
+                endline = (x+xstep, y+i*ystep)
+                dwg.add(dwg.line(startline,
+                                 endline,
+                                 stroke=svgwrite.rgb(16, 255, 16, '%'),
+                                 stroke_width=scale/15.0))
+            x += xstep * 1.2
+        if jle == 0b111: # all loops end
+            break
+
+    # break point
+    for i in range(n):
+        # flat lines
+        startline = (x, y+i*ystep)
+        endline = (x+xstep, y+i*ystep)
+        dwg.add(dwg.line(startline,
+                         endline,
+                         stroke=svgwrite.rgb(16, 255, 16, '%'),
+                         stroke_width=scale/15.0))
+    x += xstep * 0.2
+
+    # ####
+    # outer
+    # ####
+
+    # j schedule
+    SVSHAPE0 = SVSHAPE()
+    SVSHAPE0.lims = [xdim, 0b0000010, 0]
+    SVSHAPE0.submode2 = 0b100
+    SVSHAPE0.mode = 0b01
+    SVSHAPE0.skip = 0b00
+    SVSHAPE0.offset = 0       # experiment with different offset, here
+    SVSHAPE0.invxyz = [0,0,0] # inversion if desired
+    # j+halfstep schedule
+    SVSHAPE1 = SVSHAPE()
+    SVSHAPE1.lims = [xdim, 0b0000010, 0]
+    SVSHAPE1.mode = 0b01
+    SVSHAPE1.submode2 = 0b100
+    SVSHAPE1.skip = 0b01
+    SVSHAPE1.offset = 0       # experiment with different offset, here
+    SVSHAPE1.invxyz = [0,0,0] # inversion if desired
+
+    # enumerate over the iterator function, getting new indices
+    i0 = iterate_dct_outer_butterfly_indices(SVSHAPE0)
+    i1 = iterate_dct_outer_butterfly_indices(SVSHAPE1)
+    for k, ((jl, jle), (jh, jhe)) in enumerate(zip(i0, i1)):
+        if redir:
+            jl = vec[jl]
+            jh = vec[jh]
+        print ("itersum    jr", jl, jh,
+                "end", bin(jle), bin(jhe))
+        # jh to jl
+        startline = (x, y+jh*ystep)
+        endline = (x+xstep, y+jl*ystep)
+        dwg.add(dwg.line(startline,
+                         endline,
+                         stroke=svgwrite.rgb(255, 16, 16, '%'),
+                         stroke_width=scale/10.0))
+        # plus sign
+        dwg.add(dwg.text("+",
+                         lineoffs(endline, scale*0.9),
+                         fill='black'))
+        if (jle & 0b010):
+            for i in range(n):
+                # flat lines
+                startline = (x, y+i*ystep)
+                endline = (x+xstep, y+i*ystep)
+                dwg.add(dwg.line(startline,
+                                 endline,
+                                 stroke=svgwrite.rgb(16, 255, 16, '%'),
+                                 stroke_width=scale/15.0))
+            x += xstep * 1.2
+        if jle == 0b111: # all loops end
+            break
+
+    print("transform2 result", vec)
+
+    dwg.save()
+
+
+if __name__ == '__main__':
+    create_dct("dct_butterfly.svg", 16)
+    create_idct("idct_butterfly.svg", 16)