fail svinterfaces testcases on yosys error exit
[yosys.git] / tests / tools / vcdcd.pl
1 #!/usr/bin/perl -w
2 #
3 # Note: You might need to install the Verilog::VCD package using CPAN..
4
5 use strict;
6 use Data::Dumper;
7 use Verilog::VCD qw(parse_vcd list_sigs);
8
9 $| = 1;
10
11 my $opt_width = 0;
12 my $opt_delay = 0;
13
14 while (1)
15 {
16 if ($ARGV[0] eq '-w') {
17 $opt_width = +$ARGV[1];
18 shift @ARGV;
19 shift @ARGV;
20 next;
21 }
22 if ($ARGV[0] eq '-d') {
23 $opt_delay = +$ARGV[1];
24 shift @ARGV;
25 shift @ARGV;
26 next;
27 }
28 last;
29 }
30
31 if ($#ARGV != 1) {
32 print STDERR "\n";
33 print STDERR "VCDCD - Value Change Dump Change Dumper\n";
34 print STDERR "\n";
35 print STDERR "Usage: $0 [-w N] [-d N] gold.vcd gate.vcd\n";
36 print STDERR "\n";
37 print STDERR " -w N\n";
38 print STDERR " reserve N characters for bitmap in text output (default: auto)\n";
39 print STDERR "\n";
40 print STDERR " -d N\n";
41 print STDERR " allow for N timesteps delay between gate and gold (default: 0)\n";
42 print STDERR "\n";
43 print STDERR "Compare a known-good (gold) vcd file with a second (gate) vcd file.\n";
44 print STDERR "This is not very efficient -- so use with care on large vcd files.\n";
45 print STDERR "\n";
46 exit 1;
47 }
48
49 my $fn_gold = $ARGV[0];
50 my $fn_gate = $ARGV[1];
51
52 print "Finding common signals..\n";
53 my @gold_signals = list_sigs($fn_gold);
54 my @gate_signals = list_sigs($fn_gate);
55
56 my %gold_signals_hash;
57 my %gate_signals_hash;
58
59 for (@gold_signals) {
60 my $fullname = $_;
61 s/(\[([0-9]+|[0-9]+:[0-9]+)\])$//;
62 $gold_signals_hash{$_}->{$fullname} = 1 unless /(^|\.)_[0-9]+_/;
63 }
64
65 for (@gate_signals) {
66 my $fullname = $_;
67 s/(\[([0-9]+|[0-9]+:[0-9]+)\])$//;
68 $gate_signals_hash{$_}->{$fullname} = 1 unless /(^|\.)_[0-9]+_/;
69 }
70
71 my @signals;
72 for my $net (sort keys %gold_signals_hash) {
73 next unless exists $gate_signals_hash{$net};
74 # next unless $net eq "tst_bench_top.i2c_top.byte_controller.bit_controller.cnt";
75 my %orig_net_names;
76 print "common signal: $net";
77 for my $fullname (keys $gold_signals_hash{$net}) {
78 $orig_net_names{$fullname} = 1;
79 }
80 for my $fullname (keys $gate_signals_hash{$net}) {
81 $orig_net_names{$fullname} = 1;
82 }
83 for my $net (sort keys %orig_net_names) {
84 push @signals, $net;
85 print " $1" if /(\[([0-9]+|[0-9]+:[0-9]+)\])$/;
86 }
87 print "\n";
88 }
89
90 print "Loading gold vcd data..\n";
91 my $vcd_gold = parse_vcd($fn_gold, {siglist => \@signals});
92
93 print "Loading gate vcd data..\n";
94 my $vcd_gate = parse_vcd($fn_gate, {siglist => \@signals});
95
96 # print Dumper($vcd_gold);
97 # print Dumper($vcd_gate);
98
99 my %times;
100 my $signal_maxlen = 8;
101 my $data_gold = { };
102 my $data_gate = { };
103
104 sub checklen($$)
105 {
106 my ($net, $val) = @_;
107 my $thislen = length $val;
108 $thislen += $1 if $net =~ /\[([0-9]+)\]$/;
109 $thislen += $1 if $net =~ /\[([0-9]+):[0-9]+\]$/;
110 $signal_maxlen = $thislen if $signal_maxlen < $thislen;
111 }
112
113 print "Processing gold vcd data..\n";
114 for my $key (keys %$vcd_gold) {
115 for my $net (@{$vcd_gold->{$key}->{'nets'}}) {
116 my $netname = $net->{'hier'} . "." . $net->{'name'};
117 for my $tv (@{$vcd_gold->{$key}->{'tv'}}) {
118 my $time = int($tv->[0]);
119 my $value = $tv->[1];
120 checklen($netname, $value);
121 $data_gold->{$time}->{$netname} = $value;
122 $times{$time} = 1;
123 }
124 }
125 }
126
127 print "Processing gate vcd data..\n";
128 for my $key (keys %$vcd_gate) {
129 for my $net (@{$vcd_gate->{$key}->{'nets'}}) {
130 my $netname = $net->{'hier'} . "." . $net->{'name'};
131 for my $tv (@{$vcd_gate->{$key}->{'tv'}}) {
132 my $time = int($tv->[0]);
133 my $value = $tv->[1];
134 checklen($netname, $value);
135 $data_gate->{$time}->{$netname} = $value;
136 $times{$time} = 1;
137 }
138 }
139 }
140
141 $signal_maxlen = $opt_width if $opt_width > 0;
142
143 my $diffcount = 0;
144 my %state_gold;
145 my %state_gate;
146 my %signal_sync;
147 my %touched_nets;
148
149 sub set_state_bit($$$$)
150 {
151 my ($state, $net, $bit, $value) = @_;
152 my @data;
153 @data = split //, $state->{$net} if exists $state->{$net};
154 unshift @data, "-" while $#data < $bit;
155 $data[$#data - $bit] = $value;
156 $state->{$net} = join "", @data;
157 $signal_sync{$net} = 1 unless exists $signal_sync{$net};
158 $touched_nets{$net} = 1;
159 }
160
161 sub set_state($$$)
162 {
163 my ($state, $net, $value) = @_;
164
165 if ($net =~ /(.*)\[([0-9]+)\]$/) {
166 set_state_bit($state, $1, $2, $value);
167 return;
168 }
169
170 if ($net =~ /(.*)\[([0-9]+):([0-9]+)\]$/) {
171 my ($n, $u, $d) = ($1, $2, $3);
172 my @bits = split //, $value;
173 my $extbit = $bits[0] eq "1" ? "0" : $bits[0];
174 unshift @bits, $extbit while $#bits < $u - $d;
175 set_state_bit($state, $n, $u--, shift @bits) while $u >= $d;
176 return;
177 }
178
179 $state->{$net} = $value;
180 $signal_sync{$net} = 1 unless exists $signal_sync{$net};
181 $touched_nets{$net} = 1;
182 }
183
184 sub cmp_signal($$)
185 {
186 my ($a, $b) = @_;
187 return 1 if $a eq $b;
188
189 my @a = split //, $a;
190 my @b = split //, $b;
191
192 my $trail_a = $#a < 0 ? '-' : $a[0] eq '1' ? '0' : $a[0];
193 my $trail_b = $#b < 0 ? '-' : $b[0] eq '1' ? '0' : $b[0];
194
195 unshift @a, $trail_a while $#a < $#b;
196 unshift @b, $trail_b while $#b < $#a;
197
198 for (my $i = 0; $i <= $#a; $i++) {
199 next if $a[$i] eq "-" || $b[$i] eq "-";
200 return 0 if $a[$i] ne "x" && $a[$i] ne $b[$i];
201 }
202
203 return 1;
204 }
205
206 # Message objects: .text, .time, .signal, .sync
207 my @messages;
208
209 print "Comparing vcd data..\n";
210 for my $time (sort { $a <=> $b } keys %times)
211 {
212 %touched_nets = ();
213 for my $net (keys %{$data_gold->{$time}}) {
214 set_state(\%state_gold, $net, $data_gold->{$time}->{$net});
215 }
216 for my $net (keys %{$data_gate->{$time}}) {
217 set_state(\%state_gate, $net, $data_gate->{$time}->{$net});
218 }
219 for my $net (sort keys %touched_nets) {
220 my ($stgo, $stga) = ('-', '-');
221 $stgo = $state_gold{$net} if exists $state_gold{$net};
222 $stga = $state_gate{$net} if exists $state_gate{$net};
223 if (cmp_signal($stgo, $stga)) {
224 next if $signal_sync{$net};
225 my $message = { };
226 $message->{text} = sprintf "%-10s %-20d %-*s %-*s %s\n", "<sync>", $time, $signal_maxlen, $stgo, $signal_maxlen, $stga, $net;
227 $message->{time} = $time;
228 $message->{signal} = $net;
229 $message->{sync} = 1;
230 push @messages, $message;
231 $signal_sync{$net} = 1;
232 } else {
233 my $message = { };
234 $message->{text} = sprintf "%-10d %-20d %-*s %-*s %s\n", $diffcount, $time, $signal_maxlen, $stgo, $signal_maxlen, $stga, $net;
235 $message->{time} = $time;
236 $message->{signal} = $net;
237 $message->{sync} = 0;
238 push @messages, $message;
239 $signal_sync{$net} = 0;
240 $diffcount++;
241 }
242 }
243 }
244
245 print "Found $diffcount differences.\n";
246
247 if ($opt_delay > 0) {
248 my %per_net_history;
249 my $removed_diff_count = 0;
250 for (my $i = 0; $i <= $#messages; $i++) {
251 my $message = $messages[$i];
252 $message->{deleted} = 0;
253 $per_net_history{$message->{signal}} = [ ] unless exists $per_net_history{$message->{signal}};
254 if ($message->{sync}) {
255 my $deleted_all = 1;
256 for my $j (@{$per_net_history{$message->{signal}}}) {
257 my $m = $messages[$j];
258 if ($m->{time} + $opt_delay >= $message->{time}) {
259 $m->{deleted} = 1;
260 $removed_diff_count++;
261 } else {
262 $deleted_all = 0;
263 }
264 }
265 $message->{deleted} = 1 if $deleted_all;
266 $per_net_history{$message->{signal}} = [ ];
267 } else {
268 push @{$per_net_history{$message->{signal}}}, $i;
269 }
270 }
271 my @new_messages;
272 for my $message (@messages) {
273 push @new_messages, $message unless $message->{deleted};
274 }
275 @messages = @new_messages;
276 printf "Removed %d differences using delay filtering.\n", $removed_diff_count;
277 $diffcount = $diffcount - $removed_diff_count;
278 }
279
280 if ($#messages >= 0) {
281 printf "\n%-10s %-20s %-*s %-*s %s\n", "count", "time", $signal_maxlen, "gold", $signal_maxlen, "gate", "net" if $diffcount++ == 0;
282 for (my $i = 0; $i <= $#messages; $i++) {
283 printf "%s", $messages[$i]->{text};
284 }
285 }
286
287 exit ($diffcount > 0 ? 1 : 0);