Compare commits

..
26 Commits
Author SHA1 Message Date
Wilson Snyder cc1d380864 Version bump 2019-05-08 21:15:56 -04:00
Wilson Snyder f96942a526 Internals: Detab and fix spacing style issues in include files. No functional change.
When merging, recommend using "git merge -Xignore-all-space"
2019-05-08 21:13:38 -04:00
Wilson Snyder b23fc06388 Internals: Detab and fix spacing style issues in some include files. No functional change. 2019-05-07 23:30:24 -04:00
Wilson Snyder f818ddc71c Internals: Detab and fix spacing style issues in tests and scripts. No functional change. 2019-05-07 22:34:09 -04:00
Wilson Snyder 37c8cc82b2 Auto-extend and WIDTH warn on unsized X/Zs, bug1423. 2019-05-07 21:57:38 -04:00
Wilson Snyder 03ebd5554f Fix table compile error with multiinterfaces, bug1431. 2019-05-06 19:33:54 -04:00
Wilson Snyder a2a7021914 Reorder VCD codes for better viewer packing. 2019-05-06 18:55:38 -04:00
Wilson Snyder c6650f88e1 Internals: Remove some uses of AstConst taking V3Number. No functional change intended. 2019-05-03 21:21:18 -04:00
Wilson Snyder 55a25674a2 Add --trace-fst-thread. 2019-05-02 20:33:05 -04:00
Wilson Snyder 05c3d520a6 Test: Ignore tabs on new .out 2019-05-02 20:32:50 -04:00
Wilson Snyder 6b3304320b For FST tracing use LZ4 compression. 2019-05-02 19:55:16 -04:00
Wilson Snyder 8d15276625 Tests: Use golden_filename consistently. 2019-05-02 19:02:40 -04:00
Todd Strader 354f107fed Tests: Converting tests to golden files for bug1305.
Signed-off-by: Wilson Snyder <[email protected]>
2019-05-02 18:45:32 -04:00
Wilson Snyder 1ff55c20e0 Support "'dx" constants, bug1423. 2019-05-01 20:02:28 -04:00
Todd Strader 9583f0d3cc Add .git file (not directory) to MANIFEST.SKIP for git worktrees
Signed-off-by: Wilson Snyder <[email protected]>
2019-05-01 19:48:27 -04:00
Wilson Snyder 3acb85a005 Fix FST enums not displaying, bug1426. 2019-05-01 19:18:45 -04:00
Wilson Snyder 08d041cb93 Add error when use parameters without value, bug1424. 2019-04-30 19:16:41 -04:00
Wilson Snyder 274b2002c2 Fix GTKWave register warning, bug1421. 2019-04-29 05:28:30 -04:00
Todd Strader 681e91f9d8 Fix FST documentation, bug1419.
Signed-off-by: Wilson Snyder <[email protected]>
2019-04-28 17:53:58 -04:00
Wilson Snyder 6e333bd9ab Fix test problems when missing fst2vcd, bug1417. 2019-04-10 20:51:38 -04:00
Larry Lee 6a331e37fc Fix missing VL_SHIFTL_ errors, bug1412, bug1415.
Signed-off-by: Wilson Snyder <[email protected]>
2019-04-05 19:32:25 -04:00
Sergey Kvachonok d8a020905a Fix MinGW GCC 6 printf formats, bug1413.
Signed-off-by: Wilson Snyder <[email protected]>
2019-04-02 18:24:36 -04:00
Wilson Snyder efa6f4cd95 Fix extraction, part of fix missing VL_SHIFTL_QQW error, bug1412. 2019-03-28 19:46:39 -04:00
Larry Lee ca537dc3ed Fix missing VL_SHIFTL_QQW error, bug1412.
Signed-off-by: Wilson Snyder <[email protected]>
2019-03-28 19:11:46 -04:00
Wilson Snyder 3b64f54cea Support '#' comments in , bug1411. 2019-03-27 07:40:14 -04:00
Wilson Snyder 32c1e38b84 devel release 2019-03-23 21:14:30 -04:00
238 changed files with 6728 additions and 5913 deletions
+27
View File
@@ -2,6 +2,33 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.014 2019-05-08
*** Add --trace-fst-thread.
**** Support '#' comments in $readmem, bug1411. [Frederick Requin]
**** Support "'dx" constants, bug1423. [Udi Finkelstein]
**** For FST tracing use LZ4 compression. [Tony Bybell]
**** Add error when use parameters without value, bug1424. [Peter Gerst]
**** Auto-extend and WIDTH warn on unsized X/Zs, bug1423. [Udi Finkelstein]
**** Fix missing VL_SHIFTL_ errors, bug1412, bug1415. [Larry Lee]
**** Fix MinGW GCC 6 printf formats, bug1413. [Sergey Kvachonok]
**** Fix test problems when missing fst2vcd, bug1417. [Todd Strader]
**** Fix GTKWave register warning, bug1421. [Pieter Kapsenberg]
**** Fix FST enums not displaying, bug1426. [Danilo Ramos]
**** Fix table compile error with multiinterfaces, bug1431. [Bogdan Vukobratovic]
* Verilator 4.012 2019-3-23
*** Add +verilator+seed, bug1396. [Stan Sokorac]
+1
View File
@@ -1,5 +1,6 @@
\.clang-tidy
\.git/
\.git$
\.svn/
\.(bak|old)/
\.(bak|old)$
+37 -25
View File
@@ -58,17 +58,17 @@ foreach my $sw (@ARGV) {
}
Getopt::Long::config("no_auto_abbrev","pass_through");
if (! GetOptions (
# Major operating modes
"help" => \&usage,
"debug:s" => \&debug,
# "version!" => \&version, # Also passthru'ed
# Switches
"gdb!" => \$opt_gdb,
"gdbbt!" => \$opt_gdbbt,
# Additional parameters
"<>" => sub {}, # Ignored
)) {
if (! GetOptions(
# Major operating modes
"help" => \&usage,
"debug:s" => \&debug,
# "version!" => \&version, # Also passthru'ed
# Switches
"gdb!" => \$opt_gdb,
"gdbbt!" => \$opt_gdbbt,
# Additional parameters
"<>" => sub {}, # Ignored
)) {
pod2usage(-exitstatus=>2, -verbose=>0);
}
@@ -361,6 +361,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
--top-module <topname> Name of top level input module
--trace Enable waveform creation
--trace-fst Enable FST waveform creation
--trace-fst-thread Enable FST threaded waveform creation
--trace-depth <levels> Depth of tracing
--trace-max-array <depth> Maximum bit width for tracing
--trace-max-width <width> Maximum array depth for tracing
@@ -1291,7 +1292,14 @@ even when waveforms are not turned on during model execution.
=item --trace-fst
Enable FST waveform tracing in the model. This overrides C<--trace>.
Enable FST waveform tracing in the model. This overrides C<--trace> and
C<--trace-fst-thread>. See also C<--trace-fst-thread>.
=item --trace-fst-thread
Enable FST waveform tracing in the model, using a separate thread. This is
typically faster in runtime but slower in total computes than
C<--trace-fst>. This overrides C<--trace> and C<--trace-fst>.
=item --trace-depth I<levels>
@@ -1704,7 +1712,7 @@ This is an example similar to the above, but using SystemC.
#include "Vour.h"
int sc_main(int argc, char **argv) {
Verilated::commandArgs(argc, argv);
sc_clock clk ("clk",10, 0.5, 3, true);
sc_clock clk ("clk", 10, 0.5, 3, true);
Vour* top;
top = new Vour("top");
top->clk(clk);
@@ -2074,7 +2082,7 @@ command line, or the link), you'd then:
#include "svdpi.h"
#include "Vour__Dpi.h"
int add (int a, int b) { return a+b; }
int add(int a, int b) { return a+b; }
=head2 DPI System Task/Functions
@@ -2124,7 +2132,7 @@ respect to that top level module, then the scope could be set with
#include "svdpi.h"
...
svSetScope (svGetScopeFromName ("dut"));
svSetScope(svGetScopeFromName("dut"));
(Remember that Verilator adds a "V" to the top of the module hierarchy.)
@@ -2138,7 +2146,7 @@ comments within the svdpi.h header for more information.
Verilator allows writing $display like functions using this syntax:
import "DPI-C" function void
\$my_display (input string formatted /*verilator sformat*/ );
\$my_display(input string formatted /*verilator sformat*/ );
The /*verilator sformat*/ indicates that this function accepts a $display
like format specifier followed by any number of arguments to satisfy the
@@ -2246,7 +2254,7 @@ accesses the above signal "readme" would be:
#include "verilated_vpi.h" // Required to get definitions
vluint64_t main_time = 0; // See comments in first example
double sc_time_stamp () { return main_time; }
double sc_time_stamp() { return main_time; }
void read_and_check() {
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"TOP.our.readme", NULL);
@@ -2348,6 +2356,9 @@ Verilated model should not livelock nor deadlock, however, you can expect
performance to be far worse than it would be with proper stoichiometry of
threads and CPU cores.
With --trace-fst-thread, tracing occurs in a separate thread from the main
simulation thread(s). This option is orthogonal to --threads.
The remainder of this section describe behavior with --threads 1 or
--threads N (not --no-threads).
@@ -3405,7 +3416,7 @@ it's a bit slower than a non-delayed assignment.) Here's an example
always @ (posedge clk)
if (~reset_l) begin
for (i=0; i<`ARRAY_SIZE; i++) begin
array[i] = 0; // Non-delayed for verilator
array[i] = 0; // Non-delayed for verilator
end
This message is only seen on large or complicated loops because Verilator
@@ -3883,7 +3894,7 @@ Often UNOPTFLAT is caused by logic that isn't truly circular as viewed by
synthesis which analyzes interconnection per-bit, but is circular to
simulation which analyzes per-bus:
wire [2:0] x = {x[1:0],shift_in};
wire [2:0] x = {x[1:0], shift_in};
This statement needs to be evaluated multiple times, as a change in
"shift_in" requires "x" to be computed 3 times before it becomes stable.
@@ -3892,12 +3903,12 @@ causes the warning.
For significantly better performance, split this into 2 separate signals:
wire [2:0] xout = {x[1:0],shift_in};
wire [2:0] xout = {x[1:0], shift_in};
and change all receiving logic to instead receive "xout". Alternatively,
change it to
wire [2:0] x = {xin[1:0],shift_in};
wire [2:0] x = {xin[1:0], shift_in};
and change all driving logic to instead drive "xin".
@@ -4013,7 +4024,7 @@ Concatenate leading zeros when doing arithmetic. In the statement
The best fix, which clarifies intent and will also make all tools happy is:
wire [5:0] plus_one = from[5:0] + 6'd1 + {5'd0,carry[0]};
wire [5:0] plus_one = from[5:0] + 6'd1 + {5'd0, carry[0]};
Ignoring this warning will only suppress the lint check, it will simulate
correctly.
@@ -4025,12 +4036,12 @@ has an indeterminate width. In most cases this violates the Verilog rule
that widths inside concatenates and replicates must be sized, and should be
fixed in the code.
wire [63:0] concat = {1,2};
wire [63:0] concat = {1, 2};
An example where this is technically legal (though still bad form) is:
parameter PAR = 1;
wire [63:0] concat = {PAR,PAR};
wire [63:0] concat = {PAR, PAR};
The correct fix is to either size the 1 ("32'h1"), or add the width to the
parameter definition ("parameter [31:0]"), or add the width to the
@@ -4233,7 +4244,8 @@ trace file if you want all data to land in the same output file.
FST a format by GTKWave.
This version provides a basic FST support.
To dump FST format, add the --trace switch to Verilator and change the include path in the testbench to:
To dump FST format, add the --trace-fst switch to Verilator and change the include
path in the testbench to:
#include "verilated_fst_c.h"
VerilatedFstC* tfp = new VerilatedFstC;
+38 -38
View File
@@ -19,8 +19,8 @@ require 5.006_001;
use warnings;
BEGIN {
if ($ENV{DIRPROJECT} && $ENV{DIRPROJECT_PERL_BOOT}) {
# Magic to allow author testing of perl packages in local directory
require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
# Magic to allow author testing of perl packages in local directory
require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
}
}
@@ -56,12 +56,12 @@ foreach my $sw (@ARGV) {
Getopt::Long::config("no_auto_abbrev","pass_through");
if (! GetOptions (
# Major operating modes
"help" => \&usage,
"debug:s" => \&debug,
# "version!" => \&version, # Also passthru'ed
# Additional parameters
"<>" => sub {}, # Ignored
# Major operating modes
"help" => \&usage,
"debug:s" => \&debug,
# "version!" => \&version, # Also passthru'ed
# Additional parameters
"<>" => sub {}, # Ignored
)) {
pod2usage(-exitstatus=>2, -verbose=>0);
}
@@ -90,25 +90,25 @@ sub verilator_coverage_bin {
my $bin = "";
# Use VERILATOR_ROOT if defined, else assume verilator_bin is in the search path
my $basename = ($ENV{VERILATOR_COVERAGE_BIN}
|| "verilator_coverage_bin_dbg");
|| "verilator_coverage_bin_dbg");
if (defined($ENV{VERILATOR_ROOT})) {
my $dir = $ENV{VERILATOR_ROOT};
my $dir = $ENV{VERILATOR_ROOT};
if (-x "$dir/bin/$basename"
|| -x "$dir/bin/$basename.exe") { # From a "make install" into VERILATOR_ROOT
$bin = "$dir/bin/$basename";
} else {
$bin = "$dir/$basename"; # From pointing to kit directory
}
$bin = "$dir/bin/$basename";
} else {
$bin = "$dir/$basename"; # From pointing to kit directory
}
} else {
if (-x "$RealBin/$basename"
|| -x "$RealBin/$basename.exe") {
$bin = "$RealBin/$basename"; # From path/to/verilator with verilator_bin installed
} else {
$bin = $basename; # Find in PATH
}
# Note we don't look under bin/$basename which would be right if running
# in the kit dir. Running that would likely break, since
# VERILATOR_ROOT wouldn't be set and Verilator won't find internal files.
$bin = "$RealBin/$basename"; # From path/to/verilator with verilator_bin installed
} else {
$bin = $basename; # Find in PATH
}
# Note we don't look under bin/$basename which would be right if running
# in the kit dir. Running that would likely break, since
# VERILATOR_ROOT wouldn't be set and Verilator won't find internal files.
}
return $bin;
}
@@ -125,23 +125,23 @@ sub run {
system($command);
my $status = $?;
if ($status) {
if ($! =~ /no such file or directory/i) {
warn "%Error: verilator_coverage: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
}
if ($Debug) { # For easy rerunning
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
warn "%Error: $command\n";
}
if ($status & 127) {
if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
warn "%Error: Verilator_coverage internal fault, sorry.\n" if !$Debug;
} elsif (($status & 127) == 6) { # SIGABRT
warn "%Error: Verilator_coverage aborted.\n" if !$Debug;
} else {
warn "%Error: Verilator_coverage threw signal $status.\n" if !$Debug;
}
}
die "%Error: Command Failed $command\n";
if ($! =~ /no such file or directory/i) {
warn "%Error: verilator_coverage: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
}
if ($Debug) { # For easy rerunning
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
warn "%Error: $command\n";
}
if ($status & 127) {
if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
warn "%Error: Verilator_coverage internal fault, sorry.\n" if !$Debug;
} elsif (($status & 127) == 6) { # SIGABRT
warn "%Error: Verilator_coverage aborted.\n" if !$Debug;
} else {
warn "%Error: Verilator_coverage threw signal $status.\n" if !$Debug;
}
}
die "%Error: Command Failed $command\n";
}
}
+52 -52
View File
@@ -38,11 +38,11 @@ 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,
if (! GetOptions(
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
"lineno!" => \$Opt_Lineno,
)) {
die "%Error: Bad usage, try 'verilator_difftree --help'\n";
}
@@ -68,22 +68,22 @@ sub diff_dir {
my %files;
foreach my $fn (glob("$a/*.tree")) {
(my $base = $fn) =~ s!.*/!!;
$files{$base}{a} = $fn;
(my $base = $fn) =~ s!.*/!!;
$files{$base}{a} = $fn;
}
foreach my $fn (glob("$b/*.tree")) {
(my $base = $fn) =~ s!.*/!!;
$files{$base}{b} = $fn;
(my $base = $fn) =~ s!.*/!!;
$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;
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");
@@ -101,7 +101,7 @@ sub diff_file {
my $vera = version_from($a);
my $verb = version_from($b);
my $verCvt = (($vera < 0x3900 && $verb >= 0x3900)
|| ($vera >= 0x3900 && $verb < 0x3900));
|| ($vera >= 0x3900 && $verb < 0x3900));
filter($a, $tmp_a, $verCvt);
filter($b, $tmp_b, $verCvt);
@@ -115,8 +115,8 @@ sub version_from {
# Return dump format
my $f1 = IO::File->new ($fn) or die "%Error: $! $fn,";
while (defined (my $line=$f1->getline())) {
last if $. > 10;
return hex $1 if $line =~ /\(format (0x[0-9.]+)\)/;
last if $. > 10;
return hex $1 if $line =~ /\(format (0x[0-9.]+)\)/;
}
return 1.0;
}
@@ -130,36 +130,36 @@ sub filter {
my $f2 = IO::File->new ($fn2,"w") or die "%Error: $! $fn2,";
while (defined (my $line=$f1->getline())) {
same_line:
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;
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;
}
$f1->close;
$f2->close;
@@ -179,11 +179,11 @@ sub debug {
sub parameter {
my $param = shift;
if (!defined $Opt_A) {
$Opt_A = $param;
$Opt_A = $param;
} elsif (!defined $Opt_B) {
$Opt_B = $param;
$Opt_B = $param;
} else {
die "%Error: Unknown parameter: $param\n";
die "%Error: Unknown parameter: $param\n";
}
}
+84 -84
View File
@@ -24,11 +24,11 @@ my $Opt_File;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions (
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
)) {
if (! GetOptions(
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
)) {
die "%Error: Bad usage, try 'verilator_profcfunc --help'\n";
}
@@ -50,9 +50,9 @@ sub debug {
sub parameter {
my $param = shift;
if (!defined $Opt_File) {
$Opt_File = $param;
$Opt_File = $param;
} else {
die "%Error: Unknown parameter: $param\n";
die "%Error: Unknown parameter: $param\n";
}
}
@@ -66,13 +66,13 @@ sub profcfunc {
my %funcs;
while (defined (my $line=$fh->getline())) {
# %time cumesec selfsec calls {stuff} name
if ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
my $pct=$1; my $sec=$2; my $calls=$3; my $func=$4;
$funcs{$func}{pct} += $pct;
$funcs{$func}{sec} += $sec;
$funcs{$func}{calls} += $calls;
}
# %time cumesec selfsec calls {stuff} name
if ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
my $pct=$1; my $sec=$2; my $calls=$3; my $func=$4;
$funcs{$func}{pct} += $pct;
$funcs{$func}{sec} += $sec;
$funcs{$func}{calls} += $calls;
}
# Older gprofs have no call column for single-call functions
# %time cumesec selfsec {stuff} name
elsif ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
@@ -88,10 +88,10 @@ sub profcfunc {
my %pointer_mods;
my %verilated_mods;
foreach my $func (keys %funcs) {
if ($func =~ /(.*)::_eval\(([a-zA-Z_0-9]+__Syms).*\)$/) {
$verilated_mods{$1} = qr/^$1/;
$pointer_mods{$2} = $1;
}
if ($func =~ /(.*)::_eval\(([a-zA-Z_0-9]+__Syms).*\)$/) {
$verilated_mods{$1} = qr/^$1/;
$pointer_mods{$2} = $1;
}
}
#print Dumper(\%pointer_mods, \%verilated_mods);
@@ -99,72 +99,72 @@ sub profcfunc {
my %vfuncs;
my %groups;
foreach my $func (keys %funcs) {
my $pct = $funcs{$func}{pct};
my $vfunc = $func;
my $design;
my $pct = $funcs{$func}{pct};
my $vfunc = $func;
my $design;
if ($func =~ /\(([a-zA-Z_0-9]+__Syms)/) {
$design = $pointer_mods{$1};
}
if ($func =~ /\(([a-zA-Z_0-9]+__Syms)/) {
$design = $pointer_mods{$1};
}
foreach my $vde (keys %verilated_mods) {
last if $design;
if ($func =~ /$verilated_mods{$vde}/) {
$design=$vde;
last;
}
}
foreach my $vde (keys %verilated_mods) {
last if $design;
if ($func =~ /$verilated_mods{$vde}/) {
$design=$vde;
last;
}
}
if ($vfunc =~ /__PROF__([a-zA-Z_0-9]+)__l?([0-9]+)\(/) {
$vfunc = sprintf("VBlock %s:%d", $1, $2);
$groups{type}{"Verilog Blocks under $design"} += $pct;
$groups{design}{$design} += $pct;
$groups{module}{$1} += $pct;
} else {
if ($design) {
$vfunc = sprintf("VCommon %s", $func);
$groups{type}{"Common code under $design"} += $pct;
$groups{design}{$design} += $pct;
$groups{module}{$design." common code"} += $pct;
} elsif ($func =~ /^VL_[A-Z0-9_]+/
|| $func =~ /^_?vl_[a-zA-Z0-9_]+/
|| $func =~ /^verilated/i) {
$vfunc = sprintf("VLib %s", $func);
$groups{type}{'VLib'} += $pct;
$groups{design}{'VLib'} += $pct;
$groups{module}{'VLib'} += $pct;
} elsif ($func =~ /^_mcount_private/) {
$vfunc = sprintf("Prof %s", $func);
$groups{type}{'Prof'} += $pct;
$groups{design}{'Prof'} += $pct;
$groups{module}{'Prof'} += $pct;
} else {
$vfunc = sprintf("C++ %s", $func);
$groups{type}{'C++'} += $pct;
$groups{design}{'C++'} += $pct;
$groups{module}{'C++'} += $pct;
}
}
$vfuncs{$vfunc} = $funcs{$func};
if ($vfunc =~ /__PROF__([a-zA-Z_0-9]+)__l?([0-9]+)\(/) {
$vfunc = sprintf("VBlock %s:%d", $1, $2);
$groups{type}{"Verilog Blocks under $design"} += $pct;
$groups{design}{$design} += $pct;
$groups{module}{$1} += $pct;
} else {
if ($design) {
$vfunc = sprintf("VCommon %s", $func);
$groups{type}{"Common code under $design"} += $pct;
$groups{design}{$design} += $pct;
$groups{module}{$design." common code"} += $pct;
} elsif ($func =~ /^VL_[A-Z0-9_]+/
|| $func =~ /^_?vl_[a-zA-Z0-9_]+/
|| $func =~ /^verilated/i) {
$vfunc = sprintf("VLib %s", $func);
$groups{type}{'VLib'} += $pct;
$groups{design}{'VLib'} += $pct;
$groups{module}{'VLib'} += $pct;
} elsif ($func =~ /^_mcount_private/) {
$vfunc = sprintf("Prof %s", $func);
$groups{type}{'Prof'} += $pct;
$groups{design}{'Prof'} += $pct;
$groups{module}{'Prof'} += $pct;
} else {
$vfunc = sprintf("C++ %s", $func);
$groups{type}{'C++'} += $pct;
$groups{design}{'C++'} += $pct;
$groups{module}{'C++'} += $pct;
}
}
$vfuncs{$vfunc} = $funcs{$func};
}
foreach my $type (qw(type design module)) {
my $missing = 100;
foreach (sort (keys %{$groups{$type}})) {
$missing -= $groups{$type}{$_};
}
if ($missing) {
$groups{$type}{"\377Unaccounted for/rounding error"} = $missing;
}
my $missing = 100;
foreach (sort (keys %{$groups{$type}})) {
$missing -= $groups{$type}{$_};
}
if ($missing) {
$groups{$type}{"\377Unaccounted for/rounding error"} = $missing;
}
print("Overall summary by $type:\n");
printf(" %-6s %s\n","% time",$type);
foreach my $what (sort (keys %{$groups{$type}})) {
(my $pwhat = $what) =~ s/^\377//; # Just used to establish sort order
printf(" %6.2f %s\n", $groups{$type}{$what}, $pwhat);
}
print("\n");
print("Overall summary by $type:\n");
printf(" %-6s %s\n","% time",$type);
foreach my $what (sort (keys %{$groups{$type}})) {
(my $pwhat = $what) =~ s/^\377//; # Just used to establish sort order
printf(" %6.2f %s\n", $groups{$type}{$what}, $pwhat);
}
print("\n");
}
print("Verilog code profile:\n");
@@ -181,14 +181,14 @@ sub profcfunc {
my $cume = 0;
foreach my $func (sort {$vfuncs{$b}{sec} <=> $vfuncs{$a}{sec}
|| $a cmp $b}
(keys %vfuncs)) {
$cume += $vfuncs{$func}{sec};
printf +("%6.2f %9.2f %8.2f %8d %s\n",
$vfuncs{$func}{pct},
$cume, $vfuncs{$func}{sec},
$vfuncs{$func}{calls},
$func);
|| $a cmp $b}
(keys %vfuncs)) {
$cume += $vfuncs{$func}{sec};
printf +("%6.2f %9.2f %8.2f %8d %s\n",
$vfuncs{$func}{pct},
$cume, $vfuncs{$func}{sec},
$vfuncs{$func}{calls},
$func);
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.012 2019-03-23],
AC_INIT([Verilator],[4.014 2019-05-08],
[https://www.veripool.org/verilator],
[verilator],[https://www.veripool.org/verilator])
# When releasing, also update header of Changes file
+6 -6
View File
@@ -41,7 +41,7 @@ int main(int argc, char** argv, char** env) {
Verilated::commandArgs(argc, argv);
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
Vtop* top = new Vtop; // Or use a const unique_ptr, or the VL_UNIQUE_PTR wrapper
Vtop* top = new Vtop; // Or use a const unique_ptr, or the VL_UNIQUE_PTR wrapper
#if VM_TRACE
// If verilator was invoked with --trace argument,
@@ -94,14 +94,14 @@ int main(int argc, char** argv, char** env) {
#if VM_TRACE
// Dump trace data for this cycle
if (tfp) tfp->dump (main_time);
if (tfp) tfp->dump(main_time);
#endif
// Read outputs
VL_PRINTF ("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
" -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n",
main_time, top->clk, top->reset_l, top->in_quad,
top->out_quad, top->out_wide[2], top->out_wide[1], top->out_wide[0]);
VL_PRINTF("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
" -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n",
main_time, top->clk, top->reset_l, top->in_quad,
top->out_quad, top->out_wide[2], top->out_wide[1], top->out_wide[0]);
}
// Final model cleanup
+2 -2
View File
@@ -115,9 +115,9 @@ int sc_main(int argc, char* argv[]) {
// Apply inputs
if (VL_TIME_Q() > 1 && VL_TIME_Q() < 10) {
reset_l = !1; // Assert reset
reset_l = !1; // Assert reset
} else if (VL_TIME_Q() > 1) {
reset_l = !0; // Deassert reset
reset_l = !0; // Deassert reset
}
// Simulate 1ns
+1 -1
View File
@@ -49,7 +49,7 @@ module sub
// An example assertion
always_ff @ (posedge clk) begin
AssertionExample: assert (!reset_l || count_c<100);
AssertionExample: assert(!reset_l || count_c<100);
end
// And example coverage analysis
+1 -1
View File
@@ -248,7 +248,7 @@ static const int LZ4_minLength = (MFLIMIT+1);
/**************************************
* Common functions
**************************************/
static unsigned LZ4_NbCommonBytes (register size_t val)
static unsigned LZ4_NbCommonBytes (size_t val)
{
if (LZ4_isLittleEndian())
{
+458 -455
View File
File diff suppressed because it is too large Load Diff
+483 -460
View File
File diff suppressed because it is too large Load Diff
+15 -1
View File
@@ -116,8 +116,22 @@ endif
ifneq ($(VM_THREADS),0)
ifneq ($(VM_THREADS),)
CPPFLAGS += -DVL_THREADED
VK_LIBS_THREADED=1
endif
endif
ifneq ($(VM_TRACE_THREADED),0)
ifneq ($(VM_TRACE_THREADED),)
CPPFLAGS += -DVL_TRACE_THREADED
VK_LIBS_THREADED=1
endif
endif
ifneq ($(VK_LIBS_THREADED),0)
ifneq ($(VK_LIBS_THREADED),)
# Need C++11 at least, so always default to newest
CPPFLAGS += -DVL_THREADED $(CFG_CXXFLAGS_STD_NEWEST)
CPPFLAGS += $(CFG_CXXFLAGS_STD_NEWEST)
LDLIBS += $(CFG_LDLIBS_THREADS)
endif
endif
+236 -236
View File
@@ -50,10 +50,10 @@ public: // But only local to this file
// CONSTRUCTORS
// Derived classes should call zero() in their constructor
VerilatedCovImpItem() {
for (int i=0; i<MAX_KEYS; ++i) {
m_keys[i]=KEY_UNDEF;
m_vals[i]=0;
}
for (int i=0; i<MAX_KEYS; ++i) {
m_keys[i] = KEY_UNDEF;
m_vals[i] = 0;
}
}
virtual ~VerilatedCovImpItem() {}
virtual vluint64_t count() const = 0;
@@ -96,7 +96,7 @@ private:
private:
// MEMBERS
VerilatedMutex m_mutex; ///< Protects all members, when VL_THREADED. Wrapper deals with setting it.
VerilatedMutex m_mutex; ///< Protects all members, when VL_THREADED. Wrapper deals with setting it.
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items
@@ -107,294 +107,294 @@ private:
// CONSTRUCTORS
VerilatedCovImp() {
m_insertp = NULL;
m_insertFilenamep = NULL;
m_insertLineno = 0;
m_insertp = NULL;
m_insertFilenamep = NULL;
m_insertLineno = 0;
}
VL_UNCOPYABLE(VerilatedCovImp);
public:
~VerilatedCovImp() { clearGuts(); }
static VerilatedCovImp& imp() VL_MT_SAFE {
static VerilatedCovImp s_singleton;
return s_singleton;
static VerilatedCovImp s_singleton;
return s_singleton;
}
private:
// PRIVATE METHODS
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
static int nextIndex = KEY_UNDEF+1;
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
if (iter != m_valueIndexes.end()) return iter->second;
nextIndex++; assert(nextIndex>0);
m_valueIndexes.insert(std::make_pair(value, nextIndex));
m_indexValues.insert(std::make_pair(nextIndex, value));
return nextIndex;
static int nextIndex = KEY_UNDEF+1;
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
if (iter != m_valueIndexes.end()) return iter->second;
nextIndex++; assert(nextIndex>0);
m_valueIndexes.insert(std::make_pair(value, nextIndex));
m_indexValues.insert(std::make_pair(nextIndex, value));
return nextIndex;
}
static std::string dequote(const std::string& text) VL_PURE {
// Quote any special characters
std::string rtn;
for (const char* pos = text.c_str(); *pos; ++pos) {
if (!isprint(*pos) || *pos=='%' || *pos=='"') {
char hex[10]; sprintf(hex,"%%%02X",pos[0]);
rtn += hex;
} else {
rtn += *pos;
}
}
return rtn;
// Quote any special characters
std::string rtn;
for (const char* pos = text.c_str(); *pos; ++pos) {
if (!isprint(*pos) || *pos=='%' || *pos=='"') {
char hex[10]; sprintf(hex, "%%%02X", pos[0]);
rtn += hex;
} else {
rtn += *pos;
}
}
return rtn;
}
static bool legalKey(const std::string& key) VL_PURE {
// Because we compress long keys to a single letter, and
// don't want applications to either get confused if they use
// a letter differently, nor want them to rely on our compression...
// (Considered using numeric keys, but will remain back compatible.)
if (key.length()<2) return false;
if (key.length()==2 && isdigit(key[1])) return false;
return true;
// Because we compress long keys to a single letter, and
// don't want applications to either get confused if they use
// a letter differently, nor want them to rely on our compression...
// (Considered using numeric keys, but will remain back compatible.)
if (key.length()<2) return false;
if (key.length()==2 && isdigit(key[1])) return false;
return true;
}
static std::string keyValueFormatter(const std::string& key, const std::string& value) VL_PURE {
std::string name;
if (key.length()==1 && isalpha(key[0])) {
name += std::string("\001")+key;
} else {
name += std::string("\001")+dequote(key);
}
name += std::string("\002")+dequote(value);
return name;
std::string name;
if (key.length()==1 && isalpha(key[0])) {
name += std::string("\001")+key;
} else {
name += std::string("\001")+dequote(key);
}
name += std::string("\002")+dequote(value);
return name;
}
static std::string combineHier(const std::string& old, const std::string& add) VL_PURE {
// (foo.a.x, foo.b.x) => foo.*.x
// (foo.a.x, foo.b.y) => foo.*
// (foo.a.x, foo.b) => foo.*
if (old == add) return add;
// (foo.a.x, foo.b.x) => foo.*.x
// (foo.a.x, foo.b.y) => foo.*
// (foo.a.x, foo.b) => foo.*
if (old == add) return add;
if (old.empty()) return add;
if (add.empty()) return old;
const char* a = old.c_str();
const char* b = add.c_str();
const char* a = old.c_str();
const char* b = add.c_str();
// Scan forward to first mismatch
const char* apre = a;
const char* bpre = b;
while (*apre == *bpre) { apre++; bpre++; }
// Scan forward to first mismatch
const char* apre = a;
const char* bpre = b;
while (*apre == *bpre) { apre++; bpre++; }
// We used to backup and split on only .'s but it seems better to be verbose
// and not assume . is the separator
std::string prefix = std::string(a,apre-a);
// We used to backup and split on only .'s but it seems better to be verbose
// and not assume . is the separator
std::string prefix = std::string(a, apre-a);
// Scan backward to last mismatch
const char* apost = a+strlen(a)-1;
const char* bpost = b+strlen(b)-1;
while (*apost == *bpost
&& apost>apre && bpost>bpre) { apost--; bpost--; }
// Scan backward to last mismatch
const char* apost = a+strlen(a)-1;
const char* bpost = b+strlen(b)-1;
while (*apost == *bpost
&& apost>apre && bpost>bpre) { apost--; bpost--; }
// Forward to . so we have a whole word
std::string suffix = *bpost ? std::string(bpost+1) : "";
// Forward to . so we have a whole word
std::string suffix = *bpost ? std::string(bpost+1) : "";
std::string out = prefix+"*"+suffix;
std::string out = prefix+"*"+suffix;
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
return out;
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
return out;
}
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match) VL_REQUIRES(m_mutex) {
for (int i=0; i<MAX_KEYS; ++i) {
if (itemp->m_keys[i] != KEY_UNDEF) {
// We don't compare keys, only values
std::string val = m_indexValues[itemp->m_vals[i]];
if (std::string::npos != val.find(match)) { // Found
return true;
}
}
}
return false;
for (int i=0; i<MAX_KEYS; ++i) {
if (itemp->m_keys[i] != KEY_UNDEF) {
// We don't compare keys, only values
std::string val = m_indexValues[itemp->m_vals[i]];
if (std::string::npos != val.find(match)) { // Found
return true;
}
}
}
return false;
}
static void selftest() VL_MT_SAFE {
// Little selftest
if (combineHier ("a.b.c","a.b.c") !="a.b.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("a.b.c","a.b") !="a.b*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("a.x.c","a.y.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("a.z.z.z.c","a.b.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("z","a") !="*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("q.a","q.b") !="q.*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("q.za","q.zb") !="q.z*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("1.2.3.a","9.8.7.a") !="*.a") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
// Little selftest
if (combineHier("a.b.c","a.b.c") !="a.b.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("a.b.c","a.b") !="a.b*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("a.x.c","a.y.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("a.z.z.z.c","a.b.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("z","a") !="*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("q.a","q.b") !="q.*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("q.za","q.zb") !="q.z*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("1.2.3.a","9.8.7.a") !="*.a") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
}
void clearGuts() VL_REQUIRES(m_mutex) {
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
delete itemp;
}
m_items.clear();
m_indexValues.clear();
m_valueIndexes.clear();
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
delete itemp;
}
m_items.clear();
m_indexValues.clear();
m_valueIndexes.clear();
}
public:
// PUBLIC METHODS
void clear() VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
clearGuts();
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
clearGuts();
}
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
if (matchp && matchp[0]) {
ItemList newlist;
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
if (!itemMatchesString(itemp, matchp)) {
delete itemp;
} else {
newlist.push_back(itemp);
}
}
m_items = newlist;
}
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
if (matchp && matchp[0]) {
ItemList newlist;
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
if (!itemMatchesString(itemp, matchp)) {
delete itemp;
} else {
newlist.push_back(itemp);
}
}
m_items = newlist;
}
}
void zero() VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
(*it)->zero();
}
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
(*it)->zero();
}
}
// We assume there's always call to i/f/p in that order
void inserti(VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
assert(!m_insertp);
m_insertp = itemp;
VerilatedLockGuard lock(m_mutex);
assert(!m_insertp);
m_insertp = itemp;
}
void insertf(const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
m_insertFilenamep = filenamep;
m_insertLineno = lineno;
VerilatedLockGuard lock(m_mutex);
m_insertFilenamep = filenamep;
m_insertLineno = lineno;
}
void insertp(const char* ckeyps[MAX_KEYS],
const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
assert(m_insertp);
// First two key/vals are filename
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
std::string linestr = vlCovCvtToStr(m_insertLineno);
ckeyps[1]="lineno"; valps[1]=linestr.c_str();
// Default page if not specified
const char* fnstartp = m_insertFilenamep;
while (const char* foundp = strchr(fnstartp,'/')) fnstartp=foundp+1;
const char* fnendp = fnstartp;
while (*fnendp && *fnendp!='.') fnendp++;
std::string page_default = "sp_user/"+std::string(fnstartp,fnendp-fnstartp);
ckeyps[2]="page"; valps[2]=page_default.c_str();
VerilatedLockGuard lock(m_mutex);
assert(m_insertp);
// First two key/vals are filename
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
std::string linestr = vlCovCvtToStr(m_insertLineno);
ckeyps[1]="lineno"; valps[1]=linestr.c_str();
// Default page if not specified
const char* fnstartp = m_insertFilenamep;
while (const char* foundp = strchr(fnstartp,'/')) fnstartp = foundp+1;
const char* fnendp = fnstartp;
while (*fnendp && *fnendp!='.') fnendp++;
std::string page_default = "sp_user/"+std::string(fnstartp, fnendp-fnstartp);
ckeyps[2]="page"; valps[2]=page_default.c_str();
// Keys -> strings
std::string keys[MAX_KEYS];
for (int i=0; i<MAX_KEYS; ++i) {
if (ckeyps[i] && ckeyps[i][0]) {
keys[i] = ckeyps[i];
}
}
// Ignore empty keys
for (int i=0; i<MAX_KEYS; ++i) {
// Keys -> strings
std::string keys[MAX_KEYS];
for (int i=0; i<MAX_KEYS; ++i) {
if (ckeyps[i] && ckeyps[i][0]) {
keys[i] = ckeyps[i];
}
}
// Ignore empty keys
for (int i=0; i<MAX_KEYS; ++i) {
if (!keys[i].empty()) {
for (int j=i+1; j<MAX_KEYS; ++j) {
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
keys[i] = "";
break;
}
}
}
}
// Insert the values
int addKeynum=0;
for (int i=0; i<MAX_KEYS; ++i) {
const std::string key = keys[i];
for (int j=i+1; j<MAX_KEYS; ++j) {
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
keys[i] = "";
break;
}
}
}
}
// Insert the values
int addKeynum = 0;
for (int i=0; i<MAX_KEYS; ++i) {
const std::string key = keys[i];
if (!keys[i].empty()) {
const std::string val = valps[i];
//cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
m_insertp->m_keys[addKeynum] = valueIndex(key);
m_insertp->m_vals[addKeynum] = valueIndex(val);
addKeynum++;
if (!legalKey(key)) {
std::string msg = "%Error: Coverage keys of one character, or letter+digit are illegal: "+key;
VL_FATAL_MT("",0,"",msg.c_str());
}
}
}
m_items.push_back(m_insertp);
// Prepare for next
m_insertp = NULL;
const std::string val = valps[i];
//cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
m_insertp->m_keys[addKeynum] = valueIndex(key);
m_insertp->m_vals[addKeynum] = valueIndex(val);
addKeynum++;
if (!legalKey(key)) {
std::string msg = "%Error: Coverage keys of one character, or letter+digit are illegal: "+key;
VL_FATAL_MT("", 0, "", msg.c_str());
}
}
}
m_items.push_back(m_insertp);
// Prepare for next
m_insertp = NULL;
}
void write(const char* filename) VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
#ifndef VM_COVERAGE
VL_FATAL_MT("",0,"","%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
VL_FATAL_MT("", 0, "", "%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
#endif
selftest();
selftest();
std::ofstream os(filename);
if (os.fail()) {
std::string msg = std::string("%Error: Can't write '")+filename+"'";
VL_FATAL_MT("",0,"",msg.c_str());
return;
}
os << "# SystemC::Coverage-3\n";
if (os.fail()) {
std::string msg = std::string("%Error: Can't write '")+filename+"'";
VL_FATAL_MT("", 0, "", msg.c_str());
return;
}
os << "# SystemC::Coverage-3\n";
// Build list of events; totalize if collapsing hierarchy
typedef std::map<std::string,std::pair<std::string,vluint64_t> > EventMap;
EventMap eventCounts;
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
std::string name;
std::string hier;
bool per_instance = false;
// Build list of events; totalize if collapsing hierarchy
typedef std::map<std::string,std::pair<std::string,vluint64_t> > EventMap;
EventMap eventCounts;
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
std::string name;
std::string hier;
bool per_instance = false;
for (int i=0; i<MAX_KEYS; ++i) {
if (itemp->m_keys[i] != KEY_UNDEF) {
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
std::string val = m_indexValues[itemp->m_vals[i]];
if (key == VL_CIK_PER_INSTANCE) {
if (val != "0") per_instance = true;
}
if (key == VL_CIK_HIER) {
hier = val;
} else {
// Print it
name += keyValueFormatter(key,val);
}
}
}
if (per_instance) { // Not collapsing hierarchies
name += keyValueFormatter(VL_CIK_HIER,hier);
hier = "";
}
for (int i=0; i<MAX_KEYS; ++i) {
if (itemp->m_keys[i] != KEY_UNDEF) {
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
std::string val = m_indexValues[itemp->m_vals[i]];
if (key == VL_CIK_PER_INSTANCE) {
if (val != "0") per_instance = true;
}
if (key == VL_CIK_HIER) {
hier = val;
} else {
// Print it
name += keyValueFormatter(key, val);
}
}
}
if (per_instance) { // Not collapsing hierarchies
name += keyValueFormatter(VL_CIK_HIER, hier);
hier = "";
}
// Group versus point labels don't matter here, downstream
// deals with it. Seems bad for sizing though and doesn't
// allow easy addition of new group codes (would be
// inefficient)
// Group versus point labels don't matter here, downstream
// deals with it. Seems bad for sizing though and doesn't
// allow easy addition of new group codes (would be
// inefficient)
// Find or insert the named event
EventMap::iterator cit = eventCounts.find(name);
if (cit != eventCounts.end()) {
const std::string& oldhier = cit->second.first;
cit->second.second += itemp->count();
cit->second.first = combineHier(oldhier, hier);
} else {
eventCounts.insert(std::make_pair(name, make_pair(hier,itemp->count())));
}
}
// Find or insert the named event
EventMap::iterator cit = eventCounts.find(name);
if (cit != eventCounts.end()) {
const std::string& oldhier = cit->second.first;
cit->second.second += itemp->count();
cit->second.first = combineHier(oldhier, hier);
} else {
eventCounts.insert(std::make_pair(name, make_pair(hier, itemp->count())));
}
}
// Output body
for (EventMap::const_iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
os<<"C '"<<std::dec;
os<<it->first;
if (!it->second.first.empty()) os<<keyValueFormatter(VL_CIK_HIER,it->second.first);
os<<"' "<<it->second.second;
os<<std::endl;
}
// Output body
for (EventMap::const_iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
os<<"C '"<<std::dec;
os<<it->first;
if (!it->second.first.empty()) os<<keyValueFormatter(VL_CIK_HIER, it->second.first);
os<<"' "<<it->second.second;
os<<std::endl;
}
}
};
@@ -420,7 +420,7 @@ void VerilatedCov::_inserti(vluint64_t* itemp) VL_MT_SAFE {
VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint64_t>(itemp));
}
void VerilatedCov::_insertf(const char* filename, int lineno) VL_MT_SAFE {
VerilatedCovImp::imp().insertf(filename,lineno);
VerilatedCovImp::imp().insertf(filename, lineno);
}
#define K(n) const char* key ## n
@@ -446,14 +446,14 @@ void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
// And versions with fewer arguments (oh for a language with named parameters!)
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)) VL_MT_SAFE {
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
}
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)) VL_MT_SAFE {
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19),
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19),
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
}
// Backward compatibility for Verilator
void VerilatedCov::_insertp(A(0), A(1), K(2),int val2, K(3),int val3,
@@ -461,10 +461,10 @@ void VerilatedCov::_insertp(A(0), A(1), K(2),int val2, K(3),int val3,
std::string val2str = vlCovCvtToStr(val2);
std::string val3str = vlCovCvtToStr(val3);
_insertp(C(0),C(1),
key2,val2str.c_str(), key3,val3str.c_str(), key4, val4.c_str(),
C(5),C(6),N(7),N(8),N(9),
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
key2,val2str.c_str(), key3,val3str.c_str(), key4, val4.c_str(),
C(5),C(6),N(7),N(8),N(9),
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
}
#undef A
#undef C
+19 -19
View File
@@ -44,31 +44,31 @@
/// The value may be a string, or another type which will be auto-converted to a string.
///
/// Some typical keys:
/// filename File the recording occurs in. Defaults to __FILE__
/// lineno Line number the recording occurs in. Defaults to __LINE__
/// column Column number (or occurrence# for dup file/lines). Defaults to undef.
/// hier Hierarchical name. Defaults to name()
/// type Type of coverage. Defaults to "user"
/// Other types are 'block', 'fsm', 'toggle'.
/// comment Description of the coverage event. Should be set by the user.
/// Comments for type==block: 'if', 'else', 'elsif', 'case'
/// thresh Threshold to consider fully covered.
/// If unspecified, downstream tools will determine it.
/// filename File the recording occurs in. Defaults to __FILE__
/// lineno Line number the recording occurs in. Defaults to __LINE__
/// column Column number (or occurrence# for dup file/lines). Defaults to undef.
/// hier Hierarchical name. Defaults to name()
/// type Type of coverage. Defaults to "user"
/// Other types are 'block', 'fsm', 'toggle'.
/// comment Description of the coverage event. Should be set by the user.
/// Comments for type==block: 'if', 'else', 'elsif', 'case'
/// thresh Threshold to consider fully covered.
/// If unspecified, downstream tools will determine it.
///
/// Examples:
///
/// vluint32_t m_cases[10];
/// constructor {
/// for (int i=0; i<10; ++i) { m_cases[i]=0; }
/// vluint32_t m_cases[10];
/// constructor {
/// for (int i=0; i<10; ++i) { m_cases[i]=0; }
/// }
/// for (int i=0; i<10; ++i) {
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
/// }
/// for (int i=0; i<10; ++i) {
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
/// }
#define VL_COVER_INSERT(countp,args...) \
VL_IF_COVER(VerilatedCov::_inserti(countp); \
VerilatedCov::_insertf(__FILE__,__LINE__); \
VerilatedCov::_insertp("hier", name(), args))
VL_IF_COVER(VerilatedCov::_inserti(countp); \
VerilatedCov::_insertf(__FILE__,__LINE__); \
VerilatedCov::_insertp("hier", name(), args))
//=============================================================================
/// Convert VL_COVER_INSERT value arguments to strings
+10
View File
@@ -24,6 +24,12 @@
#include "verilated.h"
#include "verilated_fst_c.h"
// GTKWave configuration
#ifdef VL_TRACE_THREADED
# define HAVE_LIBPTHREAD
# define FST_WRITER_PARALLEL
#endif
// Include the GTKWave implementation directly
#include "gtkwave/fastlz.c"
#include "gtkwave/fstapi.c"
@@ -72,6 +78,10 @@ VerilatedFst::VerilatedFst(void* fst)
void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
m_assertOne.check();
m_fst = fstWriterCreate(filename, 1);
fstWriterSetPackType(m_fst, FST_WR_PT_LZ4);
#ifdef VL_TRACE_THREADED
fstWriterSetParallelMode(m_fst, 1);
#endif
m_curScope.clear();
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
+149 -145
View File
@@ -92,32 +92,32 @@ public:
// METHODS
//// Add message to queue (called by producer)
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
m_queue.insert(msg); // Pass by value to copy the message into queue
++m_depth;
VerilatedLockGuard lock(m_mutex);
m_queue.insert(msg); // Pass by value to copy the message into queue
++m_depth;
}
/// Service queue until completion (called by consumer)
void process() VL_EXCLUDES(m_mutex) {
// Tracking m_depth is redundant to e.g. getting the mutex and looking at queue size,
// but on the reader side it's 4x faster to test an atomic then getting a mutex
while (m_depth) {
// Wait for a message to be added to the queue
// We don't use unique_lock as want to unlock with the message copy still in scope
// Tracking m_depth is redundant to e.g. getting the mutex and looking at queue size,
// but on the reader side it's 4x faster to test an atomic then getting a mutex
while (m_depth) {
// Wait for a message to be added to the queue
// We don't use unique_lock as want to unlock with the message copy still in scope
m_mutex.lock();
assert(!m_queue.empty()); // Otherwise m_depth is wrong
// Unfortunately to release the lock we need to copy the message
// (Or have the message be a pointer, but then new/delete cost on each message)
// We assume messages are small, so copy
auto it = m_queue.begin();
const VerilatedMsg msg = *(it);
m_queue.erase(it);
m_mutex.unlock();
m_depth--; // Ok if outside critical section as only this code checks the value
{
// (Or have the message be a pointer, but then new/delete cost on each message)
// We assume messages are small, so copy
auto it = m_queue.begin();
const VerilatedMsg msg = *(it);
m_queue.erase(it);
m_mutex.unlock();
m_depth--; // Ok if outside critical section as only this code checks the value
{
VL_DEBUG_IF(VL_DBG_MSGF("Executing callback from mtaskId=%d\n", msg.mtaskId()););
msg.run();
}
}
}
}
}
};
@@ -128,15 +128,15 @@ public:
// CONSTRUCTORS
VerilatedThreadMsgQueue() { }
~VerilatedThreadMsgQueue() {
// The only call of this with a non-empty queue is a fatal error.
// So this does not flush the queue, as the destination queue is not known to this class.
// The only call of this with a non-empty queue is a fatal error.
// So this does not flush the queue, as the destination queue is not known to this class.
}
private:
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
// METHODS
static VerilatedThreadMsgQueue& threadton() {
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
return t_s;
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
return t_s;
}
public:
/// Add message to queue, called by producer
@@ -153,11 +153,11 @@ public:
}
/// Push all messages to the eval's queue
static void flush(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
while (!threadton().m_queue.empty()) {
evalMsgQp->post(threadton().m_queue.front());
threadton().m_queue.pop();
Verilated::endOfEvalReqdDec();
}
while (!threadton().m_queue.empty()) {
evalMsgQp->post(threadton().m_queue.front());
threadton().m_queue.pop();
Verilated::endOfEvalReqdDec();
}
}
};
#endif // VL_THREADED
@@ -200,11 +200,11 @@ class VerilatedImp {
public: // But only for verilated*.cpp
// CONSTRUCTORS
VerilatedImp()
: m_argVecLoaded(false), m_exportNext(0) {
m_fdps.resize(3);
m_fdps[0] = stdin;
m_fdps[1] = stdout;
m_fdps[2] = stderr;
: m_argVecLoaded(false), m_exportNext(0) {
m_fdps.resize(3);
m_fdps[0] = stdin;
m_fdps[1] = stdout;
m_fdps[2] = stderr;
}
~VerilatedImp() {}
private:
@@ -219,21 +219,21 @@ public:
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
VerilatedLockGuard lock(s_s.m_argMutex);
// Note prefixp does not include the leading "+"
size_t len = strlen(prefixp);
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
s_s.m_argVecLoaded = true; // Complain only once
VL_FATAL_MT("unknown",0,"",
"%Error: Verilog called $test$plusargs or $value$plusargs without"
" testbench C first calling Verilated::commandArgs(argc,argv).");
}
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
if ((*it)[0]=='+') {
if (0==strncmp(prefixp, it->c_str()+1, len)) return *it;
}
}
return "";
VerilatedLockGuard lock(s_s.m_argMutex);
// Note prefixp does not include the leading "+"
size_t len = strlen(prefixp);
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
s_s.m_argVecLoaded = true; // Complain only once
VL_FATAL_MT("unknown", 0, "",
"%Error: Verilog called $test$plusargs or $value$plusargs without"
" testbench C first calling Verilated::commandArgs(argc,argv).");
}
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
if ((*it)[0]=='+') {
if (0==strncmp(prefixp, it->c_str()+1, len)) return *it;
}
}
return "";
}
private:
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex);
@@ -247,75 +247,77 @@ public:
// There's often many more scopes than userdata's and thus having a ~48byte
// per map overhead * N scopes would take much more space and cache thrashing.
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
if (it != s_s.m_userMap.end()) it->second = userData;
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep,userKey),userData));
VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep, userKey));
if (it != s_s.m_userMap.end()) it->second = userData;
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData));
}
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
else return NULL;
VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep, userKey));
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
else return NULL;
}
private:
/// Symbol table destruction cleans up the entries for each scope.
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope on destruction, so we simply iterate.
VerilatedLockGuard lock(s_s.m_userMapMutex);
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
if (it->first.first == scopep) {
s_s.m_userMap.erase(it++);
} else {
++it;
}
}
// Slow ok - called once/scope on destruction, so we simply iterate.
VerilatedLockGuard lock(s_s.m_userMapMutex);
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
if (it->first.first == scopep) {
s_s.m_userMap.erase(it++);
} else {
++it;
}
}
}
static void userDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
bool first = true;
for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; }
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n",
it->first.first, it->first.second, it->second);
}
VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
bool first = true;
for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; }
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n",
it->first.first, it->first.second, it->second);
}
}
public: // But only for verilated*.cpp
// METHODS - scope name
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope at construction
VerilatedLockGuard lock(s_s.m_nameMutex);
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
if (it == s_s.m_nameMap.end()) {
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(),scopep));
}
// Slow ok - called once/scope at construction
VerilatedLockGuard lock(s_s.m_nameMutex);
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
if (it == s_s.m_nameMap.end()) {
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
}
}
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_nameMutex); // If too slow, can assume this is only VL_MT_SAFE_POSINIT
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
else return NULL;
VerilatedLockGuard lock(s_s.m_nameMutex);
// If too slow, can assume this is only VL_MT_SAFE_POSINIT
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
else return NULL;
}
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope at destruction
VerilatedLockGuard lock(s_s.m_nameMutex);
userEraseScope(scopep);
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
// Slow ok - called once/scope at destruction
VerilatedLockGuard lock(s_s.m_nameMutex);
userEraseScope(scopep);
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
}
static void scopesDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_nameMutex);
VL_PRINTF_MT(" scopesDump:\n");
for (VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) {
const VerilatedScope* scopep = it->second;
scopep->scopeDump();
}
VL_PRINTF_MT("\n");
VerilatedLockGuard lock(s_s.m_nameMutex);
VL_PRINTF_MT(" scopesDump:\n");
for (VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.begin();
it!=s_s.m_nameMap.end(); ++it) {
const VerilatedScope* scopep = it->second;
scopep->scopeDump();
}
VL_PRINTF_MT("\n");
}
static const VerilatedScopeNameMap* scopeNameMap() VL_MT_SAFE_POSTINIT {
// Thread save only assuming this is called only after model construction completed
// Thread save only assuming this is called only after model construction completed
return &s_s.m_nameMap;
}
@@ -329,40 +331,42 @@ public: // But only for verilated*.cpp
// Rather than a 2D map, the integer scheme saves 500ish ns on a likely
// miss at the cost of a multiply, and all lookups move to slowpath.
static int exportInsert(const char* namep) VL_MT_SAFE {
// Slow ok - called once/function at creation
VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
if (it == s_s.m_exportMap.end()) {
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
return s_s.m_exportNext++;
} else {
return it->second;
}
// Slow ok - called once/function at creation
VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
if (it == s_s.m_exportMap.end()) {
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
return s_s.m_exportNext++;
} else {
return it->second;
}
}
static int exportFind(const char* namep) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::const_iterator it=s_s.m_exportMap.find(namep);
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
std::string msg = (std::string("%Error: Testbench C called ")+namep
+" but no such DPI export function name exists in ANY model");
VL_FATAL_MT("unknown",0,"", msg.c_str());
return -1;
VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::const_iterator it=s_s.m_exportMap.find(namep);
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
std::string msg = (std::string("%Error: Testbench C called ")+namep
+" but no such DPI export function name exists in ANY model");
VL_FATAL_MT("unknown", 0, "", msg.c_str());
return -1;
}
static const char* exportName(int funcnum) VL_MT_SAFE {
// Slowpath; find name for given export; errors only so no map to reverse-map it
VerilatedLockGuard lock(s_s.m_exportMutex);
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
if (it->second == funcnum) return it->first;
}
return "*UNKNOWN*";
// Slowpath; find name for given export; errors only so no map to reverse-map it
VerilatedLockGuard lock(s_s.m_exportMutex);
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin();
it!=s_s.m_exportMap.end(); ++it) {
if (it->second == funcnum) return it->first;
}
return "*UNKNOWN*";
}
static void exportsDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_exportMutex);
bool first = true;
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
}
VerilatedLockGuard lock(s_s.m_exportMutex);
bool first = true;
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin();
it!=s_s.m_exportMap.end(); ++it) {
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
}
}
// We don't free up m_exportMap until the end, because we can't be sure
// what other models are using the assigned funcnum's.
@@ -370,32 +374,32 @@ public: // But only for verilated*.cpp
public: // But only for verilated*.cpp
// METHODS - file IO
static IData fdNew(FILE* fp) VL_MT_SAFE {
if (VL_UNLIKELY(!fp)) return 0;
// Bit 31 indicates it's a descriptor not a MCD
VerilatedLockGuard lock(s_s.m_fdMutex);
if (s_s.m_fdFree.empty()) {
// Need to create more space in m_fdps and m_fdFree
size_t start = s_s.m_fdps.size();
s_s.m_fdps.resize(start*2);
for (size_t i=start; i<start*2; ++i) s_s.m_fdFree.push_back(static_cast<IData>(i));
}
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
s_s.m_fdps[idx] = fp;
return (idx | (1UL<<31)); // bit 31 indicates not MCD
if (VL_UNLIKELY(!fp)) return 0;
// Bit 31 indicates it's a descriptor not a MCD
VerilatedLockGuard lock(s_s.m_fdMutex);
if (s_s.m_fdFree.empty()) {
// Need to create more space in m_fdps and m_fdFree
size_t start = s_s.m_fdps.size();
s_s.m_fdps.resize(start*2);
for (size_t i=start; i<start*2; ++i) s_s.m_fdFree.push_back(static_cast<IData>(i));
}
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
s_s.m_fdps[idx] = fp;
return (idx | (1UL<<31)); // bit 31 indicates not MCD
}
static void fdDelete(IData fdi) VL_MT_SAFE {
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard lock(s_s.m_fdMutex);
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
s_s.m_fdps[idx] = NULL;
s_s.m_fdFree.push_back(idx);
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard lock(s_s.m_fdMutex);
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
s_s.m_fdps[idx] = NULL;
s_s.m_fdFree.push_back(idx);
}
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
return s_s.m_fdps[idx];
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
return s_s.m_fdps[idx];
}
};
+57 -59
View File
@@ -56,17 +56,17 @@ bool VerilatedDeserialize::readDiffers(const void* __restrict datap, size_t size
const vluint8_t* __restrict dp = static_cast<const vluint8_t* __restrict>(datap);
vluint8_t miss = 0;
while (size--) {
miss |= (*dp++ ^ *m_cp++);
miss |= (*dp++ ^ *m_cp++);
}
return (miss!=0);
}
VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
if (VL_UNLIKELY(readDiffers(datap,size))) {
std::string fn = filename();
std::string msg = std::string("Can't deserialize save-restore file as was made from different model");
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
if (VL_UNLIKELY(readDiffers(datap, size))) {
std::string fn = filename();
std::string msg = std::string("Can't deserialize save-restore file as was made from different model");
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
}
return *this; // For function chaining
}
@@ -84,10 +84,10 @@ void VerilatedSerialize::header() VL_MT_UNSAFE_ONE {
void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
std::string fn = filename();
std::string msg = std::string("Can't deserialize; file has wrong header signature");
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
std::string fn = filename();
std::string msg = std::string("Can't deserialize; file has wrong header signature");
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
}
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
}
@@ -101,10 +101,10 @@ void VerilatedSerialize::trailer() VL_MT_UNSAFE_ONE {
void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
std::string fn = filename();
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature");
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
std::string fn = filename();
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature");
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
}
}
@@ -116,19 +116,19 @@ void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
m_assertOne.check();
if (isOpen()) return;
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n",filenamep););
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n", filenamep););
if (filenamep[0]=='|') {
assert(0); // Not supported yet.
} else {
// cppcheck-suppress duplicateExpression
// cppcheck-suppress duplicateExpression
m_fd = ::open(filenamep, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK|O_CLOEXEC
, 0666);
if (m_fd<0) {
// User code can check isOpen()
m_isOpen = false;
return;
}
if (m_fd<0) {
// User code can check isOpen()
m_isOpen = false;
return;
}
}
m_isOpen = true;
m_filename = filenamep;
@@ -139,19 +139,19 @@ void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
m_assertOne.check();
if (isOpen()) return;
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n",filenamep););
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n", filenamep););
if (filenamep[0]=='|') {
assert(0); // Not supported yet.
} else {
// cppcheck-suppress duplicateExpression
// cppcheck-suppress duplicateExpression
m_fd = ::open(filenamep, O_CREAT|O_RDONLY|O_LARGEFILE|O_CLOEXEC
, 0666);
if (m_fd<0) {
// User code can check isOpen()
m_isOpen = false;
return;
}
if (m_fd<0) {
// User code can check isOpen()
m_isOpen = false;
return;
}
}
m_isOpen = true;
m_filename = filenamep;
@@ -184,21 +184,21 @@ void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
if (VL_UNLIKELY(!isOpen())) return;
vluint8_t* wp = m_bufp;
while (1) {
ssize_t remaining = (m_cp - wp);
if (remaining==0) break;
errno = 0;
ssize_t remaining = (m_cp - wp);
if (remaining==0) break;
errno = 0;
ssize_t got = ::write(m_fd, wp, remaining);
if (got>0) {
wp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
VL_FATAL_MT("",0,"",msg.c_str());
close();
break;
}
}
if (got>0) {
wp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
close();
break;
}
}
}
m_cp = m_bufp; // Reset buffer
}
@@ -213,30 +213,28 @@ void VerilatedRestore::fill() VL_MT_UNSAFE_ONE {
m_cp = m_bufp; // Reset buffer
// Read into buffer starting at m_endp
while (1) {
ssize_t remaining = (m_bufp+bufferSize() - m_endp);
if (remaining==0) break;
errno = 0;
ssize_t remaining = (m_bufp+bufferSize() - m_endp);
if (remaining==0) break;
errno = 0;
ssize_t got = ::read(m_fd, m_endp, remaining);
if (got>0) {
m_endp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
VL_FATAL_MT("",0,"",msg.c_str());
close();
break;
if (got>0) {
m_endp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
close();
break;
}
} else { // got==0, EOF
// Fill buffer from here to end with NULLs so reader's don't
// need to check eof each character.
while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0';
break;
}
while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0';
break;
}
}
}
//=============================================================================
// Serialization of types
+55 -55
View File
@@ -34,10 +34,10 @@ class VerilatedSerialize {
protected:
// MEMBERS
// For speed, keep m_cp as the first member of this structure
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
vluint8_t* m_bufp; ///< Output buffer
bool m_isOpen; ///< True indicates open file/stream
std::string m_filename; ///< Filename, for error messages
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
vluint8_t* m_bufp; ///< Output buffer
bool m_isOpen; ///< True indicates open file/stream
std::string m_filename; ///< Filename, for error messages
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
@@ -50,13 +50,13 @@ protected:
VL_UNCOPYABLE(VerilatedSerialize);
public:
VerilatedSerialize() {
m_isOpen = false;
m_bufp = new vluint8_t [bufferSize()];
m_cp = m_bufp;
m_isOpen = false;
m_bufp = new vluint8_t [bufferSize()];
m_cp = m_bufp;
}
virtual ~VerilatedSerialize() {
close();
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
close();
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
}
// METHODS
bool isOpen() const { return m_isOpen; }
@@ -64,24 +64,24 @@ public:
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
virtual void flush() VL_MT_UNSAFE_ONE {}
inline VerilatedSerialize& write(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
while (size) {
bufferCheck();
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
const vluint8_t* __restrict maxp = dp + blk;
while (dp < maxp) *m_cp++ = *dp++;
size -= blk;
}
return *this; // For function chaining
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
while (size) {
bufferCheck();
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
const vluint8_t* __restrict maxp = dp + blk;
while (dp < maxp) *m_cp++ = *dp++;
size -= blk;
}
return *this; // For function chaining
}
private:
VerilatedSerialize& bufferCheck() VL_MT_UNSAFE_ONE {
// Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
flush();
}
return *this; // For function chaining
// Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
flush();
}
return *this; // For function chaining
}
};
@@ -93,12 +93,12 @@ class VerilatedDeserialize {
protected:
// MEMBERS
// For speed, keep m_cp as the first member of this structure
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
vluint8_t* m_bufp; ///< Output buffer
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
bool m_isOpen; ///< True indicates open file/stream
std::string m_filename; ///< Filename, for error messages
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
vluint8_t* m_bufp; ///< Output buffer
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
bool m_isOpen; ///< True indicates open file/stream
std::string m_filename; ///< Filename, for error messages
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
inline static size_t bufferInsertSize() { return 16*1024; }
@@ -111,14 +111,14 @@ protected:
VL_UNCOPYABLE(VerilatedDeserialize);
public:
VerilatedDeserialize() {
m_isOpen = false;
m_bufp = new vluint8_t [bufferSize()];
m_cp = m_bufp;
m_endp = NULL;
m_isOpen = false;
m_bufp = new vluint8_t [bufferSize()];
m_cp = m_bufp;
m_endp = NULL;
}
virtual ~VerilatedDeserialize() {
close();
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
close();
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
}
// METHODS
bool isOpen() const { return m_isOpen; }
@@ -126,15 +126,15 @@ public:
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
virtual void flush() VL_MT_UNSAFE_ONE {}
inline VerilatedDeserialize& read(void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
while (size) {
bufferCheck();
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
const vluint8_t* __restrict maxp = dp + blk;
while (dp < maxp) *dp++ = *m_cp++;
size -= blk;
}
return *this; // For function chaining
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
while (size) {
bufferCheck();
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
const vluint8_t* __restrict maxp = dp + blk;
while (dp < maxp) *dp++ = *m_cp++;
size -= blk;
}
return *this; // For function chaining
}
// Read a datum and compare with expected value
VerilatedDeserialize& readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
@@ -143,12 +143,12 @@ public:
private:
bool readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
VerilatedDeserialize& bufferCheck() VL_MT_UNSAFE_ONE {
// Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line
if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
fill();
}
return *this; // For function chaining
// Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line
if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
fill();
}
return *this; // For function chaining
}
};
@@ -158,7 +158,7 @@ private:
class VerilatedSave : public VerilatedSerialize {
private:
int m_fd; ///< File descriptor we're writing to
int m_fd; ///< File descriptor we're writing to
public:
// CONSTRUCTORS
@@ -177,7 +177,7 @@ public:
class VerilatedRestore : public VerilatedDeserialize {
private:
int m_fd; ///< File descriptor we're writing to
int m_fd; ///< File descriptor we're writing to
public:
// CONSTRUCTORS
@@ -237,12 +237,12 @@ inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, float& rhs) {
return os.read(&rhs, sizeof(rhs));
}
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, std::string& rhs) {
vluint32_t len=rhs.length();
vluint32_t len = rhs.length();
os<<len;
return os.write(rhs.data(), len);
}
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, std::string& rhs) {
vluint32_t len=0;
vluint32_t len = 0;
os>>len;
rhs.resize(len);
return os.read((void*)rhs.data(), len);
+15 -8
View File
@@ -134,17 +134,24 @@ private:
// cppcheck-suppress functionConst
void dumpDone();
inline void printCode(vluint32_t code) {
if (code>=(94*94*94)) *m_writep++ = static_cast<char>((code/94/94/94)%94+33);
if (code>=(94*94)) *m_writep++ = static_cast<char>((code/94/94)%94+33);
if (code>=(94)) *m_writep++ = static_cast<char>((code/94)%94+33);
*m_writep++ = static_cast<char>((code)%94+33);
*m_writep++ = static_cast<char>('!' + code % 94);
code /= 94;
while (code) {
code--;
*m_writep++ = static_cast<char>('!' + code % 94);
code /= 94;
}
}
static std::string stringCode(vluint32_t code) VL_PURE {
std::string out;
if (code>=(94*94*94)) out += static_cast<char>((code/94/94/94)%94+33);
if (code>=(94*94)) out += static_cast<char>((code/94/94)%94+33);
if (code>=(94)) out += static_cast<char>((code/94)%94+33);
return out + static_cast<char>((code)%94+33);
out += static_cast<char>('!' + code % 94);
code /= 94;
while (code) {
code--;
out += static_cast<char>('!' + code % 94);
code /= 94;
}
return out;
}
// CONSTRUCTORS
+547 -529
View File
File diff suppressed because it is too large Load Diff
+86 -86
View File
@@ -16,11 +16,11 @@
/// \file
/// \brief Verilator: Common include for OS portability (verilated & verilator)
///
/// This header is used by both the Verilator source code (run on the
/// build and host system), and the Verilated output (run on the target
/// system). Code needed by only the host system goes into
/// config_build.h.in, code needed by Verilated code only goes into
/// verilated.h, and code needed by both goes here (verilatedos.h).
/// This header is used by both the Verilator source code (run on the
/// build and host system), and the Verilated output (run on the target
/// system). Code needed by only the host system goes into
/// config_build.h.in, code needed by Verilated code only goes into
/// verilated.h, and code needed by both goes here (verilatedos.h).
///
/// Code available from: http://www.veripool.org/verilator
///
@@ -37,11 +37,7 @@
# define VL_ATTR_ALIGNED(alignment) __attribute__ ((aligned (alignment)))
# define VL_ATTR_ALWINLINE __attribute__ ((always_inline))
# define VL_ATTR_NORETURN __attribute__ ((noreturn))
# ifdef _WIN32
# define VL_ATTR_PRINTF(fmtArgNum) // GCC with MS runtime will fool the print arg checker
# else
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, (fmtArgNum), (fmtArgNum)+1)))
# endif
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, (fmtArgNum), (fmtArgNum)+1)))
# define VL_ATTR_PURE __attribute__ ((pure))
# define VL_ATTR_UNUSED __attribute__ ((unused))
# define VL_FUNC __func__
@@ -58,8 +54,8 @@
# define VL_EXCLUDES(x) __attribute__ ((locks_excluded(x)))
# define VL_SCOPED_CAPABILITY __attribute__ ((scoped_lockable))
# endif
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
# define VL_UNREACHABLE __builtin_unreachable();
# define VL_PREFETCH_RD(p) __builtin_prefetch((p),0)
# define VL_PREFETCH_RW(p) __builtin_prefetch((p),1)
@@ -69,51 +65,51 @@
// Defaults for unsupported compiler features
#ifndef VL_ATTR_ALIGNED
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
#endif
#ifndef VL_ATTR_ALWINLINE
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
#endif
#ifndef VL_ATTR_NORETURN
# define VL_ATTR_NORETURN ///< Function does not ever return
# define VL_ATTR_NORETURN ///< Function does not ever return
#endif
#ifndef VL_ATTR_PRINTF
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
#endif
#ifndef VL_ATTR_PURE
# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE)
# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE)
#endif
#ifndef VL_ATTR_UNUSED
# define VL_ATTR_UNUSED ///< Function that may be never used
# define VL_ATTR_UNUSED ///< Function that may be never used
#endif
#ifndef VL_FUNC
# define VL_FUNC "__func__" ///< Name of current function for error macros
# define VL_FUNC "__func__" ///< Name of current function for error macros
#endif
#ifndef VL_CAPABILITY
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired a shared capability (-fthread-safety)
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired a shared capability (-fthread-safety)
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
#endif
#ifndef VL_LIKELY
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
#endif
#ifndef VL_UNREACHABLE
# define VL_UNREACHABLE ///< Point that may never be reached
# define VL_UNREACHABLE ///< Point that may never be reached
#endif
#ifndef VL_PREFETCH_RD
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
#endif
#ifndef VL_PREFETCH_RW
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
#endif
#ifdef VL_THREADED
@@ -124,12 +120,12 @@
# else
# error "Unsupported compiler for VL_THREADED: No thread-local declarator"
# endif
# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread
# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread
#else
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
#endif
#define VL_THREAD ///< Deprecated
#define VL_STATIC_OR_THREAD static ///< Deprecated
#define VL_THREAD ///< Deprecated
#define VL_STATIC_OR_THREAD static ///< Deprecated
#define VL_PURE ///< Comment tag that Function is pure (and thus also VL_MT_SAFE)
#define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED
@@ -138,18 +134,18 @@
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED, protected to make sure single-caller
#ifdef _MSC_VER
# define VL_ULL(c) (c##ui64) ///< Add appropriate suffix to 64-bit constant
# define VL_ULL(c) (c##ui64) ///< Add appropriate suffix to 64-bit constant
#else
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
#endif
// This is not necessarily the same as #UL, depending on what the IData typedef is.
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__)
# define VL_DANGLING(v)
#else
# define VL_DANGLING(v) do { (v) = NULL; } while(0) ///< After e.g. delete, set variable to NULL to indicate must not use later
# define VL_DANGLING(v) do { (v) = NULL; } while(0) ///< After e.g. delete, set variable to NULL to indicate must not use later
#endif
//=========================================================================
@@ -180,7 +176,7 @@
// Optimization
#ifndef VL_INLINE_OPT
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
#endif
//=========================================================================
@@ -207,37 +203,37 @@
# include <stdint.h>
# include <sys/types.h> // __WORDSIZE
# include <unistd.h> // ssize_t
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
# if defined(__uint32_t_defined) || defined(___int32_t_defined) // Newer Cygwin uint32_t in stdint.h as an unsigned int
typedef int32_t vlsint32_t; ///< 32-bit signed type
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
# else // Older Cygwin has long==uint32_t
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
typedef long vlsint32_t; ///< 32-bit signed type
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
typedef long vlsint32_t; ///< 32-bit signed type
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
# endif
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
typedef long vlsint64_t; ///< 64-bit signed type
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
typedef long vlsint64_t; ///< 64-bit signed type
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
# else
typedef long long vlsint64_t; ///< 64-bit signed type
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
typedef long long vlsint64_t; ///< 64-bit signed type
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
# endif
#elif defined(_WIN32) && defined(_MSC_VER)
typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility)
typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility)
typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility)
typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type
typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type
typedef signed __int32 vlsint32_t; ///< 32-bit signed type
typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility)
typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility)
typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility)
typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type
typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type
typedef signed __int32 vlsint32_t; ///< 32-bit signed type
typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
# ifndef _SSIZE_T_DEFINED
# ifdef _WIN64
@@ -253,16 +249,16 @@ typedef signed __int32 ssize_t; ///< signed size_t; returned fro
# include <stdint.h> // Linux and most flavors
# include <sys/types.h> // __WORDSIZE
# include <unistd.h> // ssize_t
typedef uint8_t vluint8_t; ///< 32-bit unsigned type
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
typedef int vlsint32_t; ///< 32-bit signed type
typedef uint32_t vluint32_t; ///< 32-bit signed type
typedef uint8_t vluint8_t; ///< 32-bit unsigned type
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
typedef int vlsint32_t; ///< 32-bit signed type
typedef uint32_t vluint32_t; ///< 32-bit signed type
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
typedef long vlsint64_t; ///< 64-bit signed type
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
typedef long vlsint64_t; ///< 64-bit signed type
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
# else
typedef long long vlsint64_t; ///< 64-bit signed type
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
typedef long long vlsint64_t; ///< 64-bit signed type
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
# endif
#endif
@@ -270,10 +266,14 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
// Printing printf/scanf formats
// Alas cinttypes isn't that standard yet
#ifdef _WIN32
# define __STDC_FORMAT_MACROS 1 // Otherwise MinGW doesn't get PRId64 for fstapi.c
// Use Microsoft-specific format specifiers for Microsoft Visual C++ only
#ifdef _MSC_VER
# define VL_PRI64 "I64"
#else // Linux or compliant Unix flavors
#else // use standard C99 format specifiers
# ifdef __MINGW32__
# define __USE_MINGW_ANSI_STDIO 1 // Force old MinGW (GCC 5 and older) to use C99 formats
# define __STDC_FORMAT_MACROS 1 // Otherwise MinGW doesn't get PRId64 for fstapi.c
# endif
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
# define VL_PRI64 "l"
# else
@@ -305,11 +305,11 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
//=========================================================================
// Integer size macros
#define VL_BYTESIZE 8 ///< Bits in a byte
#define VL_SHORTSIZE 16 ///< Bits in a short
#define VL_WORDSIZE 32 ///< Bits in a word
#define VL_QUADSIZE 64 ///< Bits in a quadword
#define VL_WORDSIZE_LOG2 5 ///< log2(VL_WORDSIZE)
#define VL_BYTESIZE 8 ///< Bits in a byte
#define VL_SHORTSIZE 16 ///< Bits in a short
#define VL_WORDSIZE 32 ///< Bits in a word
#define VL_QUADSIZE 64 ///< Bits in a quadword
#define VL_WORDSIZE_LOG2 5 ///< log2(VL_WORDSIZE)
/// Bytes this number of bits needs (1 bit=1 byte)
#define VL_BYTES_I(nbits) (((nbits)+(VL_BYTESIZE-1))/VL_BYTESIZE)
@@ -327,21 +327,21 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
//=========================================================================
// Verilated function size macros
#define VL_MULS_MAX_WORDS 16 ///< Max size in words of MULS operation
#define VL_TO_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
#define VL_MULS_MAX_WORDS 16 ///< Max size in words of MULS operation
#define VL_TO_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
//=========================================================================
// Base macros
#define VL_SIZEBITS_I (VL_WORDSIZE-1) ///< Bit mask for bits in a word
#define VL_SIZEBITS_Q (VL_QUADSIZE-1) ///< Bit mask for bits in a quad
#define VL_SIZEBITS_I (VL_WORDSIZE-1) ///< Bit mask for bits in a word
#define VL_SIZEBITS_Q (VL_QUADSIZE-1) ///< Bit mask for bits in a quad
/// Mask for words with 1's where relevant bits are (0=all bits)
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) \
? ((1U << ((nbits) & VL_SIZEBITS_I) )-1) : ~0)
? ((1U << ((nbits) & VL_SIZEBITS_I) )-1) : ~0)
/// Mask for quads with 1's where relevant bits are (0=all bits)
#define VL_MASK_Q(nbits) (((nbits) & VL_SIZEBITS_Q) \
? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q) )-VL_ULL(1)) : VL_ULL(~0))
? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q) )-VL_ULL(1)) : VL_ULL(~0))
#define VL_BITWORD_I(bit) ((bit)/VL_WORDSIZE) ///< Word number for a wide quantity
#define VL_BITBIT_I(bit) ((bit)&VL_SIZEBITS_I) ///< Bit number for a bit in a long
#define VL_BITBIT_Q(bit) ((bit)&VL_SIZEBITS_Q) ///< Bit number for a bit in a quad
+18 -18
View File
@@ -23,9 +23,9 @@ our $Debug;
our $Opt_Unsup;
if (! GetOptions (
#"help" => \&usage,
"debug" => sub { $Debug = 1; },
"unsup!" => \$Opt_Unsup, # Ignore unsupported
#"help" => \&usage,
"debug" => sub { $Debug = 1; },
"unsup!" => \$Opt_Unsup, # Ignore unsupported
)) {
die "usage();"
}
@@ -59,24 +59,24 @@ sub prep {
my $rule = "";
my $skip = 1;
while (defined(my $line = $fh->getline)) {
if ($skip == 1) {
next if $line !~ /%token/;
$skip = 2;
}
if ($skip == 1) {
next if $line !~ /%token/;
$skip = 2;
}
if ($Opt_Unsup) {
$line =~ s!//UNSUP!|!g;
$line =~ s!(\s+)\|(\s+)!$1$2!g; # As "UNSUP" often replaces "|"
}
if ($Opt_Unsup) {
$line =~ s!//UNSUP!|!g;
$line =~ s!(\s+)\|(\s+)!$1$2!g; # As "UNSUP" often replaces "|"
}
# %type<foo>
$line =~ s/^(%\S+)<(\S+)>/$1/;
# rule<foo>
$line =~ s/^([a-zA-Z0-9_]+)<\S+>:/$1:/;
# Productions
$line =~ s/[ \t]{[^}]*?}/\t{}/g;
# %type<foo>
$line =~ s/^(%\S+)<(\S+)>/$1/;
# rule<foo>
$line =~ s/^([a-zA-Z0-9_]+)<\S+>:/$1:/;
# Productions
$line =~ s/[ \t]{[^}]*?}/\t{}/g;
$fho->print($line);
$fho->print($line);
}
}
+20 -20
View File
@@ -32,27 +32,27 @@ foreach my $line (<STDIN>) {
$line =~ s!\s+! !g;
next if $line eq '';
if ($line =~ m!^\%\%!) {
$body++;
$body++;
} elsif ($body == 1) {
$rule .= $line;
if ($line =~ m!^\s*;\s*$!) {
#print "Rule: $rule\n";
($rule =~ /^([a-zA-Z0-9_]+)(<\S+>)?:(.*)$/) or die "%Error: No rule name: $1\n";
my $rulename = $1; my $preaction = $3;
$declared{$rulename} = $lineno;
$preaction =~ s/\{[^\}]*\}/ /g;
#print "RULEN $rulename PA $preaction\n" if $Debug;
$rule = '';
foreach my $ref (split /\s+/, $preaction) {
next if $ref !~ /^[a-zA-Z]/;
next if $ref eq $rulename;
if (!$used{$ref} && $declared{$ref}) {
print " %Warning: $lineno: $ref used by $rulename after declaration\n";
}
$used{$ref} = $lineno;
print " ref $ref\n" if $Debug;
}
}
$rule .= $line;
if ($line =~ m!^\s*;\s*$!) {
#print "Rule: $rule\n";
($rule =~ /^([a-zA-Z0-9_]+)(<\S+>)?:(.*)$/) or die "%Error: No rule name: $1\n";
my $rulename = $1; my $preaction = $3;
$declared{$rulename} = $lineno;
$preaction =~ s/\{[^\}]*\}/ /g;
#print "RULEN $rulename PA $preaction\n" if $Debug;
$rule = '';
foreach my $ref (split /\s+/, $preaction) {
next if $ref !~ /^[a-zA-Z]/;
next if $ref eq $rulename;
if (!$used{$ref} && $declared{$ref}) {
print " %Warning: $lineno: $ref used by $rulename after declaration\n";
}
$used{$ref} = $lineno;
print " ref $ref\n" if $Debug;
}
}
}
}
+36 -36
View File
@@ -24,11 +24,11 @@ $Debug = 0;
my $opt_filename;
autoflush STDOUT 1;
autoflush STDERR 1;
if (! GetOptions (
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
)) {
if (! GetOptions(
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
)) {
usage();
}
@@ -49,9 +49,9 @@ sub debug {
sub parameter {
my $param = shift;
if (!$opt_filename) {
$opt_filename = $param;
$opt_filename = $param;
} else {
die "%Error: Unknown parameter: $param\n";
die "%Error: Unknown parameter: $param\n";
}
}
@@ -64,30 +64,30 @@ sub dotread {
my $header = 1;
my $vnum = 0;
while (defined (my $line = $fh->getline)) {
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
next if $1 eq 'nTITLE';
$header = 0;
$Vertexes{$1} = {num => $vnum++,
line => $line,
name => $1,};
}
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
my $from=$1; my $to=$2;
my $weight = 1; $weight = $1 if $line =~ /weight=(\d+)/;
my $cutable = undef; $cutable = $1 if $line =~ /style=(\S+)/;
my $edge = {num => $vnum++,
line => $line,
weight => $weight,
cutable => $cutable,
from => $from,
to => $to,};
push @Edges, $edge;
$Edges{$from}{$to} = $edge;
}
elsif ($header) {
push @Header, $line;
print "IGNORE: $line";
}
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
next if $1 eq 'nTITLE';
$header = 0;
$Vertexes{$1} = {num => $vnum++,
line => $line,
name => $1,};
}
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
my $from=$1; my $to=$2;
my $weight = 1; $weight = $1 if $line =~ /weight=(\d+)/;
my $cutable = undef; $cutable = $1 if $line =~ /style=(\S+)/;
my $edge = {num => $vnum++,
line => $line,
weight => $weight,
cutable => $cutable,
from => $from,
to => $to,};
push @Edges, $edge;
$Edges{$from}{$to} = $edge;
}
elsif ($header) {
push @Header, $line;
print "IGNORE: $line";
}
}
}
@@ -100,14 +100,14 @@ sub cwrite {
$fh->print("void V3GraphTestImport::dotImport() {\n");
$fh->print(" DfaGraph* gp = &m_graph;\n");
foreach my $ver (sort {$a->{num} <=> $b->{num}} (values %Vertexes)) {
$fh->printf(" V3GraphTestVertex* %s = new V3GraphTestVertex(gp, \"%s\"); if (%s) {}\n",
$ver->{name}, $ver->{name}, $ver->{name});
$fh->printf(" V3GraphTestVertex* %s = new V3GraphTestVertex(gp, \"%s\"); if (%s) {}\n",
$ver->{name}, $ver->{name}, $ver->{name});
}
$fh->print("\n");
foreach my $edge (@Edges) {
$fh->printf(" new V3GraphEdge(gp, %s, %s, %s, %s);\n",
$edge->{from}, $edge->{to},
$edge->{weight}, $edge->{cutable}?"true":"false");
$fh->printf(" new V3GraphEdge(gp, %s, %s, %s, %s);\n",
$edge->{from}, $edge->{to},
$edge->{weight}, $edge->{cutable}?"true":"false");
}
$fh->print("}\n");
}
+35 -35
View File
@@ -26,12 +26,12 @@ my $opt_filename;
my $opt_circle;
autoflush STDOUT 1;
autoflush STDERR 1;
if (! GetOptions (
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
"circle=s" => \$opt_circle,
)) {
if (! GetOptions(
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
"circle=s" => \$opt_circle,
)) {
usage();
}
@@ -54,9 +54,9 @@ sub debug {
sub parameter {
my $param = shift;
if (!$opt_filename) {
$opt_filename = $param;
$opt_filename = $param;
} else {
die "%Error: Unknown parameter: $param\n";
die "%Error: Unknown parameter: $param\n";
}
}
@@ -68,16 +68,16 @@ sub dotread {
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
my $header = 1;
while (defined (my $line = $fh->getline)) {
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
$header = 0;
$Vertexes{$1} = $2;
}
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
$Edges{$1}{$2} = $3;
}
elsif ($header) {
push @Header, $line;
}
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
$header = 0;
$Vertexes{$1} = $2;
}
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
$Edges{$1}{$2} = $3;
}
elsif ($header) {
push @Header, $line;
}
}
}
@@ -85,12 +85,12 @@ sub dotread {
sub simplify {
foreach my $ver (sort (keys %Vertexes)) {
$Vertexes{$ver} = _simplify($Vertexes{$ver});
$Vertexes{$ver} = _simplify($Vertexes{$ver});
}
foreach my $v1 (sort (keys %Edges)) {
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
$Edges{$v1}{$v2} = _simplify($Edges{$v1}{$v2});
}
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
$Edges{$v1}{$v2} = _simplify($Edges{$v1}{$v2});
}
}
}
@@ -103,15 +103,15 @@ sub _simplify {
sub dotwrite {
foreach my $line (@Header) {
print "$line";
print "$line";
}
foreach my $ver (sort (keys %Vertexes)) {
print "\t$ver\t$Vertexes{$ver}\n";
print "\t$ver\t$Vertexes{$ver}\n";
}
foreach my $v1 (sort (keys %Edges)) {
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
print "\t$v1 -> $v2\t$Edges{$v1}{$v2}\n";
}
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
print "\t$v1 -> $v2\t$Edges{$v1}{$v2}\n";
}
}
print "}\n";
}
@@ -125,15 +125,15 @@ sub circle {
_circle_recurse($node, 1);
foreach my $ver (keys %Vertexes) {
if (!$User{$ver}) {
delete $Vertexes{$ver};
delete $Edges{$ver};
}
if (!$User{$ver}) {
delete $Vertexes{$ver};
delete $Edges{$ver};
}
}
foreach my $v1 (sort (keys %Edges)) {
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
if (!$Vertexes{$v2}) { delete $Edges{$v1}{$v2}; }
}
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
if (!$Vertexes{$v2}) { delete $Edges{$v1}{$v2}; }
}
}
}
@@ -148,7 +148,7 @@ sub _circle_recurse {
$User2{$node} = 1;
my $r = 0;
foreach my $v2 (keys %{$Edges{$node}}) {
$r |= _circle_recurse($v2,$level++)||0;
$r |= _circle_recurse($v2,$level++)||0;
}
$User{$node} = 1 if $r;
$User2{$node} = 2;
+51 -51
View File
@@ -18,11 +18,11 @@ our $Opt_Jobs = calc_jobs();
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions (
"debug" => sub { $Debug = 1; },
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
"stage=i" => \$Opt_Stage,
"j=i" => \$Opt_Jobs,
if (! GetOptions(
"debug" => sub { $Debug = 1; },
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
"stage=i" => \$Opt_Stage,
"j=i" => \$Opt_Jobs,
)) {
die "%Error: Bad usage, try 'install_test --help'\n";
}
@@ -46,51 +46,51 @@ sub test {
my $testdirn= $srcdir."/test_regress/obj_dir/install_test_testn";
if ($Opt_Stage <= 0) {
run("/bin/rm -rf $blddir");
run("/bin/mkdir -p $blddir");
run("cd $blddir && $srcdir/configure --prefix $prefix");
run("cd $blddir && make -j $Opt_Jobs");
run("/bin/rm -rf $blddir");
run("/bin/mkdir -p $blddir");
run("cd $blddir && $srcdir/configure --prefix $prefix");
run("cd $blddir && make -j $Opt_Jobs");
}
# Install it under the prefix
if ($Opt_Stage <= 1) {
run("/bin/rm -rf $prefix");
run("/bin/mkdir -p $prefix");
run("cd $blddir && make install");
run("test -e $prefix/share/man/man1/verilator.1");
run("/bin/rm -rf $prefix");
run("/bin/mkdir -p $prefix");
run("cd $blddir && make install");
run("test -e $prefix/share/man/man1/verilator.1");
run("test -e $prefix/share/verilator/examples/tracing_c/Makefile");
run("test -e $prefix/share/verilator/include/verilated.h");
run("test -e $prefix/bin/verilator");
run("test -e $prefix/bin/verilator_bin");
run("test -e $prefix/bin/verilator_bin_dbg");
run("test -e $prefix/share/verilator/include/verilated.h");
run("test -e $prefix/bin/verilator");
run("test -e $prefix/bin/verilator_bin");
run("test -e $prefix/bin/verilator_bin_dbg");
run("test -e $prefix/bin/verilator_gantt");
run("test -e $prefix/bin/verilator_profcfunc");
run("test -e $prefix/bin/verilator_profcfunc");
}
# Run a test using just the path
if ($Opt_Stage <= 2) {
my $dir = $testdirp;
run("/bin/rm -rf $dir");
run("/bin/mkdir -p $dir");
my $bin1 = $prefix."/bin";
my $bin2 = $prefix."/share/bin";
write_verilog($dir);
run("cd $dir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v --exe foo.cpp");
run("cd $dir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
run("cd $dir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
my $dir = $testdirp;
run("/bin/rm -rf $dir");
run("/bin/mkdir -p $dir");
my $bin1 = $prefix."/bin";
my $bin2 = $prefix."/share/bin";
write_verilog($dir);
run("cd $dir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v --exe foo.cpp");
run("cd $dir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
run("cd $dir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
}
# Run a test using exact path to binary
if ($Opt_Stage <= 3) {
my $dir = $testdirn;
run("/bin/rm -rf $dir");
run("/bin/mkdir -p $dir");
write_verilog($dir);
my $bin1 = $prefix."/bin";
my $bin2 = $prefix."/share/bin";
run("cd $dir && $bin1/verilator --cc foo.v --exe foo.cpp");
run("cd $dir/obj_dir && make -f Vfoo.mk");
run("cd $dir/obj_dir && ./Vfoo");
my $dir = $testdirn;
run("/bin/rm -rf $dir");
run("/bin/mkdir -p $dir");
write_verilog($dir);
my $bin1 = $prefix."/bin";
my $bin2 = $prefix."/share/bin";
run("cd $dir && $bin1/verilator --cc foo.v --exe foo.cpp");
run("cd $dir/obj_dir && make -f Vfoo.mk");
run("cd $dir/obj_dir && ./Vfoo");
}
if ($Opt_Stage <= 9) {
@@ -102,29 +102,29 @@ sub write_verilog {
my $dir = shift;
IO::File->new(">$dir/foo.v")->print('module t; initial begin $display("HELLO WORLD"); $finish; end endmodule'."\n");
my $fh = IO::File->new(">$dir/foo.cpp");
$fh->print('#include "Vfoo.h"' ,"\n");
$fh->print('unsigned int main_time = 0;' ,"\n");
$fh->print('#include "Vfoo.h"' ,"\n");
$fh->print('unsigned int main_time = 0;' ,"\n");
$fh->print('double sc_time_stamp() {' ,"\n");
$fh->print(' return main_time;' ,"\n");
$fh->print('}' ,"\n");
$fh->print('int main() {' ,"\n");
$fh->print(' Vfoo *top = new Vfoo;' ,"\n");
$fh->print(' return main_time;' ,"\n");
$fh->print('}' ,"\n");
$fh->print('int main() {' ,"\n");
$fh->print(' Vfoo *top = new Vfoo;' ,"\n");
$fh->print(' while (!Verilated::gotFinish()) {',"\n");
$fh->print(' top->eval();' ,"\n");
$fh->print(' main_time++;' ,"\n");
$fh->print(' }' ,"\n");
$fh->print(' top->final();' ,"\n");
$fh->print('}' ,"\n");
$fh->print(' }' ,"\n");
$fh->print(' top->final();' ,"\n");
$fh->print('}' ,"\n");
}
sub cleanenv {
foreach my $var (keys %ENV) {
if ($var eq "VERILATOR_ROOT"
if ($var eq "VERILATOR_ROOT"
|| $var eq "VERILATOR_INCLUDE"
|| $var eq "VERILATOR_NO_OPT_BUILD") {
print "unset $var # Was '$ENV{$var}'\n";
delete $ENV{$var}
}
print "unset $var # Was '$ENV{$var}'\n";
delete $ENV{$var}
}
}
}
@@ -132,8 +132,8 @@ sub cleanenv {
sub calc_jobs {
my $ok = eval "
use Unix::Processors;
return Unix::Processors->new->max_online;
use Unix::Processors;
return Unix::Processors->new->max_online;
";
$ok && !$@ or return 1;
print "driver.pl: Found $ok cores, using -j ",$ok+1,"\n" if $Debug;
+143 -143
View File
@@ -23,11 +23,11 @@ $Debug = 0;
my $opt_filename;
autoflush STDOUT 1;
autoflush STDERR 1;
if (! GetOptions (
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
)) {
if (! GetOptions(
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
)) {
usage();
}
@@ -51,9 +51,9 @@ sub debug {
sub parameter {
my $param = shift;
if (!$opt_filename) {
$opt_filename = $param;
$opt_filename = $param;
} else {
die "%Error: Unknown parameter: $param\n";
die "%Error: Unknown parameter: $param\n";
}
}
@@ -64,45 +64,45 @@ sub vread {
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
my $lasthier="";
$Tree = {
op => 'NETLIST',
t => [[],[],[],[],[],],
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;
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;
$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 $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];
my @hiers = (1,split(/:/,$hier));
my $depth = $#hiers+1;
my $newchild = $hiers[$#hiers];
#print "DD $depth $newchild $op\n";
#print "DD $depth $newchild $op\n";
push @{$stack[$depth-1]->{t}[$newchild]}, $self;
$stack[$depth] = $self;
push @{$stack[$depth-1]->{t}[$newchild]}, $self;
$stack[$depth] = $self;
$lasthier = $hier;
#print " $lasthier\n";
#print Dumper($Tree);
}
$lasthier = $hier;
#print " $lasthier\n";
#print Dumper($Tree);
}
}
}
@@ -168,125 +168,125 @@ sub nl { p "\n"," "x$Indent; }
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 ")"; },
'REDXNOR' => 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 "]"; },
'XNOR' => sub { p1;p " ~^ ";p2; },
'XOR' => sub { p1;p " ^";p2; },
'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 ")"; },
'REDXNOR' => 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 "]"; },
'XNOR' => sub { p1;p " ~^ ";p2; },
'XOR' => sub { p1;p " ^";p2; },
);
}
sub p_var {
my $self = $Code_Self;
if ($self->{etc} =~ /\[I\]/) {
print "input";
print "input";
} elsif ($self->{etc} =~ /\[O\]/) {
print "output";
print "output";
} else {
print "reg";
print "reg";
}
p "\t";
{
local $Avoid_Hex=1;
t1;
local $Avoid_Hex=1;
t1;
}
p "\t";
a1;
if (exists2()) {
p " = ";
t2;
p " = ";
t2;
}
p ";";
nl;
@@ -295,10 +295,10 @@ sub p_var {
sub p_const {
my $v = $Code_Self->{args}[0];
if ($v =~ /\?32\?h(.*)$/
|| ($Avoid_Hex && $v =~ /^[0-9?]*h(.*)$/)) {
print hex $1;
|| ($Avoid_Hex && $v =~ /^[0-9?]*h(.*)$/)) {
print hex $1;
} else {
print $v;
print $v;
}
}
+4
View File
@@ -230,6 +230,10 @@ private:
}
insureCleanAndNext(nodep->bodysp());
}
virtual void visit(AstTraceDecl* nodep) {
// No cleaning, or would loose pointer to enum
iterateChildren(nodep);
}
virtual void visit(AstTraceInc* nodep) {
iterateChildren(nodep);
insureCleanAndNext(nodep->valuep());
+3 -3
View File
@@ -2887,7 +2887,7 @@ class EmitCTrace : EmitCStmts {
puts(",");
putsQuoted(nodep->showname());
// Direction
if (v3Global.opt.traceFormat() == TraceFormat::FST) {
if (v3Global.opt.traceFormat().fstFlavor()) {
puts(","+cvtToStr(enumNum));
// fstVarDir
if (nodep->declDirection().isInoutish()) puts(",FST_VD_INOUT");
@@ -2954,9 +2954,9 @@ class EmitCTrace : EmitCStmts {
int emitTraceDeclDType(AstNodeDType* nodep) {
// Return enum number or -1 for none
if (v3Global.opt.traceFormat() == TraceFormat::FST) {
if (v3Global.opt.traceFormat().fstFlavor()) {
// Skip over refs-to-refs, but stop before final ref so can get data type name
// Alternatively back in V3Width we could have push enum names from upper typedefs
// Alternatively back in V3Width we could push enum names from upper typedefs
if (AstEnumDType* enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) {
int enumNum = enump->user1();
if (!enumNum) {
+3
View File
@@ -61,6 +61,9 @@ public:
of.puts("VM_THREADS = "); of.puts(cvtToStr(v3Global.opt.threads())); of.puts("\n");
of.puts("# Tracing output mode? 0/1 (from --trace)\n");
of.puts("VM_TRACE = "); of.puts(v3Global.opt.trace()?"1":"0"); of.puts("\n");
of.puts("# Tracing threadeds output mode? 0/1 (from --trace-fst-thread)\n");
of.puts("VM_TRACE_THREADED = "); of.puts(v3Global.opt.traceFormat().threaded()
?"1":"0"); of.puts("\n");
of.puts("\n### Object file lists...\n");
for (int support=0; support<3; support++) {
+24 -14
View File
@@ -153,18 +153,16 @@ V3Number::V3Number(FileLine* fileline, const char* sourcep) {
got_01 = 1;
break;
}
case 'z': case '?': {
if (!m_sized) m_fileline->v3error("Unsized X/Z/? not legal in decimal constant: "<<*cp);
setAllBitsZ();
got_z = 1;
break;
}
case 'x': {
if (!m_sized) m_fileline->v3error("Unsized X/Z/? not legal in decimal constant: "<<*cp);
got_x = 1;
setAllBitsX();
break;
}
case 'z': case '?': {
got_z = 1;
setAllBitsZ();
break;
}
case 'x': {
got_x = 1;
setAllBitsX();
break;
}
case '_': break;
default: {
m_fileline->v3error("Illegal character in decimal constant: "<<*cp);
@@ -1658,8 +1656,20 @@ V3Number& V3Number::opAssign(const V3Number& lhs) {
V3Number& V3Number::opExtendS(const V3Number& lhs, uint32_t lbits) {
// Note may be a width change during the sign extension
setZero();
for(int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIsExtend(bit, lbits));
for (int bit=0; bit < width(); bit++) {
char extendWith = lhs.bitIsExtend(bit, lbits);
setBit(bit, extendWith);
}
return *this;
}
V3Number& V3Number::opExtendXZ(const V3Number& lhs, uint32_t lbits) {
// Note may be a width change during the X/Z extension
setZero();
for (int bit=0; bit < width(); bit++) {
char extendWith = lhs.bitIsExtend(bit, lbits);
if (extendWith == '1' || extendWith == 1) extendWith = 0;
setBit(bit, lhs.bitIsExtend(bit, lbits));
}
return *this;
}
+4 -2
View File
@@ -199,6 +199,7 @@ public:
bool isLtXZ(const V3Number& rhs) const; // operator< with XZ compared
void isSigned(bool ssigned) { m_signed=ssigned; }
bool isUnknown() const;
bool isMsbXZ() const { return bitIsXZ(m_width); }
uint32_t toUInt() const;
vlsint32_t toSInt() const;
vluint64_t toUQuad() const;
@@ -231,8 +232,9 @@ public:
V3Number& opBitsZ (const V3Number& lhs); // Z->1, 0/1/X->0
V3Number& opBitsNonZ(const V3Number& lhs); // Z->0, 0/1/X->1
//
V3Number& opAssign (const V3Number& lhs);
V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension
V3Number& opAssign (const V3Number& lhs);
V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension
V3Number& opExtendXZ(const V3Number& lhs, uint32_t lbits); // X/Z extension
V3Number& opRedOr (const V3Number& lhs);
V3Number& opRedAnd (const V3Number& lhs);
V3Number& opRedXor (const V3Number& lhs);
+13 -4
View File
@@ -699,10 +699,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( onoff (sw, "-stats-vars", flag/*ref*/) ) { m_statsVars = flag; m_stats |= flag; }
else if ( !strcmp (sw, "-sv") ) { m_defaultLanguage = V3LangCode::L1800_2005; }
else if ( onoff (sw, "-threads-coarsen", flag/*ref*/)) { m_threadsCoarsen = flag; } // Undocumented, debug
else if ( onoff (sw, "-trace", flag/*ref*/) ) { m_trace = flag; }
else if ( onoff (sw, "-trace-fst", flag/*ref*/) ) { m_trace = flag; m_traceFormat = TraceFormat::FST; addLdLibs("-lz"); }
else if ( onoff (sw, "-trace-dups", flag/*ref*/) ) { m_traceDups = flag; }
else if ( onoff (sw, "-trace-params", flag/*ref*/) ) { m_traceParams = flag; }
else if ( onoff (sw, "-trace", flag/*ref*/) ) { m_trace = flag; }
else if ( onoff (sw, "-trace-dups", flag/*ref*/) ) { m_traceDups = flag; }
else if ( onoff (sw, "-trace-params", flag/*ref*/) ) { m_traceParams = flag; }
else if ( onoff (sw, "-trace-structs", flag/*ref*/) ) { m_traceStructs = flag; }
else if ( onoff (sw, "-trace-underscore", flag/*ref*/) ) { m_traceUnderscore = flag; }
else if ( onoff (sw, "-underline-zero", flag/*ref*/) ) { m_underlineZero = flag; } // Undocumented, old Verilator-2
@@ -869,6 +868,16 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
shift;
m_outputSplitCTrace = atoi(argv[i]);
}
else if (!strcmp(sw, "-trace-fst")) {
m_trace = true;
m_traceFormat = TraceFormat::FST;
addLdLibs("-lz");
}
else if (!strcmp(sw, "-trace-fst-thread")) {
m_trace = true;
m_traceFormat = TraceFormat::FST_THREAD;
addLdLibs("-lz");
}
else if ( !strcmp (sw, "-trace-depth") && (i+1)<argc ) {
shift;
m_traceDepth = atoi(argv[i]);
+6 -1
View File
@@ -41,14 +41,18 @@ class TraceFormat {
public:
enum en {
VCD = 0,
FST
FST,
FST_THREAD
} m_e;
inline TraceFormat(en _e = VCD) : m_e(_e) {}
explicit inline TraceFormat(int _e) : m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
bool fstFlavor() const { return m_e == FST || m_e == FST_THREAD; }
bool threaded() const { return m_e == FST_THREAD; }
string classBase() const {
static const char* const names[] = {
"VerilatedVcd",
"VerilatedFst",
"VerilatedFst"
};
return names[m_e];
@@ -56,6 +60,7 @@ public:
string sourceName() const {
static const char* const names[] = {
"verilated_vcd",
"verilated_fst",
"verilated_fst"
};
return names[m_e];
+22 -14
View File
@@ -271,21 +271,29 @@ private:
// Make sure all parameters are constantified
virtual void visit(AstVar* nodep) {
if (!nodep->user5SetOnce()) { // Process once
if (!nodep->user5SetOnce()) { // Process once
iterateChildren(nodep);
if (nodep->isParam()) {
if (!nodep->valuep()) { nodep->v3fatalSrc("Parameter without initial value"); }
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
if (!VN_IS(nodep->valuep(), Const)) { // Complex init, like an array
// Make a new INITIAL to set the value.
// This allows the normal array/struct handling code to properly initialize the parameter
nodep->addNext(new AstInitial(nodep->fileline(),
new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
nodep->valuep()->cloneTree(true))));
}
}
}
if (nodep->isParam()) {
if (!nodep->valuep()) {
nodep->v3error("Parameter without initial value is never given value"
<<" (IEEE 1800-2017 6.20.1): "
<<nodep->prettyName());
} else {
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
if (!VN_IS(nodep->valuep(), Const)) { // Complex init, like an array
// Make a new INITIAL to set the value.
// This allows the normal array/struct handling code to properly
// initialize the parameter.
nodep->addNext(
new AstInitial(nodep->fileline(),
new AstAssign(
nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
nodep->valuep()->cloneTree(true))));
}
}
}
}
}
// Make sure varrefs cause vars to constify before things above
virtual void visit(AstVarRef* nodep) {
+14 -6
View File
@@ -226,7 +226,9 @@ private:
}
void createTableVars(AstNode* nodep) {
// Create table for each output
// Create table for each output
typedef std::map<string,int> NameCounts;
NameCounts namecounts;
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin(); it!=m_outVarps.end(); ++it) {
AstVarScope* outvscp = *it;
AstVar* outvarp = outvscp->varp();
@@ -234,11 +236,17 @@ private:
AstNodeArrayDType* dtypep
= new AstUnpackArrayDType(fl, outvarp->dtypep(),
new AstRange(fl, VL_MASK_I(m_inWidth), 0));
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
AstVar* tablevarp
= new AstVar(fl, AstVarType::MODULETEMP,
"__Vtable" + cvtToStr(m_modTables) +"_"+outvarp->name(),
dtypep);
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
string name = "__Vtable"+cvtToStr(m_modTables)+"_"+outvarp->name();
NameCounts::iterator nit = namecounts.find(name);
if (nit != namecounts.end()) {
// Multiple scopes can have same var name. We could append the
// scope name but that is very long, so just deduplicate.
name += "__dedup"+cvtToStr(++nit->second);
} else {
namecounts[name] = 0;
}
AstVar* tablevarp = new AstVar(fl, AstVarType::MODULETEMP, name, dtypep);
tablevarp->isConst(true);
tablevarp->isStatic(true);
tablevarp->valuep(new AstInitArray(nodep->fileline(), dtypep, NULL));
+1 -1
View File
@@ -511,7 +511,7 @@ private:
}
} else {
AstNode* clrp = new AstAssign(fl, new AstVarRef(fl, m_activityVscp, true),
new AstConst(fl, V3Number(fl, m_activityVscp->width())));
new AstConst(fl, V3Number(fl, m_activityVscp->width(), 0)));
m_fullFuncp->addFinalsp(clrp->cloneTree(true));
m_chgFuncp->addFinalsp(clrp);
}
+20 -2
View File
@@ -3170,8 +3170,26 @@ private:
nodepr = newp;
return true;
}
}
return false; // No change
// X/Z also upper bit extend. In pre-SV only to 32-bits, SV forever.
else if (!constp->num().sized()
// Make it the proper size. Careful of proper extension of 0's/1's
&& expWidth > 32 && constp->num().isMsbXZ()) {
constp->v3warn(WIDTH, "Unsized constant being X/Z extended to "
<<expWidth<<" bits: "<<constp->prettyName());
V3Number num (constp->fileline(), expWidth);
num.opExtendXZ(constp->num(), constp->width());
AstNode* newp = new AstConst(constp->fileline(), num);
// Spec says always unsigned with proper width
if (debug()>4) constp->dumpTree(cout," fixUnszExtend_old: ");
if (debug()>4) newp->dumpTree(cout," _new: ");
constp->replaceWith(newp);
constp->deleteTree(); VL_DANGLING(constp);
// Tell caller the new constp, and that we changed it.
nodepr = newp;
return true;
}
}
return false; // No change
}
bool similarDTypeRecurse(AstNodeDType* node1p, AstNodeDType* node2p) {
+58 -58
View File
@@ -32,35 +32,35 @@
class VlcBuckets {
private:
// MEMBERS
vluint64_t* m_datap; ///< Pointer to first bucket (dynamically allocated)
vluint64_t m_dataSize; ///< Current entries in m_datap
vluint64_t m_bucketsCovered; ///< Num buckets with sufficient coverage
vluint64_t* m_datap; ///< Pointer to first bucket (dynamically allocated)
vluint64_t m_dataSize; ///< Current entries in m_datap
vluint64_t m_bucketsCovered; ///< Num buckets with sufficient coverage
private:
static inline vluint64_t covBit(vluint64_t point) { return 1ULL<<(point & 63); }
inline vluint64_t allocSize() const { return sizeof(vluint64_t) * m_dataSize / 64; }
void allocate(vluint64_t point) {
vluint64_t oldsize = m_dataSize;
if (m_dataSize<point) m_dataSize=(point+64) & ~63ULL; // Keep power of two
m_dataSize *= 2;
vluint64_t oldsize = m_dataSize;
if (m_dataSize<point) m_dataSize=(point+64) & ~63ULL; // Keep power of two
m_dataSize *= 2;
//UINFO(9, "Realloc "<<allocSize()<<" for "<<point<<" "<<cvtToHex(m_datap)<<endl);
vluint64_t* newp = (vluint64_t*)realloc(m_datap, allocSize());
if (!newp) { free(m_datap); v3fatal("Out of memory increasing buckets"); }
m_datap = newp;
for (vluint64_t i=oldsize; i<m_dataSize; i+=64) m_datap[i/64] = 0;
vluint64_t* newp = (vluint64_t*)realloc(m_datap, allocSize());
if (!newp) { free(m_datap); v3fatal("Out of memory increasing buckets"); }
m_datap = newp;
for (vluint64_t i=oldsize; i<m_dataSize; i+=64) m_datap[i/64] = 0;
}
public:
// CONSTRUCTORS
VlcBuckets() {
m_dataSize = 0;
m_datap = NULL;
m_bucketsCovered = 0;
allocate(1024);
m_dataSize = 0;
m_datap = NULL;
m_bucketsCovered = 0;
allocate(1024);
}
~VlcBuckets() {
m_dataSize = 0;
free(m_datap); m_datap=NULL;
m_dataSize = 0;
free(m_datap); m_datap=NULL;
}
// ACCESSORS
@@ -69,66 +69,66 @@ public:
// METHODS
void addData(vluint64_t point, vluint64_t hits) {
if (hits >= sufficient()) {
//UINFO(9," addData "<<point<<" "<<hits<<" size="<<m_dataSize<<endl);
if (point >= m_dataSize) allocate(point);
m_datap[point/64] |= covBit(point);
m_bucketsCovered++;
}
if (hits >= sufficient()) {
//UINFO(9," addData "<<point<<" "<<hits<<" size="<<m_dataSize<<endl);
if (point >= m_dataSize) allocate(point);
m_datap[point/64] |= covBit(point);
m_bucketsCovered++;
}
}
void clearHits(vluint64_t point) const {
if (point >= m_dataSize) {
return;
} else {
m_datap[point/64] &= ~covBit(point);
}
if (point >= m_dataSize) {
return;
} else {
m_datap[point/64] &= ~covBit(point);
}
}
bool exists(vluint64_t point) const {
if (point >= m_dataSize) {
return false;
} else {
return (m_datap[point/64] & covBit(point)) ? 1:0;
}
if (point >= m_dataSize) {
return false;
} else {
return (m_datap[point/64] & covBit(point)) ? 1:0;
}
}
vluint64_t hits(vluint64_t point) const {
if (point >= m_dataSize) {
return 0;
} else {
return (m_datap[point/64] & covBit(point)) ? 1:0;
}
if (point >= m_dataSize) {
return 0;
} else {
return (m_datap[point/64] & covBit(point)) ? 1:0;
}
}
vluint64_t popCount() const {
vluint64_t pop = 0;
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i)) pop++;
}
return pop;
vluint64_t pop = 0;
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i)) pop++;
}
return pop;
}
vluint64_t dataPopCount(const VlcBuckets& remaining) {
vluint64_t pop = 0;
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i) && remaining.hits(i)) pop++;
}
return pop;
vluint64_t pop = 0;
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i) && remaining.hits(i)) pop++;
}
return pop;
}
void orData(const VlcBuckets& ordata) {
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i) && ordata.hits(i)) {
clearHits(i);
}
}
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i) && ordata.hits(i)) {
clearHits(i);
}
}
}
void dump() const {
cout<<"# ";
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i)) cout<<","<<i;
}
cout<<endl;
cout<<"# ";
for (vluint64_t i=0; i<m_dataSize; i++) {
if (hits(i)) cout<<","<<i;
}
cout<<endl;
}
};
//######################################################################
#endif // guard
#endif // guard
+67 -68
View File
@@ -43,7 +43,7 @@
void VlcOptions::addReadFile(const string& filename) {
if (m_readFiles.find(filename) == m_readFiles.end()) {
m_readFiles.insert(filename);
m_readFiles.insert(filename);
}
}
@@ -59,9 +59,9 @@ bool VlcOptions::onoff(const char* sw, const char* arg, bool& flag) {
// if sw=="-noarg", then return true (found it), and flag=false
// else return false
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.");
if (0==strcmp(sw,arg)) { flag=true; return true; }
else if (0==strncmp(sw,"-no",3) && (0==strcmp(sw+3,arg+1))) { flag=false; return true; }
else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag=false; return true; }
if (0==strcmp(sw,arg)) { flag = true; return true; }
else if (0==strncmp(sw,"-no",3) && (0==strcmp(sw+3,arg+1))) { flag = false; return true; }
else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag = false; return true; }
return false;
}
@@ -71,58 +71,58 @@ void VlcOptions::parseOptsList(int argc, char** argv) {
// May be called recursively when there are -f files.
#define shift { ++i; }
for (int i=0; i<argc; ) {
UINFO(9, " Option: "<<argv[i]<<endl);
if (argv[i][0]=='-') {
const char *sw = argv[i];
bool flag = true;
// Allow gnu -- switches
if (sw[0]=='-' && sw[1]=='-') ++sw;
if (0) {}
// Single switches
else if ( onoff (sw, "-annotate-all", flag/*ref*/) ) { m_annotateAll = flag; }
else if ( onoff (sw, "-rank", flag/*ref*/) ) { m_rank = flag; }
else if ( onoff (sw, "-unlink", flag/*ref*/) ) { m_unlink = flag; }
// Parameterized switches
UINFO(9, " Option: "<<argv[i]<<endl);
if (argv[i][0]=='-') {
const char *sw = argv[i];
bool flag = true;
// Allow gnu -- switches
if (sw[0]=='-' && sw[1]=='-') ++sw;
if (0) {}
// Single switches
else if ( onoff (sw, "-annotate-all", flag/*ref*/) ) { m_annotateAll = flag; }
else if ( onoff (sw, "-rank", flag/*ref*/) ) { m_rank = flag; }
else if ( onoff (sw, "-unlink", flag/*ref*/) ) { m_unlink = flag; }
// Parameterized switches
else if ( !strcmp (sw, "-annotate-min") && (i+1)<argc ) {
shift;
m_annotateMin = atoi(argv[i]);
}
else if ( !strcmp (sw, "-annotate") && (i+1)<argc ) {
shift;
m_annotateOut = argv[i];
}
else if ( !strcmp (sw, "-debug") ) {
V3Error::debugDefault(3);
}
else if ( !strcmp (sw, "-debugi") && (i+1)<argc ) {
shift;
V3Error::debugDefault(atoi(argv[i]));
}
else if ( !strcmp (sw, "-V") ) {
showVersion(true);
exit(0);
}
else if ( !strcmp (sw, "-version") ) {
showVersion(false);
exit(0);
}
else if ( !strcmp (sw, "-write") && (i+1)<argc ) {
shift;
m_writeFile = argv[i];
}
else {
else if ( !strcmp (sw, "-annotate") && (i+1)<argc ) {
shift;
m_annotateOut = argv[i];
}
else if ( !strcmp (sw, "-debug") ) {
V3Error::debugDefault(3);
}
else if ( !strcmp (sw, "-debugi") && (i+1)<argc ) {
shift;
V3Error::debugDefault(atoi(argv[i]));
}
else if ( !strcmp (sw, "-V") ) {
showVersion(true);
exit(0);
}
else if ( !strcmp (sw, "-version") ) {
showVersion(false);
exit(0);
}
else if ( !strcmp (sw, "-write") && (i+1)<argc ) {
shift;
m_writeFile = argv[i];
}
else {
v3fatal("Invalid option: "<<argv[i]);
}
shift;
} // - options
else if (1) {
addReadFile(argv[i]);
shift;
}
else {
}
shift;
} // - options
else if (1) {
addReadFile(argv[i]);
shift;
}
else {
v3fatal("Invalid argument: "<<argv[i]);
shift;
}
shift;
}
}
#undef shift
}
@@ -154,20 +154,20 @@ int main(int argc, char** argv, char** env) {
top.opt.parseOptsList(argc-1, argv+1);
if (top.opt.readFiles().empty()) {
top.opt.addReadFile("vlt_coverage.dat");
top.opt.addReadFile("vlt_coverage.dat");
}
{
const VlStringSet& readFiles = top.opt.readFiles();
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
string filename = *it;
top.readCoverage(filename);
}
const VlStringSet& readFiles = top.opt.readFiles();
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
string filename = *it;
top.readCoverage(filename);
}
}
if (debug() >= 9) {
top.tests().dump(true);
top.points().dump();
top.tests().dump(true);
top.points().dump();
}
V3Error::abortIfWarnings();
@@ -176,19 +176,19 @@ int main(int argc, char** argv, char** env) {
}
if (top.opt.rank()) {
top.rank();
top.tests().dump(false);
top.rank();
top.tests().dump(false);
}
if (!top.opt.writeFile().empty()) {
top.writeCoverage(top.opt.writeFile());
V3Error::abortIfWarnings();
top.writeCoverage(top.opt.writeFile());
V3Error::abortIfWarnings();
if (top.opt.unlink()) {
const VlStringSet& readFiles = top.opt.readFiles();
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
string filename = *it;
unlink(filename.c_str());
}
const VlStringSet& readFiles = top.opt.readFiles();
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
string filename = *it;
unlink(filename.c_str());
}
}
}
@@ -201,4 +201,3 @@ int main(int argc, char** argv, char** env) {
// Local Variables:
// compile-command: "v4make bin/verilator_coverage --debugi 9 test_regress/t/t_vlcov_data_*.dat"
// End:
+12 -12
View File
@@ -38,13 +38,13 @@ typedef std::set<string> VlStringSet;
class VlcOptions {
// MEMBERS (general options)
string m_annotateOut; // main switch: --annotate I<output_directory>
bool m_annotateAll; // main switch: --annotate-all
int m_annotateMin; // main switch: --annotate-min I<count>
VlStringSet m_readFiles; // main switch: --read
bool m_rank; // main switch: --rank
bool m_unlink; // main switch: --unlink
string m_writeFile; // main switch: --write
string m_annotateOut; // main switch: --annotate I<output_directory>
bool m_annotateAll; // main switch: --annotate-all
int m_annotateMin; // main switch: --annotate-min I<count>
VlStringSet m_readFiles; // main switch: --read
bool m_rank; // main switch: --rank
bool m_unlink; // main switch: --unlink
string m_writeFile; // main switch: --write
private:
// METHODS
@@ -54,10 +54,10 @@ private:
public:
// CONSTRUCTORS
VlcOptions() {
m_annotateAll = false;
m_annotateMin = 10;
m_rank = false;
m_unlink = false;
m_annotateAll = false;
m_annotateMin = 10;
m_rank = false;
m_unlink = false;
}
~VlcOptions() {}
void setDebugMode(int level);
@@ -81,4 +81,4 @@ public:
//######################################################################
#endif // guard
#endif // guard
+49 -49
View File
@@ -36,18 +36,18 @@
class VlcPoint {
private:
// MEMBERS
string m_name; //< Name of the point
vluint64_t m_pointNum; //< Point number
vluint64_t m_testsCovering;//< Number tests with non-zero coverage of this point
vluint64_t m_count; //< Count of hits across all tests
string m_name; //< Name of the point
vluint64_t m_pointNum; //< Point number
vluint64_t m_testsCovering; //< Number tests with non-zero coverage of this point
vluint64_t m_count; //< Count of hits across all tests
public:
// CONSTRUCTORS
VlcPoint(const string& name, int pointNum) {
m_name = name;
m_pointNum = pointNum;
m_testsCovering = 0;
m_count = 0;
m_name = name;
m_pointNum = pointNum;
m_testsCovering = 0;
m_count = 0;
}
~VlcPoint() {}
// ACCESSORS
@@ -66,31 +66,31 @@ public:
int column() const { return atoi(keyExtract(VL_CIK_COLUMN).c_str()); }
// METHODS
string keyExtract(const char* shortKey) const {
// Hot function
size_t shortLen = strlen(shortKey);
const string namestr = name();
for (const char* cp = namestr.c_str(); *cp; ++cp) {
if (*cp == '\001') {
if (0==strncmp(cp+1, shortKey, shortLen)
&& cp[shortLen+1] == '\002') {
cp += shortLen+2; // Skip \001+short+\002
const char* ep = cp;
while (*ep && *ep != '\001') ++ep;
return string(cp, ep-cp);
}
}
}
return "";
// Hot function
size_t shortLen = strlen(shortKey);
const string namestr = name();
for (const char* cp = namestr.c_str(); *cp; ++cp) {
if (*cp == '\001') {
if (0==strncmp(cp+1, shortKey, shortLen)
&& cp[shortLen+1] == '\002') {
cp += shortLen+2; // Skip \001+short+\002
const char* ep = cp;
while (*ep && *ep != '\001') ++ep;
return string(cp, ep-cp);
}
}
}
return "";
}
static void dumpHeader() {
cout<<"Points:\n";
cout<<" Num, TestsCover, Count, Name"<<endl;
cout<<"Points:\n";
cout<<" Num, TestsCover, Count, Name"<<endl;
}
void dump() const {
cout<<" "<<std::setw(8)<<std::setfill('0')<<pointNum()
<<", "<<std::setw(7)<<std::setfill(' ')<<testsCovering()
<<", "<<std::setw(7)<<std::setfill(' ')<<count()
<<", \""<<name()<<"\""<<endl;
<<", \""<<name()<<"\""<<endl;
}
};
@@ -115,40 +115,40 @@ public:
public:
// CONSTRUCTORS
VlcPoints() {
m_numPoints = 0;
m_numPoints = 0;
}
~VlcPoints() {}
// METHODS
void dump() {
UINFO(2,"dumpPoints...\n");
VlcPoint::dumpHeader();
for (VlcPoints::ByName::iterator it=begin(); it!=end(); ++it) {
const VlcPoint& point = pointNumber(it->second);
point.dump();
}
UINFO(2,"dumpPoints...\n");
VlcPoint::dumpHeader();
for (VlcPoints::ByName::iterator it=begin(); it!=end(); ++it) {
const VlcPoint& point = pointNumber(it->second);
point.dump();
}
}
VlcPoint& pointNumber(vluint64_t num) {
return m_points[num];
return m_points[num];
}
vluint64_t findAddPoint(const string& name, vluint64_t count) {
vluint64_t pointnum;
NameMap::iterator iter = m_nameMap.find(name);
if (iter != m_nameMap.end()) {
pointnum = iter->second;
m_points[pointnum].countInc(count);
}
else {
pointnum = m_numPoints++;
VlcPoint point (name, pointnum);
point.countInc(count);
m_points.push_back(point);
m_nameMap.insert(make_pair(point.name(), point.pointNum()));
}
return pointnum;
vluint64_t pointnum;
NameMap::iterator iter = m_nameMap.find(name);
if (iter != m_nameMap.end()) {
pointnum = iter->second;
m_points[pointnum].countInc(count);
}
else {
pointnum = m_numPoints++;
VlcPoint point (name, pointnum);
point.countInc(count);
m_points.push_back(point);
m_nameMap.insert(make_pair(point.name(), point.pointNum()));
}
return pointnum;
}
};
//######################################################################
#endif // guard
#endif // guard
+36 -36
View File
@@ -33,18 +33,18 @@
class VlcSourceCount {
private:
// MEMBERS
int m_lineno; ///< Line number
int m_column; ///< Column number
vluint64_t m_count; ///< Count
bool m_ok; ///< Coverage is above threshold
int m_lineno; ///< Line number
int m_column; ///< Column number
vluint64_t m_count; ///< Count
bool m_ok; ///< Coverage is above threshold
public:
// CONSTRUCTORS
VlcSourceCount(int lineno, int column) {
m_lineno = lineno;
m_column = column;
m_count = 0;
m_ok = false;
m_lineno = lineno;
m_column = column;
m_count = 0;
m_ok = false;
}
~VlcSourceCount() {}
@@ -56,8 +56,8 @@ public:
// METHODS
void incCount(vluint64_t count, bool ok) {
m_count += count;
if (ok) m_ok = true;
m_count += count;
if (ok) m_ok = true;
}
};
@@ -72,15 +72,15 @@ public:
private:
// MEMBERS
string m_name; //< Name of the source file
bool m_needed; //< Need to annotate; has low coverage
LinenoMap m_lines; //< Map of each annotated line
string m_name; //< Name of the source file
bool m_needed; //< Need to annotate; has low coverage
LinenoMap m_lines; //< Map of each annotated line
public:
// CONSTRUCTORS
explicit VlcSource(const string& name) {
m_name = name;
m_needed = false;
m_name = name;
m_needed = false;
}
~VlcSource() {}
@@ -92,17 +92,17 @@ public:
// METHODS
void incCount(int lineno, int column, vluint64_t count, bool ok) {
LinenoMap::iterator lit = m_lines.find(lineno);
if (lit == m_lines.end()) {
lit = m_lines.insert(make_pair(lineno,ColumnMap())).first;
}
ColumnMap& cmap = lit->second;
ColumnMap::iterator cit = cmap.find(column);
if (cit == cmap.end()) {
cit = cmap.insert(make_pair(column,VlcSourceCount(lineno, column))).first;
}
VlcSourceCount& sc = cit->second;
sc.incCount(count,ok);
LinenoMap::iterator lit = m_lines.find(lineno);
if (lit == m_lines.end()) {
lit = m_lines.insert(make_pair(lineno, ColumnMap())).first;
}
ColumnMap& cmap = lit->second;
ColumnMap::iterator cit = cmap.find(column);
if (cit == cmap.end()) {
cit = cmap.insert(make_pair(column, VlcSourceCount(lineno, column))).first;
}
VlcSourceCount& sc = cit->second;
sc.incCount(count, ok);
}
};
@@ -115,7 +115,7 @@ public:
typedef std::map<string,VlcSource> NameMap;
private:
// MEMBERS
NameMap m_sources; //< List of all sources
NameMap m_sources; //< List of all sources
public:
// ITERATORS
@@ -130,17 +130,17 @@ public:
// METHODS
VlcSource& findNewSource(const string& name) {
NameMap::iterator iter = m_sources.find(name);
if (iter != m_sources.end()) {
return iter->second;
}
else {
iter = m_sources.insert(make_pair(name, VlcSource(name))).first;
return iter->second;
}
NameMap::iterator iter = m_sources.find(name);
if (iter != m_sources.end()) {
return iter->second;
}
else {
iter = m_sources.insert(make_pair(name, VlcSource(name))).first;
return iter->second;
}
}
};
//######################################################################
#endif // Guard
#endif // Guard
+36 -36
View File
@@ -36,23 +36,23 @@
class VlcTest {
private:
// MEMBERS
string m_name; //< Name of the test
double m_computrons; //< Runtime for the test
vluint64_t m_testrun; //< Test run number, for database use
vluint64_t m_rank; //< Execution rank suggestion
vluint64_t m_rankPoints; //< Ranked additional points
vluint64_t m_user; //< User data for algorithms (not persisted in .dat file)
VlcBuckets m_buckets; //< Coverage data for each coverage point
string m_name; //< Name of the test
double m_computrons; //< Runtime for the test
vluint64_t m_testrun; //< Test run number, for database use
vluint64_t m_rank; //< Execution rank suggestion
vluint64_t m_rankPoints; //< Ranked additional points
vluint64_t m_user; //< User data for algorithms (not persisted in .dat file)
VlcBuckets m_buckets; //< Coverage data for each coverage point
public:
// CONSTRUCTORS
VlcTest(const string& name, vluint64_t testrun, double comp) {
m_name = name;
m_computrons = comp;
m_testrun = testrun;
m_rank = 0;
m_rankPoints = 0;
m_user = 0;
m_name = name;
m_computrons = comp;
m_testrun = testrun;
m_rank = 0;
m_rankPoints = 0;
m_user = 0;
}
~VlcTest() {}
@@ -71,20 +71,20 @@ public:
// METHODS
static void dumpHeader() {
cout<<"Tests:\n";
//cout<<" Testrun, Computrons,"; // Currently not loaded
cout<<" Covered, Rank, RankPts, Filename"<<endl;
cout<<"Tests:\n";
//cout<<" Testrun, Computrons,"; // Currently not loaded
cout<<" Covered, Rank, RankPts, Filename"<<endl;
}
void dump(bool bucketsToo) {
if (testrun() || computrons()!=0.0) {
if (testrun() || computrons()!=0.0) {
cout<<" "<<std::setw(8)<<std::setfill('0')<<testrun()
<<", "<<std::setw(7)<<std::setfill(' ')<<computrons()<<",";
}
}
cout<<" "<<std::setw(7)<<std::setfill(' ')<<bucketsCovered()
<<", "<<std::setw(7)<<std::setfill(' ')<<rank()
<<", "<<std::setw(7)<<std::setfill(' ')<<rankPoints()
<<", \""<<name()<<"\""<<endl;
if (bucketsToo) m_buckets.dump();
<<", \""<<name()<<"\""<<endl;
if (bucketsToo) m_buckets.dump();
}
};
@@ -97,7 +97,7 @@ public:
typedef std::vector<VlcTest*> ByName;
private:
// MEMBERS
ByName m_tests; //< List of all tests
ByName m_tests; //< List of all tests
public:
// ITERATORS
@@ -109,31 +109,31 @@ public:
// CONSTRUCTORS
VlcTests() {}
~VlcTests() {
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
delete *it; *it=NULL;
}
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
delete *it; *it=NULL;
}
}
// METHODS
void dump(bool bucketsToo) {
UINFO(2,"dumpTests...\n");
VlcTest::dumpHeader();
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
(*it)->dump(bucketsToo);
}
UINFO(2,"dumpTests...\n");
VlcTest::dumpHeader();
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
(*it)->dump(bucketsToo);
}
}
VlcTest* newTest(const string& name, vluint64_t testrun, double comp) {
VlcTest* testp = new VlcTest(name, testrun, comp);
m_tests.push_back(testp);
return testp;
VlcTest* testp = new VlcTest(name, testrun, comp);
m_tests.push_back(testp);
return testp;
}
void clearUser() {
for (ByName::iterator it = m_tests.begin(); it != m_tests.end(); ++it) {
(*it)->user(0);
}
for (ByName::iterator it = m_tests.begin(); it != m_tests.end(); ++it) {
(*it)->user(0);
}
}
};
//######################################################################
#endif // Guard
#endif // Guard
+122 -122
View File
@@ -34,8 +34,8 @@ void VlcTop::readCoverage(const string& filename, bool nonfatal) {
std::ifstream is(filename.c_str());
if (!is) {
if (!nonfatal) v3fatal("Can't read "<<filename);
return;
if (!nonfatal) v3fatal("Can't read "<<filename);
return;
}
// Testrun and computrons argument unsupported as yet
@@ -45,23 +45,23 @@ void VlcTop::readCoverage(const string& filename, bool nonfatal) {
string line = V3Os::getline(is);
//UINFO(9," got "<<line<<endl);
if (line[0] == 'C') {
string::size_type secspace=3;
for (; secspace<line.length(); secspace++) {
if (line[secspace]=='\'' && line[secspace+1]==' ') break;
}
string point = line.substr(3,secspace-3);
vluint64_t hits = atoll(line.c_str()+secspace+1);
//UINFO(9," point '"<<point<<"'"<<" "<<hits<<endl);
string::size_type secspace = 3;
for (; secspace<line.length(); secspace++) {
if (line[secspace]=='\'' && line[secspace+1]==' ') break;
}
string point = line.substr(3, secspace-3);
vluint64_t hits = atoll(line.c_str()+secspace+1);
//UINFO(9," point '"<<point<<"'"<<" "<<hits<<endl);
vluint64_t pointnum = points().findAddPoint(point, hits);
if (pointnum) {} // Prevent unused
if (opt.rank()) { // Only if ranking - uses a lot of memory
if (hits >= VlcBuckets::sufficient()) {
points().pointNumber(pointnum).testsCoveringInc();
testp->buckets().addData(pointnum, hits);
}
}
}
vluint64_t pointnum = points().findAddPoint(point, hits);
if (pointnum) {} // Prevent unused
if (opt.rank()) { // Only if ranking - uses a lot of memory
if (hits >= VlcBuckets::sufficient()) {
points().pointNumber(pointnum).testsCoveringInc();
testp->buckets().addData(pointnum, hits);
}
}
}
}
}
@@ -70,14 +70,14 @@ void VlcTop::writeCoverage(const string& filename) {
std::ofstream os(filename.c_str());
if (!os) {
v3fatal("Can't write "<<filename);
return;
v3fatal("Can't write "<<filename);
return;
}
os << "# SystemC::Coverage-3" << endl;
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
const VlcPoint& point = m_points.pointNumber(it->second);
os <<"C '"<<point.name()<<"' " << point.count()<<endl;
const VlcPoint& point = m_points.pointNumber(it->second);
os <<"C '"<<point.name()<<"' " << point.count()<<endl;
}
}
@@ -85,32 +85,32 @@ void VlcTop::writeCoverage(const string& filename) {
struct CmpComputrons {
inline bool operator() (const VlcTest* lhsp, const VlcTest* rhsp) const {
if (lhsp->computrons() != rhsp->computrons()) {
return lhsp->computrons() < rhsp->computrons();
}
return lhsp->bucketsCovered() > rhsp->bucketsCovered();
if (lhsp->computrons() != rhsp->computrons()) {
return lhsp->computrons() < rhsp->computrons();
}
return lhsp->bucketsCovered() > rhsp->bucketsCovered();
}
};
void VlcTop::rank() {
UINFO(2,"rank...\n");
vluint64_t nextrank=1;
vluint64_t nextrank = 1;
// Sort by computrons, so fast tests get selected first
std::vector<VlcTest*> bytime;
for (VlcTests::ByName::iterator it=m_tests.begin(); it!=m_tests.end(); ++it) {
VlcTest* testp = *it;
if (testp->bucketsCovered()) { // else no points, so can't help us
bytime.push_back(*it);
}
VlcTest* testp = *it;
if (testp->bucketsCovered()) { // else no points, so can't help us
bytime.push_back(*it);
}
}
sort(bytime.begin(), bytime.end(), CmpComputrons()); // Sort the vector
sort(bytime.begin(), bytime.end(), CmpComputrons()); // Sort the vector
VlcBuckets remaining;
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
VlcPoint* pointp = &points().pointNumber(it->second);
// If any tests hit this point, then we'll need to cover it.
if (pointp->testsCovering()) { remaining.addData(pointp->pointNum(), 1); }
VlcPoint* pointp = &points().pointNumber(it->second);
// If any tests hit this point, then we'll need to cover it.
if (pointp->testsCovering()) { remaining.addData(pointp->pointNum(), 1); }
}
// Additional Greedy algorithm
@@ -118,26 +118,26 @@ void VlcTop::rank() {
// then hierarchically solve a small subset of tests, and take resulting
// solution and move up to larger subset of tests. (Aka quick sort.)
while (1) {
if (debug()) { UINFO(9,"Left on iter"<<nextrank<<": "); remaining.dump(); }
VlcTest* bestTestp = NULL;
vluint64_t bestRemain = 0;
if (debug()) { UINFO(9,"Left on iter"<<nextrank<<": "); remaining.dump(); }
VlcTest* bestTestp = NULL;
vluint64_t bestRemain = 0;
for (std::vector<VlcTest*>::iterator it=bytime.begin(); it!=bytime.end(); ++it) {
VlcTest* testp = *it;
if (!testp->rank()) {
vluint64_t remain = testp->buckets().dataPopCount(remaining);
if (remain > bestRemain) {
bestTestp = testp;
bestRemain = remain;
}
}
}
if (VlcTest* testp = bestTestp) {
testp->rank(nextrank++);
testp->rankPoints(bestRemain);
remaining.orData(bestTestp->buckets());
} else {
break; // No test covering more stuff found
}
VlcTest* testp = *it;
if (!testp->rank()) {
vluint64_t remain = testp->buckets().dataPopCount(remaining);
if (remain > bestRemain) {
bestTestp = testp;
bestRemain = remain;
}
}
}
if (VlcTest* testp = bestTestp) {
testp->rank(nextrank++);
testp->rankPoints(bestRemain);
remaining.orData(bestTestp->buckets());
} else {
break; // No test covering more stuff found
}
}
}
@@ -146,18 +146,18 @@ void VlcTop::rank() {
void VlcTop::annotateCalc() {
// Calculate per-line information into filedata structure
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
const VlcPoint& point = m_points.pointNumber(it->second);
string filename = point.filename();
int lineno = point.lineno();
const VlcPoint& point = m_points.pointNumber(it->second);
string filename = point.filename();
int lineno = point.lineno();
if (!filename.empty() && lineno!=0) {
int column = point.column();
VlcSource& source = sources().findNewSource(filename);
string threshStr = point.thresh();
int column = point.column();
VlcSource& source = sources().findNewSource(filename);
string threshStr = point.thresh();
unsigned thresh = (!threshStr.empty()) ? atoi(threshStr.c_str()) : opt.annotateMin();
bool ok = (point.count() >= thresh);
UINFO(9, "AnnoCalc count "<<filename<<" "<<lineno<<" "<<point.count()<<endl);
source.incCount(lineno, column, point.count(), ok);
}
bool ok = (point.count() >= thresh);
UINFO(9, "AnnoCalc count "<<filename<<" "<<lineno<<" "<<point.count()<<endl);
source.incCount(lineno, column, point.count(), ok);
}
}
}
@@ -167,23 +167,23 @@ void VlcTop::annotateCalcNeeded() {
int totCases = 0;
int totOk = 0;
for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
VlcSource& source = sit->second;
//UINFO(1,"Source "<<source.name()<<endl);
if (opt.annotateAll()) source.needed(true);
VlcSource::LinenoMap& lines = source.lines();
for (VlcSource::LinenoMap::iterator lit=lines.begin(); lit!=lines.end(); ++lit) {
VlcSource::ColumnMap& cmap = lit->second;
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
VlcSourceCount& col = cit->second;
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
++totCases;
if (col.ok()) {
++totOk;
} else {
source.needed(true);
}
}
}
VlcSource& source = sit->second;
//UINFO(1,"Source "<<source.name()<<endl);
if (opt.annotateAll()) source.needed(true);
VlcSource::LinenoMap& lines = source.lines();
for (VlcSource::LinenoMap::iterator lit=lines.begin(); lit!=lines.end(); ++lit) {
VlcSource::ColumnMap& cmap = lit->second;
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
VlcSourceCount& col = cit->second;
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
++totCases;
if (col.ok()) {
++totOk;
} else {
source.needed(true);
}
}
}
}
float pct = totCases ? (100*totOk / totCases) : 0;
cout<<"Total coverage ("<<totOk<<"/"<<totCases<<") "
@@ -195,60 +195,61 @@ void VlcTop::annotateOutputFiles(const string& dirname) {
// Create if uncreated, ignore errors
V3Os::createDir(dirname);
for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
VlcSource& source = sit->second;
if (!source.needed()) continue;
string filename = source.name();
string outfilename = dirname+"/"+V3Os::filenameNonDir(filename);
VlcSource& source = sit->second;
if (!source.needed()) continue;
string filename = source.name();
string outfilename = dirname+"/"+V3Os::filenameNonDir(filename);
UINFO(1,"annotateOutputFile "<<filename<<" -> "<<outfilename<<endl);
UINFO(1,"annotateOutputFile "<<filename<<" -> "<<outfilename<<endl);
std::ifstream is(filename.c_str());
if (!is) {
v3error("Can't read "<<filename);
return;
}
if (!is) {
v3error("Can't read "<<filename);
return;
}
std::ofstream os(outfilename.c_str());
if (!os) {
v3fatal("Can't write "<<outfilename);
return;
}
if (!os) {
v3fatal("Can't write "<<outfilename);
return;
}
os << "\t// verilator_coverage annotation"<<endl;
os << "\t// verilator_coverage annotation"<<endl;
int lineno = 0;
while (!is.eof()) {
int lineno = 0;
while (!is.eof()) {
lineno++;
string line = V3Os::getline(is);
bool first = true;
bool first = true;
VlcSource::LinenoMap& lines = source.lines();
VlcSource::LinenoMap::iterator lit=lines.find(lineno);
if (lit != lines.end()) {
VlcSource::ColumnMap& cmap = lit->second;
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
VlcSourceCount& col = cit->second;
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
os<<(col.ok()?" ":"%")
VlcSource::LinenoMap& lines = source.lines();
VlcSource::LinenoMap::iterator lit=lines.find(lineno);
if (lit != lines.end()) {
VlcSource::ColumnMap& cmap = lit->second;
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
VlcSourceCount& col = cit->second;
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
os<<(col.ok()?" ":"%")
<<std::setfill('0')<<std::setw(6)<<col.count()
<<"\t"<<line<<endl;
if (first) {
first = false;
// Multiple columns on same line; print line just once
<<"\t"<<line<<endl;
if (first) {
first = false;
// Multiple columns on same line; print line just once
string indent;
for (string::const_iterator pos=line.begin(); pos!=line.end() && isspace(*pos); ++pos) {
indent += *pos;
}
line = indent + "verilator_coverage: (next point on previous line)\n";
}
}
}
for (string::const_iterator pos=line.begin();
pos!=line.end() && isspace(*pos); ++pos) {
indent += *pos;
}
line = indent + "verilator_coverage: (next point on previous line)\n";
}
}
}
if (first) {
os<<"\t"<<line<<endl;
}
}
if (first) {
os<<"\t"<<line<<endl;
}
}
}
}
@@ -258,4 +259,3 @@ void VlcTop::annotate(const string& dirname) {
annotateCalcNeeded();
annotateOutputFiles(dirname);
}
+291 -291
View File
@@ -7,7 +7,7 @@ use Getopt::Long;
use IO::File;
use Pod::Usage;
use strict;
use vars qw ($Debug @Types %Classes %Children %ClassRefs %Stages);
use vars qw($Debug @Types %Classes %Children %ClassRefs %Stages);
#======================================================================
# main
@@ -17,8 +17,8 @@ my $opt_classes;
my $opt_report;
my @Opt_Cpt;
my @Opt_I;
Getopt::Long::config ("pass_through", "no_auto_abbrev");
if (! GetOptions (
Getopt::Long::config("pass_through", "no_auto_abbrev");
if (! GetOptions(
"help" => \&usage,
"debug" => sub { $Debug = 1; },
"classes!" => \$opt_classes,
@@ -51,17 +51,17 @@ foreach my $cpt (@Opt_Cpt) {
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit (1);
exit(1);
}
sub parameter {
my $param = shift;
if ($param =~ /^-+I(\S+)/) {
push @Opt_I, $1;
push @Opt_I, $1;
} elsif ($param =~ s/\.cpp$//) {
push @Opt_Cpt, $param;
push @Opt_Cpt, $param;
} else {
die "%Error: Unknown parameter: $param,";
die "%Error: Unknown parameter: $param,";
}
}
@@ -72,21 +72,21 @@ sub read_types {
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
while (defined (my $line = $fh->getline())) {
$line =~ s/\/\/.*$//;
next if $line =~ /^\s*$/;
if ($line =~ /^\s*(class|struct)\s*(\S+)/) {
my $class = $2;
my $inh = "";
$inh = $1 if ($line =~ /:\s*public\s+(\S+)/);
print "class $class : $inh\n" if $Debug;
$inh = "" if $class eq "AstNode";
if ($inh =~ /Ast/ || $class eq "AstNode") {
$class =~ s/^Ast//;
$inh =~ s/^Ast//;
$Classes{$class} = $inh;
$Children{$inh}{$class} = 1;
}
}
$line =~ s/\/\/.*$//;
next if $line =~ /^\s*$/;
if ($line =~ /^\s*(class|struct)\s*(\S+)/) {
my $class = $2;
my $inh = "";
$inh = $1 if ($line =~ /:\s*public\s+(\S+)/);
print "class $class : $inh\n" if $Debug;
$inh = "" if $class eq "AstNode";
if ($inh =~ /Ast/ || $class eq "AstNode") {
$class =~ s/^Ast//;
$inh =~ s/^Ast//;
$Classes{$class} = $inh;
$Children{$inh}{$class} = 1;
}
}
}
}
@@ -96,14 +96,14 @@ sub read_stages {
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
my $n = 0;
while (defined (my $line = $fh->getline())) {
$line =~ s/\/\/.*$//;
next if $line =~ /^\s*$/;
if ($line =~ /^\s*([A-Za-z0-9]+)::/) {
my $stage = $1.".cpp";
if (!defined ($Stages{$stage})) {
$Stages{$stage} = $n++;
}
}
$line =~ s/\/\/.*$//;
next if $line =~ /^\s*$/;
if ($line =~ /^\s*([A-Za-z0-9]+)::/) {
my $stage = $1.".cpp";
if (!defined ($Stages{$stage})) {
$Stages{$stage} = $n++;
}
}
}
}
@@ -111,17 +111,17 @@ sub read_refs {
my @filenames = @_;
foreach my $filename (@filenames) {
(my $basename = $filename) =~ s!.*/!!;
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
while (defined (my $line = $fh->getline())) {
$line =~ s/\/\/.*$//;
while ($line =~ /\bnew\s*(Ast[A-Za-z0-9_]+)/g) {
$ClassRefs{$1}{newed}{$basename} = 1;
}
while ($line =~ /\b(Ast[A-Za-z0-9_]+)/g) {
$ClassRefs{$1}{used}{$basename} = 1;
}
}
(my $basename = $filename) =~ s!.*/!!;
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
while (defined (my $line = $fh->getline())) {
$line =~ s/\/\/.*$//;
while ($line =~ /\bnew\s*(Ast[A-Za-z0-9_]+)/g) {
$ClassRefs{$1}{newed}{$basename} = 1;
}
while ($line =~ /\b(Ast[A-Za-z0-9_]+)/g) {
$ClassRefs{$1}{used}{$basename} = 1;
}
}
}
#use Data::Dumper;print Dumper(\%ClassRefs);
}
@@ -142,8 +142,8 @@ sub subclasses_of {
my @cllist;
for (my $subclass = $::Classes{$type}; $subclass; ) {
push @cllist, $subclass;
$subclass = $::Classes{$subclass};
push @cllist, $subclass;
$subclass = $::Classes{$subclass};
}
return (reverse @cllist);
@@ -156,10 +156,10 @@ sub children_of {
my @todo;
push @todo, $type;
while (my $subclass = shift @todo) {
foreach my $child (sort keys %{$::Children{$subclass}}) {
push @todo, $child;
push @cllist, $child;
}
foreach my $child (sort keys %{$::Children{$subclass}}) {
push @todo, $child;
push @cllist, $child;
}
}
return (@cllist);
@@ -173,39 +173,39 @@ sub write_report {
$fh->print("Processing stages (approximate, based on order in Verilator.cpp):\n");
foreach my $class (sort {$Stages{$a} <=> $Stages{$b}} keys %Stages) {
$fh->print("\t$class\n");
$fh->print("\t$class\n");
}
$fh->print("\nProcessing stages (approximate, based on order in Verilator.cpp):\n");
foreach my $type (sort (keys %Classes)) {
printf $fh " class %-20s\n", "Ast${type}";
$fh->print("\tparent:\t");
foreach my $subclass (subclasses_of($type)) {
next if $subclass eq 'Node';
printf $fh "Ast%-12s ",$subclass;
}
printf $fh "\n";
$fh->print("\tchilds:\t");
foreach my $subclass (children_of($type)) {
next if $subclass eq 'Node';
printf $fh "Ast%-12s ",$subclass;
}
printf $fh "\n";
if (my $refs = $ClassRefs{"Ast${type}"}) {
$fh->print("\tnewed:\t");
foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)}
keys %{$refs->{newed}}) {
$fh->print($stage." ");
}
$fh->print("\n");
$fh->print("\tused:\t");
foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)}
keys %{$refs->{used}}) {
$fh->print($stage." ");
}
$fh->print("\n");
}
$fh->print("\n");
printf $fh " class %-20s\n", "Ast${type}";
$fh->print("\tparent:\t");
foreach my $subclass (subclasses_of($type)) {
next if $subclass eq 'Node';
printf $fh "Ast%-12s ",$subclass;
}
printf $fh "\n";
$fh->print("\tchilds:\t");
foreach my $subclass (children_of($type)) {
next if $subclass eq 'Node';
printf $fh "Ast%-12s ",$subclass;
}
printf $fh "\n";
if (my $refs = $ClassRefs{"Ast${type}"}) {
$fh->print("\tnewed:\t");
foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)}
keys %{$refs->{newed}}) {
$fh->print($stage." ");
}
$fh->print("\n");
$fh->print("\tused:\t");
foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)}
keys %{$refs->{used}}) {
$fh->print($stage." ");
}
$fh->print("\n");
}
$fh->print("\n");
}
}
@@ -213,11 +213,11 @@ sub write_classes {
my $fh = open_file(@_);
printf $fh "class AstNode;\n";
foreach my $type (sort (keys %Classes)) {
printf $fh "class %-20s // ", "Ast${type};";
foreach my $subclass (subclasses_of($type)) {
printf $fh "Ast%-12s ",$subclass;
}
printf $fh "\n";
printf $fh "class %-20s // ", "Ast${type};";
foreach my $subclass (subclasses_of($type)) {
printf $fh "Ast%-12s ",$subclass;
}
printf $fh "\n";
}
$fh->close();
}
@@ -225,12 +225,12 @@ sub write_classes {
sub write_visitor {
my $fh = open_file(@_);
foreach my $type (sort (keys %Classes)) {
my $base = $Classes{$type};
if ($base) {
printf $fh " virtual void visit(Ast${type}* nodep) { visit((Ast${base}*)(nodep)); }\n";
} else {
printf $fh " virtual void visit(Ast${type}*) = 0;\n";
}
my $base = $Classes{$type};
if ($base) {
printf $fh " virtual void visit(Ast${type}* nodep) { visit((Ast${base}*)(nodep)); }\n";
} else {
printf $fh " virtual void visit(Ast${type}*) = 0;\n";
}
}
$fh->close();
}
@@ -262,11 +262,11 @@ sub write_impl {
print $fh "\n";
print $fh " // These for use by VN_IS macro only\n";
foreach my $type (sort (keys %Classes)) {
if (children_of($type)) {
if (children_of($type)) {
print $fh "inline bool AstNode::privateIs",$type,"(const AstNode* nodep) { return (bool)(dynamic_cast<const Ast",$type,"*>(nodep)); }\n";
} else {
} else {
print $fh "inline bool AstNode::privateIs",$type,"(const AstNode* nodep) { return nodep && nodep->type() == AstType::at",$type,"; }\n";
}
}
}
foreach my $type (sort (keys %Classes)) {
@@ -285,16 +285,16 @@ sub write_types {
printf $fh " enum en {\n";
# Add "at" prefix to avoid conflicting with FOPEN and other macros in include files
foreach my $type (sort (keys %Classes)) {
next if $type =~ /^Node/;
print $fh "\tat",$type,",\n";
next if $type =~ /^Node/;
print $fh "\tat",$type,",\n";
}
printf $fh "\t_ENUM_END\n";
printf $fh " };\n";
printf $fh " const char* ascii() const {\n";
printf $fh " const char* const names[] = {\n";
foreach my $type (sort (keys %Classes)) {
next if $type =~ /^Node/;
print $fh "\t\"", uc $type, "\",\n";
next if $type =~ /^Node/;
print $fh "\t\"", uc $type, "\",\n";
}
printf $fh "\t\"_ENUM_END\"\n";
printf $fh " };\n";
@@ -332,11 +332,11 @@ sub _output_line {
sub process {
my $self = {
in_filename => undef,
out_filename => undef,
out_lines => [],
out_linenum => 1,
@_,
in_filename => undef,
out_filename => undef,
out_lines => [],
out_linenum => 1,
@_,
};
bless $self, __PACKAGE__;
@@ -346,25 +346,25 @@ sub process {
# Read the file and parse into list of functions that generate output
my $fhi = IO::File->new($self->{in_filename}) or die "%Error: $! $self->{in_filename},";
while (defined(my $line = $fhi->getline)) {
if (!$didln) {
$self->print("#line $. \"$self->{in_filename}\"\n");
$didln = 1;
}
if ($line =~ /^\s+(TREE.*)$/) {
my $func = $1;
$self->{in_linenum} = $.;
$self->print("//$line");
$self->output_func(sub{my $self=shift; $self->_output_line(); });
$self->tree_line ($func);
$didln = 0;
}
elsif ($line !~ /^\s*\/[\/\*]\s*TREE/
&& $line =~ /\s+TREE/) {
$self->error("Unknown astgen line: $line");
}
else {
$self->print($line);
}
if (!$didln) {
$self->print("#line $. \"$self->{in_filename}\"\n");
$didln = 1;
}
if ($line =~ /^\s+(TREE.*)$/) {
my $func = $1;
$self->{in_linenum} = $.;
$self->print("//$line");
$self->output_func(sub{my $self=shift; $self->_output_line(); });
$self->tree_line($func);
$didln = 0;
}
elsif ($line !~ /^\s*\/[\/\*]\s*TREE/
&& $line =~ /\s+TREE/) {
$self->error("Unknown astgen line: $line");
}
else {
$self->print($line);
}
}
$fhi->close;
@@ -373,16 +373,16 @@ sub process {
my $fho = ::open_file($self->{out_filename});
my @togen = @{$self->{out_lines}};
foreach my $line (@togen) {
if (ref $line) {
$self->{out_lines} = [];
&$line($self);
} else {
$self->{out_lines} = [$line];
}
foreach my $out (@{$self->{out_lines}}) {
$self->{out_linenum}++ while ($out =~ /\n/smg);
print $fho $out;
}
if (ref $line) {
$self->{out_lines} = [];
&$line($self);
} else {
$self->{out_lines} = [$line];
}
foreach my $out (@{$self->{out_lines}}) {
$self->{out_linenum}++ while ($out =~ /\n/smg);
print $fho $out;
}
}
$fho->close;
}
@@ -396,64 +396,64 @@ sub tree_line {
# doflag "S" indicates an op specifying short-circuiting for a type.
if ($func =~ /TREEOP(1?)([VCS]?)\s*\(\s* \"([^\"]*)\" \s*,\s* \"([^\"]*)\" \s*\)/sx) {
my $order = $1; my $doflag = $2; my $from = $3; my $to = $4;
#$self->print("// $from $to\n");
if (!$self->{did_out_tree}) {
$self->{did_out_tree} = 1;
$self->output_func(sub{ my $self=shift;
$self->tree_match();
$self->tree_base();
});
}
$from =~ /Ast([a-zA-Z0-9]+)\s*\{(.*)\}\s*$/
or $self->error("Can't parse from function: $func");
my $type = $1;
my $subnodes = $2;
(::subclasses_of($type)) or $self->error("Unknown AstNode type: $type: in $func");
my $order = $1; my $doflag = $2; my $from = $3; my $to = $4;
#$self->print("// $from $to\n");
if (!$self->{did_out_tree}) {
$self->{did_out_tree} = 1;
$self->output_func(sub{ my $self=shift;
$self->tree_match();
$self->tree_base();
});
}
$from =~ /Ast([a-zA-Z0-9]+)\s*\{(.*)\}\s*$/
or $self->error("Can't parse from function: $func");
my $type = $1;
my $subnodes = $2;
(::subclasses_of($type)) or $self->error("Unknown AstNode type: $type: in $func");
my $mif;
if ($doflag eq '') { $mif = "m_doNConst"; }
elsif ($doflag eq 'V') { $mif = "m_doV"; }
elsif ($doflag eq 'C') { $mif = ""; }
elsif ($doflag eq 'S') { $mif = "m_doNConst"; } # Not just for m_doGenerate
else { die; }
$subnodes =~ s/,,/__ESCAPEDCOMMA__/g;
foreach my $subnode (split /\s*,\s*/, $subnodes) {
$subnode =~ s/__ESCAPEDCOMMA__/,/g;
next if $subnode =~ /^\$([a-z0-9]+)$/gi; # "$lhs" is just a comment that this op has a lhs
$mif .= " && " if $mif;
my $subnodeif = $subnode;
my $mif;
if ($doflag eq '') { $mif = "m_doNConst"; }
elsif ($doflag eq 'V') { $mif = "m_doV"; }
elsif ($doflag eq 'C') { $mif = ""; }
elsif ($doflag eq 'S') { $mif = "m_doNConst"; } # Not just for m_doGenerate
else { die; }
$subnodes =~ s/,,/__ESCAPEDCOMMA__/g;
foreach my $subnode (split /\s*,\s*/, $subnodes) {
$subnode =~ s/__ESCAPEDCOMMA__/,/g;
next if $subnode =~ /^\$([a-z0-9]+)$/gi; # "$lhs" is just a comment that this op has a lhs
$mif .= " && " if $mif;
my $subnodeif = $subnode;
$subnodeif =~ s/\$([a-zA-Z0-9]+)\.cast([A-Z][A-Za-z0-9]+)$/VN_IS(nodep->$1(),$2)/g;
$subnodeif =~ s/\$([a-zA-Z0-9]+)\.([a-zA-Z0-9]+)$/nodep->$1()->$2()/g;
$subnodeif = add_nodep($subnodeif);
$mif .= $subnodeif;
}
$subnodeif =~ s/\$([a-zA-Z0-9]+)\.([a-zA-Z0-9]+)$/nodep->$1()->$2()/g;
$subnodeif = add_nodep($subnodeif);
$mif .= $subnodeif;
}
my $exec_func = treeop_exec_func($self, $to);
my $exec_func = treeop_exec_func($self, $to);
while ($exec_func =~ s/([-()a-zA-Z0-9_>]+)->cast([A-Z][A-Za-z0-9]+)\(\)/VN_CAST($1,$2)/) {}
$self->{treeop}{$type} ||= [];
my $n = $#{$self->{treeop}{$type}} + 1;
my $typefunc = {
order => $order,
comment => $func,
match_func => "match_${type}_${n}",
match_if => $mif,
exec_func => $exec_func,
uinfo_level => ($to =~ /^!/ ? 0:7),
short_circuit => ($doflag eq 'S'),
};
$self->{treeop}{$type} ||= [];
my $n = $#{$self->{treeop}{$type}} + 1;
my $typefunc = {
order => $order,
comment => $func,
match_func => "match_${type}_${n}",
match_if => $mif,
exec_func => $exec_func,
uinfo_level => ($to =~ /^!/ ? 0:7),
short_circuit => ($doflag eq 'S'),
};
($typefunc->{uinfo} = $func) =~ s/[ \t\"\{\}]+/ /g;
push @{$self->{treeop}{$type}}, $typefunc;
($typefunc->{uinfo} = $func) =~ s/[ \t\"\{\}]+/ /g;
push @{$self->{treeop}{$type}}, $typefunc;
}
elsif ($func =~ /TREE_SKIP_VISIT\s*\(\s* \"([^\"]*)\" \s*\)/sx) {
my $type = $1;
$self->{tree_skip_visit}{$type} = 1;
$::Classes{$type} or $self->error("Unknown node type: $type");
my $type = $1;
$self->{tree_skip_visit}{$type} = 1;
$::Classes{$type} or $self->error("Unknown node type: $type");
}
else {
$self->error("Unknown astgen op: $func");
$self->error("Unknown astgen op: $func");
}
}
@@ -468,12 +468,12 @@ our $_Exec_Nsyms;
sub _exec_syms_recurse {
my $aref = shift;
foreach my $sym (@{$aref}) {
if (ref $sym) { _exec_syms_recurse($sym); }
elsif ($sym =~ /^\$.*/) {
if (!defined $_Exec_Syms{$sym}) {
$_Exec_Syms{$sym} = "arg".(++$_Exec_Nsyms)."p";
}
}
if (ref $sym) { _exec_syms_recurse($sym); }
elsif ($sym =~ /^\$.*/) {
if (!defined $_Exec_Syms{$sym}) {
$_Exec_Syms{$sym} = "arg".(++$_Exec_Nsyms)."p";
}
}
}
}
@@ -482,14 +482,14 @@ sub _exec_new_recurse {
my $out = "new ".$aref->[0]."(nodep->fileline()";
my $first = 1;
foreach my $sym (@{$aref}) {
if ($first) { $first=0; next; }
$out .= ", ";
if (ref $sym) { $out.=_exec_new_recurse($sym); }
elsif ($sym =~ /^\$.*/) {
$out .= $_Exec_Syms{$sym};
} else {
$out .= $sym;
}
if ($first) { $first=0; next; }
$out .= ", ";
if (ref $sym) { $out.=_exec_new_recurse($sym); }
elsif ($sym =~ /^\$.*/) {
$out .= $_Exec_Syms{$sym};
} else {
$out .= $sym;
}
}
return $out.")";
}
@@ -500,142 +500,142 @@ sub treeop_exec_func {
my $out = "";
$func =~ s/^!//;
if ($func =~ /^\s*[a-zA-Z0-9]+\s*\(/) { # Function call
(my $outl = $func) =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g;
$out .= $outl.";";
(my $outl = $func) =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g;
$out .= $outl.";";
}
elsif ($func =~ /^\s*Ast([a-zA-Z0-9]+) \s*\{\s* (.*) \s* \}$/x) {
my $nargs = 0;
my %argnums; # Number for each argument name
my $nargs = 0;
my %argnums; # Number for each argument name
my $aref = undef; # Recursive array with structure to form
my @astack;
my $forming = "";
my $argtext = $func . "\000"; # EOF character
#print "FF $func\n" if $Debug;
while ($argtext =~ s/^(.)//) {
my $tok = $1;
#print "TOK: $tok $forming\n" if $tok !~ /[a-zA-Z0-9]/;
my $aref = undef; # Recursive array with structure to form
my @astack;
my $forming = "";
my $argtext = $func . "\000"; # EOF character
#print "FF $func\n" if $Debug;
while ($argtext =~ s/^(.)//) {
my $tok = $1;
#print "TOK: $tok $forming\n" if $tok !~ /[a-zA-Z0-9]/;
if ($tok eq "\000") {
} elsif ($tok =~ /\s+/) {
} elsif ($tok eq "{") {
my $newref = [$forming];
push @{$aref}, $newref;
push @astack, $aref if $aref;
$aref = $newref;
$forming = "";
} elsif ($tok eq "}") {
push @{$aref}, $forming if $forming;
$aref = pop @astack;
$aref or $self->error("Too many } in execution function: $func\n");
$forming = "";
} elsif ($tok eq ",") {
push @{$aref}, $forming if $forming;
$forming = "";
} else {
$forming .= $tok;
}
}
($aref && ref $aref->[0] && !$aref->[1]) or $self->error("Badly formed execution function: $func\n");
$aref = $aref->[0];
#use Data::Dumper; print Dumper($aref),"\n";
if ($tok eq "\000") {
} elsif ($tok =~ /\s+/) {
} elsif ($tok eq "{") {
my $newref = [$forming];
push @{$aref}, $newref;
push @astack, $aref if $aref;
$aref = $newref;
$forming = "";
} elsif ($tok eq "}") {
push @{$aref}, $forming if $forming;
$aref = pop @astack;
$aref or $self->error("Too many } in execution function: $func\n");
$forming = "";
} elsif ($tok eq ",") {
push @{$aref}, $forming if $forming;
$forming = "";
} else {
$forming .= $tok;
}
}
($aref && ref $aref->[0] && !$aref->[1]) or $self->error("Badly formed execution function: $func\n");
$aref = $aref->[0];
#use Data::Dumper; print Dumper($aref),"\n";
# Assign numbers to each $ symbol
%_Exec_Syms = ();
$_Exec_Nsyms = 0;
_exec_syms_recurse($aref);
# Assign numbers to each $ symbol
%_Exec_Syms = ();
$_Exec_Nsyms = 0;
_exec_syms_recurse($aref);
foreach my $sym (sort {$_Exec_Syms{$a} cmp $_Exec_Syms{$b}} (keys %_Exec_Syms)) {
my $argnp = $_Exec_Syms{$sym};
my $arg = add_nodep($sym);
$out .= "AstNode* ${argnp} = ${arg}->unlinkFrBack();\n";
}
foreach my $sym (sort {$_Exec_Syms{$a} cmp $_Exec_Syms{$b}} (keys %_Exec_Syms)) {
my $argnp = $_Exec_Syms{$sym};
my $arg = add_nodep($sym);
$out .= "AstNode* ${argnp} = ${arg}->unlinkFrBack();\n";
}
$out .= "AstNode* newp = " . _exec_new_recurse($aref).";\n";
$out .= "nodep->replaceWith(newp);";
$out .= "nodep->deleteTree(); VL_DANGLING(nodep);";
#print "FF $out\n" if $Debug;
$out .= "AstNode* newp = " . _exec_new_recurse($aref).";\n";
$out .= "nodep->replaceWith(newp);";
$out .= "nodep->deleteTree(); VL_DANGLING(nodep);";
#print "FF $out\n" if $Debug;
} elsif ($func eq "NEVER") {
$out .= "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");";
$out .= "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");";
} elsif ($func eq "DONE") {
} else {
$self->error("Unknown execution function format: $func\n");
$self->error("Unknown execution function format: $func\n");
}
return $out;
}
sub tree_match {
my $self = shift;
$self->print (" // TREEOP functions, each return true if they matched & transformed\n");
$self->print(" // TREEOP functions, each return true if they matched & transformed\n");
#use Data::Dumper; print Dumper($self);
foreach my $base (sort (keys %{$self->{treeop}})) {
foreach my $typefunc (@{$self->{treeop}{$base}}) {
$self->print(" // Generated by astgen\n");
$self->print(" bool $typefunc->{match_func}(Ast${base}* nodep) {\n",
"\t// $typefunc->{comment}\n",);
$self->print( "\tif ($typefunc->{match_if}) {\n");
foreach my $typefunc (@{$self->{treeop}{$base}}) {
$self->print(" // Generated by astgen\n");
$self->print(" bool $typefunc->{match_func}(Ast${base}* nodep) {\n",
"\t// $typefunc->{comment}\n",);
$self->print( "\tif ($typefunc->{match_if}) {\n");
$self->print( "\t UINFO($typefunc->{uinfo_level},cvtToHex(nodep)"
."<<\" $typefunc->{uinfo}\\n\");\n");
$self->print( "\t $typefunc->{exec_func}\n");
$self->print( "\t return true;\n");
$self->print( "\t}\n");
$self->print( "\treturn false;\n");
$self->print(" }\n",);
}
$self->print( "\t $typefunc->{exec_func}\n");
$self->print( "\t return true;\n");
$self->print( "\t}\n");
$self->print( "\treturn false;\n");
$self->print(" }\n",);
}
}
}
sub tree_base {
my $self = shift;
$self->print (" // TREEOP visitors, call each base type's match\n");
$self->print (" // Bottom class up, as more simple transforms are generally better\n");
$self->print(" // TREEOP visitors, call each base type's match\n");
$self->print(" // Bottom class up, as more simple transforms are generally better\n");
foreach my $type (sort (keys %::Classes)) {
my $base = $::Classes{$type};
my @out_for_type_sc;
my @out_for_type;
foreach my $base (::subclasses_of($type), $type) {
foreach my $typefunc (@{$self->{treeop}{$base}}) {
my $base = $::Classes{$type};
my @out_for_type_sc;
my @out_for_type;
foreach my $base (::subclasses_of($type), $type) {
foreach my $typefunc (@{$self->{treeop}{$base}}) {
my @lines = (" if ($typefunc->{match_func}(nodep)) return;\n",);
if ($typefunc->{short_circuit}) { # short-circuit match fn
push @out_for_type_sc, @lines;
} else { # Standard match fn
if ($typefunc->{order}) {
unshift @out_for_type, @lines; # TREEOP1's go in front of others
} else {
push @out_for_type, @lines;
}
}
}
}
if ($typefunc->{short_circuit}) { # short-circuit match fn
push @out_for_type_sc, @lines;
} else { # Standard match fn
if ($typefunc->{order}) {
unshift @out_for_type, @lines; # TREEOP1's go in front of others
} else {
push @out_for_type, @lines;
}
}
}
}
# We need to deal with two cases. For short circuited functions we
# evaluate the LHS, then apply the short-circuit matches, then
# evaluate the RHS and possibly THS (ternary operators may
# short-circuit) and apply all the other matches.
# We need to deal with two cases. For short circuited functions we
# evaluate the LHS, then apply the short-circuit matches, then
# evaluate the RHS and possibly THS (ternary operators may
# short-circuit) and apply all the other matches.
# For types without short-circuits, we just use iterateChildren, which
# saves one comparison.
if ($out_for_type_sc[0]) { # Short-circuited types
$self->print(" // Generated by astgen with short-circuiting\n",
" virtual void visit(Ast${type}* nodep) {\n",
# For types without short-circuits, we just use iterateChildren, which
# saves one comparison.
if ($out_for_type_sc[0]) { # Short-circuited types
$self->print(" // Generated by astgen with short-circuiting\n",
" virtual void visit(Ast${type}* nodep) {\n",
" iterateAndNextNull(nodep->lhsp());\n",
@out_for_type_sc);
@out_for_type_sc);
$self->print(" iterateAndNextNull(nodep->rhsp());\n",
" AstNodeTriop *tnp = VN_CAST(nodep, NodeTriop);\n",
" if (tnp && tnp->thsp()) iterateAndNextNull(tnp->thsp());\n",
@out_for_type,
" }\n") if ($out_for_type[0]);
} elsif ($out_for_type[0]) { # Other types with something to print
my $skip = $self->{tree_skip_visit}{$type};
my $gen = $skip ? "Gen" : "";
$self->print(" // Generated by astgen\n",
" virtual void visit$gen(Ast${type}* nodep) {\n",
($skip?"":
@out_for_type,
" }\n") if ($out_for_type[0]);
} elsif ($out_for_type[0]) { # Other types with something to print
my $skip = $self->{tree_skip_visit}{$type};
my $gen = $skip ? "Gen" : "";
$self->print(" // Generated by astgen\n",
" virtual void visit$gen(Ast${type}* nodep) {\n",
($skip?"":
" iterateChildren(nodep);\n"),
@out_for_type,
" }\n");
}
@out_for_type,
" }\n");
}
}
}
+237 -237
View File
@@ -7,7 +7,7 @@ use Getopt::Long;
use IO::File;
use Pod::Usage;
use strict;
use vars qw ($Debug $VERSION);
use vars qw($Debug $VERSION);
$VERSION = '3.404';
@@ -28,21 +28,21 @@ our $Opt_Input;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config ("no_auto_abbrev");
if (! GetOptions (
# Local options
"help" => \&usage,
"version" => sub { print "Version $VERSION\n"; exit(0); },
"yacc=s" => \$Opt_Yacc,
# Passed to Bison
"t|debug" => sub { $Opt_Debug = 1; },
"b|file-prefix=s" => \$Opt_File_Prefix,
"d" => \$Opt_Definitions,
"k|token-table" => \$Opt_Token_Table,
"o=s" => \$Opt_Output,
"p|name-prefix=s" => \$Opt_Name_Prefix,
"v|verbose" => \$Opt_Verbose,
"<>" => \&parameter,
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions(
# Local options
"help" => \&usage,
"version" => sub { print "Version $VERSION\n"; exit(0); },
"yacc=s" => \$Opt_Yacc,
# Passed to Bison
"t|debug" => sub { $Opt_Debug = 1; },
"b|file-prefix=s" => \$Opt_File_Prefix,
"d" => \$Opt_Definitions,
"k|token-table" => \$Opt_Token_Table,
"o=s" => \$Opt_Output,
"p|name-prefix=s" => \$Opt_Name_Prefix,
"v|verbose" => \$Opt_Verbose,
"<>" => \&parameter,
)) {
die "%Error: Bad usage, try 'bisonpre --help'\n";
}
@@ -57,15 +57,15 @@ process();
sub usage {
print "Version $VERSION\n";
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT, -noperldoc=>1);
exit (1);
exit(1);
}
sub parameter {
my $param = shift;
if (!defined $Opt_Input) {
$Opt_Input = $param;
$Opt_Input = $param;
} else {
die "bisonpre: %Error: Unknown parameter: $param\n";
die "bisonpre: %Error: Unknown parameter: $param\n";
}
}
@@ -81,31 +81,31 @@ sub process {
# Run bison
my $command = ($Opt_Yacc
.($Opt_Debug?" -t":"")
.($Opt_Definitions?" -d":"")
.($Opt_Token_Table?" -k":"")
.($Opt_Verbose?" -v":"")
.(($Opt_Verbose && $supports_report)?" --report=itemset --report=lookahead":"")
# -p required for GLR parsers; they write to -p basename, not -o
.($Opt_Name_Prefix?" -p $Opt_Name_Prefix":"")
." -b ".tmp_prefix()
." -o ".tmp_prefix().".c"
." ".tmp_prefix().".y" );
.($Opt_Debug?" -t":"")
.($Opt_Definitions?" -d":"")
.($Opt_Token_Table?" -k":"")
.($Opt_Verbose?" -v":"")
.(($Opt_Verbose && $supports_report)?" --report=itemset --report=lookahead":"")
# -p required for GLR parsers; they write to -p basename, not -o
.($Opt_Name_Prefix?" -p $Opt_Name_Prefix":"")
." -b ".tmp_prefix()
." -o ".tmp_prefix().".c"
." ".tmp_prefix().".y" );
print " $command\n";
system $command;
my $status = $?;
if ($status != 0) {
remove_outputs();
my $v = bison_version_check();
die "bisonpre: %Error: $Opt_Yacc version $v run failed due to errors\n";
remove_outputs();
my $v = bison_version_check();
die "bisonpre: %Error: $Opt_Yacc version $v run failed due to errors\n";
}
clean_output(tmp_prefix().".output",output_prefix().".output", 1,0);
warning_check(output_prefix().".output");
clean_output(tmp_prefix().".c", output_prefix().".c", 0,1);
clean_output(tmp_prefix().".h", output_prefix().".h", 0,1);
clean_output(tmp_prefix().".c", output_prefix().".c", 0,1);
clean_output(tmp_prefix().".h", output_prefix().".h", 0,1);
remove_tmp();
}
@@ -116,10 +116,10 @@ sub tmp_prefix {
sub output_prefix {
my $o;
if ($Opt_Output) {
(my $o = $Opt_Output) =~ s!\.[^.]*$!!;
return $o;
(my $o = $Opt_Output) =~ s!\.[^.]*$!!;
return $o;
} else {
return $Opt_File_Prefix.".tab";
return $Opt_File_Prefix.".tab";
}
}
@@ -139,11 +139,11 @@ sub remove_outputs {
sub bison_version_check {
my $v = `$Opt_Yacc --version`;
if ($v && $v =~ /([0-9]+\.[0-9]+)/) {
my $v = $1;
($v >= 1.875) or die "bisonpre: %Error: '$Opt_Yacc' is version $v; version 1.875 or newer is required\n";
return $v;
my $v = $1;
($v >= 1.875) or die "bisonpre: %Error: '$Opt_Yacc' is version $v; version 1.875 or newer is required\n";
return $v;
} else {
die "bisonpre: %Error: '$Opt_Yacc' is not installed, or not working\n";
die "bisonpre: %Error: '$Opt_Yacc' is not installed, or not working\n";
}
}
@@ -164,55 +164,55 @@ sub clean_output {
$newbase =~ s/\.y/./;
if ($is_output) {
my %state_line; my $l=0;
foreach my $line (@lines) {
$l++;
# We add a colon so it's easy to search for the definition
$state_line{$1} = $l if $line =~ s/^state (\d+)\s*$/state $1:/;
}
my @out;
foreach my $line (@lines) {
if ($line =~ /^State (\d+) (conflicts)/) {
chomp $line;
$line .= " // line $state_line{$1}" if $state_line{$1};
$line .= "\n";
}
push @out, $line;
}
@lines = @out; @out = ();
my %state_line; my $l=0;
foreach my $line (@lines) {
$l++;
# We add a colon so it's easy to search for the definition
$state_line{$1} = $l if $line =~ s/^state (\d+)\s*$/state $1:/;
}
my @out;
foreach my $line (@lines) {
if ($line =~ /^State (\d+) (conflicts)/) {
chomp $line;
$line .= " // line $state_line{$1}" if $state_line{$1};
$line .= "\n";
}
push @out, $line;
}
@lines = @out; @out = ();
}
if ($is_c) {
my %token_values;
my $in_en=0;
foreach my $line (@lines) {
$in_en=1 if $line =~ /enum\s+yytokentype/;
$in_en=0 if $line =~ /;/;
$token_values{$2} = $1 if $in_en && $line =~ /\b(\S+) = (\d+)/;
}
my @out;
foreach my $line (@lines) {
if ($line =~ /BISONPRE_TOKEN_NAMES/) {
push @out, $line;
foreach my $tv (sort keys %token_values) {
push @out, sprintf("\tcase %d: return \"%s\";\n",
$tv, $token_values{$tv});
}
next;
}
push @out, $line;
}
@lines = @out; @out = ();
my %token_values;
my $in_en=0;
foreach my $line (@lines) {
$in_en=1 if $line =~ /enum\s+yytokentype/;
$in_en=0 if $line =~ /;/;
$token_values{$2} = $1 if $in_en && $line =~ /\b(\S+) = (\d+)/;
}
my @out;
foreach my $line (@lines) {
if ($line =~ /BISONPRE_TOKEN_NAMES/) {
push @out, $line;
foreach my $tv (sort keys %token_values) {
push @out, sprintf("\tcase %d: return \"%s\";\n",
$tv, $token_values{$tv});
}
next;
}
push @out, $line;
}
@lines = @out; @out = ();
}
$fh = IO::File->new(">$outname") or die "%Error: $! writing $outname\n";
foreach my $line (@lines) {
# Fix filename refs
$line =~ s!$basename!$newbase!g;
# Fix bison 2.3 and GCC 4.2.1
$line =~ s!\(YY_\("!(YY_((char*)"!g;
# Fix bison 2.3 glr-parser warning about yyerrorloc.YYTYPE::yydummy uninit
$line =~ s!(YYLTYPE yyerrloc;)!$1 yyerrloc.yydummy=0;/*bisonpre*/!g;
$fh->write($line);
# Fix filename refs
$line =~ s!$basename!$newbase!g;
# Fix bison 2.3 and GCC 4.2.1
$line =~ s!\(YY_\("!(YY_((char*)"!g;
# Fix bison 2.3 glr-parser warning about yyerrorloc.YYTYPE::yydummy uninit
$line =~ s!(YYLTYPE yyerrloc;)!$1 yyerrloc.yydummy=0;/*bisonpre*/!g;
$fh->write($line);
}
$fh->close;
}
@@ -222,9 +222,9 @@ sub warning_check {
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
while (defined(my $line = $fh->getline)) {
if ($line =~ /(conflicts|warning:|^useless)/i) {
die "%Error: $filename:$.: $line\n";
}
if ($line =~ /(conflicts|warning:|^useless)/i) {
die "%Error: $filename:$.: $line\n";
}
}
$fh->close;
}
@@ -249,160 +249,160 @@ sub clean_input {
my $last_rule;
my $section = 1;
{
my @linesin = @lines; @lines=(); my $l=0;
foreach my $line (@linesin) {
$l++;
# ^/ to prevent comments from matching
$line =~ m!^[a-zA-Z0-9_<>]+:[^/]*[a-zA-Z]! and die "%Error: $filename:$l: Move text on rule line to next line: $line\n";
if ($line =~ /^%%/) {
$section++;
if ($section==2) { $last_rule = undef; }
}
elsif ($line =~ s/^([a-zA-Z0-9_]+)<(\S*)>:/$1:/) {
!$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n";
$types{$2}{$1} = 1;
$rules{$1}{name} = $1;
$rules{$1}{type} = $2;
!$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n";
$last_rule = $1;
} elsif ($line =~ /^([a-zA-Z0-9_]+):/) {
!$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n";
$rules{$1}{name} = $1;
$rules{$1}{type} = "";
!$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n";
$last_rule = $1;
}
push @lines, $line;
# Now clean the line and extract some more info
(my $cline = $line) =~ s/\/\/.*$/\n/;
(my $rline = $line) =~ s/\/\/.*$/\n/;
if ($cline =~ /^\s*;/) {
$last_rule or die "%Error: $filename:$l: Stray semicolon\n";
$last_rule = undef;
} elsif ($last_rule) {
$rules{$last_rule}{rules_and_productions} .= $cline;
}
if ($cline =~ /^%token\s*<(\S+)>\s*(\S+)/) {
!$tokens{$2} or die "%Error: $filename:$l: Redeclaring '$2': $line\n";
$tokens{$2} = $1;
}
foreach my $tok (split /[^a-zA-Z0-9_]+/, $cline) {
if ($last_rule && $tok=~/^[a-zA-Z]/) {
#print "TT $last_rule $tok\n";
$rules{$last_rule}{subrules}{$tok} = 1;
$rules{$tok}{parentrules}{$last_rule} = 1;
}
}
}
my @linesin = @lines; @lines=(); my $l=0;
foreach my $line (@linesin) {
$l++;
# ^/ to prevent comments from matching
$line =~ m!^[a-zA-Z0-9_<>]+:[^/]*[a-zA-Z]! and die "%Error: $filename:$l: Move text on rule line to next line: $line\n";
if ($line =~ /^%%/) {
$section++;
if ($section==2) { $last_rule = undef; }
}
elsif ($line =~ s/^([a-zA-Z0-9_]+)<(\S*)>:/$1:/) {
!$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n";
$types{$2}{$1} = 1;
$rules{$1}{name} = $1;
$rules{$1}{type} = $2;
!$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n";
$last_rule = $1;
} elsif ($line =~ /^([a-zA-Z0-9_]+):/) {
!$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n";
$rules{$1}{name} = $1;
$rules{$1}{type} = "";
!$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n";
$last_rule = $1;
}
push @lines, $line;
# Now clean the line and extract some more info
(my $cline = $line) =~ s/\/\/.*$/\n/;
(my $rline = $line) =~ s/\/\/.*$/\n/;
if ($cline =~ /^\s*;/) {
$last_rule or die "%Error: $filename:$l: Stray semicolon\n";
$last_rule = undef;
} elsif ($last_rule) {
$rules{$last_rule}{rules_and_productions} .= $cline;
}
if ($cline =~ /^%token\s*<(\S+)>\s*(\S+)/) {
!$tokens{$2} or die "%Error: $filename:$l: Redeclaring '$2': $line\n";
$tokens{$2} = $1;
}
foreach my $tok (split /[^a-zA-Z0-9_]+/, $cline) {
if ($last_rule && $tok=~/^[a-zA-Z]/) {
#print "TT $last_rule $tok\n";
$rules{$last_rule}{subrules}{$tok} = 1;
$rules{$tok}{parentrules}{$last_rule} = 1;
}
}
}
}
#use Data::Dumper; print Dumper(\%rules);
# Replace BISONPRE_VERSION(ver,,...) with expanded list
{
my @linesin = @lines; @lines=(); my $l=0;
foreach my $line (@linesin) {
$l++;
if ($line =~ /BISONPRE_VERSION/) {
# 1 3 4
($line =~ /BISONPRE_VERSION\((\S+)\s*,\s*((\S+)\s*,)?\s*([^\),]+)\)\s*$/)
or die "%Error: $filename:$l: Bad form of BISONPRE_VERSION: $line\n";
my $ver=$1; my $ver_max=$3; my $cmd=$4;
if ($Self->{bison_version} >= $1
&& (!$ver_max || $Self->{bison_version} <= $ver_max)) {
$line = $cmd."\n";
} else {
$line = "//NOP: $line";
}
}
push @lines, $line;
}
my @linesin = @lines; @lines=(); my $l=0;
foreach my $line (@linesin) {
$l++;
if ($line =~ /BISONPRE_VERSION/) {
# 1 3 4
($line =~ /BISONPRE_VERSION\((\S+)\s*,\s*((\S+)\s*,)?\s*([^\),]+)\)\s*$/)
or die "%Error: $filename:$l: Bad form of BISONPRE_VERSION: $line\n";
my $ver=$1; my $ver_max=$3; my $cmd=$4;
if ($Self->{bison_version} >= $1
&& (!$ver_max || $Self->{bison_version} <= $ver_max)) {
$line = $cmd."\n";
} else {
$line = "//NOP: $line";
}
}
push @lines, $line;
}
}
# Replace BISONPRE_NOT(type,...) with expanded list
{
my @linesin = @lines; @lines=(); my $l=0;
foreach my $line (@linesin) {
$l++;
if ($line =~ /BISONPRE_NOT/) {
($line =~ s/BISONPRE_NOT\((\S+)\)\s*(\{[^}]+})\s*$//)
or die "%Error: $filename:$l: Bad form of BISONPRE_NOT: $line\n";
my $endtok = $1; my $action = $2;
my @endtoks = split (/,/, $endtok);
map { $tokens{$_} or die "%Error: $filename:$l: Can't find definition for token: $_\n"
} @endtoks;
# Push it all onto one line to avoid error messages changing
my $bar = "";
tok:
foreach my $tok (sort keys %tokens) {
foreach (@endtoks) {
next tok if $tok eq $_;
}
if ($endtok ne $tok) {
$line .= "\t$bar $tok $action";
$bar = "|";
}
}
$line .= "\n";
}
push @lines, $line;
}
my @linesin = @lines; @lines=(); my $l=0;
foreach my $line (@linesin) {
$l++;
if ($line =~ /BISONPRE_NOT/) {
($line =~ s/BISONPRE_NOT\((\S+)\)\s*(\{[^}]+})\s*$//)
or die "%Error: $filename:$l: Bad form of BISONPRE_NOT: $line\n";
my $endtok = $1; my $action = $2;
my @endtoks = split(/,/, $endtok);
map { $tokens{$_} or die "%Error: $filename:$l: Can't find definition for token: $_\n"
} @endtoks;
# Push it all onto one line to avoid error messages changing
my $bar = "";
tok:
foreach my $tok (sort keys %tokens) {
foreach (@endtoks) {
next tok if $tok eq $_;
}
if ($endtok ne $tok) {
$line .= "\t$bar $tok $action";
$bar = "|";
}
}
$line .= "\n";
}
push @lines, $line;
}
}
# Replace BISONPRE_COPY(type,{code})
{
my @linesin = @lines; @lines=(); my $l=0;
foreach my $line (@linesin) {
$l++;
if ($line =~ /BISONPRE_COPY/) {
$line = _bisonpre_copy($line,$l,0);
}
push @lines, $line;
}
my @linesin = @lines; @lines=(); my $l=0;
foreach my $line (@linesin) {
$l++;
if ($line =~ /BISONPRE_COPY/) {
$line = _bisonpre_copy($line,$l,0);
}
push @lines, $line;
}
}
# Replace ~[x]~ - must be after BISONPRE_COPY expansion
{
my @linesin = @lines; @lines=(); my $l=0;
foreach my $line (@linesin) {
$l++;
$line =~ s/~[a-zA-Z0-9_]+~//g;
push @lines, $line;
}
my @linesin = @lines; @lines=(); my $l=0;
foreach my $line (@linesin) {
$l++;
$line =~ s/~[a-zA-Z0-9_]+~//g;
push @lines, $line;
}
}
# Find "BISONPRE_TYPES"
{
my @linesin = @lines; @lines=(); my $l=0;
my $needmore = 0;
foreach my $line (@linesin) {
$l++;
if ($line =~ m!//BISONPRE_TYPES!) {
push @lines, $line;
foreach my $type (sort keys %types) {
next if !$type;
my $line = "%type<$type>\t";
foreach my $rule (sort keys %{$types{$type}}) {
$line.=" ".$rule;
}
$line .= "\n";
push @lines, $line;
$needmore++
}
} elsif ($needmore) {
# Bison doesn't have a #line directive, so we need somewhere to insert into
$line =~ s!^\s*//.*$!!;
($line =~ m/^\s*$/) or die "%Error: $filename:$l: Need $needmore more blank lines to insure line numbers are constant\n";
$needmore--;
} else {
push @lines, $line;
}
}
my @linesin = @lines; @lines=(); my $l=0;
my $needmore = 0;
foreach my $line (@linesin) {
$l++;
if ($line =~ m!//BISONPRE_TYPES!) {
push @lines, $line;
foreach my $type (sort keys %types) {
next if !$type;
my $line = "%type<$type>\t";
foreach my $rule (sort keys %{$types{$type}}) {
$line.=" ".$rule;
}
$line .= "\n";
push @lines, $line;
$needmore++
}
} elsif ($needmore) {
# Bison doesn't have a #line directive, so we need somewhere to insert into
$line =~ s!^\s*//.*$!!;
($line =~ m/^\s*$/) or die "%Error: $filename:$l: Need $needmore more blank lines to insure line numbers are constant\n";
$needmore--;
} else {
push @lines, $line;
}
}
}
$fh = IO::File->new(">$outname") or die "%Error: $! writing $outname\n";
foreach my $line (@lines) {
$fh->write($line);
$fh->write($line);
}
$fh->close;
}
@@ -412,28 +412,28 @@ sub _bisonpre_copy {
my $l = shift;
my $depth = shift;
while ($text =~ /BISONPRE_COPY/) {
($text =~ s/BISONPRE_COPY(_ONCE)?\((\S+)\s*,\s*\{([^}]*)}\s*\)/{HERE}/)
or die "%Error: $Self->{filename}:$l: Bad form of BISONPRE_NOT: $text\n";
my $once = $1; my $rule = $2; my $code = $3;
$Self->{rules}{$rule} or die "%Error: $Self->{filename}:$l: Can't find definition for rule: $rule\n";
if ($depth > 0 && $once) {
# _ONCE means don't inherit
$text =~ s/\|[ \t]+{HERE}//; # Don't OR in nothing
$text =~ s/{HERE}//;
} else {
# Push it all onto one line to avoid error messages changing
my $insert = $Self->{rules}{$rule}{rules_and_productions};
$insert =~ s/^\S+://g; # Strip rule name
# Recurse so BISONPRE under B
#print "COPY $l code $code\n";
#print "COPY $l in $insert\n";
$_=$insert; eval("$code; \$_;"); $insert = $_;
#print "COPY $l out $insert\n";
while ($insert =~ s/[ \t\n]+\n/\n/go) {}
while ($insert =~ s/\n/ /go) {} # Optional - preserve line numbering
$text =~ s/{HERE}/$insert/;
}
$depth++;
($text =~ s/BISONPRE_COPY(_ONCE)?\((\S+)\s*,\s*\{([^}]*)}\s*\)/{HERE}/)
or die "%Error: $Self->{filename}:$l: Bad form of BISONPRE_NOT: $text\n";
my $once = $1; my $rule = $2; my $code = $3;
$Self->{rules}{$rule} or die "%Error: $Self->{filename}:$l: Can't find definition for rule: $rule\n";
if ($depth > 0 && $once) {
# _ONCE means don't inherit
$text =~ s/\|[ \t]+{HERE}//; # Don't OR in nothing
$text =~ s/{HERE}//;
} else {
# Push it all onto one line to avoid error messages changing
my $insert = $Self->{rules}{$rule}{rules_and_productions};
$insert =~ s/^\S+://g; # Strip rule name
# Recurse so BISONPRE under B
#print "COPY $l code $code\n";
#print "COPY $l in $insert\n";
$_=$insert; eval("$code; \$_;"); $insert = $_;
#print "COPY $l out $insert\n";
while ($insert =~ s/[ \t\n]+\n/\n/go) {}
while ($insert =~ s/\n/ /go) {} # Optional - preserve line numbering
$text =~ s/{HERE}/$insert/;
}
$depth++;
}
return $text;
}
+90 -90
View File
@@ -7,7 +7,7 @@ use Getopt::Long;
use IO::File;
use Pod::Usage;
use strict;
use vars qw ($Debug $VERSION);
use vars qw($Debug $VERSION);
$VERSION = '3.881';
@@ -23,12 +23,12 @@ our $Opt_Debug;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config ("no_auto_abbrev","pass_through");
Getopt::Long::config("no_auto_abbrev","pass_through");
our @Opt_Args = ("cppcheck", @ARGV);
if (! GetOptions (
# Local options
"help" => \&usage,
"version" => sub { print "Version $VERSION\n"; system("cppcheck","--version"); exit(0); },
if (! GetOptions(
# Local options
"help" => \&usage,
"version" => sub { print "Version $VERSION\n"; system("cppcheck","--version"); exit(0); },
)) {
die "%Error: Bad usage, try 'cppcheck_filtered --help'\n";
}
@@ -40,7 +40,7 @@ process();
sub usage {
print "Version $VERSION\n";
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT, -noperldoc=>1);
exit (1);
exit(1);
}
#######################################################################
@@ -54,72 +54,72 @@ sub process {
my %errs;
my $last_error = "";
while (defined(my $line = $fh->getline())) {
$line =~ s/^\s+//;
$line =~ s/Checking usage of global functions\.+//; # Sometimes tacked at end-of-line
# General gunk
next if $uniq{$line}++;
next if $line =~ m!^<\?xml version!;
next if $line =~ m!^<cppcheck!;
next if $line =~ m!^<results!;
next if $line =~ m!^</results>!;
next if $line =~ m!^<errors!;
next if $line =~ m!^</error>!;
next if $line =~ m!^</errors>!;
next if $line =~ m!^<error.*id="unmatchedSuppression"!; # --suppress=unmatchedSuppression doesn't work
next if $line =~ m!Cppcheck cannot find all the include files!; # An earlier id line is more specific
next if $line =~ m!^Checking !;
next if $line =~ m!^make.*Entering directory !;
next if $line =~ m!^make.*Leaving directory !;
next if $line =~ m!^\s+$!g;
$line =~ s/^\s+//;
$line =~ s/Checking usage of global functions\.+//; # Sometimes tacked at end-of-line
# General gunk
next if $uniq{$line}++;
next if $line =~ m!^<\?xml version!;
next if $line =~ m!^<cppcheck!;
next if $line =~ m!^<results!;
next if $line =~ m!^</results>!;
next if $line =~ m!^<errors!;
next if $line =~ m!^</error>!;
next if $line =~ m!^</errors>!;
next if $line =~ m!^<error.*id="unmatchedSuppression"!; # --suppress=unmatchedSuppression doesn't work
next if $line =~ m!Cppcheck cannot find all the include files!; # An earlier id line is more specific
next if $line =~ m!^Checking !;
next if $line =~ m!^make.*Entering directory !;
next if $line =~ m!^make.*Leaving directory !;
next if $line =~ m!^\s+$!g;
# Specific suppressions (see _suppress also)
next if $line =~ m!id="unusedPrivateFunction" .*::debug!; # Doesn't know UINFO will use it
# Output
if ($line =~ /^cppcheck --/) {
print $line if $Debug;
} elsif ($line =~ m!^\d+/\d+ files checked!) {
print $line;
} else {
my $suppress;
# --xml-format=1
if ($line =~ /file="([^"]+)"\s+line="(\d+)"\s+id="([^"]+)"/) {
my $file = $1; my $linenum = $2; my $id = $3;
$suppress = 1 if _suppress($file,$linenum,$id);
}
# --xml-format=2
if ($line =~ /<error id.*/) {
$last_error = $line;
chomp $last_error;
$suppress = 1;
}
elsif ($line =~ /<location.* file="([^"]+)"\s+line="(\d+)"/) {
my $file = $1; my $linenum = $2; my $id;
if ($last_error =~ / id="([^"]+)"/) {
$id = $1;
} else {
$id = "?";
}
$suppress = 1 if _suppress($file,$linenum,$id);
$suppress = 1 if $file eq "*";
if (!$suppress) {
chomp $line;
print "$file:$linenum: ".$last_error."\n";
$suppress = 1;
}
}
if (!$suppress) {
my $eline = "%Error: cppcheck: $line";
print $eline;
$errs{$eline}++;
}
}
# Output
if ($line =~ /^cppcheck --/) {
print $line if $Debug;
} elsif ($line =~ m!^\d+/\d+ files checked!) {
print $line;
} else {
my $suppress;
# --xml-format=1
if ($line =~ /file="([^"]+)"\s+line="(\d+)"\s+id="([^"]+)"/) {
my $file = $1; my $linenum = $2; my $id = $3;
$suppress = 1 if _suppress($file,$linenum,$id);
}
# --xml-format=2
if ($line =~ /<error id.*/) {
$last_error = $line;
chomp $last_error;
$suppress = 1;
}
elsif ($line =~ /<location.* file="([^"]+)"\s+line="(\d+)"/) {
my $file = $1; my $linenum = $2; my $id;
if ($last_error =~ / id="([^"]+)"/) {
$id = $1;
} else {
$id = "?";
}
$suppress = 1 if _suppress($file,$linenum,$id);
$suppress = 1 if $file eq "*";
if (!$suppress) {
chomp $line;
print "$file:$linenum: ".$last_error."\n";
$suppress = 1;
}
}
if (!$suppress) {
my $eline = "%Error: cppcheck: $line";
print $eline;
$errs{$eline}++;
}
}
}
if (scalar(keys %errs)) {
#my $all = join('',sort(keys %errs));
#$Self->error("Cppcheck errors:\n$all");
#die "%Error: cppcheck_filtered found errors\n";
exit(1);
#my $all = join('',sort(keys %errs));
#$Self->error("Cppcheck errors:\n$all");
#die "%Error: cppcheck_filtered found errors\n";
exit(1);
}
}
@@ -143,32 +143,32 @@ sub _suppress {
my $fh = IO::File->new("<$filename");
if (!$fh) {
warn "%Warning: $! $filename,";
return undef;
warn "%Warning: $! $filename,";
return undef;
}
my $l = 0;
while (defined(my $line = $fh->getline())) {
++$l;
if ($l+1 == $linenum) {
if ($line =~ /cppcheck-suppress((\s+\S+)+)/) {
my $supids = $1;
foreach my $supid (split /\s+/, $supids) {
if ($supid eq $id
|| $supid eq ($SuppressMap{$id}||'')) {
return 1;
}
}
warn "%Warning: $filename: $l: Found suppress for ids='$supids', not expected id='$id'\n";
}
}
if ($l == $linenum) {
if (0 && # We now use VL_DANGLING instead of this rule
$id eq "uselessAssignmentPtrArg"
&& $line =~ /(delete|Delete|Edit).*p *= *(NULL|nullptr);/) {
# delete(nodep); nodep=NULL; # This is ok, it's how we prevent later using nodep
return 1;
}
}
++$l;
if ($l+1 == $linenum) {
if ($line =~ /cppcheck-suppress((\s+\S+)+)/) {
my $supids = $1;
foreach my $supid (split /\s+/, $supids) {
if ($supid eq $id
|| $supid eq ($SuppressMap{$id}||'')) {
return 1;
}
}
warn "%Warning: $filename: $l: Found suppress for ids='$supids', not expected id='$id'\n";
}
}
if ($l == $linenum) {
if (0 && # We now use VL_DANGLING instead of this rule
$id eq "uselessAssignmentPtrArg"
&& $line =~ /(delete|Delete|Edit).*p *= *(NULL|nullptr);/) {
# delete(nodep); nodep=NULL; # This is ok, it's how we prevent later using nodep
return 1;
}
}
}
return undef;
}
+5 -9
View File
@@ -2085,7 +2085,9 @@ param_assignment<varp>: // ==IEEE: param_assignment
id/*new-parameter*/ variable_dimensionListE sigAttrListE '=' exprOrDataType
/**/ { $$ = VARDONEA($<fl>1,*$1, $2, $3); $$->valuep($5); }
| id/*new-parameter*/ variable_dimensionListE sigAttrListE
/**/ { $$ = VARDONEA($<fl>1,*$1, $2, $3); }
/**/ { $$ = VARDONEA($<fl>1,*$1, $2, $3);
if ($<fl>1->language() < V3LangCode::L1800_2009) {
$<fl>1->v3error("Parameter requires default value, or use IEEE 1800-2009 or later."); } }
;
list_of_param_assignments<varp>: // ==IEEE: list_of_param_assignments
@@ -3985,14 +3987,8 @@ void V3ParseGrammar::argWrapList(AstNodeFTaskRef* nodep) {
}
AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, string name, int value) {
FileLine* newfl = new FileLine(fileline);
newfl->warnOff(V3ErrorCode::WIDTH, true);
AstNode* nodep = new AstConst(newfl, V3Number(newfl));
// Adding a NOT is less work than figuring out how wide to make it
if (value) nodep = new AstNot(newfl, nodep);
nodep = new AstAssignW(newfl, new AstVarRef(fileline, name, true),
nodep);
return nodep;
return new AstAssignW(fileline, new AstVarRef(fileline, name, true),
new AstConst(fileline, V3Number(fileline, (value ? "'1" : "'0"))));
}
AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) {
+52 -52
View File
@@ -7,7 +7,7 @@ use Getopt::Long;
use IO::File;
use Pod::Usage;
use strict;
use vars qw ($Debug);
use vars qw($Debug);
our @Items;
@@ -16,12 +16,12 @@ our @Items;
$Debug = 0;
my $Opt_Srcdir = ".";
Getopt::Long::config ("pass_through", "no_auto_abbrev");
if (! GetOptions (
"help" => \&usage,
"debug" => sub { $Debug = 1; },
"srcdir=s" => \$Opt_Srcdir,
"<>" => sub { die "%Error: Unknown parameter: $_[0],"; },
Getopt::Long::config("pass_through", "no_auto_abbrev");
if (! GetOptions(
"help" => \&usage,
"debug" => sub { $Debug = 1; },
"srcdir=s" => \$Opt_Srcdir,
"<>" => sub { die "%Error: Unknown parameter: $_[0],"; },
)) {
usage();
}
@@ -34,7 +34,7 @@ write_keys("$Opt_Srcdir/../include/verilated_cov_key.h");
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit (1);
exit(1);
}
#######################################################################
@@ -44,17 +44,17 @@ sub read_keys {
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
while (defined (my $line = $fh->getline())) {
$line =~ s/\/\/.*$//;
next if $line =~ /^\s*$/;
if ($line =~ /^\s*VLCOVGEN_ITEM/) {
$line =~ /^\s*VLCOVGEN_ITEM *\( *"([^"]+)" *\)/
or die "%Error: $filename:$.: Misformed VLCOVGEN_ITEM line,";
my @data;
my $code = "\@data = ($1);";
eval $code;
die "%Error: $filename:$.: Parsing '$code': $@," if $@;
push @Items, {@data};
}
$line =~ s/\/\/.*$//;
next if $line =~ /^\s*$/;
if ($line =~ /^\s*VLCOVGEN_ITEM/) {
$line =~ /^\s*VLCOVGEN_ITEM *\( *"([^"]+)" *\)/
or die "%Error: $filename:$.: Misformed VLCOVGEN_ITEM line,";
my @data;
my $code = "\@data = ($1);";
eval $code;
die "%Error: $filename:$.: Parsing '$code': $@," if $@;
push @Items, {@data};
}
}
}
@@ -64,11 +64,11 @@ sub lint {
my %shorts;
my $ok = 1;
foreach my $itemref (@Items) {
if ($shorts{$itemref->{short}}) {
warn "%Error: Duplicate short code: $itemref->{short},";
$ok = 0;
}
$shorts{$itemref->{short}} = 1;
if ($shorts{$itemref->{short}}) {
warn "%Error: Duplicate short code: $itemref->{short},";
$ok = 0;
}
$shorts{$itemref->{short}} = 1;
}
return $ok;
}
@@ -82,40 +82,40 @@ sub write_keys {
my @out;
my $deleting;
while (defined(my $line = $fh->getline)) {
push @in, $line;
if ($line =~ /VLCOVGEN_CIK_AUTO_EDIT_BEGIN/) {
$deleting = 1;
push @out, $line;
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
push @out, sprintf("#define VL_CIK_%s \"%s\"\n",
uc $keyref->{name}, $keyref->{short});
}
}
elsif ($line =~ /VLCOVGEN_SHORT_AUTO_EDIT_BEGIN/) {
$deleting = 1;
push @out, $line;
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
push @in, $line;
if ($line =~ /VLCOVGEN_CIK_AUTO_EDIT_BEGIN/) {
$deleting = 1;
push @out, $line;
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
push @out, sprintf("#define VL_CIK_%s \"%s\"\n",
uc $keyref->{name}, $keyref->{short});
}
}
elsif ($line =~ /VLCOVGEN_SHORT_AUTO_EDIT_BEGIN/) {
$deleting = 1;
push @out, $line;
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
push @out, sprintf(" if (key == \"%s\") return VL_CIK_%s;\n",
$keyref->{name}, uc $keyref->{name});
}
}
elsif ($line =~ /VLCOVGEN_.*AUTO_EDIT_END/) {
$deleting = 0;
push @out, $line;
}
elsif ($deleting) {
}
else {
push @out, $line;
}
$keyref->{name}, uc $keyref->{name});
}
}
elsif ($line =~ /VLCOVGEN_.*AUTO_EDIT_END/) {
$deleting = 0;
push @out, $line;
}
elsif ($deleting) {
}
else {
push @out, $line;
}
}
$fh->close;
my $ok = join("", @out) eq join("", @in);
if (!$ok) {
my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename\n";
$fh->print(join "", @out);
$fh->close;
my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename\n";
$fh->print(join "", @out);
$fh->close;
}
}
+588 -584
View File
File diff suppressed because it is too large Load Diff
+31 -30
View File
@@ -19,34 +19,35 @@
class TestSimulator {
private:
struct SimTypes {
int verilator;
int icarus;
int mti;
int ncsim;
int vcs;
int verilator;
int icarus;
int mti;
int ncsim;
int vcs;
};
s_vpi_vlog_info m_info;
SimTypes m_simulators;
s_vpi_vlog_info m_info;
SimTypes m_simulators;
public:
TestSimulator() {
vpi_get_vlog_info(&m_info);
if (0 == strcmp(m_info.product, "Verilator")) {
m_simulators.verilator = true;
} else if (0 == strcmp(m_info.product, "Verilator")) {
m_simulators.icarus = true;
} else if (0 == strncmp(m_info.product, "Chronologic Simulation VCS", strlen("Chronologic Simulation VCS"))) {
m_simulators.vcs = true;
} else {
printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n",
__FILE__, __LINE__, m_info.product);
}
vpi_get_vlog_info(&m_info);
if (0 == strcmp(m_info.product, "Verilator")) {
m_simulators.verilator = true;
} else if (0 == strcmp(m_info.product, "Verilator")) {
m_simulators.icarus = true;
} else if (0 == strncmp(m_info.product, "Chronologic Simulation VCS",
strlen("Chronologic Simulation VCS"))) {
m_simulators.vcs = true;
} else {
printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n",
__FILE__, __LINE__, m_info.product);
}
}
~TestSimulator() { }
// METHORS
private:
static TestSimulator& singleton() {
static TestSimulator s_singleton;
return s_singleton;
static TestSimulator s_singleton;
return s_singleton;
}
static const SimTypes& simulators() { return singleton().m_simulators; }
public:
@@ -62,19 +63,19 @@ public:
static bool has_get_scalar() { return !simulators().icarus; }
// return test level scope
static const char* top() {
if (simulators().verilator) {
return "t";
} else {
return "top.t";
}
if (simulators().verilator) {
return "t";
} else {
return "top.t";
}
}
// return absolute scope of obj
static const char* rooted(const char *obj) {
static string buf;
ostringstream os;
os<<top()<<"."<<obj;
buf = os.str();
return buf.c_str();
static string buf;
ostringstream os;
os<<top()<<"."<<obj;
buf = os.str();
return buf.c_str();
}
};
+1 -1
View File
@@ -24,7 +24,7 @@ class TestVpiHandle {
public:
TestVpiHandle() : m_handle(NULL), m_free(true) { }
TestVpiHandle(vpiHandle h) : m_handle(h), m_free(true) { }
~TestVpiHandle() { if (m_handle && m_free) { vpi_free_object(m_handle); m_handle=NULL; } } // icarus has yet to catch up with 1800-2009
~TestVpiHandle() { if (m_handle && m_free) { vpi_free_object(m_handle); m_handle=NULL; } }
operator vpiHandle() const { return m_handle; }
inline TestVpiHandle& operator= (vpiHandle h) { m_handle = h; return *this; }
TestVpiHandle& nofree() {
+1 -1
View File
@@ -14,7 +14,7 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep ($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
}
execute(
+1 -1
View File
@@ -14,7 +14,7 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep ($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
}
execute(
+2
View File
@@ -0,0 +1,2 @@
%Error: t/t_array_pattern_bad.v:23: Assignment pattern key 'valids' not found as member
%Error: Exiting due to
+1 -3
View File
@@ -11,9 +11,7 @@ scenarios(simulator => 1);
compile(
fails => 1,
expect =>
q{%Error: t/t_array_pattern_bad.v:23: Assignment pattern key 'valids' not found as member
.*%Error: Exiting due to.*},
expect_filename => $Self->{golden_filename},
);
ok(1);
+1 -1
View File
@@ -23,7 +23,7 @@ execute(
fails => $Self->{vlt_all},
);
file_grep ("$Self->{obj_dir}/vlt_compile.log",
file_grep("$Self->{obj_dir}/vlt_compile.log",
qr/%Warning-USERFATAL: Parameter 5 is invalid...string and constant both work/);
ok(1);
+2 -2
View File
@@ -20,9 +20,9 @@ execute(
fails => 1
);
file_grep ($Self->{run_log_filename}, qr/'assert property' failed/);
file_grep($Self->{run_log_filename}, qr/'assert property' failed/);
# We expect to get a message when this assert fires:
file_grep ($Self->{run_log_filename}, qr/cyc != 3/);
file_grep($Self->{run_log_filename}, qr/cyc != 3/);
ok(1);
1;
+1 -1
View File
@@ -20,7 +20,7 @@ execute(
fails => 1
);
file_grep ($Self->{run_log_filename}, qr/'assert property' failed/);
file_grep($Self->{run_log_filename}, qr/'assert property' failed/);
ok(1);
1;
+2
View File
@@ -0,0 +1,2 @@
%Error: t/t_bitsel_const_bad.v:20: Illegal bit or array select; type does not have a bit range, or bad dimension: type is logic
%Error: Exiting due to
+1 -3
View File
@@ -12,9 +12,7 @@ scenarios(simulator => 1);
compile(
v_flags2 => ["--lint-only"],
fails => 1,
expect =>
'%Error: t/t_bitsel_const_bad.v:\d+: Illegal bit or array select; type does not have a bit range, or bad dimension: type is logic
.*%Error: Exiting due to.*',
expect_filename => $Self->{golden_filename},
);
ok(1);
+2
View File
@@ -0,0 +1,2 @@
%Error: t/t_case_genx_bad.v:13: Use of x/? constant in generate case statement, (no such thing as 'generate casez')
%Error: Exiting due to
+1 -3
View File
@@ -12,9 +12,7 @@ scenarios(simulator => 1);
compile(
v_flags2 => ["--lint-only"],
fails => 1,
expect =>
'%Error: t/t_case_genx_bad.v:\d+: Use of x/\? constant in generate case statement, \(no such thing as \'generate casez\'\)
%Error: Exiting due to.*',
expect_filename => $Self->{golden_filename},
);
ok(1);
+3 -3
View File
@@ -15,8 +15,8 @@ compile(
verilator_flags2 => ["--stats --prof-cfuncs -CFLAGS '-pg' -LDFLAGS '-pg'"],
);
file_grep ($Self->{stats}, qr/Optimizations, Tables created\s+(\d+)/i, 10);
file_grep ($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 10);
file_grep($Self->{stats}, qr/Optimizations, Tables created\s+(\d+)/i, 10);
file_grep($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 10);
unlink $_ foreach (glob "$Self->{obj_dir}/gmon.out.*");
$ENV{GMON_OUT_PREFIX} = "$Self->{obj_dir}/gmon.out";
@@ -36,7 +36,7 @@ run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{VM_PREFIX} $gmon_base > gprof.
run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc gprof.out > cfuncs.out"],
check_finished => 0);
file_grep ("$Self->{obj_dir}/cfuncs.out", qr/Overall summary by/);
file_grep("$Self->{obj_dir}/cfuncs.out", qr/Overall summary by/);
ok(1);
1;
+1 -1
View File
@@ -18,7 +18,7 @@ compile(
expect_filename => $Self->{golden_filename},
);
file_grep ("$Self->{obj_dir}/V$Self->{name}__cdc.txt", qr/CDC Report/);
file_grep("$Self->{obj_dir}/V$Self->{name}__cdc.txt", qr/CDC Report/);
ok(1);
1;
+1 -1
View File
@@ -18,7 +18,7 @@ execute(
);
if ($Self->{vlt_all}) {
file_grep ($Self->{stats}, qr/Optimizations, Gate assign merged\s+(\d+)/i, 28);
file_grep($Self->{stats}, qr/Optimizations, Gate assign merged\s+(\d+)/i, 28);
};
ok(1);
+10 -10
View File
@@ -38,16 +38,16 @@ int main(int argc, char *argv[]) {
Verilated::debug(0);
for (int i = 0; i < 2; i++) {
clockit(0, 0);
clockit(0, 1);
clockit(1, 1);
clockit(0, 0);
clockit(1, 1);
clockit(1, 0);
clockit(0, 0);
clockit(0, 1);
clockit(1, 0);
clockit(0, 0);
clockit(0, 0);
clockit(0, 1);
clockit(1, 1);
clockit(0, 0);
clockit(1, 1);
clockit(1, 0);
clockit(0, 0);
clockit(0, 1);
clockit(1, 0);
clockit(0, 0);
}
topp->check = 1;
clockit(0,0);
+1 -1
View File
@@ -17,7 +17,7 @@ execute(
check_finished => 1,
);
vcd_identical("$Self->{obj_dir}/simx.vcd", "t/$Self->{name}.out");
vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename});
ok(1);
1;
+3
View File
@@ -0,0 +1,3 @@
%Warning-WIDTHCONCAT: t/t_concat_large_bad.v:8: More than a 8k bit replication is probably wrong: 32768
%Warning-WIDTHCONCAT: Use "/* verilator lint_off WIDTHCONCAT */" and lint_on around source to disable this message.
%Error: Exiting due to
+1 -4
View File
@@ -12,10 +12,7 @@ scenarios(simulator => 1);
compile(
v_flags2 => ["--lint-only"],
fails => 1,
expect =>
'%Warning-WIDTHCONCAT: t/t_concat_large_bad.v:\d+: More than a 8k bit replication is probably wrong: 32768
%Warning-WIDTHCONCAT: Use .*
%Error: Exiting due to.*',
expect_filename => $Self->{golden_filename},
);
ok(1);
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2004 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.
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;
+21
View File
@@ -0,0 +1,21 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2019 by Wilson Snyder.
module t(/*AUTOARG*/);
initial begin
// verilator lint_off WIDTH
if (32'hxxxxxxxx !== 'hx) $stop;
if (32'hzzzzzzzz !== 'hz) $stop;
if (32'h???????? !== 'h?) $stop;
if (68'hx_xxxxxxxx_xxxxxxxx !== 'dX) $stop;
if (68'hz_zzzzzzzz_zzzzzzzz !== 'dZ) $stop;
if (68'h?_????????_???????? !== 'd?) $stop;
// verilator lint_on WIDTH
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+5
View File
@@ -0,0 +1,5 @@
%Warning-WIDTH: t/t_const_bad.v:12: Unsized constant being X/Z extended to 68 bits: ?32?bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
%Warning-WIDTH: Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message.
%Warning-WIDTH: t/t_const_bad.v:13: Unsized constant being X/Z extended to 68 bits: ?32?bzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
%Warning-WIDTH: t/t_const_bad.v:14: Unsized constant being X/Z extended to 68 bits: ?32?bzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
%Error: Exiting due to
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2004 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.
scenarios(vlt => 1);
compile(
v_flags2 => ["--lint-only"],
verilator_make_gcc => 0,
make_top_shell => 0,
make_main => 0,
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;
+19
View File
@@ -0,0 +1,19 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2019 by Wilson Snyder.
module t(/*AUTOARG*/);
initial begin
if (32'hxxxxxxxx !== 'hx) $stop;
if (32'hzzzzzzzz !== 'hz) $stop;
if (32'h???????? !== 'h?) $stop;
if (68'hx_xxxxxxxx_xxxxxxxx !== 'dX) $stop;
if (68'hz_zzzzzzzz_zzzzzzzz !== 'dZ) $stop;
if (68'h?_????????_???????? !== 'd?) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+1 -1
View File
@@ -20,7 +20,7 @@ execute(
# Read the input .v file and do any CHECK_COVER requests
inline_checks();
file_grep ($Self->{stats}, qr/Coverage, Toggle points joined\s+(\d+)/i, 25)
file_grep($Self->{stats}, qr/Coverage, Toggle points joined\s+(\d+)/i, 25)
if $Self->{vlt_all};
ok(1);
+1 -1
View File
@@ -14,7 +14,7 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep ($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 4);
file_grep($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 4);
}
ok(1);
+1 -1
View File
@@ -14,7 +14,7 @@ compile(
);
if ($Self->{vlt_all}) {
file_grep ($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 6);
file_grep($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 6);
}
ok(1);
+2 -2
View File
@@ -18,8 +18,8 @@ execute(
expect_filename => $Self->{golden_filename},
);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}__stats.txt",
qr/Node count, DISPLAY \s+ 32 \s+ 25 \s+ 25 \s+ 25/);
file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}__stats.txt",
qr/Node count, DISPLAY \s+ 32 \s+ 25 \s+ 25 \s+ 25/);
ok(1);
1;
+2 -1
View File
@@ -27,7 +27,8 @@ if (!-r "$root/.git") {
my $lineno = 0;
foreach my $line ((split /\n/, $diff), "+++ b/_the_end") {
if ($line =~ m!^\+\+\+ b/(.*)!) {
if ($file && !$atab && $btab) {
if ($file && !$atab && $btab
&& $file !~ /\.out$/) {
$summary = "File modifications adds new tabs (please untabify the patch):";
$warns{$file} = "File modification adds new tabs (please untabify the patch): $file";
}
File diff suppressed because it is too large Load Diff
+28 -28
View File
@@ -51,58 +51,58 @@ extern "C" {
int dpic_line() {
svScope scope = svGetScope();
if (!scope) {
printf("%%Warning: svGetScope failed\n");
return 0;
printf("%%Warning: svGetScope failed\n");
return 0;
}
#ifdef VERILATOR
static int didDump = 0;
if (didDump++ == 0) {
Verilated::scopesDump();
Verilated::scopesDump();
}
#endif
const char* scopenamep = svGetNameFromScope(scope);
if (!scopenamep) {
printf("%%Warning: svGetNameFromScope failed\n");
return 0;
printf("%%Warning: svGetNameFromScope failed\n");
return 0;
}
if (scope != svGetScopeFromName(scopenamep)) {
printf("%%Warning: svGetScopeFromName repeat failed\n");
return 0;
printf("%%Warning: svGetScopeFromName repeat failed\n");
return 0;
}
const char* filenamep = "";
int lineno = 0;
if (svGetCallerInfo(&filenamep, &lineno)) {
printf("Call from %s:%d:%s\n", filenamep, lineno, scopenamep);
printf("Call from %s:%d:%s\n", filenamep, lineno, scopenamep);
} else {
printf("%%Warning: svGetCallerInfo failed\n");
return 0;
printf("%%Warning: svGetCallerInfo failed\n");
return 0;
}
return lineno;
}
extern int Dpic_Unique;
int Dpic_Unique = 0; // Address used for uniqueness
int Dpic_Unique = 0; // Address used for uniqueness
int dpic_save(int value) {
svScope scope = svGetScope();
if (!scope) {
printf("%%Warning: svGetScope failed\n");
return 0;
printf("%%Warning: svGetScope failed\n");
return 0;
}
// Use union to avoid cast to different size pointer warnings
union valpack {
void* ptr;
int i;
void* ptr;
int i;
} vp;
vp.i = value;
if (svPutUserData(scope, &Dpic_Unique, vp.ptr)) {
printf("%%Warning: svPutUserData failed\n");
return 0;
printf("%%Warning: svPutUserData failed\n");
return 0;
}
return 1;
}
@@ -110,21 +110,21 @@ int dpic_save(int value) {
int dpic_restore() {
svScope scope = svGetScope();
if (!scope) {
printf("%%Warning: svGetScope failed\n");
return 0;
printf("%%Warning: svGetScope failed\n");
return 0;
}
if (void* userp = svGetUserData(scope, (void*)&Dpic_Unique)) {
// Use union to avoid cast to different size pointer warnings
union valpack {
void* ptr;
int i;
} vp;
vp.ptr = userp;
return vp.i;
// Use union to avoid cast to different size pointer warnings
union valpack {
void* ptr;
int i;
} vp;
vp.ptr = userp;
return vp.i;
} else {
printf("%%Warning: svGetUserData failed\n");
return 0;
printf("%%Warning: svGetUserData failed\n");
return 0;
}
}
+47 -47
View File
@@ -19,7 +19,7 @@
#ifdef _WIN32
# define T_PRI64 "I64"
#else // Linux or compliant Unix flavors
#else // Linux or compliant Unix flavors
# define T_PRI64 "ll"
#endif
@@ -71,20 +71,20 @@ extern "C" {
//======================================================================
#define CHECK_RESULT(type, got, exp) \
if ((got) != (exp)) { \
printf("%%Error: %s:%d:", __FILE__,__LINE__); \
union { type a; long long l; } u; \
u.l = 0; u.a = got; \
printf(" GOT = %" T_PRI64 "x", u.l); \
u.l = 0; u.a = exp; \
printf(" EXP = %" T_PRI64 "x\n", u.l); \
return __LINE__; \
#define CHECK_RESULT(type, got, exp) \
if ((got) != (exp)) { \
printf("%%Error: %s:%d:", __FILE__,__LINE__); \
union { type a; long long l; } u; \
u.l = 0; u.a = got; \
printf(" GOT = %" T_PRI64 "x", u.l); \
u.l = 0; u.a = exp; \
printf(" EXP = %" T_PRI64 "x\n", u.l); \
return __LINE__; \
}
#define CHECK_RESULT_NNULL(got) \
if (!(got)) { \
printf("%%Error: %s:%d: GOT = %p EXP = !NULL\n", __FILE__,__LINE__, (got)); \
return __LINE__; \
printf("%%Error: %s:%d: GOT = %p EXP = !NULL\n", __FILE__,__LINE__, (got)); \
return __LINE__; \
}
static int check_sub(const char* name, int i) {
@@ -112,69 +112,69 @@ int dpix_run_tests() {
static int didDump = 0;
if (didDump++ == 0) {
# ifdef TEST_VERBOSE
Verilated::internalsDump();
Verilated::internalsDump();
# endif
}
#endif
#ifndef CADENCE // Unimplemented; how hard is it?
#ifndef CADENCE // Unimplemented; how hard is it?
printf("svDpiVersion: %s\n",svDpiVersion());
CHECK_RESULT (bool,
strcmp(svDpiVersion(), "1800-2005")==0
|| strcmp(svDpiVersion(), "P1800-2005")==0
, 1);
CHECK_RESULT(bool,
strcmp(svDpiVersion(), "1800-2005")==0
|| strcmp(svDpiVersion(), "P1800-2005")==0
, 1);
#endif
CHECK_RESULT (int, dpix_int123(), 0x123 );
CHECK_RESULT(int, dpix_int123(), 0x123 );
#ifndef CADENCE // No export calls from an import
int o;
dpix_t_int(0x456, &o);
CHECK_RESULT (unsigned long, o, ~0x456UL);
CHECK_RESULT(unsigned long, o, ~0x456UL);
dpix_t_renamed(0x456, &o);
CHECK_RESULT (int, o, 0x458UL);
CHECK_RESULT(int, o, 0x458UL);
#endif
svBitVecVal vec10[1] = {0x10};
CHECK_RESULT (int, dpix_f_bit(1), 0x0);
CHECK_RESULT (int, dpix_f_bit(0), 0x1);
CHECK_RESULT (int, dpix_f_bit15(vec10) & 0x7fUL, 0x6f);
CHECK_RESULT(int, dpix_f_bit(1), 0x0);
CHECK_RESULT(int, dpix_f_bit(0), 0x1);
CHECK_RESULT(int, dpix_f_bit15(vec10) & 0x7fUL, 0x6f);
// Simulators disagree over the next three's sign extension unless we mask the upper bits
CHECK_RESULT (int, dpix_f_int(1) & 0xffffffffUL, 0xfffffffeUL);
CHECK_RESULT (int, dpix_f_byte(1) & 0xffUL, 0xfe);
CHECK_RESULT (int, dpix_f_shortint(1) & 0xffffUL, 0xfffeUL);
CHECK_RESULT(int, dpix_f_int(1) & 0xffffffffUL, 0xfffffffeUL);
CHECK_RESULT(int, dpix_f_byte(1) & 0xffUL, 0xfe);
CHECK_RESULT(int, dpix_f_shortint(1) & 0xffffUL, 0xfffeUL);
CHECK_RESULT (unsigned long long, dpix_f_longint(1), 0xfffffffffffffffeULL);
CHECK_RESULT (void*, dpix_f_chandle((void*)(12345)), (void*)(12345));
CHECK_RESULT(unsigned long long, dpix_f_longint(1), 0xfffffffffffffffeULL);
CHECK_RESULT(void*, dpix_f_chandle((void*)(12345)), (void*)(12345));
{
svBitVecVal i_vec48[2] = {0xab782a12,0x8a413bd9};
svBitVecVal o_vec48[2] = {0,0};
dpix_t_bit48(i_vec48, o_vec48);
CHECK_RESULT(int, o_vec48[0], ~i_vec48[0]);
svBitVecVal i_vec48[2] = {0xab782a12,0x8a413bd9};
svBitVecVal o_vec48[2] = {0,0};
dpix_t_bit48(i_vec48, o_vec48);
CHECK_RESULT(int, o_vec48[0], ~i_vec48[0]);
#ifdef VCS // VCS has bug where doesn't clean input
CHECK_RESULT(int, o_vec48[1], (~i_vec48[1]));
CHECK_RESULT(int, o_vec48[1], (~i_vec48[1]));
#else
CHECK_RESULT(int, o_vec48[1], (~i_vec48[1])&0x0000ffffUL);
CHECK_RESULT(int, o_vec48[1], (~i_vec48[1])&0x0000ffffUL);
#endif
}
{
svBitVecVal i_vec95[3] = {0x72912312,0xab782a12,0x8a413bd9};
svBitVecVal o_vec95[3] = {0,0,0};
dpix_t_bit95(i_vec95, o_vec95);
CHECK_RESULT(int, o_vec95[0], ~i_vec95[0]);
CHECK_RESULT(int, o_vec95[1], ~i_vec95[1]);
CHECK_RESULT(int, o_vec95[2], (~i_vec95[2])&0x7fffffffUL);
svBitVecVal i_vec95[3] = {0x72912312,0xab782a12,0x8a413bd9};
svBitVecVal o_vec95[3] = {0,0,0};
dpix_t_bit95(i_vec95, o_vec95);
CHECK_RESULT(int, o_vec95[0], ~i_vec95[0]);
CHECK_RESULT(int, o_vec95[1], ~i_vec95[1]);
CHECK_RESULT(int, o_vec95[2], (~i_vec95[2])&0x7fffffffUL);
}
{
svBitVecVal i_vec96[3] = {0xf2912312,0xab782a12,0x8a413bd9};
svBitVecVal o_vec96[3] = {0,0,0};
dpix_t_bit96(i_vec96, o_vec96);
CHECK_RESULT(int, o_vec96[0], ~i_vec96[0]);
CHECK_RESULT(int, o_vec96[1], ~i_vec96[1]);
CHECK_RESULT(int, o_vec96[2], ~i_vec96[2]);
svBitVecVal i_vec96[3] = {0xf2912312,0xab782a12,0x8a413bd9};
svBitVecVal o_vec96[3] = {0,0,0};
dpix_t_bit96(i_vec96, o_vec96);
CHECK_RESULT(int, o_vec96[0], ~i_vec96[0]);
CHECK_RESULT(int, o_vec96[1], ~i_vec96[1]);
CHECK_RESULT(int, o_vec96[2], ~i_vec96[2]);
}
extern void dpix_t_reg(svLogic i, svLogic* o);
+29 -29
View File
@@ -54,23 +54,23 @@ extern "C" {
extern double dpii_f_real (double i);
extern float dpii_f_shortreal(float i);
extern void dpii_v_bit (unsigned char i, unsigned char* o);
extern void dpii_v_int (int i, int *o);
extern void dpii_v_uint (unsigned int i, unsigned int *o);
extern void dpii_v_byte (char i, char *o);
extern void dpii_v_shortint (short int i, short int *o);
extern void dpii_v_ushort (unsigned short i, unsigned short *o);
extern void dpii_v_longint (long long i, long long *o);
extern void dpii_v_ulong (unsigned long long i, unsigned long long *o);
extern void dpii_v_struct (const svBitVecVal* i, svBitVecVal* o);
extern void dpii_v_substruct (const svBitVecVal* i, int* o);
extern void dpii_v_chandle (void* i, void* *o);
extern void dpii_v_bit (unsigned char i, unsigned char* o);
extern void dpii_v_int (int i, int *o);
extern void dpii_v_uint (unsigned int i, unsigned int *o);
extern void dpii_v_byte (char i, char *o);
extern void dpii_v_shortint (short int i, short int *o);
extern void dpii_v_ushort (unsigned short i, unsigned short *o);
extern void dpii_v_longint (long long i, long long *o);
extern void dpii_v_ulong (unsigned long long i, unsigned long long *o);
extern void dpii_v_struct (const svBitVecVal* i, svBitVecVal* o);
extern void dpii_v_substruct (const svBitVecVal* i, int* o);
extern void dpii_v_chandle (void* i, void* *o);
extern void dpii_v_string (const char* i, const char** o);
extern void dpii_v_real (double i, double* o);
extern void dpii_v_shortreal(float i, float* o);
extern void dpii_v_struct (const svBitVecVal* i, svBitVecVal* o);
extern void dpii_v_substruct (const svBitVecVal* i, int* o);
extern void dpii_v_struct (const svBitVecVal* i, svBitVecVal* o);
extern void dpii_v_substruct (const svBitVecVal* i, int* o);
extern void dpii_v_bit64(const svBitVecVal* i, svBitVecVal* o);
extern void dpii_v_bit95(const svBitVecVal* i, svBitVecVal* o);
extern void dpii_v_bit96(const svBitVecVal* i, svBitVecVal* o);
@@ -100,17 +100,17 @@ svBitVecVal dpii_f_bit9 (const svBitVecVal *i) { return 0x1ffUL & ~*i;
svBitVecVal dpii_f_bit16(const svBitVecVal *i) { return 0xffffUL & ~*i; }
svBitVecVal dpii_f_bit17(const svBitVecVal *i) { return 0x1ffffUL & ~*i; }
svBitVecVal dpii_f_bit32(const svBitVecVal *i) { return ~*i; }
long long dpii_f_bit33(const svBitVecVal *i) { return ((1ULL<<33)-1) & ~((long long)(i[1])<<32ULL | i[0]); }
long long dpii_f_bit64(const svBitVecVal *i) { return ~((long long)(i[1])<<32ULL | i[0]); }
long long dpii_f_bit33(const svBitVecVal *i) { return ((1ULL<<33)-1) & ~((long long)(i[1])<<32ULL | i[0]); }
long long dpii_f_bit64(const svBitVecVal *i) { return ~((long long)(i[1])<<32ULL | i[0]); }
int dpii_f_int (int i) { return ~i; }
char dpii_f_byte (char i) { return ~i; }
short int dpii_f_shortint(short int i) { return ~i; }
long long dpii_f_longint (long long i) { return ~i; }
void* dpii_f_chandle (void* i) { return i; }
const char* dpii_f_string (const char* i) { return i; }
double dpii_f_real (double i) { return i+1.5; }
float dpii_f_shortreal(float i) { return i+1.5f; }
int dpii_f_int (int i) { return ~i; }
char dpii_f_byte (char i) { return ~i; }
short int dpii_f_shortint(short int i) { return ~i; }
long long dpii_f_longint (long long i) { return ~i; }
void* dpii_f_chandle (void* i) { return i; }
const char* dpii_f_string (const char* i) { return i; }
double dpii_f_real (double i) { return i+1.5; }
float dpii_f_shortreal(float i) { return i+1.5f; }
void dpii_v_bit(unsigned char i, unsigned char *o) { *o = 1 & ~i; }
void dpii_v_int(int i, int *o) { *o = ~i; }
@@ -149,33 +149,33 @@ void dpii_v_time(const svLogicVecVal* i, svLogicVecVal* o) {
o[1].bval = 0;
}
void dpii_v_struct (const svBitVecVal* i, svBitVecVal* o) {
void dpii_v_struct(const svBitVecVal* i, svBitVecVal* o) {
o[0] = ~i[0];
o[1] = ~i[1];
o[2] = ~i[2];
}
void dpii_v_substruct (const svBitVecVal* i, int* o) {
void dpii_v_substruct(const svBitVecVal* i, int* o) {
// To be most like other tools, this should automagically take the substruct_t
// as an argument, and not require this cast...
substruct_t* issp = (substruct_t*) i;
o[0] = issp->b - issp->a;
}
void dpii_v_bit64(const svBitVecVal* i, svBitVecVal* o) {
void dpii_v_bit64(const svBitVecVal* i, svBitVecVal* o) {
o[0] = ~i[0];
o[1] = ~i[1];
}
void dpii_v_bit95(const svBitVecVal* i, svBitVecVal* o) {
void dpii_v_bit95(const svBitVecVal* i, svBitVecVal* o) {
o[0] = (~i[0]);
o[1] = (~i[1]);
o[2] = (~i[2]) & 0x7fffffffUL;
}
void dpii_v_bit96(const svBitVecVal* i, svBitVecVal* o) {
void dpii_v_bit96(const svBitVecVal* i, svBitVecVal* o) {
o[0] = ~i[0];
o[1] = ~i[1];
o[2] = ~i[2];
}
int dpii_f_strlen (const char* i) { return strlen(i); }
int dpii_f_strlen(const char* i) { return strlen(i); }
//======================================================================
+9 -9
View File
@@ -56,9 +56,9 @@ int dpii_failure() { return failure; }
void dpii_lib_bit_check() {
svBitVecVal bv [3];
bv[0] = 0xa3a2a1a0; // 31..0
bv[1] = 0xa7a6a5a4; // 63..32
bv[2] = 0xabaaa9a8; // 95..64
bv[0] = 0xa3a2a1a0; // 31..0
bv[1] = 0xa7a6a5a4; // 63..32
bv[2] = 0xabaaa9a8; // 95..64
CHECK_RESULT_HEX((int)svGetBitselBit(bv, 32), 0);
CHECK_RESULT_HEX((int)svGetBitselBit(bv, 33), 0);
CHECK_RESULT_HEX((int)svGetBitselBit(bv, 34), 1);
@@ -88,12 +88,12 @@ void dpii_lib_bit_check() {
void dpii_lib_logic_check() {
svLogicVecVal lv [3];
lv[0].aval = 0xb3b2b1b0; // 31..0
lv[1].aval = 0xb7b6b5b4; // 63..32
lv[2].aval = 0xbbbab9b8; // 95..64
lv[0].bval = 0xc3c2c1c0; // 31..0
lv[1].bval = 0xc7c6c5c4; // 63..32
lv[2].bval = 0xcbcac9c8; // 95..64
lv[0].aval = 0xb3b2b1b0; // 31..0
lv[1].aval = 0xb7b6b5b4; // 63..32
lv[2].aval = 0xbbbab9b8; // 95..64
lv[0].bval = 0xc3c2c1c0; // 31..0
lv[1].bval = 0xc7c6c5c4; // 63..32
lv[2].bval = 0xcbcac9c8; // 95..64
CHECK_RESULT_HEX((int)svGetBitselLogic(lv, 32), 0);
CHECK_RESULT_HEX((int)svGetBitselLogic(lv, 33), 0);
CHECK_RESULT_HEX((int)svGetBitselLogic(lv, 34), 3);
+1 -1
View File
@@ -85,7 +85,7 @@ int dpii_failure() { return failure; }
#ifdef _WIN32
# define T_PRI64 "I64"
#else // Linux or compliant Unix flavors
#else // Linux or compliant Unix flavors
# define T_PRI64 "ll"
#endif
+3
View File
@@ -0,0 +1,3 @@
%Error: t/t_dpi_openreg_bad.v:13: Unsized/open arrays ('[]') are only supported in DPI imports
%Error: t/t_dpi_openreg_bad.v:14: Unsized/open arrays ('[]') are only supported in DPI imports
%Error: Exiting due to
+1 -4
View File
@@ -12,10 +12,7 @@ scenarios(simulator => 1);
compile(
v_flags2 => ["--lint-only"],
fails => $Self->{vlt_all},
expect =>
'%Error: t/t_dpi_openreg_bad.v:\d+: Unsized/open arrays \(\'\[\]\'\) are only supported in DPI imports
%Error: t/t_dpi_openreg_bad.v:\d+: Unsized/open arrays \(\'\[\]\'\) are only supported in DPI imports
%Error: Exiting due to .*'
expect_filename => $Self->{golden_filename},
);
ok(1);
+3 -3
View File
@@ -47,10 +47,10 @@ int main(int argc, char *argv[]) {
topp->in = 1.1;
topp->eval();
if (topp->out != 1.2) {
VL_PRINTF("*-* All Finished *-*\n");
topp->final();
VL_PRINTF("*-* All Finished *-*\n");
topp->final();
} else {
vl_fatal(__FILE__,__LINE__,"top", "Unexpected results\n");
vl_fatal(__FILE__,__LINE__,"top", "Unexpected results\n");
}
return 0;
}
+15 -15
View File
@@ -42,7 +42,7 @@ void mon_do(MyMon* monp) {
#ifdef TEST_VERBOSE
VL_PRINTF("- mon_do(%08x(&%p) -> %08x(&%p));\n",
*(monp->sigsp[0]), monp->sigsp[0], *(monp->sigsp[1]), monp->sigsp[1]);
*(monp->sigsp[0]), monp->sigsp[0], *(monp->sigsp[1]), monp->sigsp[1]);
#endif
}
@@ -74,13 +74,13 @@ void mon_register_b(const char* namep, int isOut) {
const VerilatedScope* scopep = Verilated::dpiScope();
const VerilatedVar* varp = scopep->varFind(namep);
if (!varp) {
VL_PRINTF("%%Warning: mon_register_b signal not found: \"%s\"\n", namep);
VL_PRINTF("%%Warning: mon_register_b signal not found: \"%s\"\n", namep);
} else if (varp->vltype() != VLVT_UINT32) {
VL_PRINTF("%%Warning: wrong type for signal: \"%s\"\n", namep);
VL_PRINTF("%%Warning: wrong type for signal: \"%s\"\n", namep);
} else {
vluint32_t* datap = (vluint32_t*)(varp->datap());
VL_PRINTF("- mon_register_b('%s', \"%s\", %p, %d);\n", modp, namep, datap, isOut);
mons[1].sigsp[isOut] = (vluint32_t*)(varp->datap());
vluint32_t* datap = (vluint32_t*)(varp->datap());
VL_PRINTF("- mon_register_b('%s', \"%s\", %p, %d);\n", modp, namep, datap, isOut);
mons[1].sigsp[isOut] = (vluint32_t*)(varp->datap());
}
}
@@ -93,10 +93,10 @@ void mon_register_done() {
// Print list of all signals - if we didn't register2 anything we'd pick them off here
const VerilatedScope* scopep = Verilated::dpiScope();
if (VerilatedVarNameMap* varsp = scopep->varsp()) {
for (VerilatedVarNameMap::const_iterator it = varsp->begin();
it != varsp->end(); ++it) {
VL_PRINTF("- mon2: %s\n", it->first);
}
for (VerilatedVarNameMap::const_iterator it = varsp->begin();
it != varsp->end(); ++it) {
VL_PRINTF("- mon2: %s\n", it->first);
}
}
}
@@ -132,13 +132,13 @@ int main(int argc, char **argv, char **env) {
main_time += 10;
while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) {
main_time += 1;
topp->eval();
topp->clk = !topp->clk;
//mon_do();
main_time += 1;
topp->eval();
topp->clk = !topp->clk;
//mon_do();
}
if (!Verilated::gotFinish()) {
vl_fatal(__FILE__,__LINE__,"main", "%Error: Timeout; never got a $finish");
vl_fatal(__FILE__,__LINE__,"main", "%Error: Timeout; never got a $finish");
}
topp->final();
+14 -14
View File
@@ -45,24 +45,24 @@ extern "C" {
//======================================================================
extern int T_Embed_Child_Unique;
int T_Embed_Child_Unique = 0; // Address used for uniqueness
int T_Embed_Child_Unique = 0; // Address used for uniqueness
Vt_embed1_child* __get_modelp() {
svScope scope = svGetScope();
if (!scope) {
vl_fatal(__FILE__,__LINE__,__FILE__,"svGetScope failed");
return NULL;
vl_fatal(__FILE__,__LINE__,__FILE__,"svGetScope failed");
return NULL;
}
void* __modelp = svGetUserData(scope, &T_Embed_Child_Unique);
if (!__modelp) {
// Create the model
const char* scopenamep = svGetNameFromScope(scope);
if (!scopenamep) vl_fatal(__FILE__,__LINE__,__FILE__,"svGetNameFromScope failed");
__modelp = new Vt_embed1_child(scopenamep);
if (svPutUserData(scope, &T_Embed_Child_Unique, __modelp)) {
vl_fatal(__FILE__,__LINE__,__FILE__,"svPutUserData failed");
}
// Create the model
const char* scopenamep = svGetNameFromScope(scope);
if (!scopenamep) vl_fatal(__FILE__,__LINE__,__FILE__,"svGetNameFromScope failed");
__modelp = new Vt_embed1_child(scopenamep);
if (svPutUserData(scope, &T_Embed_Child_Unique, __modelp)) {
vl_fatal(__FILE__,__LINE__,__FILE__,"svPutUserData failed");
}
}
return (Vt_embed1_child*)(__modelp);
}
@@ -97,8 +97,8 @@ void t_embed_child_io_eval(unsigned char clk,
VL_DEBUG_IF(VL_PRINTF(" t_embed1_child_io_eval\n"); );
Vt_embed1_child* __modelp = __get_modelp();
VL_DEBUG_IF(VL_PRINTF("[%0ld] in clk=%x b=%x V=%x R=%x\n",
(long int) (VL_TIME_Q()), clk, bit_in, vec_in[0],
is_ref););
(long int) (VL_TIME_Q()), clk, bit_in, vec_in[0],
is_ref););
__modelp->clk = clk;
__modelp->bit_in = bit_in;
__modelp->vec_in = vec_in[0];
@@ -120,6 +120,6 @@ void t_embed_child_io_eval(unsigned char clk,
wide_out[3] = __modelp->wide_out[3];
*did_init_out = __modelp->did_init_out;
VL_DEBUG_IF(VL_PRINTF("[%0ld] out b=%x V=%x DI=%x\n",
(long int)(VL_TIME_Q()), *bit_out, *vec_out,
*did_init_out););
(long int)(VL_TIME_Q()), *bit_out, *vec_out,
*did_init_out););
}
+3
View File
@@ -0,0 +1,3 @@
%Error: t/t_enum_overlap_bad.v:11: Overlapping enumeration value: e1b
%Error: t/t_enum_overlap_bad.v:9: ... Location of original declaration
%Error: Exiting due to
+1 -4
View File
@@ -12,10 +12,7 @@ scenarios(vlt => 1);
compile(
v_flags2 => ["--lint-only"],
fails => 1,
expect =>
'%Error: t/t_enum_overlap_bad.v:\d+: Overlapping enumeration value: e1b
%Error: t/t_enum_overlap_bad.v:\d+: ... Location of original declaration
%Error: Exiting due to',
expect_filename => $Self->{golden_filename},
);
ok(1);
+1 -1
View File
@@ -17,7 +17,7 @@ scenarios(vlt => 1);
print "Old mtime=",$oldstats[9],"\n";
$oldstats[9] or error("No output file found: $outfile\n");
sleep (1); # Or else it might take < 1 second to compile and see no diff.
sleep(1); # Or else it might take < 1 second to compile and see no diff.
compile();
+3
View File
@@ -0,0 +1,3 @@
%Warning-WIDTH: t/t_flag_werror.v:9: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS's CONST '6'h2e' generates 6 bits.
%Warning-WIDTH: Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message.
%Error: Exiting due to
+1 -4
View File
@@ -14,10 +14,7 @@ top_filename("t/t_flag_werror.v");
compile(
v_flags2 => ["--lint-only"],
fails => $Self->{vlt_all},
expect =>
q{%Warning-WIDTH: t/t_flag_werror.v:\d+: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS.s CONST '6'h2e' generates 6 bits.
%Warning-WIDTH: Use .* and lint_on around source to disable this message.
%Error: Exiting due to},
expect_filename => $Self->{golden_filename},
);
ok(1);
+2
View File
@@ -0,0 +1,2 @@
%Error-WIDTH: t/t_flag_werror.v:9: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS's CONST '6'h2e' generates 6 bits.
%Error: Exiting due to

Some files were not shown because too many files have changed in this diff Show More