Writing your own VCD File
Some time ago, we discussed how you can build a scope within your own logic, and even how to get the contents of that scope back out of your FPGA. Today, we’ll finish the discussion by describing what it takes to turn that data into a Value-Change Dump (VCD) file.
The VCD file format structure is a common data format that can be used to store digital logic traces, so that you can then later view it with a waveform viewing tool. GTKWave ingests VCD files easily. Indeed, two of my favorite tools, Verilator and the wishbone scope, will both output VCD traces for this purpose.
One of the really nice parts of this standard is that it is a text-based standard. This means you can view, review, and even edit a VCD file if you really need to with your favorite text editor. While I don’t recommend it, I have needed to load VCD files into gvim from time to time to figure out what’s wrong (or right) with the file.
The standard
The actual standard for the VCD format is part of The IEEE Standard for (the) Verilog Hardware Description Language. My copy is IEEE Std 1364-2005, where the Value Change Dump (VCD) file format is discussed starting on page 325.
While this article will discuss some basic components of the standard, it will by no means by exhaustive. For further information, you’ll want to look up the standard itself.
The VCD Header
The first part of any VCD file is a header. There are two primary components to the VCD file header: basic file meta-data, and variable declarations. White space is used to separate commands, and to make the file more human legible.
The basic file meta-data identifies the program, or program version, that created the VCD file, as well as the date the trace was created on and the timescale it uses. As an example, a recent Verilator VCD output file from the wbuart32 distribution started with the following text:
The first line identifies the tool that created the
VCD
file and what it’s version is. This line begins with $version
, and ends
with $end
.
The second line identifies when this file was created. This field begins
with $date
and ends with $end
.
The third line identifies the timescale. The timescale includes a time
number (1, 10, or 100) followed by a unit (s, ms, us, ns, ps, or fs).
Time integers within the file may then be multiplied by this unit to turn them
into engineering units in a display.
I have typically used a time scale of 1ns
, although I suspect
autofpga files will use more precise
time scales so as to be able to handle multiple dissimilar clocks.
This ends the necessary file meta-data, but not the end of the header yet.
The next section of the header declares your variables. Variables are
defined within a hierarchical scope. Hence, you’ll seen sections of variables
defined by a $scope
line and ending with an $upscope
line. The first
line ($scope
) defines the name of the scope the variables are found within.
For example, variables at the top level of a
Verilator
produced
VCD
file will have a top-level scope of TOP.
The $scope
line has two words within it. The first is the type of scope
being referenced. In this case, it references a module
. The second
is the name of the scope, TOP
, being
Verilator’s
term for the top level of a design.
Variables found within a module foo
within TOP would be defined with
a similar module section, only that this section would be found within the
TOP section.
Variables themselves are declared on lines between $var
and $end
tags.
Four tokens are used, between these two flags, to define any variable,
as shown below:
The first token, var_type specifies the type of variable. The standard
allows many different variable types, although I’ve only ever used wire
.
Other types that might be useful include parameter
, and reg
, although the
standard identifies many more types.
The second token, size specifies the number of bits this value will contain.
The third token is perhaps the most cryptic, although it need not be. This is the identifer_code assigned to this particular variable. This is a printable character, or string of printable characters, used to identify the variable during the data section of the file. We’ll come back to this in a moment.
The last part of the $var
line is the reference. This is the variable
name the user has given to the trace. If the variable had a width, it would
then be followed by something like [MSB:LSB]
. For example, a four bit
trace i_button
could have the reference of i_button[3:0]
.
One line that
GTKWave
understand’s that I haven’t found in the specification is a $timezero
line. This line has three items in it, $timezero
, the internal time
where the zero occurs, and the $end
tag.
wbscope uses this tag to place the
trigger at time zero.
Finally, the header section is ended by an $enddefinitions
line:
If you are confused about these values and terms, consider looking through a VCD file from a reader that works. The files just aren’t that hard to understand.
Data Section
From the end of the header to the end of the file is the data section. This section contains two types of lines: simulation time lines and value change lines.
Simulation time lines start with a #
and a time value. That’s it.
For example,
specifies that the following changes happen at 295
time units. Exactly
how much time this references depends upon the $timescale
command in the
header. Further, the simulation time is an unsigned number. Negative
numbers are not allowed, and will really mess up your
VCD
file. (I know … I’ve tried.)
Value change lines contain the value the variable is taking on, followed by the identifier code for the variable that was assigned in the header. These lines are only necessary any time the value in question changes.
For single bit values, the value in a value change line consists of a
0
, 1
, x
, or z
followed by
the identifier code that was assigned to this value in the header. For
multibit values, a b
precedes all of the bits.
If not all of the bits are given, then the value is left-extended in an
unsigned fashion.
As an example, if J
is defined in the header to reference i_clk
, then
specifies that the clock is now set to zero. Likewise if #
is assigned
to the 8-bit data value i_data[7:0]
, then this value can be set with
Conclusion
While most FPGA programmers will not need to read or write VCD files, anyone wanting to build their own digital logic scope will find it valuable to know how to create VCD files.
And the vision of all is become unto you as the words of a book that is sealed, which men deliver to one that is learned, saying, Read this, I pray thee: and he saith, I cannot; for it is sealed (Is 29:11)