Convert verilator_difftree to Python
This commit is contained in:
parent
496b9f9c63
commit
18c543f2f2
18
Makefile.in
18
Makefile.in
|
|
@ -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 \
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
"<>" => \¶meter,
|
|
||||||
"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:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue