Fast Signal Trace reader/writer for Ruby

This gem is a Ruby binding to the fstapi library designed by the GTKWave authors. It allows to read and write Fast Signal Trace (FST) format waveforms from Ruby.

FST is an open format for dumpfiles generated by EDA logic simulation tools such as GHDL, nvc or Icarus Verilog. It was created by the author of GTKWave in 2014 as an alternative to the VCD (Value Change Dump) file format. Unlike VCD, FST is a compressed binary format designed for very fast sequential and random access.

Although the FST format and library are widely used, there is unfortunately no documentation for the libfst library API (more details on this: FST API documentation · Issue #70 · gtkwave/gtkwave · GitHub). However, an unofficial specification of the format can be found at this address: https://blog.timhutt.co.uk/fst_spec/.

A similar binding for Python can be found here.

Examples

Write an FST file from Ruby

require 'libfst'

fst = LibFST::Writer.new 'out.fst'

fst.set_date_string 'Wed Apr 17 21:40:39 2024'
fst.set_version_string __FILE__
fst.set_comment 'This is a comment'
fst.set_file_type :vhdl
fst.set_time_scale :ns

fst.set_scope(:vcd_module, name: 'testbench')
clk = fst.create_variable('clk', type: :sv_logic)
fst.set_scope(:vcd_module, name: 'uart')
rx = fst.create_variable('rx', type: :sv_logic, direction: :input)
data = fst.create_variable('data', type: :sv_logic, direction: :output, length: 8)
cnt = fst.create_variable('cnt', type: :vcd_integer)
fst.set_upscope
fst.set_scope(:vcd_module, name: 'analog')
ch0 = fst.create_variable('ch0', type: :vcd_real)
fst.set_upscope
fst.set_upscope

message = 'Hello, world!'.bytes
clk_period = 1000
time = 0
fst.emit_time_change(time)
clock = 0
clk.value = clock
rx.value = 1
cnt.value = 0
counter = 0
byte = nil
bit_cnt = -2

loop do
  time += clk_period
  fst.emit_time_change(time)
  ch0.value = 1.65 + 1.25*(Math.sin(2*Math::PI*4*time/1400000) + 0.5*(rand()-0.5))

  clock ^= 1
  clk.value = clock
  counter += 1
  if counter >= 10 then
    counter = 0
    bit_cnt += 1
    if bit_cnt == -1 then # start bit
      rx.value = 0
      byte = message.shift
    elsif bit_cnt < 8 then
      break if byte.nil?
      rx.value = byte[bit_cnt]
    elsif bit_cnt == 8 then # stop bit 1
      rx.value = 1
      data.value = byte
    else # stop bit 2
      bit_cnt = -2
    end
  end
  cnt.value = counter
end

fst.close  # finalize the output file
# The writer instance should not be used after it has been closed

Opening the output file out.fst with GTKWave gives something like this: gtkwave screenshot

Read an FST file from Ruby

Install

LibFST can be installed from rubygems.org:

gem install libfst

Build from sources

Package the gem file and install it:

git clone https://gitlab.ensta-bretagne.fr/bollenth/libfst.rb.git
cd libfst.rb
gem build libfst.gemspec
gem install --local ./libfst-*.gem

Build the documentation:

# Install Yard if you don't have it already
gem install yard
# Generate the documentation
cd libfst.rb
yard
# View the doc
firefox doc/index.html