VCD

VCD is the Verilog Value Change Dump file format. It's often used in EDA tools to trace values over time and can be displayed with tools like GTKWave.

The following package can be used to generate VCD files:

package require TclOO
package provide vcd

oo::class create VCD {
    constructor {fnm} {
        variable f
        variable c0 32
        variable c1 32
        variable c2 32
        variable c3 32
        set f [open $fnm w]
    }
    destructor {
        variable f
        close $f
    }
    method get_id {} {
        variable c0
        variable c1
        variable c2
        variable c3
        incr c0
        if {$c0 >= 127} {
            incr c1
            set n0 33
        }
        if {$c1 >= 127} {
            incr c2
            set n1 33
        }
        if {$c2 >= 127} {
            incr c3
            set n2 33
        }
        if {$c3 >= 127} {
            error "Out of id's"
        }
        set id ""
        if {$c3 > 32} {
            append id [format %c $c3]
        }
        if {$c2 > 32} {
            append id [format %c $c2]
        }
        if {$c1 > 32} {
            append id [format %c $c1]
        }
        if {$c0 > 32} {
            append id [format %c $c0]
        }
        return $id
    }
    method comment {txt} {
        variable f
        puts $f "\$comment\n$txt\n\$end"
    }
    method date {} {
        variable f
        puts $f "\$date [clock format [clock seconds]] \$end"
    }
    method timescale {number scale} {
        variable f
        puts $f "\$timescale $number $scale \$end"
    }
    method define_variable {type width reference} {
        variable ids
        variable typ
        variable wid
        variable f
        set ids($reference) [my get_id]
        set typ($reference) $type
        set wid($reference) $width
        puts $f "\$var $type $width $ids($reference) $reference \$end"
    }
    method enddefinitions {} {
        variable f
        puts $f "\$enddefinitions \$end"
    }
    method scope {type identifier} {
        variable f
        puts $f "\$scope $type $identifier \$end"
    }
    method upscope { } {
        variable f
        puts $f "\$upscope \$end"
    }
    method version {txt} {
        variable f
        puts $f "\$version\n$txt\n\$end"
    }
    method simulation_time {time} {
        variable f
        puts $f "\#$time"
    }
    method value {reference value} {
        variable ids
        variable typ
        variable wid
        variable f
        switch -exact -- $typ($reference) {
            "integer" {
                if {![string is integer -strict $value]} {
                    error "Value '$value' for reference '$reference' is not an integer"
                }
                puts $f "b[string trimleft [format %b $value] 0] $ids($reference)"
            }
            "real" {
                error "Unsupported type '$typ($reference)' for reference '$reference'"
            }
            default {
                if {$value ni {0 1 x z}} {
                    error "Value '$value' for reference '$reference' must be 0, 1, x or z"
                }
                puts $f "$value$ids($reference)"
            }
        }
    }
}

Example usage:

