This tutorial is about generating better GTKWave documents (*.gtkw) from Python. The goal is to ease analysis of traces generated by unit-tests, and at the same time to better understand the inner working of modules, for which we are writing such tests.

Stylish GTKWave Documents

In this tutorial, you will learn how to:

  1. Use individual trace colors.
    For instance, use different color styles for input, output, debug and internal traces.
  2. Use numeric bases besides the default hex.
  3. Create collapsible trace groups
    Useful to hide and show, at once, groups of debug, internal and sub-module traces.
    Select the opening or closing brace, then use the T key.
  4. Add comments in the signal names pane
  5. Change the displayed name of a trace
  6. Use a sane default for initial zoom level
  7. Place markers on interesting places
  8. Put the generating file name as a comment in the file

Basic trace display

First, we need a VCD file. Try:

python -m nmutil.test.example_gtkwave

Among other files, it will generate test_shifter.vcd.

Lets write a simple GTKW document. First, import the function:

from nmutil.gtkw import write_gtkw

Create a list of the traces you want to see. Some hints:

  1. Put all trace names in quotes.
  2. Use the same names as you would see in the trace pane of GTKWave
  3. If a trace is multi-bit, use array notation 'name[max:min]'

For example:

traces = [
    # prev port
    'op__sdir', 'p_data_i[7:0]', 'p_shift_i[7:0]', 'p_valid_i', 'p_ready_o',
    # internal signals
    'fsm_state', 'count[3:0]', 'shift_reg[7:0]',
    # next port
    'n_data_o[7:0]', 'n_valid_o', 'n_ready_i'

Now, create the document:

write_gtkw("simple.gtkw", "test_shifter.vcd", traces, module='top.shf')


  1. simple.gtkw is the name of our GTKWave document
  2. test_shifter.vcd is the VCD file
  3. traces is a list of trace names
  4. top.shf is the hierarchy path of the module

Now try:

gtkwave simple.gtkw


  1. No need to press the "zoom to fit" button. The default zoom level is adequate for a 1 MHz clock.
  2. If you made a mistake, there will be no warning. The trace will simply not appear
  3. The reload button will only reload the VCD file, not the GTKW document. If you regenerate the document, you need to close and open a new tab, or exit GTKWave and run again: gtkwave simple.gtkw
  4. If you feel tired of seeing the GTKWave splash window every time, do: echo splash_disable 1 >> ~/.gtkwaverc
  5. If you modify the document manually, better to save it with another name

Adding color

Go back to the trace list and replace the 'op__sdir' string with:

('op__sdir', {'color': 'orange'})

Recreate the document (you can change the file name):

write_gtkw("color.gtkw", "test_shifter.vcd", traces, module='top.shf')

If you now run gtkwave color.gtkw, you will see that op__sdir has the new color.

Writing GTKWave documents, with style

Let's say we want all input traces be orange, and all output traces be yellow. To change them one by one, as we did with op__sdir, would be very tedious and verbose. Also, hardcoding the color name will make it difficult to change it later.

To solve this, lets create a style specification:

style = {
    'in': {'color': 'orange'},
    'out': {'color': 'yellow'}

Then, change:

('op__sdir', {'color': 'orange'})


('op__sdir', 'in')

then (notice how we add style):

write_gtkw("style1.gtkw", "test_shifter.vcd", traces, style, module='top.shf')

If you now run gtkwave style1.gtkw, you will see that op__sdir still has the new color.

Let's add more color:

traces = [
    # prev port
    ('op__sdir', 'in'),
    ('p_data_i[7:0]', 'in'),
    ('p_shift_i[7:0]', 'in'),
    ('p_valid_i', 'in'),
    ('p_ready_o', 'out'),
    # internal signals
    # next port
    ('n_data_o[7:0]', 'out'),
    ('n_valid_o', 'out'),
    ('n_ready_i', 'in'),


write_gtkw("style2.gtkw", "test_shifter.vcd", traces, style, module='top.shf')

If you now run gtkwave style2.gtkw, you will see that input, output and internal signals have different color.

New signals at simulation time

At simulation time, you can declare a new signal, and use it inside the test case, as any other signal. By including it in the "traces" parameter of Simulator.write_vcd, it is included in the trace dump file.

Useful for adding "printf" style debugging for GTKWave.

String traces

When declaring a Signal, you can pass a custom decoder that translates the Signal logic level to a string. nMigen uses this internally to display Enum traces, but it is available for general use.

Some applications are:

  1. Display a string when a signal is at high level, otherwise show a single horizontal line. Useful to draw attention to a time interval.
  2. Display the stages of a unit test
  3. Display arbitrary debug statements along the timeline.