diff --git a/Changes b/Changes index cd853b515..ecb293a7d 100644 --- a/Changes +++ b/Changes @@ -3,6 +3,10 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. [by ...] indicates the contributor was also the author of the fix; Thanks! +* Verilator 3.71**** + +**** Fix VCD files showing internal flattened hierarchy, broke in 3.714. + * Verilator 3.714 2009/09/18 ** Add --bbox-sys option to blackbox $system calls. diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index e6c8f81a1..4bac79500 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -139,6 +139,21 @@ string AstNode::dedotName(const string& namein) { return pretty; } +string AstNode::vcdName(const string& namein) { + // VCD tracing expects space to separate hiearchy + // Dots are reserved for dots the user put in the name + string pretty = namein; + string::size_type pos; + while ((pos=pretty.find("__DOT__")) != string::npos) { + pretty.replace(pos, 7, " "); + } + while ((pos=pretty.find(".")) != string::npos) { + pretty.replace(pos, 1, " "); + } + // Now convert escaped special characters, etc + return prettyName(pretty); +} + string AstNode::prettyName(const string& namein) { string pretty; pretty = ""; diff --git a/src/V3Ast.h b/src/V3Ast.h index 5c40fe699..222be95be 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -676,6 +676,7 @@ public: static string prettyName(const string& namein); // Name for printing out to the user static string encodeName(const string& namein); // Encode user name into internal C representation static string encodeNumber(vlsint64_t numin); // Encode number into internal C representation + static string vcdName(const string& namein); // Name for printing out to vcd files string prettyName() const { return prettyName(name()); } string prettyTypeName() const; // "VARREF name" for error messages FileLine* fileline() const { return m_fileline; } diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index b9531c046..36e644d5d 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -125,8 +125,10 @@ private: AstVar* varp = nodep->varp(); AstScope* scopep = nodep->scopep(); // Compute show name - string showname = scopep->prettyName() + "." + varp->prettyName(); - if (showname.substr(0,4) == "TOP.") showname.replace(0,4,""); + // This code assumes SPTRACEVCDC_VERSION >= 1330; + // it uses spaces to separate hierarchy components. + string showname = AstNode::vcdName(scopep->name() + " " + varp->name()); + if (showname.substr(0,4) == "TOP ") showname.replace(0,4,""); if (!m_initSubFuncp) nodep->v3fatalSrc("NULL"); if (varIgnoreTrace(varp)) { m_statIgnSigs++; diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 0200f5eb7..29502bef8 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -13,7 +13,7 @@ BEGIN { use Getopt::Long; use IO::File; use Pod::Usage; -use Data::Dumper; +use Data::Dumper; $Data::Dumper::Sortkeys=1; use strict; use vars qw ($Debug %Vars $Driver $Fork); use POSIX qw(strftime); @@ -903,17 +903,59 @@ sub vcd_identical { my $fn2 = shift; if (!-r $fn1) { $self->error("File does not exist $fn1\n"); return 0; } if (!-r $fn2) { $self->error("File does not exist $fn2\n"); return 0; } - my $out = `vcddiff --help`; - if ($out !~ /Usage:/) { $self->skip("No vcddiff installed\n"); return 0; } - $out = `vcddiff "$fn1" "$fn2"`; - if ($out ne '') { - print $out; - $self->error("VCD miscompare $fn1 $fn2\n"); - return 0; + { + # vcddiff to check transitions, if installed + my $out = `vcddiff --help`; + if ($out !~ /Usage:/) { $self->skip("No vcddiff installed\n"); return 0; } + my $cmd = qq{vcddiff "$fn1" "$fn2"}; + print "\t$cmd\n" if $::Debug; + $out = `$cmd`; + if ($out ne '') { + print $out; + $self->error("VCD miscompare $fn1 $fn2\n"); + return 0; + } + } + { + # vcddiff doesn't check module and variable scope, so check that + # Also provides backup if vcddiff not installed + my $h1 = $self->_vcd_read($fn1); + my $h2 = $self->_vcd_read($fn2); + $Data::Dumper::Sortkeys=1; + my $a = Dumper($h1); + my $b = Dumper($h2); + if ($a ne $b) { + print "$a\n$b\n" if $::Debug; + $self->error("VCD hier mismatch $fn1 $fn2\n"); + return 0; + } } return 1; } +sub _vcd_read { + my $self = (ref $_[0]? shift : $Self); + my $filename = shift; + my $data = {}; + my $fh = IO::File->new ("<$filename"); + if (!$fh) { warn "%Error: $! $filename\n"; return $data; } + my @hier = ($data); + while (defined(my $line = $fh->getline)) { + if ($line =~ /\$scope module\s+(\S+)/) { + $hier[$#hier]->{$1} ||= {}; + push @hier, $hier[$#hier]->{$1}; + } elsif ($line =~ /(\$var \S+\s+\d+\s+)\S+\s+(\S+)/) { + $hier[$#hier]->{$1.$2} ||= 1; + } elsif ($line =~ /\$enddefinitions/) { + last; + } + while ($line =~ s/\$upscope//) { + pop @hier; + } + } + return $data; +} + sub file_grep_not { my $self = (ref $_[0]? shift : $Self); my $filename = shift; diff --git a/test_regress/t/t_trace_public_func.pl b/test_regress/t/t_trace_public_func.pl index 6374be6b4..7d33dd264 100755 --- a/test_regress/t/t_trace_public_func.pl +++ b/test_regress/t/t_trace_public_func.pl @@ -20,10 +20,9 @@ if ($Self->{v3}) { check_finished=>1, ); - ok(vcd_identical ("$Self->{obj_dir}/simx.vcd", - "t/$Self->{name}.out")); -} -else { - ok(1); + vcd_identical ("$Self->{obj_dir}/simx.vcd", + "t/$Self->{name}.out"); } + +ok(1); 1; diff --git a/test_regress/t/t_trace_public_sig.pl b/test_regress/t/t_trace_public_sig.pl index d6cc41cb1..e0c98cb95 100755 --- a/test_regress/t/t_trace_public_sig.pl +++ b/test_regress/t/t_trace_public_sig.pl @@ -20,10 +20,10 @@ if ($Self->{v3}) { check_finished=>1, ); - ok(vcd_identical ("$Self->{obj_dir}/simx.vcd", - "t/$Self->{name}.out")); -} -else { - ok(1); + vcd_identical ("$Self->{obj_dir}/simx.vcd", + "t/$Self->{name}.out"); + # vcd_identical doesn't detect "$var a.b;" vs "$scope module a; $var b;" + file_grep ("$Self->{obj_dir}/simx.vcd", qr/module glbl/i); } +ok(1); 1; diff --git a/test_regress/t/t_var_escape.out b/test_regress/t/t_var_escape.out new file mode 100644 index 000000000..413243f37 --- /dev/null +++ b/test_regress/t/t_var_escape.out @@ -0,0 +1,244 @@ +$version Generated by SpTraceVcd $end +$date Sat Sep 26 08:06:30 2009 + $end +$timescale 1ns $end + + $scope module TOP $end + $var wire 1 * 9num $end + $var wire 1 + bra[ket]slash/dash-colon:9backslash\done $end + $var wire 1 ' clk $end + $var wire 1 ) double__underscore $end + $var wire 1 ( escaped_normal $end + $scope module v $end + $var wire 1 * 9num $end + $var wire 32 & a0.cyc [31:0] $end + $var wire 1 + bra[ket]slash/dash-colon:9backslash\done $end + $var wire 1 $ check:alias $end + $var wire 1 % check;alias $end + $var wire 1 $ check_alias $end + $var wire 1 ' clk $end + $var wire 32 # cyc [31:0] $end + $var wire 1 ) double__underscore $end + $var wire 1 ( escaped_normal $end + $var wire 32 & other.cyc [31:0] $end + $var wire 1 $ wire $end + $scope module a0 $end + $var wire 32 # cyc [31:0] $end + $upscope $end + $scope module mod.with_dot $end + $var wire 32 # cyc [31:0] $end + $upscope $end + $upscope $end + $upscope $end +$enddefinitions $end + + +#1 +1$ +0% +b11111111111111111111111111111110 & +b00000000000000000000000000000001 # +1' +1( +1) +1* +1+ +#2 +#3 +#4 +#5 +0' +#6 +#7 +#8 +#9 +#10 +0$ +1% +b11111111111111111111111111111101 & +b00000000000000000000000000000010 # +1' +0( +0) +0* +0+ +#11 +#12 +#13 +#14 +#15 +0' +#16 +#17 +#18 +#19 +#20 +1$ +0% +b11111111111111111111111111111100 & +b00000000000000000000000000000011 # +1' +1( +1) +1* +1+ +#21 +#22 +#23 +#24 +#25 +0' +#26 +#27 +#28 +#29 +#30 +0$ +1% +b11111111111111111111111111111011 & +b00000000000000000000000000000100 # +1' +0( +0) +0* +0+ +#31 +#32 +#33 +#34 +#35 +0' +#36 +#37 +#38 +#39 +#40 +1$ +0% +b11111111111111111111111111111010 & +b00000000000000000000000000000101 # +1' +1( +1) +1* +1+ +#41 +#42 +#43 +#44 +#45 +0' +#46 +#47 +#48 +#49 +#50 +0$ +1% +b11111111111111111111111111111001 & +b00000000000000000000000000000110 # +1' +0( +0) +0* +0+ +#51 +#52 +#53 +#54 +#55 +0' +#56 +#57 +#58 +#59 +#60 +1$ +0% +b11111111111111111111111111111000 & +b00000000000000000000000000000111 # +1' +1( +1) +1* +1+ +#61 +#62 +#63 +#64 +#65 +0' +#66 +#67 +#68 +#69 +#70 +0$ +1% +b11111111111111111111111111110111 & +b00000000000000000000000000001000 # +1' +0( +0) +0* +0+ +#71 +#72 +#73 +#74 +#75 +0' +#76 +#77 +#78 +#79 +#80 +1$ +0% +b11111111111111111111111111110110 & +b00000000000000000000000000001001 # +1' +1( +1) +1* +1+ +#81 +#82 +#83 +#84 +#85 +0' +#86 +#87 +#88 +#89 +#90 +0$ +1% +b11111111111111111111111111110101 & +b00000000000000000000000000001010 # +1' +0( +0) +0* +0+ +#91 +#92 +#93 +#94 +#95 +0' +#96 +#97 +#98 +#99 +#100 +1$ +0% +b11111111111111111111111111110100 & +b00000000000000000000000000001011 # +1' +1( +1) +1* +1+ diff --git a/test_regress/t/t_var_escape.pl b/test_regress/t/t_var_escape.pl index 30a6bcc16..6e155aa8d 100755 --- a/test_regress/t/t_var_escape.pl +++ b/test_regress/t/t_var_escape.pl @@ -19,7 +19,11 @@ execute ( if ($Self->{v3}) { file_grep ("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x); my $sig = quotemeta("bra[ket]slash/dash-colon:9"); - file_grep ("$Self->{obj_dir}/simx.vcd", qr/$sig/); + file_grep ("$Self->{obj_dir}/simx.vcd", qr/ $sig/); + file_grep ("$Self->{obj_dir}/simx.vcd", qr/ other\.cyc /); + file_grep ("$Self->{obj_dir}/simx.vcd", qr/ module mod\.with_dot /); + vcd_identical ("$Self->{obj_dir}/simx.vcd", + "t/$Self->{name}.out"); } ok(1); diff --git a/test_regress/t/t_var_escape.v b/test_regress/t/t_var_escape.v index bf4e3c1d9..4d063ec85 100644 --- a/test_regress/t/t_var_escape.v +++ b/test_regress/t/t_var_escape.v @@ -38,6 +38,8 @@ module t (/*AUTOARG*/ sub a0 (.cyc(cyc)); + sub \mod.with_dot (.cyc(cyc)); + always @ (posedge clk) begin cyc <= cyc + 1; if (escaped_normal != cyc[0]) $stop;