VCD create log test.vcd
log comment "Some comments from the user"
log date
log define_variable integer 32 var1
log define_variable integer 32 var2
log define_variable integer 32 var3
log define_variable integer 32 var4
log define_variable integer 32 var5
log define_variable integer 32 var6
log define_variable integer 32 var7
log define_variable integer 32 var8
log define_variable wire 1 wire1
log define_variable wire 1 wire2
log define_variable wire 1 wire3
log define_variable wire 1 wire4
log define_variable wire 1 wire5
log define_variable wire 1 wire6
log define_variable wire 1 wire7
log define_variable wire 1 wire8
log timescale 10 ns
log enddefinitions
log simulation_time 10
log value var1 [expr {entier(rand()*0xffffffff)}]
log value wire1 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log simulation_time 20
log value var2 [expr {entier(rand()*0xffffffff)}]
log value wire1 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log simulation_time 30
log value var3 [expr {entier(rand()*0xffffffff)}]
log value wire1 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log simulation_time 40
log value var4 [expr {entier(rand()*0xffffffff)}]
log value var5 [expr {entier(rand()*0xffffffff)}]
log value wire1 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log simulation_time 50
log value var6 [expr {entier(rand()*0xffffffff)}]
log value var7 [expr {entier(rand()*0xffffffff)}]
log value var8 [expr {entier(rand()*0xffffffff)}]
log value var1 [expr {entier(rand()*0xffffffff)}]
log value wire1 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log value wire6 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log simulation_time 60
log value var2 [expr {entier(rand()*0xffffffff)}]
log value var3 [expr {entier(rand()*0xffffffff)}]
log value wire1 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log value wire5 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log simulation_time 70
log value var4 [expr {entier(rand()*0xffffffff)}]
log value var5 [expr {entier(rand()*0xffffffff)}]
log value var6 [expr {entier(rand()*0xffffffff)}]
log value wire1 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log value wire4 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log simulation_time 80
log value var7 [expr {entier(rand()*0xffffffff)}]
log value var8 [expr {entier(rand()*0xffffffff)}]
log value wire1 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log value wire2 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log simulation_time 90
log value var1 [expr {entier(rand()*0xffffffff)}]
log value var3 [expr {entier(rand()*0xffffffff)}]
log value wire1 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log value wire2 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log simulation_time 100
log value var5 [expr {entier(rand()*0xffffffff)}]
log value var7 [expr {entier(rand()*0xffffffff)}]
log value var2 [expr {entier(rand()*0xffffffff)}]
log value var4 [expr {entier(rand()*0xffffffff)}]
log value var6 [expr {entier(rand()*0xffffffff)}]
log value var8 [expr {entier(rand()*0xffffffff)}]
log value var1 [expr {entier(rand()*0xffffffff)}]
log value var3 [expr {entier(rand()*0xffffffff)}]
log value wire1 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log value wire1 [lindex {0 1 x z} [expr {round(rand()*3)}]]
log destroy

The resulting output file looks like this:

$comment
Some comments from the user
$end
$date Thu Oct 28 17:24:16 CEST 2010 $end
$var integer 32 ! var1 $end
$var integer 32 " var2 $end
$var integer 32 # var3 $end
$var integer 32 $ var4 $end
$var integer 32 % var5 $end
$var integer 32 & var6 $end
$var integer 32 ' var7 $end
$var integer 32 ( var8 $end
$var wire 1 ) wire1 $end
$var wire 1 * wire2 $end
$var wire 1 + wire3 $end
$var wire 1 , wire4 $end
$var wire 1 - wire5 $end
$var wire 1 . wire6 $end
$var wire 1 / wire7 $end
$var wire 1 0 wire8 $end
$timescale 10 ns $end
$enddefinitions $end
#10
b1001010000001011110011111110 !
1)
#20
b111110010011110000101100111100 "
x)
#30
b10111101010011110101010110111010 #
x)
#40
b10010011011111101001101010100000 $
b1011100110110011100101000000110 %
z)
#50
b1110000001110010101111000110 &
b11111000110010101101101101011010 '
b11001110000001110111000101010000 (
b1001010101000001010010011011100 !
1)
1.
#60
b11000010100101110010000010010010 "
b1001111110110111011010100001100 #
z)
0-
#70
b1110110110010111110011011101000 $
b1000100101001001100011001000110 %
b10011101110101010100000011011110 &
0)
0,
#80
b100111010011011001000011011010 '
b1010101011000001110110001011110 (
1)
z*
#90
b11110101101011001011100011010000 !
b11110100110011101110110110010 #
0)
0*
#100
b10100010101111011101001101110100 %
b1011100100001011011100000100100 '
b1001110111111000111001011110000 "
b10011111110111100001001100010010 $
b10101100101101100101010010111100 &
b11110110011101010101101100111000 (
b10010010101110000011011111110000 !
b1111100011000001011100011010000 #
x)
x)