Skip to content

Reader

Wavekit has three readers: VcdReader for VCD files, FstReader for FST files, and FsdbReader for FSDB files. They share the same interface. Use readers as context managers so their resources are released automatically when the block exits:

from wavekit import FsdbReader, FstReader, VcdReader

with VcdReader('simulation.vcd') as reader:
    signal = reader['tb.dut.data']
    print(signal.name, signal.width)    # data 8

with FstReader('simulation.fst') as reader:
    signal = reader['tb.dut.data']
    print(signal.name, signal.width)    # data 8

with FsdbReader('simulation.fsdb') as reader:
    signal = reader['tb.dut.data']
    print(signal.name, signal.width)    # data 8

FsdbReader requires the Verdi NPI runtime (libNPI.so). See the FSDB installation and runtime setup before opening an FSDB file.

Hierarchy

Once a reader opens a file, it exposes a tree of Scope and Signal nodes, rooted at reader.top_scopes.

A Scope corresponds to a module instance or a generate block; a Signal corresponds to a concrete signal, which may be a plain scalar or a composite type such as struct, array, or union. Each Signal carries basic metadata such as width and composite_type.

from wavekit import Scope, Signal

top = reader.top_scopes[0]
for child in top.children:
    if isinstance(child, Scope):
        print('Scope', child.name)
    elif isinstance(child, Signal):
        print('Signal', child.name, child.width)

See Signal query for how to locate a Signal or Scope by name.

Waveform

Sampling a signal on a clock produces a Waveform, three equal-length arrays:

  • .value — the sampled value at each edge;
  • .cycle — absolute clock-cycle number, with cycle 0 at the first sampling edge in the file;
  • .time — the simulation timestamp of each sample.
with reader.clock_domain(clock='tb.clk'):
    data = reader['tb.dut.data[7:0]'].w
    valid = reader['tb.dut.valid'].w
    ready = reader['tb.dut.ready'].w

print(data.cycle[:5])   # [0 1 2 3 4]
print(data.value[:5])   # [0 3 3 7 12]

# Operate on the whole Waveform at once; the result is a Waveform too
fire = valid & ready   # whether the handshake fired each cycle

Operations on a Waveform (filtering, bitwise, arithmetic, etc.) return a new Waveform and keep these three arrays aligned, so results can always be traced back to the original cycle or timestamp.

See Signal query for how to load a signal as a Waveform, and Waveform analysis for the operations it supports.