Move new write_gtkw and its example to nmutil
authorCesar Strauss <cestrauss@gmail.com>
Fri, 28 Aug 2020 09:55:10 +0000 (06:55 -0300)
committerCesar Strauss <cestrauss@gmail.com>
Sat, 29 Aug 2020 21:08:14 +0000 (18:08 -0300)
But keep using it to generate the GTKWave document for this unit test.

setup.py
src/soc/experiment/alu_fsm.py

index 737c7c996e993552f93f940eca194d592b06b663..bbe5e144786b32dad76ea934dcdaeb5eb2d0c470 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -16,7 +16,6 @@ install_requires = [
     'nmigen-soc',  # install manually from git.libre-soc.org
     'ply',  # needs to be installed manually
     'astor',
-    'pyvcd',  # for stylish GTKWave save files
 
     # install from https://salsa.debian.org/Kazan-team/power-instruction-analyzer
     'power-instruction-analyzer',
index 596fc3d49764081c40bf075e8098919a6f5e1979..28bbde6580a6fa8f48f6c234f343948a9196acc1 100644 (file)
@@ -29,7 +29,7 @@ from nmutil.iocontrol import PrevControl, NextControl
 from soc.fu.base_input_record import CompOpSubsetBase
 from soc.decoder.power_enums import (MicrOp, Function)
 
-from vcd.gtkw import GTKWSave, GTKWColor
+from nmutil.gtkw import write_gtkw
 
 
 class CompFSMOpSubset(CompOpSubsetBase):
@@ -205,196 +205,6 @@ class Shifter(Elaboratable):
         return list(self)
 
 
-# Write a formatted GTKWave "save" file
-def write_gtkw_v1(base_name, top_dut_name, loc):
-    # hierarchy path, to prepend to signal names
-    dut = top_dut_name + "."
-    # color styles
-    style_input = GTKWColor.orange
-    style_output = GTKWColor.yellow
-    style_debug = GTKWColor.red
-    with open(base_name + ".gtkw", "wt") as gtkw_file:
-        gtkw = GTKWSave(gtkw_file)
-        gtkw.comment("Auto-generated by " + loc)
-        gtkw.dumpfile(base_name + ".vcd")
-        # set a reasonable zoom level
-        # also, move the marker to an interesting place
-        gtkw.zoom_markers(-22.9, 10500000)
-        gtkw.trace(dut + "clk")
-        # place a comment in the signal names panel
-        gtkw.blank("Shifter Demonstration")
-        with gtkw.group("prev port"):
-            gtkw.trace(dut + "op__sdir", color=style_input)
-            # demonstrates using decimal base (default is hex)
-            gtkw.trace(dut + "p_data_i[7:0]", color=style_input,
-                       datafmt='dec')
-            gtkw.trace(dut + "p_shift_i[7:0]", color=style_input,
-                       datafmt='dec')
-            gtkw.trace(dut + "p_valid_i", color=style_input)
-            gtkw.trace(dut + "p_ready_o", color=style_output)
-        with gtkw.group("debug"):
-            gtkw.blank("Some debug statements")
-            # change the displayed name in the panel
-            gtkw.trace("top.zero", alias='zero delay shift',
-                       color=style_debug)
-            gtkw.trace("top.interesting", color=style_debug)
-            gtkw.trace("top.test_case", alias="test case", color=style_debug)
-            gtkw.trace("top.msg", color=style_debug)
-        with gtkw.group("internal"):
-            gtkw.trace(dut + "fsm_state")
-            gtkw.trace(dut + "count[3:0]")
-            gtkw.trace(dut + "shift_reg[7:0]", datafmt='dec')
-        with gtkw.group("next port"):
-            gtkw.trace(dut + "n_data_o[7:0]", color=style_output,
-                       datafmt='dec')
-            gtkw.trace(dut + "n_valid_o", color=style_output)
-            gtkw.trace(dut + "n_ready_i", color=style_input)
-
-
-def write_gtkw(gtkw_name, vcd_name, gtkw_dom, gtkw_style=None,
-               module=None, loc=None, color=None, base=None,
-               zoom=-22.9, marker=-1):
-    """ Write a GTKWave document according to the supplied style and DOM.
-
-    :param gtkw_name: name of the generated GTKWave document
-    :param vcd_name: name of the waveform file
-    :param gtkw_dom: DOM style description for the trace pane
-    :param gtkw_style: style for signals, classes and groups
-    :param module: default module
-    :param color: default trace color
-    :param base: default numerical base
-    :param loc: source code location to include as a comment
-    :param zoom: initial zoom level, in GTKWave format
-    :param marker: initial location of a marker
-
-    **gtkw_style format**
-
-    Syntax: ``{selector: {attribute: value, ...}, ...}``
-
-    "selector" can be a signal, class or group
-
-    Signal groups propagate most attributes to their children
-
-    Attribute choices:
-
-    * module: instance path, for prepending to the signal name
-    * color: trace color
-    * base: numerical base for value display
-    * display: alternate text to display in the signal pane
-    * comment: comment to display in the signal pane
-
-    **gtkw_dom format**
-
-    Syntax: ``[signal, (signal, class), (group, [children]), comment, ...]``
-
-    The DOM is a list of nodes.
-
-    Nodes are signals, signal groups or comments.
-
-    * signals are strings, or tuples: ``(signal name, class, class, ...)``
-    * signal groups are tuples: ``(group name, class, class, ..., [nodes])``
-    * comments are: ``{'comment': 'comment string'}``
-
-    In place of a class name, an inline class description can be used.
-    ``(signal, {attribute: value, ...}, ...)``
-    """
-    colors = {
-        'blue': GTKWColor.blue,
-        'cycle': GTKWColor.cycle,
-        'green': GTKWColor.green,
-        'indigo': GTKWColor.indigo,
-        'normal': GTKWColor.normal,
-        'orange': GTKWColor.orange,
-        'red': GTKWColor.red,
-        'violet': GTKWColor.violet,
-        'yellow': GTKWColor.yellow,
-    }
-
-    with open(gtkw_name, "wt") as gtkw_file:
-        gtkw = GTKWSave(gtkw_file)
-        if loc is not None:
-            gtkw.comment("Auto-generated by " + loc)
-        gtkw.dumpfile(vcd_name)
-        # set a reasonable zoom level
-        # also, move the marker to an interesting place
-        gtkw.zoom_markers(zoom, marker)
-
-        # create an empty style, if needed
-        if gtkw_style is None:
-            gtkw_style = dict()
-
-        # create an empty root selector, if needed
-        root_style = gtkw_style.get('', dict())
-
-        # apply styles to the root selector, if provided
-        if module is not None:
-            root_style['module'] = module
-        if color is not None:
-            root_style['color'] = color
-        if base is not None:
-            root_style['base'] = base
-        # base cannot be None, use 'hex' by default
-        if root_style.get('base') is None:
-            root_style['base'] = 'hex'
-
-        # recursively walk the DOM
-        def walk(dom, style):
-            for node in dom:
-                node_name = None
-                children = None
-                # copy the style from the parent
-                node_style = style.copy()
-                # node is a signal name string
-                if isinstance(node, str):
-                    node_name = node
-                    # apply style from node name, if specified
-                    if node_name in gtkw_style:
-                        node_style.update(gtkw_style[node_name])
-                # node is a tuple
-                # could be a signal or a group
-                elif isinstance(node, tuple):
-                    node_name = node[0]
-                    # collect styles from the selectors
-                    # order goes from the most specific to most generic
-                    # which means earlier selectors override later ones
-                    for selector in reversed(node):
-                        # update the node style from the selector
-                        if isinstance(selector, str):
-                            if selector in gtkw_style:
-                                node_style.update(gtkw_style[selector])
-                        # apply an inline style description
-                        elif isinstance(selector, dict):
-                            node_style.update(selector)
-                    # node is a group if it has a child list
-                    if isinstance(node[-1], list):
-                        children = node[-1]
-                # comment
-                elif isinstance(node, dict):
-                    if 'comment' in node:
-                        gtkw.blank(node['comment'])
-                # emit the group delimiters and walk over the child list
-                if children is not None:
-                    gtkw.begin_group(node_name)
-                    # pass on the group style to its children
-                    walk(children, node_style)
-                    gtkw.end_group(node_name)
-                # emit a trace, if the node is a signal
-                elif node_name is not None:
-                    signal_name = node_name
-                    # prepend module name to signal
-                    if 'module' in node_style:
-                        node_module = node_style['module']
-                        if node_module is not None:
-                            signal_name = node_module + '.' + signal_name
-                    node_color = colors.get(node_style.get('color'))
-                    node_base = node_style.get('base')
-                    display = node_style.get('display')
-                    gtkw.trace(signal_name, color=node_color,
-                               datafmt=node_base, alias=display)
-
-        walk(gtkw_dom, root_style)
-
-
 def test_shifter():
     m = Module()
     m.submodules.shf = dut = Shifter(8)
@@ -407,9 +217,6 @@ def test_shifter():
     with open("test_shifter.il", "w") as f:
         f.write(il)
 
-    # Write the GTKWave project file
-    write_gtkw_v1("test_shifter", "top.shf", __file__)
-
     # Describe a GTKWave document
 
     # Style for signals, classes and groups
@@ -464,7 +271,7 @@ def test_shifter():
         ]),
     ]
 
-    write_gtkw("test_shifter_v2.gtkw", "test_shifter.vcd",
+    write_gtkw("test_shifter.gtkw", "test_shifter.vcd",
                gtkwave_desc,  gtkwave_style,
                module="top.shf", loc=__file__, marker=10500000)