Using vcd2df to load a Value Change Dump as a Data Frame

Calvin Deutschbein

Value Change Dump files

We provide the ‘vcd2df’ function, which loads a IEEE 1364-1995/2001 VCD (.vcd) file, specified as a parameter of type string containing exactly a file path, and returns an R dataframe containing values over time.

A VCD file captures the register values at discrete timepoints from a simulated trace of execution of a hardware design in Verilog or VHDL.

The returned dataframe contains a row for each register, by name, and a column for each time point, specified VCD-style using octothorpe-prefixed multiples of the timescale as strings.

The only non-trivial implementation details are that

  1. VCD ‘x’ and ‘z’ non-numerical values are encoded as negativei values (as otherwise all bit values are positive) and
  2. Registers with repeated names in distinct modules are ignored, rather than duplicated, as we anticipate these registers to have the same values.

Setup

The library and function share the same name, which we load as follows:

library(vcd2df)

Sample Data

We have created a small repository with a few VCD files from common development platforms. We will download a VCD file from the smallest, the “Naive Educational RISC-V Processor” (NERV) which uses a short testbench and generates a manageable file.

f_name <- tempfile()
vcd <- 'https://github.com/vcd2df/vcd_ex/raw/refs/heads/main/nerv.vcd'
download.file(url = vcd, destfile = f_name)

The file nerv.vcd is created as specified in the Makefile of the YosysHQ/nerv repository by running make test which generates a VCD file called testbench.vcd. We simply renamed this file to document its source design, and store it locally on our system as a tempfile().

Load into data frame

With a local file, loading is a single function call.

df <- vcd2df(f_name)

File Management

Once loaded within a data frame, the intial file may be unlinked.

unlink(f_name)

Inspect data frame

Most commonly, we can look at some register names with rownames()

rownames(df)[1:5]
[1] "wr_in_output"    "wr_in_mem_range" "trap"            "imem_addr"      
[5] "dmem_wstrb"     

… or timestamps with colnames().

colnames(df)[1:5]
[1] "#0"  "#5"  "#10" "#15" "#20"

From there, the entire R data science workflow is accessible.