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