From 7764d0ba1dcf064ae487ee985c43083a0909e7f4 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 5 Jan 2013 11:13:26 +0100 Subject: initial import --- tests/tools/vcdcd.pl | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100755 tests/tools/vcdcd.pl (limited to 'tests/tools/vcdcd.pl') diff --git a/tests/tools/vcdcd.pl b/tests/tools/vcdcd.pl new file mode 100755 index 00000000..4875eeeb --- /dev/null +++ b/tests/tools/vcdcd.pl @@ -0,0 +1,201 @@ +#!/usr/bin/perl -w +# +# Note: You might need to install the Verilog::VCD package using CPAN.. + +use strict; +use Data::Dumper; +use Verilog::VCD qw(parse_vcd list_sigs); + +$| = 1; + +if ($#ARGV != 1) { + print STDERR "\n"; + print STDERR "VCDCD - Value Change Dump Change Dumper\n"; + print STDERR "\n"; + print STDERR "Usage: $0 gold.vcd gate.vcd\n"; + print STDERR "\n"; + print STDERR "Compare a known-good (gold) vcd file with a second (gate) vcd file.\n"; + print STDERR "This is not very efficient -- so use with care with large vcd files.\n"; + print STDERR "\n"; + exit 1; +} + +my $fn_gold = $ARGV[0]; +my $fn_gate = $ARGV[1]; + +print "Finding common signals..\n"; +my @gold_signals = list_sigs($fn_gold); +my @gate_signals = list_sigs($fn_gate); + +my %gold_signals_hash; +my %gate_signals_hash; + +for (@gold_signals) { + my $fullname = $_; + s/(\[([0-9]+|[0-9]+:[0-9]+)\])$//; + $gold_signals_hash{$_}->{$fullname} = 1 unless /(^|\.)_[0-9]+_/; +} + +for (@gate_signals) { + my $fullname = $_; + s/(\[([0-9]+|[0-9]+:[0-9]+)\])$//; + $gate_signals_hash{$_}->{$fullname} = 1 unless /(^|\.)_[0-9]+_/; +} + +my @signals; +for my $net (sort keys %gold_signals_hash) { + next unless exists $gate_signals_hash{$net}; + # next unless $net eq "tst_bench_top.i2c_top.byte_controller.bit_controller.cnt"; + my %orig_net_names; + print "common signal: $net"; + for my $fullname (keys $gold_signals_hash{$net}) { + $orig_net_names{$fullname} = 1; + } + for my $fullname (keys $gate_signals_hash{$net}) { + $orig_net_names{$fullname} = 1; + } + for my $_ (sort keys %orig_net_names) { + push @signals, $_; + print " $1" if /(\[([0-9]+|[0-9]+:[0-9]+)\])$/; + } + print "\n"; +} + +print "Loading gold vcd data..\n"; +my $vcd_gold = parse_vcd($fn_gold, {siglist => \@signals}); + +print "Loading gate vcd data..\n"; +my $vcd_gate = parse_vcd($fn_gate, {siglist => \@signals}); + +# print Dumper($vcd_gold); +# print Dumper($vcd_gate); + +my %times; +my $signal_maxlen = 8; +my $data_gold = { }; +my $data_gate = { }; + +sub checklen($$) +{ + my ($net, $val) = @_; + my $thislen = length $val; + $thislen += $1 if $net =~ /\[([0-9]+)\]$/; + $thislen += $1 if $net =~ /\[([0-9]+):[0-9]+\]$/; + $signal_maxlen = $thislen if $signal_maxlen < $thislen; +} + +print "Processing gold vcd data..\n"; +for my $key (keys %$vcd_gold) { + for my $net (@{$vcd_gold->{$key}->{'nets'}}) { + my $netname = $net->{'hier'} . "." . $net->{'name'}; + for my $tv (@{$vcd_gold->{$key}->{'tv'}}) { + my $time = int($tv->[0]); + my $value = $tv->[1]; + checklen($netname, $value); + $data_gold->{$time}->{$netname} = $value; + $times{$time} = 1; + } + } +} + +print "Processing gate vcd data..\n"; +for my $key (keys %$vcd_gate) { + for my $net (@{$vcd_gate->{$key}->{'nets'}}) { + my $netname = $net->{'hier'} . "." . $net->{'name'}; + for my $tv (@{$vcd_gate->{$key}->{'tv'}}) { + my $time = int($tv->[0]); + my $value = $tv->[1]; + checklen($netname, $value); + $data_gate->{$time}->{$netname} = $value; + $times{$time} = 1; + } + } +} + +my $diffcount = 0; +my %state_gold; +my %state_gate; +my %signal_sync; +my %touched_nets; + +sub set_state_bit($$$$) +{ + my ($state, $net, $bit, $value) = @_; + my @data; + @data = split //, $state->{$net} if exists $state->{$net}; + unshift @data, "-" while $#data < $bit; + $data[$#data - $bit] = $value; + $state->{$net} = join "", @data; + $signal_sync{$net} = 1 unless exists $signal_sync{$net}; + $touched_nets{$net} = 1; +} + +sub set_state($$$) +{ + my ($state, $net, $value) = @_; + + if ($net =~ /(.*)\[([0-9]+)\]$/) { + set_state_bit($state, $1, $2, $value); + return; + } + + if ($net =~ /(.*)\[([0-9]+):([0-9]+)\]$/) { + my ($n, $u, $d) = ($1, $2, $3); + my @bits = split //, $value; + my $extbit = $bits[0] eq "1" ? "0" : $bits[0]; + unshift @bits, $extbit while $#bits < $u - $d; + set_state_bit($state, $n, $u--, shift @bits) while $u >= $d; + return; + } + + $state->{$net} = $value; + $signal_sync{$net} = 1 unless exists $signal_sync{$net}; + $touched_nets{$net} = 1; +} + +sub cmp_signal($$) +{ + my ($a, $b) = @_; + return 1 if $a eq $b; + + my @a = split //, $a; + my @b = split //, $b; + + unshift @a, "-" while $#a < $#b; + unshift @b, "-" while $#b < $#a; + + for (my $i = 0; $i <= $#a; $i++) { + return 0 if $a[$i] ne "x" && $a[$i] ne $b[$i]; + } + + return 1; +} + +print "Comparing vcd data..\n"; +for my $time (sort { $a <=> $b } keys %times) +{ + %touched_nets = (); + for my $net (keys %{$data_gold->{$time}}) { + set_state(\%state_gold, $net, $data_gold->{$time}->{$net}); + } + for my $net (keys %{$data_gate->{$time}}) { + set_state(\%state_gate, $net, $data_gate->{$time}->{$net}); + } + for my $net (sort keys %touched_nets) { + my ($stgo, $stga) = ('-', '-'); + $stgo = $state_gold{$net} if exists $state_gold{$net}; + $stga = $state_gate{$net} if exists $state_gate{$net}; + if (cmp_signal($stgo, $stga)) { + next if $signal_sync{$net}; + printf "%-10s %-20d %-*s %-*s %s\n", "", $time, $signal_maxlen, $stgo, $signal_maxlen, $stga, $net; + $signal_sync{$net} = 1; + } else { + printf "\n%-10s %-20s %-*s %-*s %s\n", "count", "time", $signal_maxlen, "gold", $signal_maxlen, "gate", "net" if $diffcount++ == 0; + printf "%-10d %-20d %-*s %-*s %s\n", $diffcount, $time, $signal_maxlen, $stgo, $signal_maxlen, $stga, $net; + $signal_sync{$net} = 0; + } + } +} + +print "Found $diffcount differences.\n"; +exit ($diffcount > 0 ? 1 : 0); -- cgit v1.2.3