Timing Diagrams for RTL and Digital Design

ADC Timing

I have recently been working as part of a team generating some custom silicon for a high speed time of flight LIDAR. The digital logic is very simple but its important to get this correct. The team has several different groups all working remotely which makes clear documentation worth the effort. Timing diagrams for a system that can be understood by a wide audience is an art form; displaying data in a understandable and information dense way is subtle. The work of Edward Tufte is wonderful to look into on this topic, one of the historic pieces of data visualization he references is Charles-Joseph Minard’s piece on Napolean’s invasion of Russia: Minard’s Napolean’s Russian Campaign Infographic

Clearly expectations are high here. These diagrams should be useful to everyone working on the part, not only to the digital designers. Hopefully the improved documentation keeps the casualties down.

Generating Timing Diagrams

I find that there are four starting points for timing diagrams

  • Documenting and existing device
    • If you have an existing device it may be best to observe the behaviour you’re describing with a logic analyzer directly. A tool like Sigrok+Pulseview will allow you to generate a wave file or a timing diagram directly.
  • Documenting an existing logic design
    • Simulate and plot.
  • Designing
    • If the logic is simple and easiest to express through RTL or software then a simulation is likely the best option. This is easy to over do and should be done only if the relation of the signals is already well known (SPI communication or a rollover counter as an example).
    • If the design is subtle then the best starting point may be to first document the timing. This will help with the verification and testing as the requirements are expressed in the timing diagrams.
    • Starting from a paper diagram I find to be the most productive approach. A graph paper notebook makes an excellent starting point for design. This leaves all the tool details separate from the actual design.
  • Replicating an existing timing diagram
    • Use WaveDROM or similar

In this case I was documenting an existing design that was not modeled in HDL. I wrote the verilog that would produce the timing plots I was given, wrote a couple test benches, and simulated it using Verilator. The results are stored in a vcd file. A faster solution would have been to use a program like WaveDROM. I had a rough timing diagram, the only required task was improving the plots. There’s a Hackaday article that introduces the tool, more information is below in the tool comparison. Simulating the design is more information dense, it is not just a visualization.

Here are the two different approaches, both are useful methods.

Matplotlib + vcdvcd Timing Diagram Plots

VCD is a straight forward ascii format for storing digital outputs. The following loads a VCD using vcdvcd and plots it using matplotlib.

I then forked vcdvcd to my fork and added a couple of plotting features. This approach was great for density of information. I only needed to change the testbench to produce all the examples I needed. All the plotting tricks can be done with the powerful plotting tools in the Python world. This can be done using other visualization tools and wave file viewers (some are listed below) but there’s a tradeoff of customizability and complexity. This approach naturally fits into a workflow using a jupyter notebook as the living design document. This technique allows the living design document to be fully executable, morphing into the user manual and delivery documentation.

The following Python script loads a VCD trace and generates a labeled timing diagram using Matplotlib. It uses a modified version of vcdvcd that supports direct plotting.

import vcdvcd
from matplotlib import pyplot as plt
import numpy as np

def plot_signal(ax, vcd, name, endtime=None):
    xscale = float(vcd.timescale["timescale"])*1e9
    if not endtime:
        endtime = vcd[name].endtime

    signal = vcd[name]
    signal.tv = vcdvcd.condition_signal_tv(signal.tv)
    x, y = list(zip(*signal.tv))
    x, y = vcdvcd.expand_signal(x, y, endtime)
    ax.plot(np.array(x)*xscale, y)


def plot_signal_in(signal, ax, xscale=1):
    signal.tv = vcdvcd.condition_signal_tv(signal.tv)
    x, y = list(zip(*signal.tv))
    ax.plot(np.array(x)*xscale, y)


def main(trace_file, save_name, signals, analog_in_signal, nbits=12):
    vcd = vcdvcd.VCDVCD(trace_file)

    fig, axes = plt.subplots(len(signals)+1, 1, sharex=True)
    xscale = float(vcd.timescale["timescale"])*1e9  #  ns

    ylabel_format = dict(rotation=0, fontsize=14, snap=True, labelpad=80)

    for ax, signal in zip(axes[1:], signals):
        name, label = signal
        ax.set_ylabel(label, **ylabel_format)
        plot_signal(ax, vcd, name)


    name, label = analog_in_signal
    axes[0].set_ylabel(label, **ylabel_format)
    plot_signal_in(vcd[name], axes[0])

    for ax, signal in zip(axes, [analog_in_signal, *signals]):
        lines = ax.get_lines()
        for line in lines:
            line.set_linestyle('-')
            line.set_color('k')
            line.set_marker(None)
    fig.set_tight_layout(True)
    fig.set_figwidth(10)
    fig.set_figheight(6)

    label_x = -0.15
    signal_max = (1<<nbits)
    margin = signal_max*.05

    axes[0].set_ylim((-margin, signal_max+margin))
    axes[-1].set_ylim((-margin, signal_max+margin))
    axes[-1].set_xlabel("Time (ns)")
    axes[-1].get_xaxis().set_visible(True)

    axes[0].set_title("ADC Timing Model")
    axes[-1].set_xlim((0, 90))
    fig.align_labels()

    plt.savefig(save_name, bbox_inches="tight")
    plt.show()

