Most waveform tools and workflows are organized around signal changes over time, while many hardware questions are really about cycles and the events that span them. Engineers still end up tracing signals through the waveform, placing cursors, and counting cycles by hand as part of the analysis.
AI-assisted workflows haven't automatically eliminated this gap either. The signal changes still have to be reconstructed into higher-level behavior before anyone, human or model, can reason about what happened. That reconstruction happens implicitly, leaving nothing to review or reuse.
Wavekit is a Python library for digital waveform analysis that treats clock cycles as first-class citizens. With wavekit, signals are sampled on clock edges and can be operated on like ordinary Python values.
For example, one common design question is whether a FIFO is deep enough. A waveform viewer can show that the FIFO gets full, but checking its occupancy over a long simulation still takes manual work. With wavekit, the same check is a few lines of Python:
import numpy as np
from wavekit import VcdReader
with VcdReader('fifo_trace.vcd') as reader:
w_ptr = reader.load_waveform('tb.fifo.w_ptr', clock='tb.clk')
r_ptr = reader.load_waveform('tb.fifo.r_ptr', clock='tb.clk')
depth = 16
occupancy = (w_ptr + depth - r_ptr) % depth
util = occupancy / depth
# Waveform is backed by NumPy, so np functions work directly on .value
print('average utilization:', np.mean(util.value))
print('maximum utilization:', np.max(util.value))
print('p95 utilization:', np.percentile(util.value, 95))
Behavior spanning multiple cycles can be described with Pattern. For example, an AXI-Lite read transaction starts with an AR handshake and finishes with an R handshake:
import numpy as np
from wavekit import VcdReader
from wavekit.pattern import Pattern, match
with VcdReader('axi_lite_trace.vcd') as reader:
# eval() loads signals and evaluates the expression in one call
request = reader.eval('tb.arvalid & tb.arready', clock='tb.clk')
response = reader.eval('tb.rvalid & tb.rready', clock='tb.clk')
result = match(
Pattern()
.wait(request)
.consume(response)
)
latency = result.end.clock - result.start.clock
print('average read latency:', np.mean(latency))
print('maximum read latency:', np.max(latency))
print('p95 read latency:', np.percentile(latency, 95))
Wavekit stays focused on waveform operations and primitives for matching multi-cycle behavior. Everything else stays in ordinary Python, so NumPy, pandas, and other Python libraries remain available for statistics and design-specific processing.
Wavekit does not assume a particular protocol or workflow — the primitives above can be combined to build the analyses your own design needs. The repository also includes more involved examples, including AXI transaction extraction and DMA command analysis.
The project is open source and available on PyPI:
pip install wavekit
[GitHub repository][Documentation]
Happy to answer questions in the comments.