Convert verilator_difftree to Python

This commit is contained in:
Wilson Snyder 2021-09-04 09:31:22 -04:00
parent 496b9f9c63
commit 18c543f2f2
2 changed files with 107 additions and 217 deletions

View File

@ -118,23 +118,6 @@ INFOS = verilator.html verilator.pdf
INFOS_OLD = README README.html README.pdf INFOS_OLD = README README.html README.pdf
INST_PROJ_FILES = \
bin/verilator \
bin/verilator_ccache_report \
bin/verilator_coverage \
bin/verilator_gantt \
bin/verilator_includer \
bin/verilator_profcfunc \
include/verilated.mk \
include/*.[chv]* \
include/gtkwave/*.[chv]* \
include/vltstd/*.[chv]* \
INST_PROJ_BIN_FILES = \
bin/verilator_bin$(EXEEXT) \
bin/verilator_bin_dbg$(EXEEXT) \
bin/verilator_coverage_bin_dbg$(EXEEXT) \
EXAMPLES_FIRST = \ EXAMPLES_FIRST = \
examples/make_hello_c \ examples/make_hello_c \
examples/make_hello_sc \ examples/make_hello_sc \
@ -369,6 +352,7 @@ clang-format:
PY_PROGRAMS = \ PY_PROGRAMS = \
bin/verilator_ccache_report \ bin/verilator_ccache_report \
bin/verilator_difftree \
bin/verilator_profcfunc \ bin/verilator_profcfunc \
examples/xml_py/vl_file_copy \ examples/xml_py/vl_file_copy \
examples/xml_py/vl_hier_graph \ examples/xml_py/vl_hier_graph \

View File

@ -1,233 +1,139 @@
#!/usr/bin/env perl #!/usr/bin/env python3
# See copyright, etc in below POD section. # pylint: disable=C0103,C0114,C0116
###################################################################### ######################################################################
use warnings; import argparse
use Getopt::Long; import collections
use IO::File; import glob
use Pod::Usage; import os.path
use strict; import re
use vars qw($Debug); import sys
#======================================================================
# main
$Debug = 0; def diff(a, b):
my $Opt_A;
my $Opt_B;
my $Opt_Lineno = 1;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions(
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
"lineno!" => \$Opt_Lineno,
)) {
die "%Error: Bad usage, try 'verilator_difftree --help'\n";
}
defined $Opt_A or die "%Error: No old diff filename\n"; if not os.path.exists(a):
defined $Opt_B or die "%Error: No new diff filename\n"; sys.exit("%Error: No old diff filename found: " + a)
if not os.path.exists(b):
sys.exit("%Error: No new diff filename found: " + b)
-e $Opt_A or die "%Error: No old diff filename found: $Opt_A\n"; if os.path.isdir(a) and os.path.isdir(b):
-e $Opt_B or die "%Error: No new diff filename found: $Opt_B\n"; diff_dir(a, b)
elif os.path.isfile(a) and os.path.isfile(b):
diff_file(a, b)
else:
sys.exit("%Error: Mix of files and dirs")
if (-d $Opt_A && -d $Opt_B) {
diff_dir($Opt_A, $Opt_B);
} elsif (-f $Opt_A && -f $Opt_B) {
diff_file($Opt_A, $Opt_B);
} else {
die "%Error: Mix of files and dirs\n";
}
sub diff_dir { def diff_dir(a, b):
my $a = shift;
my $b = shift;
# Diff all files under two directories # Diff all files under two directories
my %files; files = collections.defaultdict(lambda: {})
foreach my $fn (glob("$a/*.tree")) { for fn in glob.glob(a + "/*.tree"):
(my $base = $fn) =~ s!.*/!!; base = re.sub(r'.*/', '', fn)
$files{$base}{a} = $fn; files[base]['a'] = fn
} for fn in glob.glob(b + "/*.tree"):
foreach my $fn (glob("$b/*.tree")) { base = re.sub(r'.*/', '', fn)
(my $base = $fn) =~ s!.*/!!; files[base]['b'] = fn
$files{$base}{b} = $fn;
}
my $any;
foreach my $base (sort (keys %files)) {
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;
}
$any or warn("%Warning: No .tree files found that have similar base names:\n "
.join("\n ", sort keys %files),"\n");
}
sub diff_file { anyfile = False
my $a = shift; for base in sorted(files.keys()):
my $b = shift; a = files[base]['a']
b = files[base]['b']
if not a or not b:
continue
print("=" * 70)
print("= %s <-> %s" % (a, b))
diff_file(a, b)
anyfile = True
if not anyfile:
sys.stderr.write(
"%Warning: No .tree files found that have similar base names\n")
def diff_file(a, b):
# Compare the two tree files # Compare the two tree files
(my $short_a = $a) =~ s/[^a-zA-Z0-9.]+/_/g; short_a = re.sub(r'[^a-zA-Z0-9.]+', '_', a)
(my $short_b = $b) =~ s/[^a-zA-Z0-9.]+/_/g; short_b = re.sub(r'[^a-zA-Z0-9.]+', '_', b)
my $tmp_a = "/tmp/${$}_${short_a}.a"; tmp_a = "/tmp/%s_%s.a" % (os.getpid(), short_a)
my $tmp_b = "/tmp/${$}_${short_b}.b"; tmp_b = "/tmp/%s_%s.b" % (os.getpid(), short_b)
my $vera = version_from($a); # Version conversion deprecated, but for future...
my $verb = version_from($b); # vera = version_from(a)
my $verCvt = (($vera < 0x3900 && $verb >= 0x3900) # verb = version_from(b)
|| ($vera >= 0x3900 && $verb < 0x3900)); # verCvt = ((vera < 0x3900 and verb >= 0x3900)
# or (vera >= 0x3900 and verb < 0x3900))
filter($a, $tmp_a, $verCvt); filterf(a, tmp_a)
filter($b, $tmp_b, $verCvt); filterf(b, tmp_b)
system("diff -u $tmp_a $tmp_b"); os.system("diff -u " + tmp_a + " " + tmp_b)
unlink $tmp_a; os.unlink(tmp_a)
unlink $tmp_b; os.unlink(tmp_b)
}
sub version_from {
my $fn = shift; def version_from(filename):
# Return dump format # Return dump format
my $f1 = IO::File->new ($fn) or die "%Error: $! $fn,"; with open(filename) as fh:
while (defined (my $line=$f1->getline())) { lineno = 0
last if $. > 10; for line in fh:
return hex $1 if $line =~ /\(format (0x[0-9.]+)\)/; if lineno > 10:
} break
return 1.0; match = re.search(r'format (0x[0-9.]+)', line)
} if match:
return hex(match.group(1))
return 1.0
sub filter {
my $fn1 = shift; def filterf(fn1, fn2):
my $fn2 = shift;
my $verCvt = shift;
# Remove hex numbers before diffing # Remove hex numbers before diffing
my $f1 = IO::File->new ($fn1) or die "%Error: $! $fn1,"; with open(fn1) as fh1:
my $f2 = IO::File->new ($fn2,"w") or die "%Error: $! $fn2,"; with open(fn2, "w") as fh2:
while (defined (my $line=$f1->getline())) { for line in fh1:
same_line: if re.search(r' This=', line):
next if $line =~ / This=/; continue
$line =~ s/0x[a-f0-9]+/0x/g; line = re.sub(r'0x[a-f0-9]+', '0x', line)
$line =~ s/<e[0-9]+\#?>/<e>/g; line = re.sub(r'<e[0-9]+\#?>', '<e>', line)
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno; if not Args.no_lineno:
if ($verCvt) { line = re.sub(r'{[a-z]*\d+}', '{}', line)
next if $line =~ /^ NETLIST/; fh2.write(line)
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;
}
}
}
print $f2 $line;
}
$f1->close;
$f2->close;
}
#----------------------------------------------------------------------
sub usage { ######################################################################
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT); ######################################################################
exit(1); # Unreachable
}
sub debug { parser = argparse.ArgumentParser(
$Debug = 1; allow_abbrev=False,
} formatter_class=argparse.RawDescriptionHelpFormatter,
description="""Compare two Verilator debugging trees""",
sub parameter { epilog=
my $param = shift; """Verilator_difftree is used for debugging Verilator tree output files.
if (!defined $Opt_A) { It performs a diff between two files, or all files common between two
$Opt_A = $param;
} elsif (!defined $Opt_B) {
$Opt_B = $param;
} else {
die "%Error: Unknown parameter: $param\n";
}
}
#######################################################################
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. directories, ignoring irrelevant pointer differences.
=head1 ARGUMENTS For documentation see
https://verilator.org/guide/latest/exe_verilator_difftree.html
=over 4
=item --help
Displays this message and program version and exits.
=item --nolineno
Do not show differences in line numbering.
=back
=head1 DISTRIBUTION
The latest version is available from L<https://verilator.org>.
Copyright 2005-2021 by Wilson Snyder. This program is free software; you Copyright 2005-2021 by Wilson Snyder. This program is free software; you
can redistribute it and/or modify it under the terms of either the GNU can redistribute it and/or modify it under the terms of either the GNU
Lesser General Public License Version 3 or the Perl Artistic License Lesser General Public License Version 3 or the Perl Artistic License
Version 2.0. Version 2.0.
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
=head1 AUTHORS parser.add_argument('--debug',
action='store_const',
const=9,
help='enable debug')
parser.add_argument('--no-lineno',
action='store_false',
help='do not show differences in line numbering')
parser.add_argument('filea', help='input file a to diff')
parser.add_argument('fileb', help='input file b to diff')
Wilson Snyder <wsnyder@wsnyder.org> Args = parser.parse_args()
diff(Args.filea, Args.fileb)
=head1 SEE ALSO
C<verilator>
and L<https://verilator.org/verilator_doc.html> for detailed documentation.
=cut
###################################################################### ######################################################################
### Local Variables: # Local Variables:
### compile-command: "$V4/bin/verilator_difftree {$V4D,$V4}/test_regress/obj_dir/t_EXAMPLE/V*_03_*.tree" # compile-command: "./verilator_difftree ../test_regress/t/t_difftree.{a,b}.tree"
### End: # End: