2020-01-10 01:01:12 +00:00
|
|
|
#!/usr/bin/env perl
|
2008-11-19 14:43:03 +00:00
|
|
|
# See copyright, etc in below POD section.
|
2006-08-26 11:35:28 +00:00
|
|
|
######################################################################
|
|
|
|
|
|
|
|
use warnings;
|
|
|
|
use Getopt::Long;
|
|
|
|
use IO::File;
|
|
|
|
use Pod::Usage;
|
|
|
|
use strict;
|
2018-11-29 00:59:10 +00:00
|
|
|
use vars qw($Debug);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
#======================================================================
|
|
|
|
|
2012-04-28 17:00:44 +00:00
|
|
|
# Old version 1 dump nodes with no dtypep's
|
|
|
|
our %Ver1_Non_Dtyped = map {$_ => 1} qw(
|
|
|
|
ACTIVE ALWAYS ALWAYSPOST ALWAYSPUBLIC ATTROF BEGIN BREAK CASE CASEITEM
|
|
|
|
CCALL CELL CELLINLINE CFILE CFUNC CHANGEDET CLOCKING COMMENT CONTINUE
|
|
|
|
COVERDECL COVERINC COVERTOGGLE CRETURN CSTMT DEFPARAM DISABLE DISPLAY DOT
|
|
|
|
DPIEXPORT FCLOSE FFLUSH FINAL FINISH FOPEN GENCASE GENERATE GENFOR GENIF
|
|
|
|
IF IMPLICIT INITARRAY INITIAL JUMPGO JUMPLABEL MODULE NETLIST
|
|
|
|
NOTFOUNDMODULE PACKAGE PACKAGEIMPORT PARSEREF PIN PORT PRAGMA PRIMITIVE
|
|
|
|
PSLASSERT PSLCOVER PSLDEFCLOCK PULL RANGE READMEM REPEAT RETURN SCCTOR
|
|
|
|
SCDTOR SCHDR SCIMP SCIMPHDR SCINT SCOPE SELBIT SELEXTRACT SELMINUS
|
|
|
|
SELPLUS SENGATE SENITEM SENTREE SFORMAT SFORMATF STOP SYSIGNORE SYSTEMT
|
|
|
|
TASK TASKREF TEXT TOPSCOPE TYPEDEFFWD TYPETABLE UCSTMT UDPTABLE
|
|
|
|
UDPTABLELINE UNTILSTABLE VASSERT WHILE );
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
#======================================================================
|
|
|
|
# main
|
|
|
|
|
|
|
|
$Debug = 0;
|
|
|
|
my $Opt_A;
|
|
|
|
my $Opt_B;
|
2008-11-19 14:43:03 +00:00
|
|
|
my $Opt_Lineno = 1;
|
2006-08-26 11:35:28 +00:00
|
|
|
autoflush STDOUT 1;
|
|
|
|
autoflush STDERR 1;
|
2018-11-29 00:59:10 +00:00
|
|
|
Getopt::Long::config("no_auto_abbrev");
|
2019-05-08 02:34:09 +00:00
|
|
|
if (! GetOptions(
|
|
|
|
"help" => \&usage,
|
|
|
|
"debug" => \&debug,
|
|
|
|
"<>" => \¶meter,
|
|
|
|
"lineno!" => \$Opt_Lineno,
|
2008-11-19 14:43:03 +00:00
|
|
|
)) {
|
2007-05-18 18:48:22 +00:00
|
|
|
die "%Error: Bad usage, try 'verilator_difftree --help'\n";
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
defined $Opt_A or die "%Error: No old diff filename\n";
|
|
|
|
defined $Opt_B or die "%Error: No new diff filename\n";
|
|
|
|
|
2006-12-21 14:35:19 +00:00
|
|
|
-e $Opt_A or die "%Error: No old diff filename found: $Opt_A\n";
|
|
|
|
-e $Opt_B or die "%Error: No new diff filename found: $Opt_B\n";
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
if (-d $Opt_A && -d $Opt_B) {
|
2018-11-29 00:59:10 +00:00
|
|
|
diff_dir($Opt_A, $Opt_B);
|
2006-08-26 11:35:28 +00:00
|
|
|
} elsif (-f $Opt_A && -f $Opt_B) {
|
2018-11-29 00:59:10 +00:00
|
|
|
diff_file($Opt_A, $Opt_B);
|
2006-08-26 11:35:28 +00:00
|
|
|
} else {
|
|
|
|
die "%Error: Mix of files and dirs\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
sub diff_dir {
|
|
|
|
my $a = shift;
|
|
|
|
my $b = shift;
|
|
|
|
# Diff all files under two directories
|
|
|
|
my %files;
|
|
|
|
|
|
|
|
foreach my $fn (glob("$a/*.tree")) {
|
2019-05-08 02:34:09 +00:00
|
|
|
(my $base = $fn) =~ s!.*/!!;
|
|
|
|
$files{$base}{a} = $fn;
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
foreach my $fn (glob("$b/*.tree")) {
|
2019-05-08 02:34:09 +00:00
|
|
|
(my $base = $fn) =~ s!.*/!!;
|
|
|
|
$files{$base}{b} = $fn;
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2009-11-05 03:31:53 +00:00
|
|
|
my $any;
|
2006-08-26 11:35:28 +00:00
|
|
|
foreach my $base (sort (keys %files)) {
|
2019-05-08 02:34:09 +00:00
|
|
|
my $a = $files{$base}{a};
|
|
|
|
my $b = $files{$base}{b};
|
|
|
|
next if !$a || !$b;
|
|
|
|
print "="x70,"\n";
|
|
|
|
print "= $a <-> $b\n";
|
|
|
|
diff_file($a,$b);
|
|
|
|
$any = 1;
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2018-11-29 00:59:10 +00:00
|
|
|
$any or warn("%Warning: No .tree files found that have similar base names:\n "
|
|
|
|
.join("\n ", sort keys %files),"\n");
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub diff_file {
|
|
|
|
my $a = shift;
|
|
|
|
my $b = shift;
|
|
|
|
# Compare the two tree files
|
2012-07-21 13:16:19 +00:00
|
|
|
(my $short_a = $a) =~ s/[^a-zA-Z0-9.]+/_/g;
|
|
|
|
(my $short_b = $b) =~ s/[^a-zA-Z0-9.]+/_/g;
|
|
|
|
my $tmp_a = "/tmp/${$}_${short_a}.a";
|
|
|
|
my $tmp_b = "/tmp/${$}_${short_b}.b";
|
2006-08-26 11:35:28 +00:00
|
|
|
|
2012-04-28 17:00:44 +00:00
|
|
|
my $vera = version_from($a);
|
|
|
|
my $verb = version_from($b);
|
|
|
|
my $verCvt = (($vera < 0x3900 && $verb >= 0x3900)
|
2019-05-08 02:34:09 +00:00
|
|
|
|| ($vera >= 0x3900 && $verb < 0x3900));
|
2012-04-28 17:00:44 +00:00
|
|
|
|
2018-11-29 00:59:10 +00:00
|
|
|
filter($a, $tmp_a, $verCvt);
|
|
|
|
filter($b, $tmp_b, $verCvt);
|
2009-05-07 22:28:05 +00:00
|
|
|
system("diff -u $tmp_a $tmp_b");
|
2006-08-26 11:35:28 +00:00
|
|
|
unlink $tmp_a;
|
|
|
|
unlink $tmp_b;
|
|
|
|
}
|
|
|
|
|
2012-04-28 17:00:44 +00:00
|
|
|
sub version_from {
|
|
|
|
my $fn = shift;
|
|
|
|
# Return dump format
|
|
|
|
my $f1 = IO::File->new ($fn) or die "%Error: $! $fn,";
|
|
|
|
while (defined (my $line=$f1->getline())) {
|
2019-05-08 02:34:09 +00:00
|
|
|
last if $. > 10;
|
|
|
|
return hex $1 if $line =~ /\(format (0x[0-9.]+)\)/;
|
2012-04-28 17:00:44 +00:00
|
|
|
}
|
|
|
|
return 1.0;
|
|
|
|
}
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
sub filter {
|
|
|
|
my $fn1 = shift;
|
|
|
|
my $fn2 = shift;
|
2012-04-28 17:00:44 +00:00
|
|
|
my $verCvt = shift;
|
2006-08-26 11:35:28 +00:00
|
|
|
# Remove hex numbers before diffing
|
|
|
|
my $f1 = IO::File->new ($fn1) or die "%Error: $! $fn1,";
|
|
|
|
my $f2 = IO::File->new ($fn2,"w") or die "%Error: $! $fn2,";
|
|
|
|
while (defined (my $line=$f1->getline())) {
|
2012-04-28 17:00:44 +00:00
|
|
|
same_line:
|
2019-05-08 02:34:09 +00:00
|
|
|
next if $line =~ / This=/;
|
|
|
|
$line =~ s/0x[a-f0-9]+/0x/g;
|
|
|
|
$line =~ s/<e[0-9]+\#?>/<e>/g;
|
|
|
|
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
|
|
|
|
if ($verCvt) {
|
|
|
|
next if $line =~ /^ NETLIST/;
|
|
|
|
$line =~ s!\@dt=0x\(G?/?([^)]+)\)!$1!g; # NEW: @dt -> OLD: non @dt format
|
|
|
|
# # Below Ver1_Non_Dtyped may replace above further
|
|
|
|
if ($line =~ /: ([A-Z]+) /) {
|
|
|
|
my $type = $1;
|
|
|
|
next if $type =~ 'DTYPE';
|
|
|
|
if ($type eq 'TYPETABLE' || $type eq 'RANGE') {
|
|
|
|
$line =~ /^(\s+\S+:) /; my $prefix = $1;
|
|
|
|
while (defined ($line=$f1->getline())) {
|
|
|
|
next if $line =~ /^\s+[a-z]/; # Table body
|
|
|
|
next if $line =~ /^${prefix}[0-9]:/;
|
|
|
|
goto same_line;
|
|
|
|
}
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
if ($Ver1_Non_Dtyped{$type}) {
|
|
|
|
$line =~ s! w[0-9]+!!g;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$line =~ s!\@dt=0$!NoW!g; # NEW: dt=null -> common format
|
|
|
|
$line =~ s!\@dt=0 !NoW !g; # NEW: dt=null -> common format
|
|
|
|
$line =~ s! s?w0$! NoW!g; # OLD: no width -> common format
|
|
|
|
$line =~ s! s?w0 ! NoW !g; # OLD: no width -> common format
|
|
|
|
}
|
|
|
|
print $f2 $line;
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
$f1->close;
|
|
|
|
$f2->close;
|
|
|
|
}
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
|
|
|
|
sub usage {
|
2019-10-01 03:15:10 +00:00
|
|
|
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
|
|
|
|
exit(1); # Unreachable
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub debug {
|
|
|
|
$Debug = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub parameter {
|
|
|
|
my $param = shift;
|
|
|
|
if (!defined $Opt_A) {
|
2019-05-08 02:34:09 +00:00
|
|
|
$Opt_A = $param;
|
2006-08-26 11:35:28 +00:00
|
|
|
} elsif (!defined $Opt_B) {
|
2019-05-08 02:34:09 +00:00
|
|
|
$Opt_B = $param;
|
2008-06-10 01:25:10 +00:00
|
|
|
} else {
|
2019-05-08 02:34:09 +00:00
|
|
|
die "%Error: Unknown parameter: $param\n";
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#######################################################################
|
|
|
|
|
|
|
|
sub run {
|
|
|
|
# Run a system command, check errors
|
|
|
|
my $command = shift;
|
|
|
|
print "\t$command\n";
|
|
|
|
system "$command";
|
|
|
|
my $status = $?;
|
|
|
|
($status == 0) or die "%Error: Command Failed $command, $status, stopped";
|
|
|
|
}
|
|
|
|
|
|
|
|
#######################################################################
|
|
|
|
__END__
|
|
|
|
|
|
|
|
=pod
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
verilator_difftree - Compare two Verilator debugging trees
|
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
|
|
|
verilator_difftree .../a/a.tree .../b/a.tree
|
|
|
|
verilator_difftree .../a .../b
|
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
|
|
Verilator_difftree is used for debugging Verilator tree output files. It
|
|
|
|
performs a diff between two files, or all files common between two
|
|
|
|
directories, ignoring irrelevant pointer differences.
|
|
|
|
|
|
|
|
=head1 ARGUMENTS
|
|
|
|
|
|
|
|
=over 4
|
|
|
|
|
|
|
|
=item --help
|
|
|
|
|
|
|
|
Displays this message and program version and exits.
|
|
|
|
|
2008-11-19 14:43:03 +00:00
|
|
|
=item --nolineno
|
|
|
|
|
|
|
|
Do not show differences in line numbering.
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
=back
|
|
|
|
|
|
|
|
=head1 DISTRIBUTION
|
|
|
|
|
2019-11-08 03:33:59 +00:00
|
|
|
The latest version is available from L<https://verilator.org>.
|
2006-08-26 11:35:28 +00:00
|
|
|
|
2020-01-06 23:05:53 +00:00
|
|
|
Copyright 2005-2020 by Wilson Snyder. This package is free software; you can
|
2009-05-04 21:07:57 +00:00
|
|
|
redistribute it and/or modify it under the terms of either the GNU Lesser
|
|
|
|
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
=head1 AUTHORS
|
|
|
|
|
|
|
|
Wilson Snyder <wsnyder@wsnyder.org>
|
|
|
|
|
|
|
|
=head1 SEE ALSO
|
|
|
|
|
|
|
|
C<verilator>
|
|
|
|
|
|
|
|
=cut
|
|
|
|
|
|
|
|
######################################################################
|
|
|
|
### Local Variables:
|
2012-02-21 01:48:13 +00:00
|
|
|
### compile-command: "$V4/bin/verilator_difftree {$V4D,$V4}/test_regress/obj_dir/t_EXAMPLE/V*_03_*.tree"
|
2006-08-26 11:35:28 +00:00
|
|
|
### End:
|