Timing Diagrams
7 minute read
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:
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 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.
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)
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")
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.
Articles & Resources
- Source: https://github.com/wavedrom/wavedrom
- User Manual: https://wavedrom.com/images/SNUG2016_WaveDrom.pdf
- VCD Compiler: https://github.com/nanamake/vcd2json
- Articles:
- Videos:
- WebEditor: https://wavedrom.com/editor.html
- Examples:
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
- Source: https://bitbucket.org/cdelker/schemdraw/src/master/
- Documentation: https://schemdraw.readthedocs.io/en/latest/index.html
- Articles
- Timing Section: https://schemdraw.readthedocs.io/en/latest/elements/timing.html
GTKWave
- 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).
Articles & Resources
- Source: https://github.com/gtkwave/gtkwave
- Documentation:
- Articles:
PulseView
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
Another project from WaveDROM is VCDRom which is a VCD viewer in the browser. It only supports viewing with no high level features but its great at what its for.
- Source: https://github.com/wavedrom/vcdrom
- Web Interface: https://vc.drom.io/
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
- User Manual: https://www.tug.org/texmf-dist/doc/latex/tikz-timing/tikz-timing.pdf
- VCD Compiler: https://github.com/ernstblecha/vcd2tikztiming
TimingAnalyzer
This looks like a promising library, the code looks like it needs some serious packaging improvements. I gave up on getting it to work.
Articles & Resources
- Source: Source code is distributed in zip files. It does not appear to be available in a repository. https://www.timing-diagrams.com/TimingAnalyzer_b9932.zip
- Documentation: https://www.timing-diagrams.com/index.html
Articles & Resources
WaveMe
I haven’t tried this but it exists and looks promising.
- Documentation: https://waveme.weebly.com/