forked from github/verilator
af0e535015
Convert to Not(Xor(x)) up front, to help code coverage and optimize out extra nots sooner.
351 lines
12 KiB
Perl
Executable File
351 lines
12 KiB
Perl
Executable File
#!/usr/bin/env perl
|
|
# See copyright, etc in below POD section.
|
|
######################################################################
|
|
|
|
use warnings;
|
|
use Getopt::Long;
|
|
use IO::File;
|
|
use Pod::Usage;
|
|
use Data::Dumper; $Data::Dumper::Indent=1;
|
|
use strict;
|
|
use vars qw($Debug);
|
|
|
|
#======================================================================
|
|
|
|
our $Tree;
|
|
our %OpMap;
|
|
gentree();
|
|
|
|
#======================================================================
|
|
# main
|
|
|
|
$Debug = 0;
|
|
my $opt_filename;
|
|
autoflush STDOUT 1;
|
|
autoflush STDERR 1;
|
|
if (! GetOptions(
|
|
"help" => \&usage,
|
|
"debug" => \&debug,
|
|
"<>" => \¶meter,
|
|
)) {
|
|
usage();
|
|
}
|
|
|
|
vread($opt_filename);
|
|
#print Dumper($Tree);
|
|
vwrite();
|
|
|
|
print '(query-replace-regexp "(\\([0-9a-z_]+\\))" "\\1" nil nil nil)',"\n";
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
sub usage {
|
|
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
|
|
exit(1); # Unreachable
|
|
}
|
|
|
|
sub debug {
|
|
$Debug = 1;
|
|
}
|
|
|
|
sub parameter {
|
|
my $param = shift;
|
|
if (!$opt_filename) {
|
|
$opt_filename = $param;
|
|
} else {
|
|
die "%Error: Unknown parameter: $param\n";
|
|
}
|
|
}
|
|
|
|
#######################################################################
|
|
|
|
sub vread {
|
|
my $filename = shift;
|
|
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
|
my $lasthier="";
|
|
$Tree = {
|
|
op => 'NETLIST',
|
|
t => [[],[],[],[],[],],
|
|
};
|
|
my @stack;
|
|
$stack[1] = $Tree;
|
|
while (defined (my $line = $fh->getline)) {
|
|
if ($line =~ /^\s+(\S+):\s+(\S+)\s+0x\S+\s+{(\d+)}\s+w(\d+)\s+(.*)$/) {
|
|
my $hier = $1;
|
|
my $op = $2;
|
|
my $lineno = $3;
|
|
my $width = $4;
|
|
my $etc = $5;
|
|
|
|
$etc =~ s/__DOT__/./g;
|
|
$etc =~ s/__PVT__//g;
|
|
|
|
my $self = {
|
|
op => $op,
|
|
#width => $width,
|
|
#lineno => $lineno,
|
|
#line => $line,
|
|
etc => $etc,
|
|
args => [split(/[ \t]+/,$etc)],
|
|
t => [[],[],[],[],[],],
|
|
};
|
|
|
|
my @hiers = (1,split(/:/,$hier));
|
|
my $depth = $#hiers+1;
|
|
my $newchild = $hiers[$#hiers];
|
|
|
|
#print "DD $depth $newchild $op\n";
|
|
|
|
push @{$stack[$depth-1]->{t}[$newchild]}, $self;
|
|
$stack[$depth] = $self;
|
|
|
|
$lasthier = $hier;
|
|
#print " $lasthier\n";
|
|
#print Dumper($Tree);
|
|
}
|
|
}
|
|
}
|
|
|
|
######################################################################
|
|
|
|
our $Indent = 0;
|
|
use vars qw($Code_Self);
|
|
use vars qw($Avoid_Hex);
|
|
|
|
sub vwrite {
|
|
$Indent = 0;
|
|
print vwrite_rec($Tree);
|
|
}
|
|
|
|
sub vwrite_rec {
|
|
my $self = shift;
|
|
#print "/*$self->{op}*/";
|
|
my $code = $OpMap{$self->{op}} or die "%Error: No map for $self->{op},";
|
|
local $Code_Self = $self;
|
|
#print Dumper($self->{t}[3]),"\n";
|
|
&$code;
|
|
}
|
|
|
|
######################################################################
|
|
# Tree functions
|
|
|
|
sub p { print join("",@_); }
|
|
|
|
sub exists1 { return defined $Code_Self->{t}[1][0]; }
|
|
sub exists2 { return defined $Code_Self->{t}[2][0]; }
|
|
sub exists3 { return defined $Code_Self->{t}[3][0]; }
|
|
sub exists4 { return defined $Code_Self->{t}[4][0]; }
|
|
sub exists5 { return defined $Code_Self->{t}[5][0]; }
|
|
|
|
sub t1 { foreach my $r (@{$Code_Self->{t}[1]}) { vwrite_rec($r); } }
|
|
sub t2 { foreach my $r (@{$Code_Self->{t}[2]}) { vwrite_rec($r); } }
|
|
sub t3 { foreach my $r (@{$Code_Self->{t}[3]}) { vwrite_rec($r); } }
|
|
sub t4 { foreach my $r (@{$Code_Self->{t}[4]}) { vwrite_rec($r); } }
|
|
sub t5 { foreach my $r (@{$Code_Self->{t}[5]}) { vwrite_rec($r); } }
|
|
sub p1 { p "("; t1; p ")";}
|
|
sub p2 { p "("; t2; p ")";}
|
|
sub p3 { p "("; t3; p ")";}
|
|
sub p4 { p "("; t4; p ")";}
|
|
sub p5 { p "("; t5; p ")";}
|
|
sub a1 { p $Code_Self->{args}[0]; }
|
|
sub a2 { p $Code_Self->{args}[1]; }
|
|
sub a3 { p $Code_Self->{args}[2]; }
|
|
sub a4 { p $Code_Self->{args}[3]; }
|
|
sub a5 { p $Code_Self->{args}[4]; }
|
|
sub a6 { p $Code_Self->{args}[5]; }
|
|
sub a7 { p $Code_Self->{args}[6]; }
|
|
|
|
sub indentInc { $Indent+=2; }
|
|
sub indentDec { $Indent-=2; }
|
|
sub nl { p "\n"," "x$Indent; }
|
|
|
|
######################################################################
|
|
|
|
# nl is a newline
|
|
# p# indicates to add parens
|
|
# t# indicates tree reference
|
|
# a# indicates info from dump where n1 is the width.
|
|
|
|
sub gentree {
|
|
%OpMap = (
|
|
'NULLNODE' => sub { "" },
|
|
'NETLIST' => sub { nl;t1;t2;t3;t4;t5; },
|
|
'ACTIVE' => sub { p "always_act @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
|
|
'ADD' => sub { p1;p " + ";p2; },
|
|
'ALWAYS' => sub { p "always @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
|
|
'ALWAYSPOST' => sub { p "ALWAYSPOST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'AND' => sub { p1;p " & ";p2; },
|
|
'ARRAYSEL' => sub { t1;p "[";t2;p "]"; },
|
|
'ASSIGN' => sub { t2;p " = ";t1;p ";";nl; },
|
|
'ASSIGNDLY' => sub { t2;p " <= ";t1;p ";";nl; },
|
|
'ASSIGNPOST' => sub { p "ASSIGNPOST what{";t1;p " = ";t2;p ";";nl; },
|
|
'ASSIGNPRE' => sub { p "ASSIGNPRE what{";t1;p " = ";t2;p ";";nl; },
|
|
'ASSIGNW' => sub { p "assign ";t2;p " = ";t1;p ";";nl; },
|
|
'ATTROF' => sub { p "ATTROF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'BEGIN' => sub { p "begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
|
|
'BITSEL' => sub { t1;local $Avoid_Hex=1; p "[";t2;p "]"; },
|
|
'CASE' => sub { p "CASE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'CASEITEM' => sub { p "CASEITEM what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'CAST' => sub { p "CAST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'CCALL' => sub { p "CCALL what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'CELL' => sub { a1;p " ";a7;p " (/*CELL*/);"; nl; },
|
|
'CFUNC' => sub { p "CFUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'CHANGEDET' => sub { p "CHANGEDET what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'CINCLUDE' => sub { p "CINCLUDE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'COMMENT' => sub { p "//COMMENT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl;nl; },
|
|
'CONCAT' => sub { p "{";p1;p ",";p2;p "}"; },
|
|
'CONDITIONAL' => sub { p1;p " ? ";p2;p " : ";p3; },
|
|
'CONST' => sub { p_const(); },
|
|
'COVER' => sub { p "COVER what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'CRETURN' => sub { p "CRETURN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'CSTMT' => sub { p "CSTMT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'DEFPARAM' => sub { p "defparam ";p1;p " = ";p2;p ";";nl; },
|
|
'DISPLAY' => sub { p '$write("';p1;p "\",";p2;p3;p4;p5;p ");";nl; },
|
|
'DIV' => sub { p1;p " / ";p2; },
|
|
'EQ' => sub { p1;p " == ";p2; },
|
|
'EQCASE' => sub { p1;p " === ";p2; },
|
|
'EXTEND' => sub { t1; },
|
|
'EXTRACT' => sub { t1;local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
|
|
'FINISH' => sub { p '$finish;';nl },
|
|
'FOR' => sub { p "for (";p1;p ",";p2;p ",";p3;p ") begin";indentInc;nl;p4;p5;indentDec;p "end";nl; },
|
|
'FUNC' => sub { p "FUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'FUNCREF' => sub { p "FUNCREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'GT' => sub { p1;p " > ";p2; },
|
|
'GTE' => sub { p1;p " >= ";p2; },
|
|
'IF' => sub { p "if (";p1;p ") begin";indentInc;nl;t2;indentDec;if (exists3) {p "end else begin";indentInc;nl;t3;indentDec;} p "end"; nl; },
|
|
'INITARRAY' => sub { p "INITARRAY what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'INITIAL' => sub { p "initial begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
|
|
'LOGAND' => sub { p1;p " && ";p2; },
|
|
'LOGNOT' => sub { p1;p " || ";p2; },
|
|
'LOGOR' => sub { p "!";p1; },
|
|
'LT' => sub { p1;p " < ";p2; },
|
|
'LTE' => sub { p1;p " <= ";p2; },
|
|
'MODDIV' => sub { p1;p " % ";p2; },
|
|
'MODULE' => sub { p "module ";a1;p " (/*AUTOARG*/);";indentInc;nl;t1;t2;t3;t4;t5;indentDec;nl;p "endmodule";nl; },
|
|
'MUL' => sub { p1;p " * ";p2; },
|
|
'NEQ' => sub { p1;p " != ";p2; },
|
|
'NEQCASE' => sub { p1;p " !== ";p2; },
|
|
'NOT' => sub { p " ~";p1; },
|
|
'OR' => sub { p1;p " | ";p2; },
|
|
'PIN' => sub { p ";p ";p1;p " (";p2;p "),";nl; },
|
|
'PORT' => sub { p ""; },
|
|
'PRAGMA' => sub { p "PRAGMA what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'RAND' => sub { p '$rand'; },
|
|
'RANGE' => sub { t1; local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
|
|
'REDAND' => sub { p "&(";p1;p ")"; },
|
|
'REDOR' => sub { p "|(";p1;p ")"; },
|
|
'REDXOR' => sub { p "~^(";p1;p ")"; },
|
|
'REPLICATE' => sub { p "{";p1;p "{";p2;p "}}"; },
|
|
'SCCTOR' => sub { p "SCCTOR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'SCHDR' => sub { p "SCHDR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'SCIMP' => sub { p "SCIMP what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'SCINT' => sub { p "SCINT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'SCOPE' => sub { t1;t2;t3;t4;t5; },
|
|
'SENITEM' => sub { a1;p " ";t1; },
|
|
'SENTREE' => sub { t1;t2;t3;t4;t5; },
|
|
'SHIFTL' => sub { p1;p " << ";p2; },
|
|
'SHIFTR' => sub { p1;p " >> ";p2; },
|
|
'STOP' => sub { p '$stop;';nl; },
|
|
'SUB' => sub { p1;p " - ";p2; },
|
|
'TASK' => sub { p "TASK what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'TASKREF' => sub { p "TASKREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'TEXT' => sub { p "TEXT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'TIME' => sub { p '$time'; },
|
|
'TOPSCOPE' => sub { t1;t2;t3;t4;t5; },
|
|
'TRACE' => sub { p "TRACE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'UCFUNC' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ")"; },
|
|
'UCSTMT' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ");";nl; },
|
|
'NEGATE' => sub { p " -";p1; },
|
|
'VAR' => sub { p_var(); },
|
|
'VARPIN' => sub { p "VARPIN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
|
'VARREF' => sub { a1; },
|
|
'VARSCOPE' => sub { },
|
|
'WHILE' => sub { t1; p "while (";t2;p ") begin";indentInc;nl;t3;t4;indentDec;p "end";nl; },
|
|
'WORDSEL' => sub { p1;p "[";p2;p ":";p3;p "]"; },
|
|
'XOR' => sub { p1;p " ^";p2; },
|
|
);
|
|
}
|
|
|
|
sub p_var {
|
|
my $self = $Code_Self;
|
|
if ($self->{etc} =~ /\[I\]/) {
|
|
print "input";
|
|
} elsif ($self->{etc} =~ /\[O\]/) {
|
|
print "output";
|
|
} else {
|
|
print "reg";
|
|
}
|
|
p "\t";
|
|
{
|
|
local $Avoid_Hex=1;
|
|
t1;
|
|
}
|
|
p "\t";
|
|
a1;
|
|
if (exists2()) {
|
|
p " = ";
|
|
t2;
|
|
}
|
|
p ";";
|
|
nl;
|
|
}
|
|
|
|
sub p_const {
|
|
my $v = $Code_Self->{args}[0];
|
|
if ($v =~ /\?32\?h(.*)$/
|
|
|| ($Avoid_Hex && $v =~ /^[0-9?]*h(.*)$/)) {
|
|
print hex $1;
|
|
} else {
|
|
print $v;
|
|
}
|
|
}
|
|
|
|
#######################################################################
|
|
__END__
|
|
|
|
=pod
|
|
|
|
=head1 NAME
|
|
|
|
vtree_importer -
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
vtree_importer *.log
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
dd
|
|
|
|
=head1 ARGUMENTS
|
|
|
|
=over 4
|
|
|
|
=item --help
|
|
|
|
Displays this message and program version and exits.
|
|
|
|
=back
|
|
|
|
=head1 DISTRIBUTION
|
|
|
|
Copyright 2005-2020 by Wilson Snyder. This program is free software; you
|
|
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
|
|
Version 2.0.
|
|
|
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
|
|
=head1 AUTHORS
|
|
|
|
Wilson Snyder <wsnyder@wsnyder.org>
|
|
|
|
=head1 SEE ALSO
|
|
|
|
=cut
|
|
|
|
######################################################################
|
|
### Local Variables:
|
|
### compile-command: "./vtree_importer "
|
|
### End:
|