// // This program shows that a C program can output run-time variables into // a VCD (Verilog Change Dump) formatted file and then be viewed by // any standard waveform viewer. This program does nothing interesting, // but the file it produces was viewable. // #include // VCD File FILE *vcdout; // C program variables we want to dump. unsigned int ticks, a, b; // Stick with non-whitespace chars. The character itself is arbitrary. #define TICKS_TAG '!' #define A_TAG '\"' #define B_TAG '#' // Functions for dumping to VCD file. void vcd_header (FILE *vcdout); // Standard header void vcd_startvars (FILE *vcdout); void vcd_addvar (FILE *vcdout, char *name, char tag); void vcd_endvars (FILE *vcdout); void vcd_output_var (FILE *vcdout, int when, int value, char tag); char * vcd_itob (int x); // Helper function for getting binary string for any 32-bit value. int main () { // Open VCD file as a normal ASCII text file for writing. // vcdout = fopen ("test_vcd.vcd", "w"); if (!vcdout) { printf ("\nError opening VCD file."); return 0; } // Always call this. vcd_header (vcdout); // List every variable to be dumped in here along with its // identifying tag character. // vcd_startvars (vcdout); vcd_addvar (vcdout, "ticks", TICKS_TAG); vcd_addvar (vcdout, "a", A_TAG); vcd_addvar (vcdout, "b", B_TAG); vcd_endvars (vcdout); // OK. Start doing C code.. // ticks = 0; // Need some sort of timebase. Say, we have a TICK counter.. a = 100; b = 200; for (ticks = 0; ticks < 10000; ticks++) { a = (a + 31) % 9; b = (b - 5) % 7; // Dump variables to VCD file. Dump them all at once, although the VCD // file can indicate any number at any time. // vcd_output_var (vcdout, ticks, ticks, TICKS_TAG); vcd_output_var (vcdout, ticks, a, A_TAG); vcd_output_var (vcdout, ticks, b, B_TAG); } // Good enough. Close file. fclose (vcdout); } void vcd_header (FILE *vcdout) { fprintf (vcdout, "\n$date"); fprintf (vcdout, "\n Jun 25, 1999 15:31:14"); fprintf (vcdout, "\n$end"); fprintf (vcdout, "\n$version"); fprintf (vcdout, "\n VERILOG-XL 2.5"); fprintf (vcdout, "\n$end"); fprintf (vcdout, "\n$timescale"); fprintf (vcdout, "\n 1s"); fprintf (vcdout, "\n$end"); } // The next 3 functions build up the part of the VCD file that specifies // each variable, its width, index ranges and a special tag char. // This example sticks with dumping 32-bit integers. Obviously, in Verilog, we // are allowed arbitrary widths and index ranges. // // Call this function at the beginning of the declarations. // void vcd_startvars (FILE *vcdout) { fprintf (vcdout, "\n$scope module test $end"); } // This function adds a specific variable definition. 'name' is the literal // name of the variable and is what will show up in the waveform viewer. // void vcd_addvar (FILE *vcdout, char *name, char tag) { fprintf (vcdout, "\n$var reg 32 %c %s [31:0] $end", tag, name); } // Call this one at the end. // void vcd_endvars (FILE *vcdout) { fprintf (vcdout, "\n$upscope $end"); fprintf (vcdout, "\n$enddefinitions $end"); fprintf (vcdout, "\n$dumpvars"); } // This function dumps a change. Indicate the time, the value and the tag. // void vcd_output_var (FILE *vcdout, int when, int value, char tag) { fprintf (vcdout, "\n#%d", when); fprintf (vcdout, "\nb%s %c", vcd_itob(value), tag); } // Convert integer into binary string. // char * vcd_itob (int x) { static char s[33]; int i; s[32] = '\0'; for (i = 31; i >= 0; i--) { if (x & 1) s[i] = '1'; else s[i] = '0'; x >>= 1; } return s; } /* *********************** Example of VCD Format *********************** $date Jun 25, 1999 15:31:14 $end $version VERILOG-XL 2.5 $end $timescale 1s $end $scope module test $end $var reg 1 ! clk $end $var reg 8 " a [7:0] $end $var reg 4 # b [3:0] $end $upscope $end $enddefinitions $end $dumpvars 0! b00000000 " b0000 # $end #14 b00000001 " #27 b0001 # #28 b00000010 " #42 b00000011 " #55 b0000 # #56 b00000100 " ******************************************************************************* */