signals = (("TOP.clk", "Clock"),
           ("TOP.enable", "Enable"),
           ("TOP.data_out[11:0]", "ADC Data Out"))
analog_signal = ("TOP.signal_in[11:0]","Analog Signal In")

save_name = "adc_timing_model.svg"
main("vlt_dump.vcd", save_name, signals, analog_signal)

Timing diagram matplotlib

A WaveDROM visualization rendered using the python library. This can be done with wavedrom-cli but I don’t use nodejs often so the python library fits into my workflow better. This can also also be done using the web editor or the command line tool (just not neatly in a jupyter notebook).

import wavedrom
st = '''
{ "signal": [
  { "name": "Analog Signal In", "wave": "z================", "data":["D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15", "D16", "D17", "D18", "D19"]},
  { "name": "Clock", "wave": "|n..............."},
  { "name": "Enable",       "wave": "0....1..........."},
  { "name": "ADC Data Out", "wave": "|1.........======", "data":["D4", "D5", "D6", "D7", "D8", "D9", "D10", "D11", "D12", "D13"]},
]}
'''
svg = wavedrom.render(st)
svg.saveas("adc_timing_model_wavedrom.svg")

ADC timing diagram wavedrom

The signal “wave”: “z===============” syntax uses WaveDROM’s custom wave symbols (e.g., = for a held high value). Refer to WaveDROM syntax guide for a full reference.

My preference is to use WaveDROM when making quick documentation and to write the HDL, simulate it, and plot when moving forward with the design. A tool that uses vcdvcd or similar to generate WaveDROM JSON would be useful, that would tie those workflows together.

Tool Overview

vcd2wavedrom

  • Python based command line tool to generate a WaveDROM JSON file from a VCD.
  • I had parsing issues with the signals I was using, this probably needs some extension to be able to parse a generic VCD. A version that uses the vcdvcd parser would be useful.

Articles & Resources

WaveDROM

  • Generate timing diagrams from a very concise JSON format. Seems to be the most popular method of autogenerating timing diagrams. WaveDROM Editor Example

Articles & Resources

SchemDraw

SchemDraw is a full circuit drawing library that includes a logic drawing suite forked from WaveDROM. The circuit drawing features are worth exploring on their own. The same VCD compiler can be used as with WaveDROM.

Articles & Resources

GTKWave

GTKWave Example

  • Useful and simple waveform viewer, similar to older versions of the ModelSim viewer.
  • I find this useful for exploring files but the visualization is rudimentary. Making documentation is best done using a different tool (for now atleast).

GTKWave is excellent for debugging but limited for polished documentation due to its fixed layout and bitmap output.

Articles & Resources

PulseView

PulseView Example PulseView is the frontend for the Sigrok project which I have a post on this here. It supports a wide range of input and output types so is a reasonable go to. The built in protocol parsers make this useful for all varieties of development other than its intended use as a logic analyzer GUI.

VCDRom

VCDRom Example Another project from WaveDROM is VCDRom which is a VCD (Value Change Dump) viewer in the browser. It only supports viewing with no high level features but its great at what its for.

Titz Timing

Interesting latex library that could be powerful. A compiler exists for it from VCD just like one exists to WaveDrom. Worth checking out if you have a background with latex or are already using it in a give system.

Articles & Resources

WaveMe

I haven’t tried this but it exists and looks promising.

Summary

Whether you’re sketching a protocol or documenting silicon behavior, choosing the right timing diagram tool can save hours and improve communication across your team. WaveDROM and simulation each have their strengths—pick the one that fits your project’s scale and stage without getting too.

ToolInput Format(s)Output Format(s)StrengthsLimitationsBest Use Case
WaveDROMJSONSVG, PNG, HTMLConcise format, integrates well in web docs, portable, browser editorManual editing required unless auto-generated; limited analog supportQuick documentation, embedded diagrams
vcdvcd + MatplotlibVCDSVG, PNG, PDFFull plotting control, integrates with Jupyter, supports analog signalsRequires Python skills; less compact formatDetailed diagrams from simulation/testbench
vcd2wavedromVCDWaveDROM JSONBridges simulation and WaveDROM; CLI-basedParsing is fragile on complex VCDs; limited maintenanceAuto-generating WaveDROM from simulation output
GTKWaveVCD, FST, LXT, etc.Screen display, PDFFast, mature, interactive GUI; deep introspection of signalsNot designed for polished documentation outputDebugging HDL simulations
PulseViewSigrok session filesScreen displayBroad hardware support, protocol decoders, user-friendly GUILimited export features; focused on real-world logic analyzer dataCapturing real signals and basic visualization
SchemDrawPython scriptSVG, PNG, PDFCircuit + timing diagrams; LaTeX style drawingLess intuitive than WaveDROM for timing; more verboseCombining logic symbols and timing in documents
VCDRomVCDBrowser displayNo install needed; fast and simple viewerView-only; minimal interactivity or customizationQuick online VCD viewing
TikZ-TimingLaTeX scriptPDFHighly customizable, integrates with LaTeXSteep learning curve; hard to previewAcademic papers, publication-quality diagrams
WaveMeGUI / ProprietaryUnknown (likely image)User-friendly, WYSIWYGLimited info online; may not be open sourceRapid interactive timing diagram creation