mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc1d380864 | ||
|
|
f96942a526 | ||
|
|
b23fc06388 | ||
|
|
f818ddc71c | ||
|
|
37c8cc82b2 | ||
|
|
03ebd5554f | ||
|
|
a2a7021914 | ||
|
|
c6650f88e1 | ||
|
|
55a25674a2 | ||
|
|
05c3d520a6 | ||
|
|
6b3304320b | ||
|
|
8d15276625 | ||
|
|
354f107fed | ||
|
|
1ff55c20e0 | ||
|
|
9583f0d3cc | ||
|
|
3acb85a005 | ||
|
|
08d041cb93 | ||
|
|
274b2002c2 | ||
|
|
681e91f9d8 | ||
|
|
6e333bd9ab | ||
|
|
6a331e37fc | ||
|
|
d8a020905a | ||
|
|
efa6f4cd95 | ||
|
|
ca537dc3ed | ||
|
|
3b64f54cea | ||
|
|
32c1e38b84 | ||
|
|
a7aa8820e1 | ||
|
|
2582a83376 | ||
|
|
0094cd7a81 | ||
|
|
d9b33d74a4 | ||
|
|
539a773ea7 | ||
|
|
b1831d7e33 | ||
|
|
b8ccb7a4c1 | ||
|
|
0eb75a41bb | ||
|
|
4cc47e3297 | ||
|
|
7bf3366041 | ||
|
|
c4b9f4bccf | ||
|
|
455c552132 | ||
|
|
f26fb51509 | ||
|
|
ab3c6576ed | ||
|
|
d1bd994113 | ||
|
|
d1548b1161 | ||
|
|
8a43f41ed6 | ||
|
|
42759e4011 | ||
|
|
27fa19eb94 | ||
|
|
426ed8589b |
@@ -2,6 +2,55 @@ Revision history for Verilator
|
||||
|
||||
The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
* Verilator 4.014 2019-05-08
|
||||
|
||||
*** Add --trace-fst-thread.
|
||||
|
||||
**** Support '#' comments in $readmem, bug1411. [Frederick Requin]
|
||||
|
||||
**** Support "'dx" constants, bug1423. [Udi Finkelstein]
|
||||
|
||||
**** For FST tracing use LZ4 compression. [Tony Bybell]
|
||||
|
||||
**** Add error when use parameters without value, bug1424. [Peter Gerst]
|
||||
|
||||
**** Auto-extend and WIDTH warn on unsized X/Zs, bug1423. [Udi Finkelstein]
|
||||
|
||||
**** Fix missing VL_SHIFTL_ errors, bug1412, bug1415. [Larry Lee]
|
||||
|
||||
**** Fix MinGW GCC 6 printf formats, bug1413. [Sergey Kvachonok]
|
||||
|
||||
**** Fix test problems when missing fst2vcd, bug1417. [Todd Strader]
|
||||
|
||||
**** Fix GTKWave register warning, bug1421. [Pieter Kapsenberg]
|
||||
|
||||
**** Fix FST enums not displaying, bug1426. [Danilo Ramos]
|
||||
|
||||
**** Fix table compile error with multiinterfaces, bug1431. [Bogdan Vukobratovic]
|
||||
|
||||
|
||||
* Verilator 4.012 2019-3-23
|
||||
|
||||
*** Add +verilator+seed, bug1396. [Stan Sokorac]
|
||||
|
||||
*** Support $fread. [Leendert van Doorn]
|
||||
|
||||
*** Support void' cast on functions called as tasks, bug1383. [Al Grant]
|
||||
|
||||
*** Add IGNOREDRETURN warning, bug1383.
|
||||
|
||||
**** Report PORTSHORT errors on concat constants, bug 1400. [Will Korteland]
|
||||
|
||||
**** Fix VERILATOR_GDB being ignored, msg2860. [Yu Sheng Lin]
|
||||
|
||||
**** Fix $value$plus$args missing verilated_heavy.h. [Yi-Chung Chen]
|
||||
|
||||
**** Fix MSVC compile error, bug1406. [Benjamin Gartner]
|
||||
|
||||
**** Fix maintainer test when no Parallel::Forker, msg2630. [Enzo Chi]
|
||||
|
||||
**** Fix +1364-1995ext flags applying too late, bug1384. [Al Grant]
|
||||
|
||||
|
||||
* Verilator 4.010 2019-01-27
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
\.clang-tidy
|
||||
\.git/
|
||||
\.git$
|
||||
\.svn/
|
||||
\.(bak|old)/
|
||||
\.(bak|old)$
|
||||
|
||||
+71
-39
@@ -58,17 +58,17 @@ foreach my $sw (@ARGV) {
|
||||
}
|
||||
|
||||
Getopt::Long::config("no_auto_abbrev","pass_through");
|
||||
if (! GetOptions (
|
||||
# Major operating modes
|
||||
"help" => \&usage,
|
||||
"debug:s" => \&debug,
|
||||
# "version!" => \&version, # Also passthru'ed
|
||||
# Switches
|
||||
"gdb!" => \$opt_gdb,
|
||||
"gdbbt!" => \$opt_gdbbt,
|
||||
# Additional parameters
|
||||
"<>" => sub {}, # Ignored
|
||||
)) {
|
||||
if (! GetOptions(
|
||||
# Major operating modes
|
||||
"help" => \&usage,
|
||||
"debug:s" => \&debug,
|
||||
# "version!" => \&version, # Also passthru'ed
|
||||
# Switches
|
||||
"gdb!" => \$opt_gdb,
|
||||
"gdbbt!" => \$opt_gdbbt,
|
||||
# Additional parameters
|
||||
"<>" => sub {}, # Ignored
|
||||
)) {
|
||||
pod2usage(-exitstatus=>2, -verbose=>0);
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ if ($opt_gdbbt && !gdb_works()) {
|
||||
my @quoted_sw = map {sh_escape($_)} @Opt_Verilator_Sw;
|
||||
if ($opt_gdb) {
|
||||
# Generic GDB interactive
|
||||
run (("gdb"||$ENV{VERILATOR_GDB})
|
||||
run (($ENV{VERILATOR_GDB}||"gdb")
|
||||
." ".verilator_bin()
|
||||
# Note, uncomment to set breakpoints before running:
|
||||
# ." -ex 'break main'"
|
||||
@@ -361,6 +361,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
|
||||
--top-module <topname> Name of top level input module
|
||||
--trace Enable waveform creation
|
||||
--trace-fst Enable FST waveform creation
|
||||
--trace-fst-thread Enable FST threaded waveform creation
|
||||
--trace-depth <levels> Depth of tracing
|
||||
--trace-max-array <depth> Maximum bit width for tracing
|
||||
--trace-max-width <width> Maximum array depth for tracing
|
||||
@@ -399,7 +400,8 @@ detailed descriptions in L</"RUNTIME ARGUMENTS"> for more information.
|
||||
+verilator+prof+threads+file+I<filename> Set profile filename
|
||||
+verilator+prof+threads+start+I<value> Set profile starting point
|
||||
+verilator+prof+threads+window+I<value> Set profile duration
|
||||
+verilator+rand+reset+<value> Set random reset technique
|
||||
+verilator+rand+reset+I<value> Set random reset technique
|
||||
+verilator+seed+I<value> Set random seed
|
||||
+verilator+V Verbose version and config
|
||||
+verilator+version Show version and exit
|
||||
|
||||
@@ -1290,7 +1292,14 @@ even when waveforms are not turned on during model execution.
|
||||
|
||||
=item --trace-fst
|
||||
|
||||
Enable FST waveform tracing in the model. This overrides C<--trace>.
|
||||
Enable FST waveform tracing in the model. This overrides C<--trace> and
|
||||
C<--trace-fst-thread>. See also C<--trace-fst-thread>.
|
||||
|
||||
=item --trace-fst-thread
|
||||
|
||||
Enable FST waveform tracing in the model, using a separate thread. This is
|
||||
typically faster in runtime but slower in total computes than
|
||||
C<--trace-fst>. This overrides C<--trace> and C<--trace-fst>.
|
||||
|
||||
=item --trace-depth I<levels>
|
||||
|
||||
@@ -1455,10 +1464,10 @@ Enable all code style related warning messages. This is equivalent to
|
||||
=item --x-assign unique
|
||||
|
||||
Controls the two-state value that is replaced when an assignment to X is
|
||||
encountered. --x-assign=fast, the default, converts all Xs to whatever is
|
||||
best for performance. --x-assign=0 converts all Xs to 0s, and is also fast.
|
||||
--x-assign=1 converts all Xs to 1s, this is nearly as fast as 0, but more
|
||||
likely to find reset bugs as active high logic will fire. --x-assign=unique
|
||||
encountered. C<--x-assign fast>, the default, converts all Xs to whatever is
|
||||
best for performance. C<--x-assign 0> converts all Xs to 0s, and is also fast.
|
||||
C<--x-assign 1> converts all Xs to 1s, this is nearly as fast as 0, but more
|
||||
likely to find reset bugs as active high logic will fire. C<--x-assign unique>
|
||||
will call a function to determine the value, this allows randomization of
|
||||
all Xs to find reset bugs and is the slowest, but safest for finding reset
|
||||
bugs in code.
|
||||
@@ -1483,13 +1492,13 @@ variables are controlled with --x-initial.
|
||||
Controls the two-state value that is used to initialize variables that are
|
||||
not otherwise initialized.
|
||||
|
||||
--x-initial=0, initializes all otherwise uninitialized variables to zero.
|
||||
C<--x-initial 0>, initializes all otherwise uninitialized variables to zero.
|
||||
|
||||
--x-initial=unique, the default, initializes variables using a function,
|
||||
C<--x-initial unique>, the default, initializes variables using a function,
|
||||
which determines the value to use each initialization. This gives greatest
|
||||
flexibility and allows finding reset bugs. See L</"Unknown states">.
|
||||
|
||||
--x-initial=fast, is best for performance, and initializes all variables to
|
||||
C<--x-initial fast>, is best for performance, and initializes all variables to
|
||||
a state Verilator determines is optimal. This may allow further code
|
||||
optimizations, but will likely hide any code bugs relating to missing
|
||||
resets.
|
||||
@@ -1599,6 +1608,11 @@ When a model was Verilated using "-x-inital unique", sets the
|
||||
initialization technique. 0 = Reset to zeros. 1 = Reset to all-ones. 2 =
|
||||
Randomize. See L</"Unknown states">.
|
||||
|
||||
=item +verilator+seed+I<value>
|
||||
|
||||
For $random and "-x-initial unique", set the random seed value. If zero or
|
||||
not specified picks a value from the system random number generator.
|
||||
|
||||
=item +verilator+V
|
||||
|
||||
Shows the verbose version, including configuration information.
|
||||
@@ -1698,7 +1712,7 @@ This is an example similar to the above, but using SystemC.
|
||||
#include "Vour.h"
|
||||
int sc_main(int argc, char **argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
sc_clock clk ("clk",10, 0.5, 3, true);
|
||||
sc_clock clk ("clk", 10, 0.5, 3, true);
|
||||
Vour* top;
|
||||
top = new Vour("top");
|
||||
top->clk(clk);
|
||||
@@ -1759,8 +1773,8 @@ the examples directory in the distribution.
|
||||
=head1 BENCHMARKING & OPTIMIZATION
|
||||
|
||||
For best performance, run Verilator with the "-O3 --x-assign=fast
|
||||
--x-initial=fast --noassert" flags. The -O3 flag will require longer
|
||||
compile times, and --x-assign=fast --x-initial=fast may increase the risk
|
||||
--x-initial fast --noassert" flags. The -O3 flag will require longer
|
||||
compile times, and "--x-assign fast --x-initial fast" may increase the risk
|
||||
of reset bugs in trade for performance; see the above documentation for
|
||||
these flags.
|
||||
|
||||
@@ -2068,7 +2082,7 @@ command line, or the link), you'd then:
|
||||
|
||||
#include "svdpi.h"
|
||||
#include "Vour__Dpi.h"
|
||||
int add (int a, int b) { return a+b; }
|
||||
int add(int a, int b) { return a+b; }
|
||||
|
||||
=head2 DPI System Task/Functions
|
||||
|
||||
@@ -2118,7 +2132,7 @@ respect to that top level module, then the scope could be set with
|
||||
|
||||
#include "svdpi.h"
|
||||
...
|
||||
svSetScope (svGetScopeFromName ("dut"));
|
||||
svSetScope(svGetScopeFromName("dut"));
|
||||
|
||||
(Remember that Verilator adds a "V" to the top of the module hierarchy.)
|
||||
|
||||
@@ -2132,7 +2146,7 @@ comments within the svdpi.h header for more information.
|
||||
Verilator allows writing $display like functions using this syntax:
|
||||
|
||||
import "DPI-C" function void
|
||||
\$my_display (input string formatted /*verilator sformat*/ );
|
||||
\$my_display(input string formatted /*verilator sformat*/ );
|
||||
|
||||
The /*verilator sformat*/ indicates that this function accepts a $display
|
||||
like format specifier followed by any number of arguments to satisfy the
|
||||
@@ -2240,7 +2254,7 @@ accesses the above signal "readme" would be:
|
||||
#include "verilated_vpi.h" // Required to get definitions
|
||||
|
||||
vluint64_t main_time = 0; // See comments in first example
|
||||
double sc_time_stamp () { return main_time; }
|
||||
double sc_time_stamp() { return main_time; }
|
||||
|
||||
void read_and_check() {
|
||||
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"TOP.our.readme", NULL);
|
||||
@@ -2342,6 +2356,9 @@ Verilated model should not livelock nor deadlock, however, you can expect
|
||||
performance to be far worse than it would be with proper stoichiometry of
|
||||
threads and CPU cores.
|
||||
|
||||
With --trace-fst-thread, tracing occurs in a separate thread from the main
|
||||
simulation thread(s). This option is orthogonal to --threads.
|
||||
|
||||
The remainder of this section describe behavior with --threads 1 or
|
||||
--threads N (not --no-threads).
|
||||
|
||||
@@ -3018,9 +3035,10 @@ from a four state simulator. An === comparison to X will always be false,
|
||||
so that Verilog code which checks for uninitialized logic will not fire.
|
||||
|
||||
Assigning a variable to a X will actually assign the variable to a random
|
||||
value (see the --x-assign switch.) Thus if the value is actually used, the
|
||||
random value should cause downstream errors. Integers also randomize, even
|
||||
though the Verilog 2001 specification says they initialize to zero.
|
||||
value (see the --x-assign switch and +verilator+rand+reset runtime switch.)
|
||||
Thus if the value is actually used, the random value should cause
|
||||
downstream errors. Integers also randomize, even though the Verilog 2001
|
||||
specification says they initialize to zero.
|
||||
|
||||
All variables, depending on --x-initial setting, are typically randomly
|
||||
initialized using a function. By running several random simulation runs
|
||||
@@ -3398,7 +3416,7 @@ it's a bit slower than a non-delayed assignment.) Here's an example
|
||||
always @ (posedge clk)
|
||||
if (~reset_l) begin
|
||||
for (i=0; i<`ARRAY_SIZE; i++) begin
|
||||
array[i] = 0; // Non-delayed for verilator
|
||||
array[i] = 0; // Non-delayed for verilator
|
||||
end
|
||||
|
||||
This message is only seen on large or complicated loops because Verilator
|
||||
@@ -3573,6 +3591,19 @@ code to a case statement, or a SystemVerilog 'unique if' or 'priority if'.
|
||||
Disabled by default as this is a code style warning; it will simulate
|
||||
correctly.
|
||||
|
||||
=item IGNOREDRETURN
|
||||
|
||||
Warns that a non-void function is being called as a task, and hence the
|
||||
return value is being ignored.
|
||||
|
||||
This warning is required by IEEE. The portable way to suppress this warning
|
||||
(in SystemVerilog) is to use a void cast, e.g.
|
||||
|
||||
void'(function_being_called_as_task());
|
||||
|
||||
Ignoring this warning will only suppress the lint check, it will simulate
|
||||
correctly.
|
||||
|
||||
=item IMPERFECTSCH
|
||||
|
||||
Warns that the scheduling of the model is not absolutely perfect, and some
|
||||
@@ -3863,7 +3894,7 @@ Often UNOPTFLAT is caused by logic that isn't truly circular as viewed by
|
||||
synthesis which analyzes interconnection per-bit, but is circular to
|
||||
simulation which analyzes per-bus:
|
||||
|
||||
wire [2:0] x = {x[1:0],shift_in};
|
||||
wire [2:0] x = {x[1:0], shift_in};
|
||||
|
||||
This statement needs to be evaluated multiple times, as a change in
|
||||
"shift_in" requires "x" to be computed 3 times before it becomes stable.
|
||||
@@ -3872,12 +3903,12 @@ causes the warning.
|
||||
|
||||
For significantly better performance, split this into 2 separate signals:
|
||||
|
||||
wire [2:0] xout = {x[1:0],shift_in};
|
||||
wire [2:0] xout = {x[1:0], shift_in};
|
||||
|
||||
and change all receiving logic to instead receive "xout". Alternatively,
|
||||
change it to
|
||||
|
||||
wire [2:0] x = {xin[1:0],shift_in};
|
||||
wire [2:0] x = {xin[1:0], shift_in};
|
||||
|
||||
and change all driving logic to instead drive "xin".
|
||||
|
||||
@@ -3993,7 +4024,7 @@ Concatenate leading zeros when doing arithmetic. In the statement
|
||||
|
||||
The best fix, which clarifies intent and will also make all tools happy is:
|
||||
|
||||
wire [5:0] plus_one = from[5:0] + 6'd1 + {5'd0,carry[0]};
|
||||
wire [5:0] plus_one = from[5:0] + 6'd1 + {5'd0, carry[0]};
|
||||
|
||||
Ignoring this warning will only suppress the lint check, it will simulate
|
||||
correctly.
|
||||
@@ -4005,12 +4036,12 @@ has an indeterminate width. In most cases this violates the Verilog rule
|
||||
that widths inside concatenates and replicates must be sized, and should be
|
||||
fixed in the code.
|
||||
|
||||
wire [63:0] concat = {1,2};
|
||||
wire [63:0] concat = {1, 2};
|
||||
|
||||
An example where this is technically legal (though still bad form) is:
|
||||
|
||||
parameter PAR = 1;
|
||||
wire [63:0] concat = {PAR,PAR};
|
||||
wire [63:0] concat = {PAR, PAR};
|
||||
|
||||
The correct fix is to either size the 1 ("32'h1"), or add the width to the
|
||||
parameter definition ("parameter [31:0]"), or add the width to the
|
||||
@@ -4213,7 +4244,8 @@ trace file if you want all data to land in the same output file.
|
||||
|
||||
FST a format by GTKWave.
|
||||
This version provides a basic FST support.
|
||||
To dump FST format, add the --trace switch to Verilator and change the include path in the testbench to:
|
||||
To dump FST format, add the --trace-fst switch to Verilator and change the include
|
||||
path in the testbench to:
|
||||
|
||||
#include "verilated_fst_c.h"
|
||||
VerilatedFstC* tfp = new VerilatedFstC;
|
||||
|
||||
+38
-38
@@ -19,8 +19,8 @@ require 5.006_001;
|
||||
use warnings;
|
||||
BEGIN {
|
||||
if ($ENV{DIRPROJECT} && $ENV{DIRPROJECT_PERL_BOOT}) {
|
||||
# Magic to allow author testing of perl packages in local directory
|
||||
require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
|
||||
# Magic to allow author testing of perl packages in local directory
|
||||
require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,12 +56,12 @@ foreach my $sw (@ARGV) {
|
||||
|
||||
Getopt::Long::config("no_auto_abbrev","pass_through");
|
||||
if (! GetOptions (
|
||||
# Major operating modes
|
||||
"help" => \&usage,
|
||||
"debug:s" => \&debug,
|
||||
# "version!" => \&version, # Also passthru'ed
|
||||
# Additional parameters
|
||||
"<>" => sub {}, # Ignored
|
||||
# Major operating modes
|
||||
"help" => \&usage,
|
||||
"debug:s" => \&debug,
|
||||
# "version!" => \&version, # Also passthru'ed
|
||||
# Additional parameters
|
||||
"<>" => sub {}, # Ignored
|
||||
)) {
|
||||
pod2usage(-exitstatus=>2, -verbose=>0);
|
||||
}
|
||||
@@ -90,25 +90,25 @@ sub verilator_coverage_bin {
|
||||
my $bin = "";
|
||||
# Use VERILATOR_ROOT if defined, else assume verilator_bin is in the search path
|
||||
my $basename = ($ENV{VERILATOR_COVERAGE_BIN}
|
||||
|| "verilator_coverage_bin_dbg");
|
||||
|| "verilator_coverage_bin_dbg");
|
||||
if (defined($ENV{VERILATOR_ROOT})) {
|
||||
my $dir = $ENV{VERILATOR_ROOT};
|
||||
my $dir = $ENV{VERILATOR_ROOT};
|
||||
if (-x "$dir/bin/$basename"
|
||||
|| -x "$dir/bin/$basename.exe") { # From a "make install" into VERILATOR_ROOT
|
||||
$bin = "$dir/bin/$basename";
|
||||
} else {
|
||||
$bin = "$dir/$basename"; # From pointing to kit directory
|
||||
}
|
||||
$bin = "$dir/bin/$basename";
|
||||
} else {
|
||||
$bin = "$dir/$basename"; # From pointing to kit directory
|
||||
}
|
||||
} else {
|
||||
if (-x "$RealBin/$basename"
|
||||
|| -x "$RealBin/$basename.exe") {
|
||||
$bin = "$RealBin/$basename"; # From path/to/verilator with verilator_bin installed
|
||||
} else {
|
||||
$bin = $basename; # Find in PATH
|
||||
}
|
||||
# Note we don't look under bin/$basename which would be right if running
|
||||
# in the kit dir. Running that would likely break, since
|
||||
# VERILATOR_ROOT wouldn't be set and Verilator won't find internal files.
|
||||
$bin = "$RealBin/$basename"; # From path/to/verilator with verilator_bin installed
|
||||
} else {
|
||||
$bin = $basename; # Find in PATH
|
||||
}
|
||||
# Note we don't look under bin/$basename which would be right if running
|
||||
# in the kit dir. Running that would likely break, since
|
||||
# VERILATOR_ROOT wouldn't be set and Verilator won't find internal files.
|
||||
}
|
||||
return $bin;
|
||||
}
|
||||
@@ -125,23 +125,23 @@ sub run {
|
||||
system($command);
|
||||
my $status = $?;
|
||||
if ($status) {
|
||||
if ($! =~ /no such file or directory/i) {
|
||||
warn "%Error: verilator_coverage: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
|
||||
}
|
||||
if ($Debug) { # For easy rerunning
|
||||
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
|
||||
warn "%Error: $command\n";
|
||||
}
|
||||
if ($status & 127) {
|
||||
if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
|
||||
warn "%Error: Verilator_coverage internal fault, sorry.\n" if !$Debug;
|
||||
} elsif (($status & 127) == 6) { # SIGABRT
|
||||
warn "%Error: Verilator_coverage aborted.\n" if !$Debug;
|
||||
} else {
|
||||
warn "%Error: Verilator_coverage threw signal $status.\n" if !$Debug;
|
||||
}
|
||||
}
|
||||
die "%Error: Command Failed $command\n";
|
||||
if ($! =~ /no such file or directory/i) {
|
||||
warn "%Error: verilator_coverage: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
|
||||
}
|
||||
if ($Debug) { # For easy rerunning
|
||||
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
|
||||
warn "%Error: $command\n";
|
||||
}
|
||||
if ($status & 127) {
|
||||
if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
|
||||
warn "%Error: Verilator_coverage internal fault, sorry.\n" if !$Debug;
|
||||
} elsif (($status & 127) == 6) { # SIGABRT
|
||||
warn "%Error: Verilator_coverage aborted.\n" if !$Debug;
|
||||
} else {
|
||||
warn "%Error: Verilator_coverage threw signal $status.\n" if !$Debug;
|
||||
}
|
||||
}
|
||||
die "%Error: Command Failed $command\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+52
-52
@@ -38,11 +38,11 @@ my $Opt_Lineno = 1;
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
Getopt::Long::config("no_auto_abbrev");
|
||||
if (! GetOptions (
|
||||
"help" => \&usage,
|
||||
"debug" => \&debug,
|
||||
"<>" => \¶meter,
|
||||
"lineno!" => \$Opt_Lineno,
|
||||
if (! GetOptions(
|
||||
"help" => \&usage,
|
||||
"debug" => \&debug,
|
||||
"<>" => \¶meter,
|
||||
"lineno!" => \$Opt_Lineno,
|
||||
)) {
|
||||
die "%Error: Bad usage, try 'verilator_difftree --help'\n";
|
||||
}
|
||||
@@ -68,22 +68,22 @@ sub diff_dir {
|
||||
my %files;
|
||||
|
||||
foreach my $fn (glob("$a/*.tree")) {
|
||||
(my $base = $fn) =~ s!.*/!!;
|
||||
$files{$base}{a} = $fn;
|
||||
(my $base = $fn) =~ s!.*/!!;
|
||||
$files{$base}{a} = $fn;
|
||||
}
|
||||
foreach my $fn (glob("$b/*.tree")) {
|
||||
(my $base = $fn) =~ s!.*/!!;
|
||||
$files{$base}{b} = $fn;
|
||||
(my $base = $fn) =~ s!.*/!!;
|
||||
$files{$base}{b} = $fn;
|
||||
}
|
||||
my $any;
|
||||
foreach my $base (sort (keys %files)) {
|
||||
my $a = $files{$base}{a};
|
||||
my $b = $files{$base}{b};
|
||||
next if !$a || !$b;
|
||||
print "="x70,"\n";
|
||||
print "= $a <-> $b\n";
|
||||
diff_file($a,$b);
|
||||
$any = 1;
|
||||
my $a = $files{$base}{a};
|
||||
my $b = $files{$base}{b};
|
||||
next if !$a || !$b;
|
||||
print "="x70,"\n";
|
||||
print "= $a <-> $b\n";
|
||||
diff_file($a,$b);
|
||||
$any = 1;
|
||||
}
|
||||
$any or warn("%Warning: No .tree files found that have similar base names:\n "
|
||||
.join("\n ", sort keys %files),"\n");
|
||||
@@ -101,7 +101,7 @@ sub diff_file {
|
||||
my $vera = version_from($a);
|
||||
my $verb = version_from($b);
|
||||
my $verCvt = (($vera < 0x3900 && $verb >= 0x3900)
|
||||
|| ($vera >= 0x3900 && $verb < 0x3900));
|
||||
|| ($vera >= 0x3900 && $verb < 0x3900));
|
||||
|
||||
filter($a, $tmp_a, $verCvt);
|
||||
filter($b, $tmp_b, $verCvt);
|
||||
@@ -115,8 +115,8 @@ sub version_from {
|
||||
# Return dump format
|
||||
my $f1 = IO::File->new ($fn) or die "%Error: $! $fn,";
|
||||
while (defined (my $line=$f1->getline())) {
|
||||
last if $. > 10;
|
||||
return hex $1 if $line =~ /\(format (0x[0-9.]+)\)/;
|
||||
last if $. > 10;
|
||||
return hex $1 if $line =~ /\(format (0x[0-9.]+)\)/;
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
@@ -130,36 +130,36 @@ sub filter {
|
||||
my $f2 = IO::File->new ($fn2,"w") or die "%Error: $! $fn2,";
|
||||
while (defined (my $line=$f1->getline())) {
|
||||
same_line:
|
||||
next if $line =~ / This=/;
|
||||
$line =~ s/0x[a-f0-9]+/0x/g;
|
||||
$line =~ s/<e[0-9]+\#?>/<e>/g;
|
||||
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
|
||||
if ($verCvt) {
|
||||
next if $line =~ /^ NETLIST/;
|
||||
$line =~ s!\@dt=0x\(G?/?([^)]+)\)!$1!g; # NEW: @dt -> OLD: non @dt format
|
||||
# # Below Ver1_Non_Dtyped may replace above further
|
||||
if ($line =~ /: ([A-Z]+) /) {
|
||||
my $type = $1;
|
||||
next if $type =~ 'DTYPE';
|
||||
if ($type eq 'TYPETABLE' || $type eq 'RANGE') {
|
||||
$line =~ /^(\s+\S+:) /; my $prefix = $1;
|
||||
while (defined ($line=$f1->getline())) {
|
||||
next if $line =~ /^\s+[a-z]/; # Table body
|
||||
next if $line =~ /^${prefix}[0-9]:/;
|
||||
goto same_line;
|
||||
}
|
||||
next;
|
||||
}
|
||||
if ($Ver1_Non_Dtyped{$type}) {
|
||||
$line =~ s! w[0-9]+!!g;
|
||||
}
|
||||
}
|
||||
$line =~ s!\@dt=0$!NoW!g; # NEW: dt=null -> common format
|
||||
$line =~ s!\@dt=0 !NoW !g; # NEW: dt=null -> common format
|
||||
$line =~ s! s?w0$! NoW!g; # OLD: no width -> common format
|
||||
$line =~ s! s?w0 ! NoW !g; # OLD: no width -> common format
|
||||
}
|
||||
print $f2 $line;
|
||||
next if $line =~ / This=/;
|
||||
$line =~ s/0x[a-f0-9]+/0x/g;
|
||||
$line =~ s/<e[0-9]+\#?>/<e>/g;
|
||||
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
|
||||
if ($verCvt) {
|
||||
next if $line =~ /^ NETLIST/;
|
||||
$line =~ s!\@dt=0x\(G?/?([^)]+)\)!$1!g; # NEW: @dt -> OLD: non @dt format
|
||||
# # Below Ver1_Non_Dtyped may replace above further
|
||||
if ($line =~ /: ([A-Z]+) /) {
|
||||
my $type = $1;
|
||||
next if $type =~ 'DTYPE';
|
||||
if ($type eq 'TYPETABLE' || $type eq 'RANGE') {
|
||||
$line =~ /^(\s+\S+:) /; my $prefix = $1;
|
||||
while (defined ($line=$f1->getline())) {
|
||||
next if $line =~ /^\s+[a-z]/; # Table body
|
||||
next if $line =~ /^${prefix}[0-9]:/;
|
||||
goto same_line;
|
||||
}
|
||||
next;
|
||||
}
|
||||
if ($Ver1_Non_Dtyped{$type}) {
|
||||
$line =~ s! w[0-9]+!!g;
|
||||
}
|
||||
}
|
||||
$line =~ s!\@dt=0$!NoW!g; # NEW: dt=null -> common format
|
||||
$line =~ s!\@dt=0 !NoW !g; # NEW: dt=null -> common format
|
||||
$line =~ s! s?w0$! NoW!g; # OLD: no width -> common format
|
||||
$line =~ s! s?w0 ! NoW !g; # OLD: no width -> common format
|
||||
}
|
||||
print $f2 $line;
|
||||
}
|
||||
$f1->close;
|
||||
$f2->close;
|
||||
@@ -179,11 +179,11 @@ sub debug {
|
||||
sub parameter {
|
||||
my $param = shift;
|
||||
if (!defined $Opt_A) {
|
||||
$Opt_A = $param;
|
||||
$Opt_A = $param;
|
||||
} elsif (!defined $Opt_B) {
|
||||
$Opt_B = $param;
|
||||
$Opt_B = $param;
|
||||
} else {
|
||||
die "%Error: Unknown parameter: $param\n";
|
||||
die "%Error: Unknown parameter: $param\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+84
-84
@@ -24,11 +24,11 @@ my $Opt_File;
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
Getopt::Long::config("no_auto_abbrev");
|
||||
if (! GetOptions (
|
||||
"help" => \&usage,
|
||||
"debug" => \&debug,
|
||||
"<>" => \¶meter,
|
||||
)) {
|
||||
if (! GetOptions(
|
||||
"help" => \&usage,
|
||||
"debug" => \&debug,
|
||||
"<>" => \¶meter,
|
||||
)) {
|
||||
die "%Error: Bad usage, try 'verilator_profcfunc --help'\n";
|
||||
}
|
||||
|
||||
@@ -50,9 +50,9 @@ sub debug {
|
||||
sub parameter {
|
||||
my $param = shift;
|
||||
if (!defined $Opt_File) {
|
||||
$Opt_File = $param;
|
||||
$Opt_File = $param;
|
||||
} else {
|
||||
die "%Error: Unknown parameter: $param\n";
|
||||
die "%Error: Unknown parameter: $param\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,13 +66,13 @@ sub profcfunc {
|
||||
my %funcs;
|
||||
|
||||
while (defined (my $line=$fh->getline())) {
|
||||
# %time cumesec selfsec calls {stuff} name
|
||||
if ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
|
||||
my $pct=$1; my $sec=$2; my $calls=$3; my $func=$4;
|
||||
$funcs{$func}{pct} += $pct;
|
||||
$funcs{$func}{sec} += $sec;
|
||||
$funcs{$func}{calls} += $calls;
|
||||
}
|
||||
# %time cumesec selfsec calls {stuff} name
|
||||
if ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
|
||||
my $pct=$1; my $sec=$2; my $calls=$3; my $func=$4;
|
||||
$funcs{$func}{pct} += $pct;
|
||||
$funcs{$func}{sec} += $sec;
|
||||
$funcs{$func}{calls} += $calls;
|
||||
}
|
||||
# Older gprofs have no call column for single-call functions
|
||||
# %time cumesec selfsec {stuff} name
|
||||
elsif ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
|
||||
@@ -88,10 +88,10 @@ sub profcfunc {
|
||||
my %pointer_mods;
|
||||
my %verilated_mods;
|
||||
foreach my $func (keys %funcs) {
|
||||
if ($func =~ /(.*)::_eval\(([a-zA-Z_0-9]+__Syms).*\)$/) {
|
||||
$verilated_mods{$1} = qr/^$1/;
|
||||
$pointer_mods{$2} = $1;
|
||||
}
|
||||
if ($func =~ /(.*)::_eval\(([a-zA-Z_0-9]+__Syms).*\)$/) {
|
||||
$verilated_mods{$1} = qr/^$1/;
|
||||
$pointer_mods{$2} = $1;
|
||||
}
|
||||
}
|
||||
#print Dumper(\%pointer_mods, \%verilated_mods);
|
||||
|
||||
@@ -99,72 +99,72 @@ sub profcfunc {
|
||||
my %vfuncs;
|
||||
my %groups;
|
||||
foreach my $func (keys %funcs) {
|
||||
my $pct = $funcs{$func}{pct};
|
||||
my $vfunc = $func;
|
||||
my $design;
|
||||
my $pct = $funcs{$func}{pct};
|
||||
my $vfunc = $func;
|
||||
my $design;
|
||||
|
||||
if ($func =~ /\(([a-zA-Z_0-9]+__Syms)/) {
|
||||
$design = $pointer_mods{$1};
|
||||
}
|
||||
if ($func =~ /\(([a-zA-Z_0-9]+__Syms)/) {
|
||||
$design = $pointer_mods{$1};
|
||||
}
|
||||
|
||||
foreach my $vde (keys %verilated_mods) {
|
||||
last if $design;
|
||||
if ($func =~ /$verilated_mods{$vde}/) {
|
||||
$design=$vde;
|
||||
last;
|
||||
}
|
||||
}
|
||||
foreach my $vde (keys %verilated_mods) {
|
||||
last if $design;
|
||||
if ($func =~ /$verilated_mods{$vde}/) {
|
||||
$design=$vde;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
if ($vfunc =~ /__PROF__([a-zA-Z_0-9]+)__l?([0-9]+)\(/) {
|
||||
$vfunc = sprintf("VBlock %s:%d", $1, $2);
|
||||
$groups{type}{"Verilog Blocks under $design"} += $pct;
|
||||
$groups{design}{$design} += $pct;
|
||||
$groups{module}{$1} += $pct;
|
||||
} else {
|
||||
if ($design) {
|
||||
$vfunc = sprintf("VCommon %s", $func);
|
||||
$groups{type}{"Common code under $design"} += $pct;
|
||||
$groups{design}{$design} += $pct;
|
||||
$groups{module}{$design." common code"} += $pct;
|
||||
} elsif ($func =~ /^VL_[A-Z0-9_]+/
|
||||
|| $func =~ /^_?vl_[a-zA-Z0-9_]+/
|
||||
|| $func =~ /^verilated/i) {
|
||||
$vfunc = sprintf("VLib %s", $func);
|
||||
$groups{type}{'VLib'} += $pct;
|
||||
$groups{design}{'VLib'} += $pct;
|
||||
$groups{module}{'VLib'} += $pct;
|
||||
} elsif ($func =~ /^_mcount_private/) {
|
||||
$vfunc = sprintf("Prof %s", $func);
|
||||
$groups{type}{'Prof'} += $pct;
|
||||
$groups{design}{'Prof'} += $pct;
|
||||
$groups{module}{'Prof'} += $pct;
|
||||
} else {
|
||||
$vfunc = sprintf("C++ %s", $func);
|
||||
$groups{type}{'C++'} += $pct;
|
||||
$groups{design}{'C++'} += $pct;
|
||||
$groups{module}{'C++'} += $pct;
|
||||
}
|
||||
}
|
||||
$vfuncs{$vfunc} = $funcs{$func};
|
||||
if ($vfunc =~ /__PROF__([a-zA-Z_0-9]+)__l?([0-9]+)\(/) {
|
||||
$vfunc = sprintf("VBlock %s:%d", $1, $2);
|
||||
$groups{type}{"Verilog Blocks under $design"} += $pct;
|
||||
$groups{design}{$design} += $pct;
|
||||
$groups{module}{$1} += $pct;
|
||||
} else {
|
||||
if ($design) {
|
||||
$vfunc = sprintf("VCommon %s", $func);
|
||||
$groups{type}{"Common code under $design"} += $pct;
|
||||
$groups{design}{$design} += $pct;
|
||||
$groups{module}{$design." common code"} += $pct;
|
||||
} elsif ($func =~ /^VL_[A-Z0-9_]+/
|
||||
|| $func =~ /^_?vl_[a-zA-Z0-9_]+/
|
||||
|| $func =~ /^verilated/i) {
|
||||
$vfunc = sprintf("VLib %s", $func);
|
||||
$groups{type}{'VLib'} += $pct;
|
||||
$groups{design}{'VLib'} += $pct;
|
||||
$groups{module}{'VLib'} += $pct;
|
||||
} elsif ($func =~ /^_mcount_private/) {
|
||||
$vfunc = sprintf("Prof %s", $func);
|
||||
$groups{type}{'Prof'} += $pct;
|
||||
$groups{design}{'Prof'} += $pct;
|
||||
$groups{module}{'Prof'} += $pct;
|
||||
} else {
|
||||
$vfunc = sprintf("C++ %s", $func);
|
||||
$groups{type}{'C++'} += $pct;
|
||||
$groups{design}{'C++'} += $pct;
|
||||
$groups{module}{'C++'} += $pct;
|
||||
}
|
||||
}
|
||||
$vfuncs{$vfunc} = $funcs{$func};
|
||||
}
|
||||
|
||||
|
||||
foreach my $type (qw(type design module)) {
|
||||
my $missing = 100;
|
||||
foreach (sort (keys %{$groups{$type}})) {
|
||||
$missing -= $groups{$type}{$_};
|
||||
}
|
||||
if ($missing) {
|
||||
$groups{$type}{"\377Unaccounted for/rounding error"} = $missing;
|
||||
}
|
||||
my $missing = 100;
|
||||
foreach (sort (keys %{$groups{$type}})) {
|
||||
$missing -= $groups{$type}{$_};
|
||||
}
|
||||
if ($missing) {
|
||||
$groups{$type}{"\377Unaccounted for/rounding error"} = $missing;
|
||||
}
|
||||
|
||||
print("Overall summary by $type:\n");
|
||||
printf(" %-6s %s\n","% time",$type);
|
||||
foreach my $what (sort (keys %{$groups{$type}})) {
|
||||
(my $pwhat = $what) =~ s/^\377//; # Just used to establish sort order
|
||||
printf(" %6.2f %s\n", $groups{$type}{$what}, $pwhat);
|
||||
}
|
||||
print("\n");
|
||||
print("Overall summary by $type:\n");
|
||||
printf(" %-6s %s\n","% time",$type);
|
||||
foreach my $what (sort (keys %{$groups{$type}})) {
|
||||
(my $pwhat = $what) =~ s/^\377//; # Just used to establish sort order
|
||||
printf(" %6.2f %s\n", $groups{$type}{$what}, $pwhat);
|
||||
}
|
||||
print("\n");
|
||||
}
|
||||
|
||||
print("Verilog code profile:\n");
|
||||
@@ -181,14 +181,14 @@ sub profcfunc {
|
||||
|
||||
my $cume = 0;
|
||||
foreach my $func (sort {$vfuncs{$b}{sec} <=> $vfuncs{$a}{sec}
|
||||
|| $a cmp $b}
|
||||
(keys %vfuncs)) {
|
||||
$cume += $vfuncs{$func}{sec};
|
||||
printf +("%6.2f %9.2f %8.2f %8d %s\n",
|
||||
$vfuncs{$func}{pct},
|
||||
$cume, $vfuncs{$func}{sec},
|
||||
$vfuncs{$func}{calls},
|
||||
$func);
|
||||
|| $a cmp $b}
|
||||
(keys %vfuncs)) {
|
||||
$cume += $vfuncs{$func}{sec};
|
||||
printf +("%6.2f %9.2f %8.2f %8d %s\n",
|
||||
$vfuncs{$func}{pct},
|
||||
$cume, $vfuncs{$func}{sec},
|
||||
$vfuncs{$func}{calls},
|
||||
$func);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[4.010 2019-01-27],
|
||||
AC_INIT([Verilator],[4.014 2019-05-08],
|
||||
[https://www.veripool.org/verilator],
|
||||
[verilator],[https://www.veripool.org/verilator])
|
||||
# When releasing, also update header of Changes file
|
||||
|
||||
@@ -27,17 +27,21 @@ int main(int argc, char** argv, char** env) {
|
||||
|
||||
// Prevent unused variable warnings
|
||||
if (0 && argc && argv && env) {}
|
||||
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Set debug level, 0 is off, 9 is highest presently used
|
||||
// May be overridden by commandArgs
|
||||
Verilated::debug(0);
|
||||
|
||||
// Randomization reset policy
|
||||
// May be overridden by commandArgs
|
||||
Verilated::randReset(2);
|
||||
|
||||
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
|
||||
// This needs to be called before you create any model
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
||||
Vtop* top = new Vtop; // Or use a const unique_ptr, or the VL_UNIQUE_PTR wrapper
|
||||
Vtop* top = new Vtop; // Or use a const unique_ptr, or the VL_UNIQUE_PTR wrapper
|
||||
|
||||
#if VM_TRACE
|
||||
// If verilator was invoked with --trace argument,
|
||||
@@ -90,14 +94,14 @@ int main(int argc, char** argv, char** env) {
|
||||
|
||||
#if VM_TRACE
|
||||
// Dump trace data for this cycle
|
||||
if (tfp) tfp->dump (main_time);
|
||||
if (tfp) tfp->dump(main_time);
|
||||
#endif
|
||||
|
||||
// Read outputs
|
||||
VL_PRINTF ("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
|
||||
" -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n",
|
||||
main_time, top->clk, top->reset_l, top->in_quad,
|
||||
top->out_quad, top->out_wide[2], top->out_wide[1], top->out_wide[0]);
|
||||
VL_PRINTF("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
|
||||
" -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n",
|
||||
main_time, top->clk, top->reset_l, top->in_quad,
|
||||
top->out_quad, top->out_wide[2], top->out_wide[1], top->out_wide[0]);
|
||||
}
|
||||
|
||||
// Final model cleanup
|
||||
|
||||
@@ -24,15 +24,19 @@ int sc_main(int argc, char* argv[]) {
|
||||
|
||||
// Prevent unused variable warnings
|
||||
if (0 && argc && argv) {}
|
||||
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Set debug level, 0 is off, 9 is highest presently used
|
||||
// May be overridden by commandArgs
|
||||
Verilated::debug(0);
|
||||
|
||||
// Randomization reset policy
|
||||
// May be overridden by commandArgs
|
||||
Verilated::randReset(2);
|
||||
|
||||
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
|
||||
// This needs to be called before you create any model
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// General logfile
|
||||
ios::sync_with_stdio();
|
||||
|
||||
@@ -111,9 +115,9 @@ int sc_main(int argc, char* argv[]) {
|
||||
|
||||
// Apply inputs
|
||||
if (VL_TIME_Q() > 1 && VL_TIME_Q() < 10) {
|
||||
reset_l = !1; // Assert reset
|
||||
reset_l = !1; // Assert reset
|
||||
} else if (VL_TIME_Q() > 1) {
|
||||
reset_l = !0; // Deassert reset
|
||||
reset_l = !0; // Deassert reset
|
||||
}
|
||||
|
||||
// Simulate 1ns
|
||||
|
||||
@@ -49,7 +49,7 @@ module sub
|
||||
|
||||
// An example assertion
|
||||
always_ff @ (posedge clk) begin
|
||||
AssertionExample: assert (!reset_l || count_c<100);
|
||||
AssertionExample: assert(!reset_l || count_c<100);
|
||||
end
|
||||
|
||||
// And example coverage analysis
|
||||
|
||||
@@ -248,7 +248,7 @@ static const int LZ4_minLength = (MFLIMIT+1);
|
||||
/**************************************
|
||||
* Common functions
|
||||
**************************************/
|
||||
static unsigned LZ4_NbCommonBytes (register size_t val)
|
||||
static unsigned LZ4_NbCommonBytes (size_t val)
|
||||
{
|
||||
if (LZ4_isLittleEndian())
|
||||
{
|
||||
|
||||
+535
-464
File diff suppressed because it is too large
Load Diff
+497
-466
File diff suppressed because it is too large
Load Diff
+15
-1
@@ -116,8 +116,22 @@ endif
|
||||
|
||||
ifneq ($(VM_THREADS),0)
|
||||
ifneq ($(VM_THREADS),)
|
||||
CPPFLAGS += -DVL_THREADED
|
||||
VK_LIBS_THREADED=1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(VM_TRACE_THREADED),0)
|
||||
ifneq ($(VM_TRACE_THREADED),)
|
||||
CPPFLAGS += -DVL_TRACE_THREADED
|
||||
VK_LIBS_THREADED=1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(VK_LIBS_THREADED),0)
|
||||
ifneq ($(VK_LIBS_THREADED),)
|
||||
# Need C++11 at least, so always default to newest
|
||||
CPPFLAGS += -DVL_THREADED $(CFG_CXXFLAGS_STD_NEWEST)
|
||||
CPPFLAGS += $(CFG_CXXFLAGS_STD_NEWEST)
|
||||
LDLIBS += $(CFG_LDLIBS_THREADS)
|
||||
endif
|
||||
endif
|
||||
|
||||
+236
-236
@@ -50,10 +50,10 @@ public: // But only local to this file
|
||||
// CONSTRUCTORS
|
||||
// Derived classes should call zero() in their constructor
|
||||
VerilatedCovImpItem() {
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
m_keys[i]=KEY_UNDEF;
|
||||
m_vals[i]=0;
|
||||
}
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
m_keys[i] = KEY_UNDEF;
|
||||
m_vals[i] = 0;
|
||||
}
|
||||
}
|
||||
virtual ~VerilatedCovImpItem() {}
|
||||
virtual vluint64_t count() const = 0;
|
||||
@@ -96,7 +96,7 @@ private:
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
VerilatedMutex m_mutex; ///< Protects all members, when VL_THREADED. Wrapper deals with setting it.
|
||||
VerilatedMutex m_mutex; ///< Protects all members, when VL_THREADED. Wrapper deals with setting it.
|
||||
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
|
||||
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
|
||||
ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items
|
||||
@@ -107,294 +107,294 @@ private:
|
||||
|
||||
// CONSTRUCTORS
|
||||
VerilatedCovImp() {
|
||||
m_insertp = NULL;
|
||||
m_insertFilenamep = NULL;
|
||||
m_insertLineno = 0;
|
||||
m_insertp = NULL;
|
||||
m_insertFilenamep = NULL;
|
||||
m_insertLineno = 0;
|
||||
}
|
||||
VL_UNCOPYABLE(VerilatedCovImp);
|
||||
public:
|
||||
~VerilatedCovImp() { clearGuts(); }
|
||||
static VerilatedCovImp& imp() VL_MT_SAFE {
|
||||
static VerilatedCovImp s_singleton;
|
||||
return s_singleton;
|
||||
static VerilatedCovImp s_singleton;
|
||||
return s_singleton;
|
||||
}
|
||||
|
||||
private:
|
||||
// PRIVATE METHODS
|
||||
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
|
||||
static int nextIndex = KEY_UNDEF+1;
|
||||
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
|
||||
if (iter != m_valueIndexes.end()) return iter->second;
|
||||
nextIndex++; assert(nextIndex>0);
|
||||
m_valueIndexes.insert(std::make_pair(value, nextIndex));
|
||||
m_indexValues.insert(std::make_pair(nextIndex, value));
|
||||
return nextIndex;
|
||||
static int nextIndex = KEY_UNDEF+1;
|
||||
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
|
||||
if (iter != m_valueIndexes.end()) return iter->second;
|
||||
nextIndex++; assert(nextIndex>0);
|
||||
m_valueIndexes.insert(std::make_pair(value, nextIndex));
|
||||
m_indexValues.insert(std::make_pair(nextIndex, value));
|
||||
return nextIndex;
|
||||
}
|
||||
static std::string dequote(const std::string& text) VL_PURE {
|
||||
// Quote any special characters
|
||||
std::string rtn;
|
||||
for (const char* pos = text.c_str(); *pos; ++pos) {
|
||||
if (!isprint(*pos) || *pos=='%' || *pos=='"') {
|
||||
char hex[10]; sprintf(hex,"%%%02X",pos[0]);
|
||||
rtn += hex;
|
||||
} else {
|
||||
rtn += *pos;
|
||||
}
|
||||
}
|
||||
return rtn;
|
||||
// Quote any special characters
|
||||
std::string rtn;
|
||||
for (const char* pos = text.c_str(); *pos; ++pos) {
|
||||
if (!isprint(*pos) || *pos=='%' || *pos=='"') {
|
||||
char hex[10]; sprintf(hex, "%%%02X", pos[0]);
|
||||
rtn += hex;
|
||||
} else {
|
||||
rtn += *pos;
|
||||
}
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
static bool legalKey(const std::string& key) VL_PURE {
|
||||
// Because we compress long keys to a single letter, and
|
||||
// don't want applications to either get confused if they use
|
||||
// a letter differently, nor want them to rely on our compression...
|
||||
// (Considered using numeric keys, but will remain back compatible.)
|
||||
if (key.length()<2) return false;
|
||||
if (key.length()==2 && isdigit(key[1])) return false;
|
||||
return true;
|
||||
// Because we compress long keys to a single letter, and
|
||||
// don't want applications to either get confused if they use
|
||||
// a letter differently, nor want them to rely on our compression...
|
||||
// (Considered using numeric keys, but will remain back compatible.)
|
||||
if (key.length()<2) return false;
|
||||
if (key.length()==2 && isdigit(key[1])) return false;
|
||||
return true;
|
||||
}
|
||||
static std::string keyValueFormatter(const std::string& key, const std::string& value) VL_PURE {
|
||||
std::string name;
|
||||
if (key.length()==1 && isalpha(key[0])) {
|
||||
name += std::string("\001")+key;
|
||||
} else {
|
||||
name += std::string("\001")+dequote(key);
|
||||
}
|
||||
name += std::string("\002")+dequote(value);
|
||||
return name;
|
||||
std::string name;
|
||||
if (key.length()==1 && isalpha(key[0])) {
|
||||
name += std::string("\001")+key;
|
||||
} else {
|
||||
name += std::string("\001")+dequote(key);
|
||||
}
|
||||
name += std::string("\002")+dequote(value);
|
||||
return name;
|
||||
}
|
||||
static std::string combineHier(const std::string& old, const std::string& add) VL_PURE {
|
||||
// (foo.a.x, foo.b.x) => foo.*.x
|
||||
// (foo.a.x, foo.b.y) => foo.*
|
||||
// (foo.a.x, foo.b) => foo.*
|
||||
if (old == add) return add;
|
||||
// (foo.a.x, foo.b.x) => foo.*.x
|
||||
// (foo.a.x, foo.b.y) => foo.*
|
||||
// (foo.a.x, foo.b) => foo.*
|
||||
if (old == add) return add;
|
||||
if (old.empty()) return add;
|
||||
if (add.empty()) return old;
|
||||
|
||||
const char* a = old.c_str();
|
||||
const char* b = add.c_str();
|
||||
const char* a = old.c_str();
|
||||
const char* b = add.c_str();
|
||||
|
||||
// Scan forward to first mismatch
|
||||
const char* apre = a;
|
||||
const char* bpre = b;
|
||||
while (*apre == *bpre) { apre++; bpre++; }
|
||||
// Scan forward to first mismatch
|
||||
const char* apre = a;
|
||||
const char* bpre = b;
|
||||
while (*apre == *bpre) { apre++; bpre++; }
|
||||
|
||||
// We used to backup and split on only .'s but it seems better to be verbose
|
||||
// and not assume . is the separator
|
||||
std::string prefix = std::string(a,apre-a);
|
||||
// We used to backup and split on only .'s but it seems better to be verbose
|
||||
// and not assume . is the separator
|
||||
std::string prefix = std::string(a, apre-a);
|
||||
|
||||
// Scan backward to last mismatch
|
||||
const char* apost = a+strlen(a)-1;
|
||||
const char* bpost = b+strlen(b)-1;
|
||||
while (*apost == *bpost
|
||||
&& apost>apre && bpost>bpre) { apost--; bpost--; }
|
||||
// Scan backward to last mismatch
|
||||
const char* apost = a+strlen(a)-1;
|
||||
const char* bpost = b+strlen(b)-1;
|
||||
while (*apost == *bpost
|
||||
&& apost>apre && bpost>bpre) { apost--; bpost--; }
|
||||
|
||||
// Forward to . so we have a whole word
|
||||
std::string suffix = *bpost ? std::string(bpost+1) : "";
|
||||
// Forward to . so we have a whole word
|
||||
std::string suffix = *bpost ? std::string(bpost+1) : "";
|
||||
|
||||
std::string out = prefix+"*"+suffix;
|
||||
std::string out = prefix+"*"+suffix;
|
||||
|
||||
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
|
||||
return out;
|
||||
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
|
||||
return out;
|
||||
}
|
||||
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match) VL_REQUIRES(m_mutex) {
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
if (itemp->m_keys[i] != KEY_UNDEF) {
|
||||
// We don't compare keys, only values
|
||||
std::string val = m_indexValues[itemp->m_vals[i]];
|
||||
if (std::string::npos != val.find(match)) { // Found
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
if (itemp->m_keys[i] != KEY_UNDEF) {
|
||||
// We don't compare keys, only values
|
||||
std::string val = m_indexValues[itemp->m_vals[i]];
|
||||
if (std::string::npos != val.find(match)) { // Found
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
static void selftest() VL_MT_SAFE {
|
||||
// Little selftest
|
||||
if (combineHier ("a.b.c","a.b.c") !="a.b.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("a.b.c","a.b") !="a.b*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("a.x.c","a.y.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("a.z.z.z.c","a.b.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("z","a") !="*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("q.a","q.b") !="q.*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("q.za","q.zb") !="q.z*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("1.2.3.a","9.8.7.a") !="*.a") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
// Little selftest
|
||||
if (combineHier("a.b.c","a.b.c") !="a.b.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("a.b.c","a.b") !="a.b*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("a.x.c","a.y.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("a.z.z.z.c","a.b.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("z","a") !="*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("q.a","q.b") !="q.*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("q.za","q.zb") !="q.z*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("1.2.3.a","9.8.7.a") !="*.a") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
}
|
||||
void clearGuts() VL_REQUIRES(m_mutex) {
|
||||
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
delete itemp;
|
||||
}
|
||||
m_items.clear();
|
||||
m_indexValues.clear();
|
||||
m_valueIndexes.clear();
|
||||
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
delete itemp;
|
||||
}
|
||||
m_items.clear();
|
||||
m_indexValues.clear();
|
||||
m_valueIndexes.clear();
|
||||
}
|
||||
|
||||
public:
|
||||
// PUBLIC METHODS
|
||||
void clear() VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
clearGuts();
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
clearGuts();
|
||||
}
|
||||
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
if (matchp && matchp[0]) {
|
||||
ItemList newlist;
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
if (!itemMatchesString(itemp, matchp)) {
|
||||
delete itemp;
|
||||
} else {
|
||||
newlist.push_back(itemp);
|
||||
}
|
||||
}
|
||||
m_items = newlist;
|
||||
}
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
if (matchp && matchp[0]) {
|
||||
ItemList newlist;
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
if (!itemMatchesString(itemp, matchp)) {
|
||||
delete itemp;
|
||||
} else {
|
||||
newlist.push_back(itemp);
|
||||
}
|
||||
}
|
||||
m_items = newlist;
|
||||
}
|
||||
}
|
||||
void zero() VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
(*it)->zero();
|
||||
}
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
(*it)->zero();
|
||||
}
|
||||
}
|
||||
|
||||
// We assume there's always call to i/f/p in that order
|
||||
void inserti(VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
assert(!m_insertp);
|
||||
m_insertp = itemp;
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
assert(!m_insertp);
|
||||
m_insertp = itemp;
|
||||
}
|
||||
void insertf(const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
m_insertFilenamep = filenamep;
|
||||
m_insertLineno = lineno;
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
m_insertFilenamep = filenamep;
|
||||
m_insertLineno = lineno;
|
||||
}
|
||||
void insertp(const char* ckeyps[MAX_KEYS],
|
||||
const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
assert(m_insertp);
|
||||
// First two key/vals are filename
|
||||
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
|
||||
std::string linestr = vlCovCvtToStr(m_insertLineno);
|
||||
ckeyps[1]="lineno"; valps[1]=linestr.c_str();
|
||||
// Default page if not specified
|
||||
const char* fnstartp = m_insertFilenamep;
|
||||
while (const char* foundp = strchr(fnstartp,'/')) fnstartp=foundp+1;
|
||||
const char* fnendp = fnstartp;
|
||||
while (*fnendp && *fnendp!='.') fnendp++;
|
||||
std::string page_default = "sp_user/"+std::string(fnstartp,fnendp-fnstartp);
|
||||
ckeyps[2]="page"; valps[2]=page_default.c_str();
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
assert(m_insertp);
|
||||
// First two key/vals are filename
|
||||
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
|
||||
std::string linestr = vlCovCvtToStr(m_insertLineno);
|
||||
ckeyps[1]="lineno"; valps[1]=linestr.c_str();
|
||||
// Default page if not specified
|
||||
const char* fnstartp = m_insertFilenamep;
|
||||
while (const char* foundp = strchr(fnstartp,'/')) fnstartp = foundp+1;
|
||||
const char* fnendp = fnstartp;
|
||||
while (*fnendp && *fnendp!='.') fnendp++;
|
||||
std::string page_default = "sp_user/"+std::string(fnstartp, fnendp-fnstartp);
|
||||
ckeyps[2]="page"; valps[2]=page_default.c_str();
|
||||
|
||||
// Keys -> strings
|
||||
std::string keys[MAX_KEYS];
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
if (ckeyps[i] && ckeyps[i][0]) {
|
||||
keys[i] = ckeyps[i];
|
||||
}
|
||||
}
|
||||
// Ignore empty keys
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
// Keys -> strings
|
||||
std::string keys[MAX_KEYS];
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
if (ckeyps[i] && ckeyps[i][0]) {
|
||||
keys[i] = ckeyps[i];
|
||||
}
|
||||
}
|
||||
// Ignore empty keys
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
if (!keys[i].empty()) {
|
||||
for (int j=i+1; j<MAX_KEYS; ++j) {
|
||||
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
|
||||
keys[i] = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Insert the values
|
||||
int addKeynum=0;
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
const std::string key = keys[i];
|
||||
for (int j=i+1; j<MAX_KEYS; ++j) {
|
||||
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
|
||||
keys[i] = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Insert the values
|
||||
int addKeynum = 0;
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
const std::string key = keys[i];
|
||||
if (!keys[i].empty()) {
|
||||
const std::string val = valps[i];
|
||||
//cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
|
||||
m_insertp->m_keys[addKeynum] = valueIndex(key);
|
||||
m_insertp->m_vals[addKeynum] = valueIndex(val);
|
||||
addKeynum++;
|
||||
if (!legalKey(key)) {
|
||||
std::string msg = "%Error: Coverage keys of one character, or letter+digit are illegal: "+key;
|
||||
VL_FATAL_MT("",0,"",msg.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
m_items.push_back(m_insertp);
|
||||
// Prepare for next
|
||||
m_insertp = NULL;
|
||||
const std::string val = valps[i];
|
||||
//cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
|
||||
m_insertp->m_keys[addKeynum] = valueIndex(key);
|
||||
m_insertp->m_vals[addKeynum] = valueIndex(val);
|
||||
addKeynum++;
|
||||
if (!legalKey(key)) {
|
||||
std::string msg = "%Error: Coverage keys of one character, or letter+digit are illegal: "+key;
|
||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
m_items.push_back(m_insertp);
|
||||
// Prepare for next
|
||||
m_insertp = NULL;
|
||||
}
|
||||
|
||||
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
#ifndef VM_COVERAGE
|
||||
VL_FATAL_MT("",0,"","%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
||||
VL_FATAL_MT("", 0, "", "%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
||||
#endif
|
||||
selftest();
|
||||
selftest();
|
||||
|
||||
std::ofstream os(filename);
|
||||
if (os.fail()) {
|
||||
std::string msg = std::string("%Error: Can't write '")+filename+"'";
|
||||
VL_FATAL_MT("",0,"",msg.c_str());
|
||||
return;
|
||||
}
|
||||
os << "# SystemC::Coverage-3\n";
|
||||
if (os.fail()) {
|
||||
std::string msg = std::string("%Error: Can't write '")+filename+"'";
|
||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||
return;
|
||||
}
|
||||
os << "# SystemC::Coverage-3\n";
|
||||
|
||||
// Build list of events; totalize if collapsing hierarchy
|
||||
typedef std::map<std::string,std::pair<std::string,vluint64_t> > EventMap;
|
||||
EventMap eventCounts;
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
std::string name;
|
||||
std::string hier;
|
||||
bool per_instance = false;
|
||||
// Build list of events; totalize if collapsing hierarchy
|
||||
typedef std::map<std::string,std::pair<std::string,vluint64_t> > EventMap;
|
||||
EventMap eventCounts;
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
std::string name;
|
||||
std::string hier;
|
||||
bool per_instance = false;
|
||||
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
if (itemp->m_keys[i] != KEY_UNDEF) {
|
||||
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
|
||||
std::string val = m_indexValues[itemp->m_vals[i]];
|
||||
if (key == VL_CIK_PER_INSTANCE) {
|
||||
if (val != "0") per_instance = true;
|
||||
}
|
||||
if (key == VL_CIK_HIER) {
|
||||
hier = val;
|
||||
} else {
|
||||
// Print it
|
||||
name += keyValueFormatter(key,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (per_instance) { // Not collapsing hierarchies
|
||||
name += keyValueFormatter(VL_CIK_HIER,hier);
|
||||
hier = "";
|
||||
}
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
if (itemp->m_keys[i] != KEY_UNDEF) {
|
||||
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
|
||||
std::string val = m_indexValues[itemp->m_vals[i]];
|
||||
if (key == VL_CIK_PER_INSTANCE) {
|
||||
if (val != "0") per_instance = true;
|
||||
}
|
||||
if (key == VL_CIK_HIER) {
|
||||
hier = val;
|
||||
} else {
|
||||
// Print it
|
||||
name += keyValueFormatter(key, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (per_instance) { // Not collapsing hierarchies
|
||||
name += keyValueFormatter(VL_CIK_HIER, hier);
|
||||
hier = "";
|
||||
}
|
||||
|
||||
// Group versus point labels don't matter here, downstream
|
||||
// deals with it. Seems bad for sizing though and doesn't
|
||||
// allow easy addition of new group codes (would be
|
||||
// inefficient)
|
||||
// Group versus point labels don't matter here, downstream
|
||||
// deals with it. Seems bad for sizing though and doesn't
|
||||
// allow easy addition of new group codes (would be
|
||||
// inefficient)
|
||||
|
||||
// Find or insert the named event
|
||||
EventMap::iterator cit = eventCounts.find(name);
|
||||
if (cit != eventCounts.end()) {
|
||||
const std::string& oldhier = cit->second.first;
|
||||
cit->second.second += itemp->count();
|
||||
cit->second.first = combineHier(oldhier, hier);
|
||||
} else {
|
||||
eventCounts.insert(std::make_pair(name, make_pair(hier,itemp->count())));
|
||||
}
|
||||
}
|
||||
// Find or insert the named event
|
||||
EventMap::iterator cit = eventCounts.find(name);
|
||||
if (cit != eventCounts.end()) {
|
||||
const std::string& oldhier = cit->second.first;
|
||||
cit->second.second += itemp->count();
|
||||
cit->second.first = combineHier(oldhier, hier);
|
||||
} else {
|
||||
eventCounts.insert(std::make_pair(name, make_pair(hier, itemp->count())));
|
||||
}
|
||||
}
|
||||
|
||||
// Output body
|
||||
for (EventMap::const_iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
|
||||
os<<"C '"<<std::dec;
|
||||
os<<it->first;
|
||||
if (!it->second.first.empty()) os<<keyValueFormatter(VL_CIK_HIER,it->second.first);
|
||||
os<<"' "<<it->second.second;
|
||||
os<<std::endl;
|
||||
}
|
||||
// Output body
|
||||
for (EventMap::const_iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
|
||||
os<<"C '"<<std::dec;
|
||||
os<<it->first;
|
||||
if (!it->second.first.empty()) os<<keyValueFormatter(VL_CIK_HIER, it->second.first);
|
||||
os<<"' "<<it->second.second;
|
||||
os<<std::endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -420,7 +420,7 @@ void VerilatedCov::_inserti(vluint64_t* itemp) VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint64_t>(itemp));
|
||||
}
|
||||
void VerilatedCov::_insertf(const char* filename, int lineno) VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().insertf(filename,lineno);
|
||||
VerilatedCovImp::imp().insertf(filename, lineno);
|
||||
}
|
||||
|
||||
#define K(n) const char* key ## n
|
||||
@@ -446,14 +446,14 @@ void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
|
||||
// And versions with fewer arguments (oh for a language with named parameters!)
|
||||
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)) VL_MT_SAFE {
|
||||
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
|
||||
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
|
||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
|
||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||
}
|
||||
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
|
||||
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)) VL_MT_SAFE {
|
||||
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
|
||||
C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19),
|
||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||
C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19),
|
||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||
}
|
||||
// Backward compatibility for Verilator
|
||||
void VerilatedCov::_insertp(A(0), A(1), K(2),int val2, K(3),int val3,
|
||||
@@ -461,10 +461,10 @@ void VerilatedCov::_insertp(A(0), A(1), K(2),int val2, K(3),int val3,
|
||||
std::string val2str = vlCovCvtToStr(val2);
|
||||
std::string val3str = vlCovCvtToStr(val3);
|
||||
_insertp(C(0),C(1),
|
||||
key2,val2str.c_str(), key3,val3str.c_str(), key4, val4.c_str(),
|
||||
C(5),C(6),N(7),N(8),N(9),
|
||||
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
|
||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||
key2,val2str.c_str(), key3,val3str.c_str(), key4, val4.c_str(),
|
||||
C(5),C(6),N(7),N(8),N(9),
|
||||
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
|
||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||
}
|
||||
#undef A
|
||||
#undef C
|
||||
|
||||
+19
-19
@@ -44,31 +44,31 @@
|
||||
/// The value may be a string, or another type which will be auto-converted to a string.
|
||||
///
|
||||
/// Some typical keys:
|
||||
/// filename File the recording occurs in. Defaults to __FILE__
|
||||
/// lineno Line number the recording occurs in. Defaults to __LINE__
|
||||
/// column Column number (or occurrence# for dup file/lines). Defaults to undef.
|
||||
/// hier Hierarchical name. Defaults to name()
|
||||
/// type Type of coverage. Defaults to "user"
|
||||
/// Other types are 'block', 'fsm', 'toggle'.
|
||||
/// comment Description of the coverage event. Should be set by the user.
|
||||
/// Comments for type==block: 'if', 'else', 'elsif', 'case'
|
||||
/// thresh Threshold to consider fully covered.
|
||||
/// If unspecified, downstream tools will determine it.
|
||||
/// filename File the recording occurs in. Defaults to __FILE__
|
||||
/// lineno Line number the recording occurs in. Defaults to __LINE__
|
||||
/// column Column number (or occurrence# for dup file/lines). Defaults to undef.
|
||||
/// hier Hierarchical name. Defaults to name()
|
||||
/// type Type of coverage. Defaults to "user"
|
||||
/// Other types are 'block', 'fsm', 'toggle'.
|
||||
/// comment Description of the coverage event. Should be set by the user.
|
||||
/// Comments for type==block: 'if', 'else', 'elsif', 'case'
|
||||
/// thresh Threshold to consider fully covered.
|
||||
/// If unspecified, downstream tools will determine it.
|
||||
///
|
||||
/// Examples:
|
||||
///
|
||||
/// vluint32_t m_cases[10];
|
||||
/// constructor {
|
||||
/// for (int i=0; i<10; ++i) { m_cases[i]=0; }
|
||||
/// vluint32_t m_cases[10];
|
||||
/// constructor {
|
||||
/// for (int i=0; i<10; ++i) { m_cases[i]=0; }
|
||||
/// }
|
||||
/// for (int i=0; i<10; ++i) {
|
||||
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
|
||||
/// }
|
||||
/// for (int i=0; i<10; ++i) {
|
||||
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
|
||||
/// }
|
||||
|
||||
#define VL_COVER_INSERT(countp,args...) \
|
||||
VL_IF_COVER(VerilatedCov::_inserti(countp); \
|
||||
VerilatedCov::_insertf(__FILE__,__LINE__); \
|
||||
VerilatedCov::_insertp("hier", name(), args))
|
||||
VL_IF_COVER(VerilatedCov::_inserti(countp); \
|
||||
VerilatedCov::_insertf(__FILE__,__LINE__); \
|
||||
VerilatedCov::_insertp("hier", name(), args))
|
||||
|
||||
//=============================================================================
|
||||
/// Convert VL_COVER_INSERT value arguments to strings
|
||||
|
||||
@@ -24,6 +24,12 @@
|
||||
#include "verilated.h"
|
||||
#include "verilated_fst_c.h"
|
||||
|
||||
// GTKWave configuration
|
||||
#ifdef VL_TRACE_THREADED
|
||||
# define HAVE_LIBPTHREAD
|
||||
# define FST_WRITER_PARALLEL
|
||||
#endif
|
||||
|
||||
// Include the GTKWave implementation directly
|
||||
#include "gtkwave/fastlz.c"
|
||||
#include "gtkwave/fstapi.c"
|
||||
@@ -72,6 +78,10 @@ VerilatedFst::VerilatedFst(void* fst)
|
||||
void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
|
||||
m_assertOne.check();
|
||||
m_fst = fstWriterCreate(filename, 1);
|
||||
fstWriterSetPackType(m_fst, FST_WR_PT_LZ4);
|
||||
#ifdef VL_TRACE_THREADED
|
||||
fstWriterSetParallelMode(m_fst, 1);
|
||||
#endif
|
||||
m_curScope.clear();
|
||||
|
||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
|
||||
|
||||
+149
-145
@@ -92,32 +92,32 @@ public:
|
||||
// METHODS
|
||||
//// Add message to queue (called by producer)
|
||||
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
m_queue.insert(msg); // Pass by value to copy the message into queue
|
||||
++m_depth;
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
m_queue.insert(msg); // Pass by value to copy the message into queue
|
||||
++m_depth;
|
||||
}
|
||||
/// Service queue until completion (called by consumer)
|
||||
void process() VL_EXCLUDES(m_mutex) {
|
||||
// Tracking m_depth is redundant to e.g. getting the mutex and looking at queue size,
|
||||
// but on the reader side it's 4x faster to test an atomic then getting a mutex
|
||||
while (m_depth) {
|
||||
// Wait for a message to be added to the queue
|
||||
// We don't use unique_lock as want to unlock with the message copy still in scope
|
||||
// Tracking m_depth is redundant to e.g. getting the mutex and looking at queue size,
|
||||
// but on the reader side it's 4x faster to test an atomic then getting a mutex
|
||||
while (m_depth) {
|
||||
// Wait for a message to be added to the queue
|
||||
// We don't use unique_lock as want to unlock with the message copy still in scope
|
||||
m_mutex.lock();
|
||||
assert(!m_queue.empty()); // Otherwise m_depth is wrong
|
||||
// Unfortunately to release the lock we need to copy the message
|
||||
// (Or have the message be a pointer, but then new/delete cost on each message)
|
||||
// We assume messages are small, so copy
|
||||
auto it = m_queue.begin();
|
||||
const VerilatedMsg msg = *(it);
|
||||
m_queue.erase(it);
|
||||
m_mutex.unlock();
|
||||
m_depth--; // Ok if outside critical section as only this code checks the value
|
||||
{
|
||||
// (Or have the message be a pointer, but then new/delete cost on each message)
|
||||
// We assume messages are small, so copy
|
||||
auto it = m_queue.begin();
|
||||
const VerilatedMsg msg = *(it);
|
||||
m_queue.erase(it);
|
||||
m_mutex.unlock();
|
||||
m_depth--; // Ok if outside critical section as only this code checks the value
|
||||
{
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("Executing callback from mtaskId=%d\n", msg.mtaskId()););
|
||||
msg.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -128,15 +128,15 @@ public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedThreadMsgQueue() { }
|
||||
~VerilatedThreadMsgQueue() {
|
||||
// The only call of this with a non-empty queue is a fatal error.
|
||||
// So this does not flush the queue, as the destination queue is not known to this class.
|
||||
// The only call of this with a non-empty queue is a fatal error.
|
||||
// So this does not flush the queue, as the destination queue is not known to this class.
|
||||
}
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
|
||||
// METHODS
|
||||
static VerilatedThreadMsgQueue& threadton() {
|
||||
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
|
||||
return t_s;
|
||||
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
|
||||
return t_s;
|
||||
}
|
||||
public:
|
||||
/// Add message to queue, called by producer
|
||||
@@ -153,11 +153,11 @@ public:
|
||||
}
|
||||
/// Push all messages to the eval's queue
|
||||
static void flush(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
while (!threadton().m_queue.empty()) {
|
||||
evalMsgQp->post(threadton().m_queue.front());
|
||||
threadton().m_queue.pop();
|
||||
Verilated::endOfEvalReqdDec();
|
||||
}
|
||||
while (!threadton().m_queue.empty()) {
|
||||
evalMsgQp->post(threadton().m_queue.front());
|
||||
threadton().m_queue.pop();
|
||||
Verilated::endOfEvalReqdDec();
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // VL_THREADED
|
||||
@@ -200,11 +200,11 @@ class VerilatedImp {
|
||||
public: // But only for verilated*.cpp
|
||||
// CONSTRUCTORS
|
||||
VerilatedImp()
|
||||
: m_argVecLoaded(false), m_exportNext(0) {
|
||||
m_fdps.resize(3);
|
||||
m_fdps[0] = stdin;
|
||||
m_fdps[1] = stdout;
|
||||
m_fdps[2] = stderr;
|
||||
: m_argVecLoaded(false), m_exportNext(0) {
|
||||
m_fdps.resize(3);
|
||||
m_fdps[0] = stdin;
|
||||
m_fdps[1] = stdout;
|
||||
m_fdps[2] = stderr;
|
||||
}
|
||||
~VerilatedImp() {}
|
||||
private:
|
||||
@@ -219,21 +219,21 @@ public:
|
||||
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
|
||||
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
|
||||
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
|
||||
VerilatedLockGuard lock(s_s.m_argMutex);
|
||||
// Note prefixp does not include the leading "+"
|
||||
size_t len = strlen(prefixp);
|
||||
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
|
||||
s_s.m_argVecLoaded = true; // Complain only once
|
||||
VL_FATAL_MT("unknown",0,"",
|
||||
"%Error: Verilog called $test$plusargs or $value$plusargs without"
|
||||
" testbench C first calling Verilated::commandArgs(argc,argv).");
|
||||
}
|
||||
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
||||
if ((*it)[0]=='+') {
|
||||
if (0==strncmp(prefixp, it->c_str()+1, len)) return *it;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
VerilatedLockGuard lock(s_s.m_argMutex);
|
||||
// Note prefixp does not include the leading "+"
|
||||
size_t len = strlen(prefixp);
|
||||
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
|
||||
s_s.m_argVecLoaded = true; // Complain only once
|
||||
VL_FATAL_MT("unknown", 0, "",
|
||||
"%Error: Verilog called $test$plusargs or $value$plusargs without"
|
||||
" testbench C first calling Verilated::commandArgs(argc,argv).");
|
||||
}
|
||||
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
||||
if ((*it)[0]=='+') {
|
||||
if (0==strncmp(prefixp, it->c_str()+1, len)) return *it;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
private:
|
||||
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex);
|
||||
@@ -247,75 +247,77 @@ public:
|
||||
// There's often many more scopes than userdata's and thus having a ~48byte
|
||||
// per map overhead * N scopes would take much more space and cache thrashing.
|
||||
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
|
||||
if (it != s_s.m_userMap.end()) it->second = userData;
|
||||
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
|
||||
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep,userKey),userData));
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep, userKey));
|
||||
if (it != s_s.m_userMap.end()) it->second = userData;
|
||||
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
|
||||
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData));
|
||||
}
|
||||
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
|
||||
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
|
||||
else return NULL;
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep, userKey));
|
||||
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
|
||||
else return NULL;
|
||||
}
|
||||
private:
|
||||
/// Symbol table destruction cleans up the entries for each scope.
|
||||
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope on destruction, so we simply iterate.
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
|
||||
if (it->first.first == scopep) {
|
||||
s_s.m_userMap.erase(it++);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
// Slow ok - called once/scope on destruction, so we simply iterate.
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
|
||||
if (it->first.first == scopep) {
|
||||
s_s.m_userMap.erase(it++);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void userDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
|
||||
bool first = true;
|
||||
for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
|
||||
if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; }
|
||||
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n",
|
||||
it->first.first, it->first.second, it->second);
|
||||
}
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
|
||||
bool first = true;
|
||||
for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
|
||||
if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; }
|
||||
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n",
|
||||
it->first.first, it->first.second, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - scope name
|
||||
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope at construction
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||
if (it == s_s.m_nameMap.end()) {
|
||||
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(),scopep));
|
||||
}
|
||||
// Slow ok - called once/scope at construction
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||
if (it == s_s.m_nameMap.end()) {
|
||||
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
|
||||
}
|
||||
}
|
||||
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex); // If too slow, can assume this is only VL_MT_SAFE_POSINIT
|
||||
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
|
||||
else return NULL;
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
// If too slow, can assume this is only VL_MT_SAFE_POSINIT
|
||||
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
|
||||
else return NULL;
|
||||
}
|
||||
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope at destruction
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
userEraseScope(scopep);
|
||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
||||
// Slow ok - called once/scope at destruction
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
userEraseScope(scopep);
|
||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
||||
}
|
||||
static void scopesDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
VL_PRINTF_MT(" scopesDump:\n");
|
||||
for (VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) {
|
||||
const VerilatedScope* scopep = it->second;
|
||||
scopep->scopeDump();
|
||||
}
|
||||
VL_PRINTF_MT("\n");
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
VL_PRINTF_MT(" scopesDump:\n");
|
||||
for (VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.begin();
|
||||
it!=s_s.m_nameMap.end(); ++it) {
|
||||
const VerilatedScope* scopep = it->second;
|
||||
scopep->scopeDump();
|
||||
}
|
||||
VL_PRINTF_MT("\n");
|
||||
}
|
||||
static const VerilatedScopeNameMap* scopeNameMap() VL_MT_SAFE_POSTINIT {
|
||||
// Thread save only assuming this is called only after model construction completed
|
||||
// Thread save only assuming this is called only after model construction completed
|
||||
return &s_s.m_nameMap;
|
||||
}
|
||||
|
||||
@@ -329,40 +331,42 @@ public: // But only for verilated*.cpp
|
||||
// Rather than a 2D map, the integer scheme saves 500ish ns on a likely
|
||||
// miss at the cost of a multiply, and all lookups move to slowpath.
|
||||
static int exportInsert(const char* namep) VL_MT_SAFE {
|
||||
// Slow ok - called once/function at creation
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
|
||||
if (it == s_s.m_exportMap.end()) {
|
||||
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
|
||||
return s_s.m_exportNext++;
|
||||
} else {
|
||||
return it->second;
|
||||
}
|
||||
// Slow ok - called once/function at creation
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
|
||||
if (it == s_s.m_exportMap.end()) {
|
||||
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
|
||||
return s_s.m_exportNext++;
|
||||
} else {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
static int exportFind(const char* namep) VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
ExportNameMap::const_iterator it=s_s.m_exportMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
|
||||
std::string msg = (std::string("%Error: Testbench C called ")+namep
|
||||
+" but no such DPI export function name exists in ANY model");
|
||||
VL_FATAL_MT("unknown",0,"", msg.c_str());
|
||||
return -1;
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
ExportNameMap::const_iterator it=s_s.m_exportMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
|
||||
std::string msg = (std::string("%Error: Testbench C called ")+namep
|
||||
+" but no such DPI export function name exists in ANY model");
|
||||
VL_FATAL_MT("unknown", 0, "", msg.c_str());
|
||||
return -1;
|
||||
}
|
||||
static const char* exportName(int funcnum) VL_MT_SAFE {
|
||||
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
||||
if (it->second == funcnum) return it->first;
|
||||
}
|
||||
return "*UNKNOWN*";
|
||||
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin();
|
||||
it!=s_s.m_exportMap.end(); ++it) {
|
||||
if (it->second == funcnum) return it->first;
|
||||
}
|
||||
return "*UNKNOWN*";
|
||||
}
|
||||
static void exportsDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
bool first = true;
|
||||
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
||||
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
|
||||
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
|
||||
}
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
bool first = true;
|
||||
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin();
|
||||
it!=s_s.m_exportMap.end(); ++it) {
|
||||
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
|
||||
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
|
||||
}
|
||||
}
|
||||
// We don't free up m_exportMap until the end, because we can't be sure
|
||||
// what other models are using the assigned funcnum's.
|
||||
@@ -370,32 +374,32 @@ public: // But only for verilated*.cpp
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - file IO
|
||||
static IData fdNew(FILE* fp) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
// Bit 31 indicates it's a descriptor not a MCD
|
||||
VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
if (s_s.m_fdFree.empty()) {
|
||||
// Need to create more space in m_fdps and m_fdFree
|
||||
size_t start = s_s.m_fdps.size();
|
||||
s_s.m_fdps.resize(start*2);
|
||||
for (size_t i=start; i<start*2; ++i) s_s.m_fdFree.push_back(static_cast<IData>(i));
|
||||
}
|
||||
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
|
||||
s_s.m_fdps[idx] = fp;
|
||||
return (idx | (1UL<<31)); // bit 31 indicates not MCD
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
// Bit 31 indicates it's a descriptor not a MCD
|
||||
VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
if (s_s.m_fdFree.empty()) {
|
||||
// Need to create more space in m_fdps and m_fdFree
|
||||
size_t start = s_s.m_fdps.size();
|
||||
s_s.m_fdps.resize(start*2);
|
||||
for (size_t i=start; i<start*2; ++i) s_s.m_fdFree.push_back(static_cast<IData>(i));
|
||||
}
|
||||
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
|
||||
s_s.m_fdps[idx] = fp;
|
||||
return (idx | (1UL<<31)); // bit 31 indicates not MCD
|
||||
}
|
||||
static void fdDelete(IData fdi) VL_MT_SAFE {
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
|
||||
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
|
||||
s_s.m_fdps[idx] = NULL;
|
||||
s_s.m_fdFree.push_back(idx);
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
|
||||
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
|
||||
s_s.m_fdps[idx] = NULL;
|
||||
s_s.m_fdFree.push_back(idx);
|
||||
}
|
||||
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
|
||||
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
|
||||
return s_s.m_fdps[idx];
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
|
||||
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
|
||||
return s_s.m_fdps[idx];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+57
-59
@@ -56,17 +56,17 @@ bool VerilatedDeserialize::readDiffers(const void* __restrict datap, size_t size
|
||||
const vluint8_t* __restrict dp = static_cast<const vluint8_t* __restrict>(datap);
|
||||
vluint8_t miss = 0;
|
||||
while (size--) {
|
||||
miss |= (*dp++ ^ *m_cp++);
|
||||
miss |= (*dp++ ^ *m_cp++);
|
||||
}
|
||||
return (miss!=0);
|
||||
}
|
||||
|
||||
VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||
if (VL_UNLIKELY(readDiffers(datap,size))) {
|
||||
std::string fn = filename();
|
||||
std::string msg = std::string("Can't deserialize save-restore file as was made from different model");
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
if (VL_UNLIKELY(readDiffers(datap, size))) {
|
||||
std::string fn = filename();
|
||||
std::string msg = std::string("Can't deserialize save-restore file as was made from different model");
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
@@ -84,10 +84,10 @@ void VerilatedSerialize::header() VL_MT_UNSAFE_ONE {
|
||||
void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
|
||||
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
|
||||
std::string fn = filename();
|
||||
std::string msg = std::string("Can't deserialize; file has wrong header signature");
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
std::string fn = filename();
|
||||
std::string msg = std::string("Can't deserialize; file has wrong header signature");
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
}
|
||||
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
|
||||
}
|
||||
@@ -101,10 +101,10 @@ void VerilatedSerialize::trailer() VL_MT_UNSAFE_ONE {
|
||||
void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
|
||||
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
|
||||
std::string fn = filename();
|
||||
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature");
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
std::string fn = filename();
|
||||
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature");
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,19 +116,19 @@ void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
|
||||
void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
||||
m_assertOne.check();
|
||||
if (isOpen()) return;
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n",filenamep););
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n", filenamep););
|
||||
|
||||
if (filenamep[0]=='|') {
|
||||
assert(0); // Not supported yet.
|
||||
} else {
|
||||
// cppcheck-suppress duplicateExpression
|
||||
// cppcheck-suppress duplicateExpression
|
||||
m_fd = ::open(filenamep, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK|O_CLOEXEC
|
||||
, 0666);
|
||||
if (m_fd<0) {
|
||||
// User code can check isOpen()
|
||||
m_isOpen = false;
|
||||
return;
|
||||
}
|
||||
if (m_fd<0) {
|
||||
// User code can check isOpen()
|
||||
m_isOpen = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_isOpen = true;
|
||||
m_filename = filenamep;
|
||||
@@ -139,19 +139,19 @@ void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
||||
void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
||||
m_assertOne.check();
|
||||
if (isOpen()) return;
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n",filenamep););
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n", filenamep););
|
||||
|
||||
if (filenamep[0]=='|') {
|
||||
assert(0); // Not supported yet.
|
||||
} else {
|
||||
// cppcheck-suppress duplicateExpression
|
||||
// cppcheck-suppress duplicateExpression
|
||||
m_fd = ::open(filenamep, O_CREAT|O_RDONLY|O_LARGEFILE|O_CLOEXEC
|
||||
, 0666);
|
||||
if (m_fd<0) {
|
||||
// User code can check isOpen()
|
||||
m_isOpen = false;
|
||||
return;
|
||||
}
|
||||
if (m_fd<0) {
|
||||
// User code can check isOpen()
|
||||
m_isOpen = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_isOpen = true;
|
||||
m_filename = filenamep;
|
||||
@@ -184,21 +184,21 @@ void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
|
||||
if (VL_UNLIKELY(!isOpen())) return;
|
||||
vluint8_t* wp = m_bufp;
|
||||
while (1) {
|
||||
ssize_t remaining = (m_cp - wp);
|
||||
if (remaining==0) break;
|
||||
errno = 0;
|
||||
ssize_t remaining = (m_cp - wp);
|
||||
if (remaining==0) break;
|
||||
errno = 0;
|
||||
ssize_t got = ::write(m_fd, wp, remaining);
|
||||
if (got>0) {
|
||||
wp += got;
|
||||
} else if (got < 0) {
|
||||
if (errno != EAGAIN && errno != EINTR) {
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
||||
VL_FATAL_MT("",0,"",msg.c_str());
|
||||
close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (got>0) {
|
||||
wp += got;
|
||||
} else if (got < 0) {
|
||||
if (errno != EAGAIN && errno != EINTR) {
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||
close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_cp = m_bufp; // Reset buffer
|
||||
}
|
||||
@@ -213,30 +213,28 @@ void VerilatedRestore::fill() VL_MT_UNSAFE_ONE {
|
||||
m_cp = m_bufp; // Reset buffer
|
||||
// Read into buffer starting at m_endp
|
||||
while (1) {
|
||||
ssize_t remaining = (m_bufp+bufferSize() - m_endp);
|
||||
if (remaining==0) break;
|
||||
errno = 0;
|
||||
ssize_t remaining = (m_bufp+bufferSize() - m_endp);
|
||||
if (remaining==0) break;
|
||||
errno = 0;
|
||||
ssize_t got = ::read(m_fd, m_endp, remaining);
|
||||
if (got>0) {
|
||||
m_endp += got;
|
||||
} else if (got < 0) {
|
||||
if (errno != EAGAIN && errno != EINTR) {
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
||||
VL_FATAL_MT("",0,"",msg.c_str());
|
||||
close();
|
||||
break;
|
||||
if (got>0) {
|
||||
m_endp += got;
|
||||
} else if (got < 0) {
|
||||
if (errno != EAGAIN && errno != EINTR) {
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||
close();
|
||||
break;
|
||||
}
|
||||
} else { // got==0, EOF
|
||||
// Fill buffer from here to end with NULLs so reader's don't
|
||||
// need to check eof each character.
|
||||
while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0';
|
||||
break;
|
||||
}
|
||||
while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Serialization of types
|
||||
|
||||
|
||||
|
||||
+55
-55
@@ -34,10 +34,10 @@ class VerilatedSerialize {
|
||||
protected:
|
||||
// MEMBERS
|
||||
// For speed, keep m_cp as the first member of this structure
|
||||
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
||||
vluint8_t* m_bufp; ///< Output buffer
|
||||
bool m_isOpen; ///< True indicates open file/stream
|
||||
std::string m_filename; ///< Filename, for error messages
|
||||
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
||||
vluint8_t* m_bufp; ///< Output buffer
|
||||
bool m_isOpen; ///< True indicates open file/stream
|
||||
std::string m_filename; ///< Filename, for error messages
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
|
||||
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
||||
@@ -50,13 +50,13 @@ protected:
|
||||
VL_UNCOPYABLE(VerilatedSerialize);
|
||||
public:
|
||||
VerilatedSerialize() {
|
||||
m_isOpen = false;
|
||||
m_bufp = new vluint8_t [bufferSize()];
|
||||
m_cp = m_bufp;
|
||||
m_isOpen = false;
|
||||
m_bufp = new vluint8_t [bufferSize()];
|
||||
m_cp = m_bufp;
|
||||
}
|
||||
virtual ~VerilatedSerialize() {
|
||||
close();
|
||||
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
||||
close();
|
||||
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
||||
}
|
||||
// METHODS
|
||||
bool isOpen() const { return m_isOpen; }
|
||||
@@ -64,24 +64,24 @@ public:
|
||||
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
|
||||
virtual void flush() VL_MT_UNSAFE_ONE {}
|
||||
inline VerilatedSerialize& write(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
|
||||
while (size) {
|
||||
bufferCheck();
|
||||
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
||||
const vluint8_t* __restrict maxp = dp + blk;
|
||||
while (dp < maxp) *m_cp++ = *dp++;
|
||||
size -= blk;
|
||||
}
|
||||
return *this; // For function chaining
|
||||
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
|
||||
while (size) {
|
||||
bufferCheck();
|
||||
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
||||
const vluint8_t* __restrict maxp = dp + blk;
|
||||
while (dp < maxp) *m_cp++ = *dp++;
|
||||
size -= blk;
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
private:
|
||||
VerilatedSerialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
||||
// Flush the write buffer if there's not enough space left for new information
|
||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
|
||||
flush();
|
||||
}
|
||||
return *this; // For function chaining
|
||||
// Flush the write buffer if there's not enough space left for new information
|
||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
|
||||
flush();
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
};
|
||||
|
||||
@@ -93,12 +93,12 @@ class VerilatedDeserialize {
|
||||
protected:
|
||||
// MEMBERS
|
||||
// For speed, keep m_cp as the first member of this structure
|
||||
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
||||
vluint8_t* m_bufp; ///< Output buffer
|
||||
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
|
||||
bool m_isOpen; ///< True indicates open file/stream
|
||||
std::string m_filename; ///< Filename, for error messages
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
||||
vluint8_t* m_bufp; ///< Output buffer
|
||||
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
|
||||
bool m_isOpen; ///< True indicates open file/stream
|
||||
std::string m_filename; ///< Filename, for error messages
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
|
||||
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
||||
inline static size_t bufferInsertSize() { return 16*1024; }
|
||||
@@ -111,14 +111,14 @@ protected:
|
||||
VL_UNCOPYABLE(VerilatedDeserialize);
|
||||
public:
|
||||
VerilatedDeserialize() {
|
||||
m_isOpen = false;
|
||||
m_bufp = new vluint8_t [bufferSize()];
|
||||
m_cp = m_bufp;
|
||||
m_endp = NULL;
|
||||
m_isOpen = false;
|
||||
m_bufp = new vluint8_t [bufferSize()];
|
||||
m_cp = m_bufp;
|
||||
m_endp = NULL;
|
||||
}
|
||||
virtual ~VerilatedDeserialize() {
|
||||
close();
|
||||
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
||||
close();
|
||||
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
||||
}
|
||||
// METHODS
|
||||
bool isOpen() const { return m_isOpen; }
|
||||
@@ -126,15 +126,15 @@ public:
|
||||
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
|
||||
virtual void flush() VL_MT_UNSAFE_ONE {}
|
||||
inline VerilatedDeserialize& read(void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
|
||||
while (size) {
|
||||
bufferCheck();
|
||||
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
||||
const vluint8_t* __restrict maxp = dp + blk;
|
||||
while (dp < maxp) *dp++ = *m_cp++;
|
||||
size -= blk;
|
||||
}
|
||||
return *this; // For function chaining
|
||||
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
|
||||
while (size) {
|
||||
bufferCheck();
|
||||
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
||||
const vluint8_t* __restrict maxp = dp + blk;
|
||||
while (dp < maxp) *dp++ = *m_cp++;
|
||||
size -= blk;
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
// Read a datum and compare with expected value
|
||||
VerilatedDeserialize& readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
||||
@@ -143,12 +143,12 @@ public:
|
||||
private:
|
||||
bool readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
||||
VerilatedDeserialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
||||
// Flush the write buffer if there's not enough space left for new information
|
||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||
if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
|
||||
fill();
|
||||
}
|
||||
return *this; // For function chaining
|
||||
// Flush the write buffer if there's not enough space left for new information
|
||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||
if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
|
||||
fill();
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
};
|
||||
|
||||
@@ -158,7 +158,7 @@ private:
|
||||
|
||||
class VerilatedSave : public VerilatedSerialize {
|
||||
private:
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
@@ -177,7 +177,7 @@ public:
|
||||
|
||||
class VerilatedRestore : public VerilatedDeserialize {
|
||||
private:
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
@@ -237,12 +237,12 @@ inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, float& rhs) {
|
||||
return os.read(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, std::string& rhs) {
|
||||
vluint32_t len=rhs.length();
|
||||
vluint32_t len = rhs.length();
|
||||
os<<len;
|
||||
return os.write(rhs.data(), len);
|
||||
}
|
||||
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, std::string& rhs) {
|
||||
vluint32_t len=0;
|
||||
vluint32_t len = 0;
|
||||
os>>len;
|
||||
rhs.resize(len);
|
||||
return os.read((void*)rhs.data(), len);
|
||||
|
||||
@@ -134,17 +134,24 @@ private:
|
||||
// cppcheck-suppress functionConst
|
||||
void dumpDone();
|
||||
inline void printCode(vluint32_t code) {
|
||||
if (code>=(94*94*94)) *m_writep++ = static_cast<char>((code/94/94/94)%94+33);
|
||||
if (code>=(94*94)) *m_writep++ = static_cast<char>((code/94/94)%94+33);
|
||||
if (code>=(94)) *m_writep++ = static_cast<char>((code/94)%94+33);
|
||||
*m_writep++ = static_cast<char>((code)%94+33);
|
||||
*m_writep++ = static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
while (code) {
|
||||
code--;
|
||||
*m_writep++ = static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
}
|
||||
}
|
||||
static std::string stringCode(vluint32_t code) VL_PURE {
|
||||
std::string out;
|
||||
if (code>=(94*94*94)) out += static_cast<char>((code/94/94/94)%94+33);
|
||||
if (code>=(94*94)) out += static_cast<char>((code/94/94)%94+33);
|
||||
if (code>=(94)) out += static_cast<char>((code/94)%94+33);
|
||||
return out + static_cast<char>((code)%94+33);
|
||||
out += static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
while (code) {
|
||||
code--;
|
||||
out += static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// CONSTRUCTORS
|
||||
|
||||
+547
-529
File diff suppressed because it is too large
Load Diff
+86
-86
@@ -16,11 +16,11 @@
|
||||
/// \file
|
||||
/// \brief Verilator: Common include for OS portability (verilated & verilator)
|
||||
///
|
||||
/// This header is used by both the Verilator source code (run on the
|
||||
/// build and host system), and the Verilated output (run on the target
|
||||
/// system). Code needed by only the host system goes into
|
||||
/// config_build.h.in, code needed by Verilated code only goes into
|
||||
/// verilated.h, and code needed by both goes here (verilatedos.h).
|
||||
/// This header is used by both the Verilator source code (run on the
|
||||
/// build and host system), and the Verilated output (run on the target
|
||||
/// system). Code needed by only the host system goes into
|
||||
/// config_build.h.in, code needed by Verilated code only goes into
|
||||
/// verilated.h, and code needed by both goes here (verilatedos.h).
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
@@ -37,11 +37,7 @@
|
||||
# define VL_ATTR_ALIGNED(alignment) __attribute__ ((aligned (alignment)))
|
||||
# define VL_ATTR_ALWINLINE __attribute__ ((always_inline))
|
||||
# define VL_ATTR_NORETURN __attribute__ ((noreturn))
|
||||
# ifdef _WIN32
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) // GCC with MS runtime will fool the print arg checker
|
||||
# else
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, (fmtArgNum), (fmtArgNum)+1)))
|
||||
# endif
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, (fmtArgNum), (fmtArgNum)+1)))
|
||||
# define VL_ATTR_PURE __attribute__ ((pure))
|
||||
# define VL_ATTR_UNUSED __attribute__ ((unused))
|
||||
# define VL_FUNC __func__
|
||||
@@ -58,8 +54,8 @@
|
||||
# define VL_EXCLUDES(x) __attribute__ ((locks_excluded(x)))
|
||||
# define VL_SCOPED_CAPABILITY __attribute__ ((scoped_lockable))
|
||||
# endif
|
||||
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
# define VL_UNREACHABLE __builtin_unreachable();
|
||||
# define VL_PREFETCH_RD(p) __builtin_prefetch((p),0)
|
||||
# define VL_PREFETCH_RW(p) __builtin_prefetch((p),1)
|
||||
@@ -69,51 +65,51 @@
|
||||
|
||||
// Defaults for unsupported compiler features
|
||||
#ifndef VL_ATTR_ALIGNED
|
||||
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
|
||||
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
|
||||
#endif
|
||||
#ifndef VL_ATTR_ALWINLINE
|
||||
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
|
||||
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
|
||||
#endif
|
||||
#ifndef VL_ATTR_NORETURN
|
||||
# define VL_ATTR_NORETURN ///< Function does not ever return
|
||||
# define VL_ATTR_NORETURN ///< Function does not ever return
|
||||
#endif
|
||||
#ifndef VL_ATTR_PRINTF
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
|
||||
#endif
|
||||
#ifndef VL_ATTR_PURE
|
||||
# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE)
|
||||
# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE)
|
||||
#endif
|
||||
#ifndef VL_ATTR_UNUSED
|
||||
# define VL_ATTR_UNUSED ///< Function that may be never used
|
||||
# define VL_ATTR_UNUSED ///< Function that may be never used
|
||||
#endif
|
||||
#ifndef VL_FUNC
|
||||
# define VL_FUNC "__func__" ///< Name of current function for error macros
|
||||
# define VL_FUNC "__func__" ///< Name of current function for error macros
|
||||
#endif
|
||||
#ifndef VL_CAPABILITY
|
||||
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
|
||||
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
|
||||
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
|
||||
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
|
||||
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
|
||||
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired a shared capability (-fthread-safety)
|
||||
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
|
||||
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
|
||||
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
|
||||
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
|
||||
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
|
||||
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
|
||||
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
|
||||
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
|
||||
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
|
||||
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
|
||||
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired a shared capability (-fthread-safety)
|
||||
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
|
||||
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
|
||||
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
|
||||
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
|
||||
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
|
||||
#endif
|
||||
#ifndef VL_LIKELY
|
||||
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
|
||||
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
|
||||
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
|
||||
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
|
||||
#endif
|
||||
#ifndef VL_UNREACHABLE
|
||||
# define VL_UNREACHABLE ///< Point that may never be reached
|
||||
# define VL_UNREACHABLE ///< Point that may never be reached
|
||||
#endif
|
||||
#ifndef VL_PREFETCH_RD
|
||||
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
|
||||
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
|
||||
#endif
|
||||
#ifndef VL_PREFETCH_RW
|
||||
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
|
||||
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
|
||||
#endif
|
||||
|
||||
#ifdef VL_THREADED
|
||||
@@ -124,12 +120,12 @@
|
||||
# else
|
||||
# error "Unsupported compiler for VL_THREADED: No thread-local declarator"
|
||||
# endif
|
||||
# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread
|
||||
# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread
|
||||
#else
|
||||
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
|
||||
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
|
||||
#endif
|
||||
#define VL_THREAD ///< Deprecated
|
||||
#define VL_STATIC_OR_THREAD static ///< Deprecated
|
||||
#define VL_THREAD ///< Deprecated
|
||||
#define VL_STATIC_OR_THREAD static ///< Deprecated
|
||||
|
||||
#define VL_PURE ///< Comment tag that Function is pure (and thus also VL_MT_SAFE)
|
||||
#define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED
|
||||
@@ -138,18 +134,18 @@
|
||||
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED, protected to make sure single-caller
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define VL_ULL(c) (c##ui64) ///< Add appropriate suffix to 64-bit constant
|
||||
# define VL_ULL(c) (c##ui64) ///< Add appropriate suffix to 64-bit constant
|
||||
#else
|
||||
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
|
||||
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
|
||||
#endif
|
||||
|
||||
// This is not necessarily the same as #UL, depending on what the IData typedef is.
|
||||
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
|
||||
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
|
||||
|
||||
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__)
|
||||
# define VL_DANGLING(v)
|
||||
#else
|
||||
# define VL_DANGLING(v) do { (v) = NULL; } while(0) ///< After e.g. delete, set variable to NULL to indicate must not use later
|
||||
# define VL_DANGLING(v) do { (v) = NULL; } while(0) ///< After e.g. delete, set variable to NULL to indicate must not use later
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
@@ -180,7 +176,7 @@
|
||||
// Optimization
|
||||
|
||||
#ifndef VL_INLINE_OPT
|
||||
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
|
||||
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
@@ -207,37 +203,37 @@
|
||||
# include <stdint.h>
|
||||
# include <sys/types.h> // __WORDSIZE
|
||||
# include <unistd.h> // ssize_t
|
||||
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
|
||||
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
|
||||
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
|
||||
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
|
||||
# if defined(__uint32_t_defined) || defined(___int32_t_defined) // Newer Cygwin uint32_t in stdint.h as an unsigned int
|
||||
typedef int32_t vlsint32_t; ///< 32-bit signed type
|
||||
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
|
||||
# else // Older Cygwin has long==uint32_t
|
||||
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef long vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
|
||||
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef long vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
|
||||
# endif
|
||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||
typedef long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||
typedef long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||
# else
|
||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
# endif
|
||||
|
||||
#elif defined(_WIN32) && defined(_MSC_VER)
|
||||
|
||||
typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||
typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||
typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type
|
||||
typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type
|
||||
typedef signed __int32 vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
|
||||
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
|
||||
typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||
typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||
typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type
|
||||
typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type
|
||||
typedef signed __int32 vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
|
||||
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
|
||||
|
||||
# ifndef _SSIZE_T_DEFINED
|
||||
# ifdef _WIN64
|
||||
@@ -253,16 +249,16 @@ typedef signed __int32 ssize_t; ///< signed size_t; returned fro
|
||||
# include <stdint.h> // Linux and most flavors
|
||||
# include <sys/types.h> // __WORDSIZE
|
||||
# include <unistd.h> // ssize_t
|
||||
typedef uint8_t vluint8_t; ///< 32-bit unsigned type
|
||||
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
|
||||
typedef int vlsint32_t; ///< 32-bit signed type
|
||||
typedef uint32_t vluint32_t; ///< 32-bit signed type
|
||||
typedef uint8_t vluint8_t; ///< 32-bit unsigned type
|
||||
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
|
||||
typedef int vlsint32_t; ///< 32-bit signed type
|
||||
typedef uint32_t vluint32_t; ///< 32-bit signed type
|
||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||
typedef long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||
typedef long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||
# else
|
||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -270,10 +266,14 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
// Printing printf/scanf formats
|
||||
// Alas cinttypes isn't that standard yet
|
||||
|
||||
#ifdef _WIN32
|
||||
# define __STDC_FORMAT_MACROS 1 // Otherwise MinGW doesn't get PRId64 for fstapi.c
|
||||
// Use Microsoft-specific format specifiers for Microsoft Visual C++ only
|
||||
#ifdef _MSC_VER
|
||||
# define VL_PRI64 "I64"
|
||||
#else // Linux or compliant Unix flavors
|
||||
#else // use standard C99 format specifiers
|
||||
# ifdef __MINGW32__
|
||||
# define __USE_MINGW_ANSI_STDIO 1 // Force old MinGW (GCC 5 and older) to use C99 formats
|
||||
# define __STDC_FORMAT_MACROS 1 // Otherwise MinGW doesn't get PRId64 for fstapi.c
|
||||
# endif
|
||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||
# define VL_PRI64 "l"
|
||||
# else
|
||||
@@ -305,11 +305,11 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
//=========================================================================
|
||||
// Integer size macros
|
||||
|
||||
#define VL_BYTESIZE 8 ///< Bits in a byte
|
||||
#define VL_SHORTSIZE 16 ///< Bits in a short
|
||||
#define VL_WORDSIZE 32 ///< Bits in a word
|
||||
#define VL_QUADSIZE 64 ///< Bits in a quadword
|
||||
#define VL_WORDSIZE_LOG2 5 ///< log2(VL_WORDSIZE)
|
||||
#define VL_BYTESIZE 8 ///< Bits in a byte
|
||||
#define VL_SHORTSIZE 16 ///< Bits in a short
|
||||
#define VL_WORDSIZE 32 ///< Bits in a word
|
||||
#define VL_QUADSIZE 64 ///< Bits in a quadword
|
||||
#define VL_WORDSIZE_LOG2 5 ///< log2(VL_WORDSIZE)
|
||||
|
||||
/// Bytes this number of bits needs (1 bit=1 byte)
|
||||
#define VL_BYTES_I(nbits) (((nbits)+(VL_BYTESIZE-1))/VL_BYTESIZE)
|
||||
@@ -327,21 +327,21 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
//=========================================================================
|
||||
// Verilated function size macros
|
||||
|
||||
#define VL_MULS_MAX_WORDS 16 ///< Max size in words of MULS operation
|
||||
#define VL_TO_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
|
||||
#define VL_MULS_MAX_WORDS 16 ///< Max size in words of MULS operation
|
||||
#define VL_TO_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
|
||||
|
||||
//=========================================================================
|
||||
// Base macros
|
||||
|
||||
#define VL_SIZEBITS_I (VL_WORDSIZE-1) ///< Bit mask for bits in a word
|
||||
#define VL_SIZEBITS_Q (VL_QUADSIZE-1) ///< Bit mask for bits in a quad
|
||||
#define VL_SIZEBITS_I (VL_WORDSIZE-1) ///< Bit mask for bits in a word
|
||||
#define VL_SIZEBITS_Q (VL_QUADSIZE-1) ///< Bit mask for bits in a quad
|
||||
|
||||
/// Mask for words with 1's where relevant bits are (0=all bits)
|
||||
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) \
|
||||
? ((1U << ((nbits) & VL_SIZEBITS_I) )-1) : ~0)
|
||||
? ((1U << ((nbits) & VL_SIZEBITS_I) )-1) : ~0)
|
||||
/// Mask for quads with 1's where relevant bits are (0=all bits)
|
||||
#define VL_MASK_Q(nbits) (((nbits) & VL_SIZEBITS_Q) \
|
||||
? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q) )-VL_ULL(1)) : VL_ULL(~0))
|
||||
? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q) )-VL_ULL(1)) : VL_ULL(~0))
|
||||
#define VL_BITWORD_I(bit) ((bit)/VL_WORDSIZE) ///< Word number for a wide quantity
|
||||
#define VL_BITBIT_I(bit) ((bit)&VL_SIZEBITS_I) ///< Bit number for a bit in a long
|
||||
#define VL_BITBIT_Q(bit) ((bit)&VL_SIZEBITS_Q) ///< Bit number for a bit in a quad
|
||||
|
||||
+18
-18
@@ -23,9 +23,9 @@ our $Debug;
|
||||
our $Opt_Unsup;
|
||||
|
||||
if (! GetOptions (
|
||||
#"help" => \&usage,
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"unsup!" => \$Opt_Unsup, # Ignore unsupported
|
||||
#"help" => \&usage,
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"unsup!" => \$Opt_Unsup, # Ignore unsupported
|
||||
)) {
|
||||
die "usage();"
|
||||
}
|
||||
@@ -59,24 +59,24 @@ sub prep {
|
||||
my $rule = "";
|
||||
my $skip = 1;
|
||||
while (defined(my $line = $fh->getline)) {
|
||||
if ($skip == 1) {
|
||||
next if $line !~ /%token/;
|
||||
$skip = 2;
|
||||
}
|
||||
if ($skip == 1) {
|
||||
next if $line !~ /%token/;
|
||||
$skip = 2;
|
||||
}
|
||||
|
||||
if ($Opt_Unsup) {
|
||||
$line =~ s!//UNSUP!|!g;
|
||||
$line =~ s!(\s+)\|(\s+)!$1$2!g; # As "UNSUP" often replaces "|"
|
||||
}
|
||||
if ($Opt_Unsup) {
|
||||
$line =~ s!//UNSUP!|!g;
|
||||
$line =~ s!(\s+)\|(\s+)!$1$2!g; # As "UNSUP" often replaces "|"
|
||||
}
|
||||
|
||||
# %type<foo>
|
||||
$line =~ s/^(%\S+)<(\S+)>/$1/;
|
||||
# rule<foo>
|
||||
$line =~ s/^([a-zA-Z0-9_]+)<\S+>:/$1:/;
|
||||
# Productions
|
||||
$line =~ s/[ \t]{[^}]*?}/\t{}/g;
|
||||
# %type<foo>
|
||||
$line =~ s/^(%\S+)<(\S+)>/$1/;
|
||||
# rule<foo>
|
||||
$line =~ s/^([a-zA-Z0-9_]+)<\S+>:/$1:/;
|
||||
# Productions
|
||||
$line =~ s/[ \t]{[^}]*?}/\t{}/g;
|
||||
|
||||
$fho->print($line);
|
||||
$fho->print($line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-20
@@ -32,27 +32,27 @@ foreach my $line (<STDIN>) {
|
||||
$line =~ s!\s+! !g;
|
||||
next if $line eq '';
|
||||
if ($line =~ m!^\%\%!) {
|
||||
$body++;
|
||||
$body++;
|
||||
} elsif ($body == 1) {
|
||||
$rule .= $line;
|
||||
if ($line =~ m!^\s*;\s*$!) {
|
||||
#print "Rule: $rule\n";
|
||||
($rule =~ /^([a-zA-Z0-9_]+)(<\S+>)?:(.*)$/) or die "%Error: No rule name: $1\n";
|
||||
my $rulename = $1; my $preaction = $3;
|
||||
$declared{$rulename} = $lineno;
|
||||
$preaction =~ s/\{[^\}]*\}/ /g;
|
||||
#print "RULEN $rulename PA $preaction\n" if $Debug;
|
||||
$rule = '';
|
||||
foreach my $ref (split /\s+/, $preaction) {
|
||||
next if $ref !~ /^[a-zA-Z]/;
|
||||
next if $ref eq $rulename;
|
||||
if (!$used{$ref} && $declared{$ref}) {
|
||||
print " %Warning: $lineno: $ref used by $rulename after declaration\n";
|
||||
}
|
||||
$used{$ref} = $lineno;
|
||||
print " ref $ref\n" if $Debug;
|
||||
}
|
||||
}
|
||||
$rule .= $line;
|
||||
if ($line =~ m!^\s*;\s*$!) {
|
||||
#print "Rule: $rule\n";
|
||||
($rule =~ /^([a-zA-Z0-9_]+)(<\S+>)?:(.*)$/) or die "%Error: No rule name: $1\n";
|
||||
my $rulename = $1; my $preaction = $3;
|
||||
$declared{$rulename} = $lineno;
|
||||
$preaction =~ s/\{[^\}]*\}/ /g;
|
||||
#print "RULEN $rulename PA $preaction\n" if $Debug;
|
||||
$rule = '';
|
||||
foreach my $ref (split /\s+/, $preaction) {
|
||||
next if $ref !~ /^[a-zA-Z]/;
|
||||
next if $ref eq $rulename;
|
||||
if (!$used{$ref} && $declared{$ref}) {
|
||||
print " %Warning: $lineno: $ref used by $rulename after declaration\n";
|
||||
}
|
||||
$used{$ref} = $lineno;
|
||||
print " ref $ref\n" if $Debug;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+36
-36
@@ -24,11 +24,11 @@ $Debug = 0;
|
||||
my $opt_filename;
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
if (! GetOptions (
|
||||
"help" => \&usage,
|
||||
"debug" => \&debug,
|
||||
"<>" => \¶meter,
|
||||
)) {
|
||||
if (! GetOptions(
|
||||
"help" => \&usage,
|
||||
"debug" => \&debug,
|
||||
"<>" => \¶meter,
|
||||
)) {
|
||||
usage();
|
||||
}
|
||||
|
||||
@@ -49,9 +49,9 @@ sub debug {
|
||||
sub parameter {
|
||||
my $param = shift;
|
||||
if (!$opt_filename) {
|
||||
$opt_filename = $param;
|
||||
$opt_filename = $param;
|
||||
} else {
|
||||
die "%Error: Unknown parameter: $param\n";
|
||||
die "%Error: Unknown parameter: $param\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,30 +64,30 @@ sub dotread {
|
||||
my $header = 1;
|
||||
my $vnum = 0;
|
||||
while (defined (my $line = $fh->getline)) {
|
||||
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
|
||||
next if $1 eq 'nTITLE';
|
||||
$header = 0;
|
||||
$Vertexes{$1} = {num => $vnum++,
|
||||
line => $line,
|
||||
name => $1,};
|
||||
}
|
||||
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
|
||||
my $from=$1; my $to=$2;
|
||||
my $weight = 1; $weight = $1 if $line =~ /weight=(\d+)/;
|
||||
my $cutable = undef; $cutable = $1 if $line =~ /style=(\S+)/;
|
||||
my $edge = {num => $vnum++,
|
||||
line => $line,
|
||||
weight => $weight,
|
||||
cutable => $cutable,
|
||||
from => $from,
|
||||
to => $to,};
|
||||
push @Edges, $edge;
|
||||
$Edges{$from}{$to} = $edge;
|
||||
}
|
||||
elsif ($header) {
|
||||
push @Header, $line;
|
||||
print "IGNORE: $line";
|
||||
}
|
||||
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
|
||||
next if $1 eq 'nTITLE';
|
||||
$header = 0;
|
||||
$Vertexes{$1} = {num => $vnum++,
|
||||
line => $line,
|
||||
name => $1,};
|
||||
}
|
||||
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
|
||||
my $from=$1; my $to=$2;
|
||||
my $weight = 1; $weight = $1 if $line =~ /weight=(\d+)/;
|
||||
my $cutable = undef; $cutable = $1 if $line =~ /style=(\S+)/;
|
||||
my $edge = {num => $vnum++,
|
||||
line => $line,
|
||||
weight => $weight,
|
||||
cutable => $cutable,
|
||||
from => $from,
|
||||
to => $to,};
|
||||
push @Edges, $edge;
|
||||
$Edges{$from}{$to} = $edge;
|
||||
}
|
||||
elsif ($header) {
|
||||
push @Header, $line;
|
||||
print "IGNORE: $line";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,14 +100,14 @@ sub cwrite {
|
||||
$fh->print("void V3GraphTestImport::dotImport() {\n");
|
||||
$fh->print(" DfaGraph* gp = &m_graph;\n");
|
||||
foreach my $ver (sort {$a->{num} <=> $b->{num}} (values %Vertexes)) {
|
||||
$fh->printf(" V3GraphTestVertex* %s = new V3GraphTestVertex(gp, \"%s\"); if (%s) {}\n",
|
||||
$ver->{name}, $ver->{name}, $ver->{name});
|
||||
$fh->printf(" V3GraphTestVertex* %s = new V3GraphTestVertex(gp, \"%s\"); if (%s) {}\n",
|
||||
$ver->{name}, $ver->{name}, $ver->{name});
|
||||
}
|
||||
$fh->print("\n");
|
||||
foreach my $edge (@Edges) {
|
||||
$fh->printf(" new V3GraphEdge(gp, %s, %s, %s, %s);\n",
|
||||
$edge->{from}, $edge->{to},
|
||||
$edge->{weight}, $edge->{cutable}?"true":"false");
|
||||
$fh->printf(" new V3GraphEdge(gp, %s, %s, %s, %s);\n",
|
||||
$edge->{from}, $edge->{to},
|
||||
$edge->{weight}, $edge->{cutable}?"true":"false");
|
||||
}
|
||||
$fh->print("}\n");
|
||||
}
|
||||
|
||||
+35
-35
@@ -26,12 +26,12 @@ my $opt_filename;
|
||||
my $opt_circle;
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
if (! GetOptions (
|
||||
"help" => \&usage,
|
||||
"debug" => \&debug,
|
||||
"<>" => \¶meter,
|
||||
"circle=s" => \$opt_circle,
|
||||
)) {
|
||||
if (! GetOptions(
|
||||
"help" => \&usage,
|
||||
"debug" => \&debug,
|
||||
"<>" => \¶meter,
|
||||
"circle=s" => \$opt_circle,
|
||||
)) {
|
||||
usage();
|
||||
}
|
||||
|
||||
@@ -54,9 +54,9 @@ sub debug {
|
||||
sub parameter {
|
||||
my $param = shift;
|
||||
if (!$opt_filename) {
|
||||
$opt_filename = $param;
|
||||
$opt_filename = $param;
|
||||
} else {
|
||||
die "%Error: Unknown parameter: $param\n";
|
||||
die "%Error: Unknown parameter: $param\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,16 +68,16 @@ sub dotread {
|
||||
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
||||
my $header = 1;
|
||||
while (defined (my $line = $fh->getline)) {
|
||||
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
|
||||
$header = 0;
|
||||
$Vertexes{$1} = $2;
|
||||
}
|
||||
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
|
||||
$Edges{$1}{$2} = $3;
|
||||
}
|
||||
elsif ($header) {
|
||||
push @Header, $line;
|
||||
}
|
||||
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
|
||||
$header = 0;
|
||||
$Vertexes{$1} = $2;
|
||||
}
|
||||
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
|
||||
$Edges{$1}{$2} = $3;
|
||||
}
|
||||
elsif ($header) {
|
||||
push @Header, $line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,12 +85,12 @@ sub dotread {
|
||||
|
||||
sub simplify {
|
||||
foreach my $ver (sort (keys %Vertexes)) {
|
||||
$Vertexes{$ver} = _simplify($Vertexes{$ver});
|
||||
$Vertexes{$ver} = _simplify($Vertexes{$ver});
|
||||
}
|
||||
foreach my $v1 (sort (keys %Edges)) {
|
||||
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
|
||||
$Edges{$v1}{$v2} = _simplify($Edges{$v1}{$v2});
|
||||
}
|
||||
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
|
||||
$Edges{$v1}{$v2} = _simplify($Edges{$v1}{$v2});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,15 +103,15 @@ sub _simplify {
|
||||
|
||||
sub dotwrite {
|
||||
foreach my $line (@Header) {
|
||||
print "$line";
|
||||
print "$line";
|
||||
}
|
||||
foreach my $ver (sort (keys %Vertexes)) {
|
||||
print "\t$ver\t$Vertexes{$ver}\n";
|
||||
print "\t$ver\t$Vertexes{$ver}\n";
|
||||
}
|
||||
foreach my $v1 (sort (keys %Edges)) {
|
||||
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
|
||||
print "\t$v1 -> $v2\t$Edges{$v1}{$v2}\n";
|
||||
}
|
||||
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
|
||||
print "\t$v1 -> $v2\t$Edges{$v1}{$v2}\n";
|
||||
}
|
||||
}
|
||||
print "}\n";
|
||||
}
|
||||
@@ -125,15 +125,15 @@ sub circle {
|
||||
_circle_recurse($node, 1);
|
||||
|
||||
foreach my $ver (keys %Vertexes) {
|
||||
if (!$User{$ver}) {
|
||||
delete $Vertexes{$ver};
|
||||
delete $Edges{$ver};
|
||||
}
|
||||
if (!$User{$ver}) {
|
||||
delete $Vertexes{$ver};
|
||||
delete $Edges{$ver};
|
||||
}
|
||||
}
|
||||
foreach my $v1 (sort (keys %Edges)) {
|
||||
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
|
||||
if (!$Vertexes{$v2}) { delete $Edges{$v1}{$v2}; }
|
||||
}
|
||||
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
|
||||
if (!$Vertexes{$v2}) { delete $Edges{$v1}{$v2}; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ sub _circle_recurse {
|
||||
$User2{$node} = 1;
|
||||
my $r = 0;
|
||||
foreach my $v2 (keys %{$Edges{$node}}) {
|
||||
$r |= _circle_recurse($v2,$level++)||0;
|
||||
$r |= _circle_recurse($v2,$level++)||0;
|
||||
}
|
||||
$User{$node} = 1 if $r;
|
||||
$User2{$node} = 2;
|
||||
|
||||
+51
-51
@@ -18,11 +18,11 @@ our $Opt_Jobs = calc_jobs();
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
Getopt::Long::config("no_auto_abbrev");
|
||||
if (! GetOptions (
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
|
||||
"stage=i" => \$Opt_Stage,
|
||||
"j=i" => \$Opt_Jobs,
|
||||
if (! GetOptions(
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
|
||||
"stage=i" => \$Opt_Stage,
|
||||
"j=i" => \$Opt_Jobs,
|
||||
)) {
|
||||
die "%Error: Bad usage, try 'install_test --help'\n";
|
||||
}
|
||||
@@ -46,51 +46,51 @@ sub test {
|
||||
my $testdirn= $srcdir."/test_regress/obj_dir/install_test_testn";
|
||||
|
||||
if ($Opt_Stage <= 0) {
|
||||
run("/bin/rm -rf $blddir");
|
||||
run("/bin/mkdir -p $blddir");
|
||||
run("cd $blddir && $srcdir/configure --prefix $prefix");
|
||||
run("cd $blddir && make -j $Opt_Jobs");
|
||||
run("/bin/rm -rf $blddir");
|
||||
run("/bin/mkdir -p $blddir");
|
||||
run("cd $blddir && $srcdir/configure --prefix $prefix");
|
||||
run("cd $blddir && make -j $Opt_Jobs");
|
||||
}
|
||||
|
||||
# Install it under the prefix
|
||||
if ($Opt_Stage <= 1) {
|
||||
run("/bin/rm -rf $prefix");
|
||||
run("/bin/mkdir -p $prefix");
|
||||
run("cd $blddir && make install");
|
||||
run("test -e $prefix/share/man/man1/verilator.1");
|
||||
run("/bin/rm -rf $prefix");
|
||||
run("/bin/mkdir -p $prefix");
|
||||
run("cd $blddir && make install");
|
||||
run("test -e $prefix/share/man/man1/verilator.1");
|
||||
run("test -e $prefix/share/verilator/examples/tracing_c/Makefile");
|
||||
run("test -e $prefix/share/verilator/include/verilated.h");
|
||||
run("test -e $prefix/bin/verilator");
|
||||
run("test -e $prefix/bin/verilator_bin");
|
||||
run("test -e $prefix/bin/verilator_bin_dbg");
|
||||
run("test -e $prefix/share/verilator/include/verilated.h");
|
||||
run("test -e $prefix/bin/verilator");
|
||||
run("test -e $prefix/bin/verilator_bin");
|
||||
run("test -e $prefix/bin/verilator_bin_dbg");
|
||||
run("test -e $prefix/bin/verilator_gantt");
|
||||
run("test -e $prefix/bin/verilator_profcfunc");
|
||||
run("test -e $prefix/bin/verilator_profcfunc");
|
||||
}
|
||||
|
||||
# Run a test using just the path
|
||||
if ($Opt_Stage <= 2) {
|
||||
my $dir = $testdirp;
|
||||
run("/bin/rm -rf $dir");
|
||||
run("/bin/mkdir -p $dir");
|
||||
my $bin1 = $prefix."/bin";
|
||||
my $bin2 = $prefix."/share/bin";
|
||||
write_verilog($dir);
|
||||
run("cd $dir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v --exe foo.cpp");
|
||||
run("cd $dir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
|
||||
run("cd $dir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
|
||||
my $dir = $testdirp;
|
||||
run("/bin/rm -rf $dir");
|
||||
run("/bin/mkdir -p $dir");
|
||||
my $bin1 = $prefix."/bin";
|
||||
my $bin2 = $prefix."/share/bin";
|
||||
write_verilog($dir);
|
||||
run("cd $dir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v --exe foo.cpp");
|
||||
run("cd $dir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
|
||||
run("cd $dir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
|
||||
}
|
||||
|
||||
# Run a test using exact path to binary
|
||||
if ($Opt_Stage <= 3) {
|
||||
my $dir = $testdirn;
|
||||
run("/bin/rm -rf $dir");
|
||||
run("/bin/mkdir -p $dir");
|
||||
write_verilog($dir);
|
||||
my $bin1 = $prefix."/bin";
|
||||
my $bin2 = $prefix."/share/bin";
|
||||
run("cd $dir && $bin1/verilator --cc foo.v --exe foo.cpp");
|
||||
run("cd $dir/obj_dir && make -f Vfoo.mk");
|
||||
run("cd $dir/obj_dir && ./Vfoo");
|
||||
my $dir = $testdirn;
|
||||
run("/bin/rm -rf $dir");
|
||||
run("/bin/mkdir -p $dir");
|
||||
write_verilog($dir);
|
||||
my $bin1 = $prefix."/bin";
|
||||
my $bin2 = $prefix."/share/bin";
|
||||
run("cd $dir && $bin1/verilator --cc foo.v --exe foo.cpp");
|
||||
run("cd $dir/obj_dir && make -f Vfoo.mk");
|
||||
run("cd $dir/obj_dir && ./Vfoo");
|
||||
}
|
||||
|
||||
if ($Opt_Stage <= 9) {
|
||||
@@ -102,29 +102,29 @@ sub write_verilog {
|
||||
my $dir = shift;
|
||||
IO::File->new(">$dir/foo.v")->print('module t; initial begin $display("HELLO WORLD"); $finish; end endmodule'."\n");
|
||||
my $fh = IO::File->new(">$dir/foo.cpp");
|
||||
$fh->print('#include "Vfoo.h"' ,"\n");
|
||||
$fh->print('unsigned int main_time = 0;' ,"\n");
|
||||
$fh->print('#include "Vfoo.h"' ,"\n");
|
||||
$fh->print('unsigned int main_time = 0;' ,"\n");
|
||||
$fh->print('double sc_time_stamp() {' ,"\n");
|
||||
$fh->print(' return main_time;' ,"\n");
|
||||
$fh->print('}' ,"\n");
|
||||
$fh->print('int main() {' ,"\n");
|
||||
$fh->print(' Vfoo *top = new Vfoo;' ,"\n");
|
||||
$fh->print(' return main_time;' ,"\n");
|
||||
$fh->print('}' ,"\n");
|
||||
$fh->print('int main() {' ,"\n");
|
||||
$fh->print(' Vfoo *top = new Vfoo;' ,"\n");
|
||||
$fh->print(' while (!Verilated::gotFinish()) {',"\n");
|
||||
$fh->print(' top->eval();' ,"\n");
|
||||
$fh->print(' main_time++;' ,"\n");
|
||||
$fh->print(' }' ,"\n");
|
||||
$fh->print(' top->final();' ,"\n");
|
||||
$fh->print('}' ,"\n");
|
||||
$fh->print(' }' ,"\n");
|
||||
$fh->print(' top->final();' ,"\n");
|
||||
$fh->print('}' ,"\n");
|
||||
}
|
||||
|
||||
sub cleanenv {
|
||||
foreach my $var (keys %ENV) {
|
||||
if ($var eq "VERILATOR_ROOT"
|
||||
if ($var eq "VERILATOR_ROOT"
|
||||
|| $var eq "VERILATOR_INCLUDE"
|
||||
|| $var eq "VERILATOR_NO_OPT_BUILD") {
|
||||
print "unset $var # Was '$ENV{$var}'\n";
|
||||
delete $ENV{$var}
|
||||
}
|
||||
print "unset $var # Was '$ENV{$var}'\n";
|
||||
delete $ENV{$var}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,8 +132,8 @@ sub cleanenv {
|
||||
|
||||
sub calc_jobs {
|
||||
my $ok = eval "
|
||||
use Unix::Processors;
|
||||
return Unix::Processors->new->max_online;
|
||||
use Unix::Processors;
|
||||
return Unix::Processors->new->max_online;
|
||||
";
|
||||
$ok && !$@ or return 1;
|
||||
print "driver.pl: Found $ok cores, using -j ",$ok+1,"\n" if $Debug;
|
||||
|
||||
+143
-143
@@ -23,11 +23,11 @@ $Debug = 0;
|
||||
my $opt_filename;
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
if (! GetOptions (
|
||||
"help" => \&usage,
|
||||
"debug" => \&debug,
|
||||
"<>" => \¶meter,
|
||||
)) {
|
||||
if (! GetOptions(
|
||||
"help" => \&usage,
|
||||
"debug" => \&debug,
|
||||
"<>" => \¶meter,
|
||||
)) {
|
||||
usage();
|
||||
}
|
||||
|
||||
@@ -51,9 +51,9 @@ sub debug {
|
||||
sub parameter {
|
||||
my $param = shift;
|
||||
if (!$opt_filename) {
|
||||
$opt_filename = $param;
|
||||
$opt_filename = $param;
|
||||
} else {
|
||||
die "%Error: Unknown parameter: $param\n";
|
||||
die "%Error: Unknown parameter: $param\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,45 +64,45 @@ sub vread {
|
||||
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
||||
my $lasthier="";
|
||||
$Tree = {
|
||||
op => 'NETLIST',
|
||||
t => [[],[],[],[],[],],
|
||||
op => 'NETLIST',
|
||||
t => [[],[],[],[],[],],
|
||||
};
|
||||
my @stack;
|
||||
$stack[1] = $Tree;
|
||||
while (defined (my $line = $fh->getline)) {
|
||||
if ($line =~ /^\s+(\S+):\s+(\S+)\s+0x\S+\s+{(\d+)}\s+w(\d+)\s+(.*)$/) {
|
||||
my $hier = $1;
|
||||
my $op = $2;
|
||||
my $lineno = $3;
|
||||
my $width = $4;
|
||||
my $etc = $5;
|
||||
if ($line =~ /^\s+(\S+):\s+(\S+)\s+0x\S+\s+{(\d+)}\s+w(\d+)\s+(.*)$/) {
|
||||
my $hier = $1;
|
||||
my $op = $2;
|
||||
my $lineno = $3;
|
||||
my $width = $4;
|
||||
my $etc = $5;
|
||||
|
||||
$etc =~ s/__DOT__/./g;
|
||||
$etc =~ s/__PVT__//g;
|
||||
$etc =~ s/__DOT__/./g;
|
||||
$etc =~ s/__PVT__//g;
|
||||
|
||||
my $self = {
|
||||
op => $op,
|
||||
#width => $width,
|
||||
#lineno => $lineno,
|
||||
#line => $line,
|
||||
etc => $etc,
|
||||
args => [split(/[ \t]+/,$etc)],
|
||||
t => [[],[],[],[],[],],
|
||||
};
|
||||
my $self = {
|
||||
op => $op,
|
||||
#width => $width,
|
||||
#lineno => $lineno,
|
||||
#line => $line,
|
||||
etc => $etc,
|
||||
args => [split(/[ \t]+/,$etc)],
|
||||
t => [[],[],[],[],[],],
|
||||
};
|
||||
|
||||
my @hiers = (1,split(/:/,$hier));
|
||||
my $depth = $#hiers+1;
|
||||
my $newchild = $hiers[$#hiers];
|
||||
my @hiers = (1,split(/:/,$hier));
|
||||
my $depth = $#hiers+1;
|
||||
my $newchild = $hiers[$#hiers];
|
||||
|
||||
#print "DD $depth $newchild $op\n";
|
||||
#print "DD $depth $newchild $op\n";
|
||||
|
||||
push @{$stack[$depth-1]->{t}[$newchild]}, $self;
|
||||
$stack[$depth] = $self;
|
||||
push @{$stack[$depth-1]->{t}[$newchild]}, $self;
|
||||
$stack[$depth] = $self;
|
||||
|
||||
$lasthier = $hier;
|
||||
#print " $lasthier\n";
|
||||
#print Dumper($Tree);
|
||||
}
|
||||
$lasthier = $hier;
|
||||
#print " $lasthier\n";
|
||||
#print Dumper($Tree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,125 +168,125 @@ sub nl { p "\n"," "x$Indent; }
|
||||
|
||||
sub gentree {
|
||||
%OpMap = (
|
||||
'NULLNODE' => sub { "" },
|
||||
'NETLIST' => sub { nl;t1;t2;t3;t4;t5; },
|
||||
'ACTIVE' => sub { p "always_act @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
|
||||
'ADD' => sub { p1;p " + ";p2; },
|
||||
'ALWAYS' => sub { p "always @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
|
||||
'ALWAYSPOST' => sub { p "ALWAYSPOST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'AND' => sub { p1;p " & ";p2; },
|
||||
'ARRAYSEL' => sub { t1;p "[";t2;p "]"; },
|
||||
'ASSIGN' => sub { t2;p " = ";t1;p ";";nl; },
|
||||
'ASSIGNDLY' => sub { t2;p " <= ";t1;p ";";nl; },
|
||||
'ASSIGNPOST' => sub { p "ASSIGNPOST what{";t1;p " = ";t2;p ";";nl; },
|
||||
'ASSIGNPRE' => sub { p "ASSIGNPRE what{";t1;p " = ";t2;p ";";nl; },
|
||||
'ASSIGNW' => sub { p "assign ";t2;p " = ";t1;p ";";nl; },
|
||||
'ATTROF' => sub { p "ATTROF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'BEGIN' => sub { p "begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
|
||||
'BITSEL' => sub { t1;local $Avoid_Hex=1; p "[";t2;p "]"; },
|
||||
'CASE' => sub { p "CASE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CASEITEM' => sub { p "CASEITEM what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CAST' => sub { p "CAST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CCALL' => sub { p "CCALL what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CELL' => sub { a1;p " ";a7;p " (/*CELL*/);"; nl; },
|
||||
'CFUNC' => sub { p "CFUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CHANGEDET' => sub { p "CHANGEDET what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CINCLUDE' => sub { p "CINCLUDE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'COMMENT' => sub { p "//COMMENT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl;nl; },
|
||||
'CONCAT' => sub { p "{";p1;p ",";p2;p "}"; },
|
||||
'CONDITIONAL' => sub { p1;p " ? ";p2;p " : ";p3; },
|
||||
'CONST' => sub { p_const(); },
|
||||
'COVER' => sub { p "COVER what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CRETURN' => sub { p "CRETURN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CSTMT' => sub { p "CSTMT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'DEFPARAM' => sub { p "defparam ";p1;p " = ";p2;p ";";nl; },
|
||||
'DISPLAY' => sub { p '$write("';p1;p "\",";p2;p3;p4;p5;p ");";nl; },
|
||||
'DIV' => sub { p1;p " / ";p2; },
|
||||
'EQ' => sub { p1;p " == ";p2; },
|
||||
'EQCASE' => sub { p1;p " === ";p2; },
|
||||
'EXTEND' => sub { t1; },
|
||||
'EXTRACT' => sub { t1;local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
|
||||
'FINISH' => sub { p '$finish;';nl },
|
||||
'FOR' => sub { p "for (";p1;p ",";p2;p ",";p3;p ") begin";indentInc;nl;p4;p5;indentDec;p "end";nl; },
|
||||
'FUNC' => sub { p "FUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'FUNCREF' => sub { p "FUNCREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'GT' => sub { p1;p " > ";p2; },
|
||||
'GTE' => sub { p1;p " >= ";p2; },
|
||||
'IF' => sub { p "if (";p1;p ") begin";indentInc;nl;t2;indentDec;if (exists3) {p "end else begin";indentInc;nl;t3;indentDec;} p "end"; nl; },
|
||||
'INITARRAY' => sub { p "INITARRAY what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'INITIAL' => sub { p "initial begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
|
||||
'LOGAND' => sub { p1;p " && ";p2; },
|
||||
'LOGNOT' => sub { p1;p " || ";p2; },
|
||||
'LOGOR' => sub { p "!";p1; },
|
||||
'LT' => sub { p1;p " < ";p2; },
|
||||
'LTE' => sub { p1;p " <= ";p2; },
|
||||
'MODDIV' => sub { p1;p " % ";p2; },
|
||||
'MODULE' => sub { p "module ";a1;p " (/*AUTOARG*/);";indentInc;nl;t1;t2;t3;t4;t5;indentDec;nl;p "endmodule";nl; },
|
||||
'MUL' => sub { p1;p " * ";p2; },
|
||||
'NEQ' => sub { p1;p " != ";p2; },
|
||||
'NEQCASE' => sub { p1;p " !== ";p2; },
|
||||
'NOT' => sub { p " ~";p1; },
|
||||
'OR' => sub { p1;p " | ";p2; },
|
||||
'PIN' => sub { p ";p ";p1;p " (";p2;p "),";nl; },
|
||||
'PORT' => sub { p ""; },
|
||||
'PRAGMA' => sub { p "PRAGMA what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'RAND' => sub { p '$rand'; },
|
||||
'RANGE' => sub { t1; local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
|
||||
'REDAND' => sub { p "&(";p1;p ")"; },
|
||||
'REDOR' => sub { p "|(";p1;p ")"; },
|
||||
'REDXNOR' => sub { p "~|(";p1;p ")"; },
|
||||
'REDXOR' => sub { p "~^(";p1;p ")"; },
|
||||
'REPLICATE' => sub { p "{";p1;p "{";p2;p "}}"; },
|
||||
'SCCTOR' => sub { p "SCCTOR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'SCHDR' => sub { p "SCHDR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'SCIMP' => sub { p "SCIMP what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'SCINT' => sub { p "SCINT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'SCOPE' => sub { t1;t2;t3;t4;t5; },
|
||||
'SENITEM' => sub { a1;p " ";t1; },
|
||||
'SENTREE' => sub { t1;t2;t3;t4;t5; },
|
||||
'SHIFTL' => sub { p1;p " << ";p2; },
|
||||
'SHIFTR' => sub { p1;p " >> ";p2; },
|
||||
'STOP' => sub { p '$stop;';nl; },
|
||||
'SUB' => sub { p1;p " - ";p2; },
|
||||
'TASK' => sub { p "TASK what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'TASKREF' => sub { p "TASKREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'TEXT' => sub { p "TEXT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'TIME' => sub { p '$time'; },
|
||||
'TOPSCOPE' => sub { t1;t2;t3;t4;t5; },
|
||||
'TRACE' => sub { p "TRACE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'UCFUNC' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ")"; },
|
||||
'UCSTMT' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ");";nl; },
|
||||
'NEGATE' => sub { p " -";p1; },
|
||||
'VAR' => sub { p_var(); },
|
||||
'VARPIN' => sub { p "VARPIN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'VARREF' => sub { a1; },
|
||||
'VARSCOPE' => sub { },
|
||||
'WHILE' => sub { t1; p "while (";t2;p ") begin";indentInc;nl;t3;t4;indentDec;p "end";nl; },
|
||||
'WORDSEL' => sub { p1;p "[";p2;p ":";p3;p "]"; },
|
||||
'XNOR' => sub { p1;p " ~^ ";p2; },
|
||||
'XOR' => sub { p1;p " ^";p2; },
|
||||
'NULLNODE' => sub { "" },
|
||||
'NETLIST' => sub { nl;t1;t2;t3;t4;t5; },
|
||||
'ACTIVE' => sub { p "always_act @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
|
||||
'ADD' => sub { p1;p " + ";p2; },
|
||||
'ALWAYS' => sub { p "always @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
|
||||
'ALWAYSPOST' => sub { p "ALWAYSPOST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'AND' => sub { p1;p " & ";p2; },
|
||||
'ARRAYSEL' => sub { t1;p "[";t2;p "]"; },
|
||||
'ASSIGN' => sub { t2;p " = ";t1;p ";";nl; },
|
||||
'ASSIGNDLY' => sub { t2;p " <= ";t1;p ";";nl; },
|
||||
'ASSIGNPOST' => sub { p "ASSIGNPOST what{";t1;p " = ";t2;p ";";nl; },
|
||||
'ASSIGNPRE' => sub { p "ASSIGNPRE what{";t1;p " = ";t2;p ";";nl; },
|
||||
'ASSIGNW' => sub { p "assign ";t2;p " = ";t1;p ";";nl; },
|
||||
'ATTROF' => sub { p "ATTROF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'BEGIN' => sub { p "begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
|
||||
'BITSEL' => sub { t1;local $Avoid_Hex=1; p "[";t2;p "]"; },
|
||||
'CASE' => sub { p "CASE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CASEITEM' => sub { p "CASEITEM what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CAST' => sub { p "CAST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CCALL' => sub { p "CCALL what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CELL' => sub { a1;p " ";a7;p " (/*CELL*/);"; nl; },
|
||||
'CFUNC' => sub { p "CFUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CHANGEDET' => sub { p "CHANGEDET what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CINCLUDE' => sub { p "CINCLUDE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'COMMENT' => sub { p "//COMMENT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl;nl; },
|
||||
'CONCAT' => sub { p "{";p1;p ",";p2;p "}"; },
|
||||
'CONDITIONAL' => sub { p1;p " ? ";p2;p " : ";p3; },
|
||||
'CONST' => sub { p_const(); },
|
||||
'COVER' => sub { p "COVER what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CRETURN' => sub { p "CRETURN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'CSTMT' => sub { p "CSTMT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'DEFPARAM' => sub { p "defparam ";p1;p " = ";p2;p ";";nl; },
|
||||
'DISPLAY' => sub { p '$write("';p1;p "\",";p2;p3;p4;p5;p ");";nl; },
|
||||
'DIV' => sub { p1;p " / ";p2; },
|
||||
'EQ' => sub { p1;p " == ";p2; },
|
||||
'EQCASE' => sub { p1;p " === ";p2; },
|
||||
'EXTEND' => sub { t1; },
|
||||
'EXTRACT' => sub { t1;local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
|
||||
'FINISH' => sub { p '$finish;';nl },
|
||||
'FOR' => sub { p "for (";p1;p ",";p2;p ",";p3;p ") begin";indentInc;nl;p4;p5;indentDec;p "end";nl; },
|
||||
'FUNC' => sub { p "FUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'FUNCREF' => sub { p "FUNCREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'GT' => sub { p1;p " > ";p2; },
|
||||
'GTE' => sub { p1;p " >= ";p2; },
|
||||
'IF' => sub { p "if (";p1;p ") begin";indentInc;nl;t2;indentDec;if (exists3) {p "end else begin";indentInc;nl;t3;indentDec;} p "end"; nl; },
|
||||
'INITARRAY' => sub { p "INITARRAY what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'INITIAL' => sub { p "initial begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
|
||||
'LOGAND' => sub { p1;p " && ";p2; },
|
||||
'LOGNOT' => sub { p1;p " || ";p2; },
|
||||
'LOGOR' => sub { p "!";p1; },
|
||||
'LT' => sub { p1;p " < ";p2; },
|
||||
'LTE' => sub { p1;p " <= ";p2; },
|
||||
'MODDIV' => sub { p1;p " % ";p2; },
|
||||
'MODULE' => sub { p "module ";a1;p " (/*AUTOARG*/);";indentInc;nl;t1;t2;t3;t4;t5;indentDec;nl;p "endmodule";nl; },
|
||||
'MUL' => sub { p1;p " * ";p2; },
|
||||
'NEQ' => sub { p1;p " != ";p2; },
|
||||
'NEQCASE' => sub { p1;p " !== ";p2; },
|
||||
'NOT' => sub { p " ~";p1; },
|
||||
'OR' => sub { p1;p " | ";p2; },
|
||||
'PIN' => sub { p ";p ";p1;p " (";p2;p "),";nl; },
|
||||
'PORT' => sub { p ""; },
|
||||
'PRAGMA' => sub { p "PRAGMA what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'RAND' => sub { p '$rand'; },
|
||||
'RANGE' => sub { t1; local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
|
||||
'REDAND' => sub { p "&(";p1;p ")"; },
|
||||
'REDOR' => sub { p "|(";p1;p ")"; },
|
||||
'REDXNOR' => sub { p "~|(";p1;p ")"; },
|
||||
'REDXOR' => sub { p "~^(";p1;p ")"; },
|
||||
'REPLICATE' => sub { p "{";p1;p "{";p2;p "}}"; },
|
||||
'SCCTOR' => sub { p "SCCTOR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'SCHDR' => sub { p "SCHDR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'SCIMP' => sub { p "SCIMP what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'SCINT' => sub { p "SCINT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'SCOPE' => sub { t1;t2;t3;t4;t5; },
|
||||
'SENITEM' => sub { a1;p " ";t1; },
|
||||
'SENTREE' => sub { t1;t2;t3;t4;t5; },
|
||||
'SHIFTL' => sub { p1;p " << ";p2; },
|
||||
'SHIFTR' => sub { p1;p " >> ";p2; },
|
||||
'STOP' => sub { p '$stop;';nl; },
|
||||
'SUB' => sub { p1;p " - ";p2; },
|
||||
'TASK' => sub { p "TASK what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'TASKREF' => sub { p "TASKREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'TEXT' => sub { p "TEXT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'TIME' => sub { p '$time'; },
|
||||
'TOPSCOPE' => sub { t1;t2;t3;t4;t5; },
|
||||
'TRACE' => sub { p "TRACE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'UCFUNC' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ")"; },
|
||||
'UCSTMT' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ");";nl; },
|
||||
'NEGATE' => sub { p " -";p1; },
|
||||
'VAR' => sub { p_var(); },
|
||||
'VARPIN' => sub { p "VARPIN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'VARREF' => sub { a1; },
|
||||
'VARSCOPE' => sub { },
|
||||
'WHILE' => sub { t1; p "while (";t2;p ") begin";indentInc;nl;t3;t4;indentDec;p "end";nl; },
|
||||
'WORDSEL' => sub { p1;p "[";p2;p ":";p3;p "]"; },
|
||||
'XNOR' => sub { p1;p " ~^ ";p2; },
|
||||
'XOR' => sub { p1;p " ^";p2; },
|
||||
);
|
||||
}
|
||||
|
||||
sub p_var {
|
||||
my $self = $Code_Self;
|
||||
if ($self->{etc} =~ /\[I\]/) {
|
||||
print "input";
|
||||
print "input";
|
||||
} elsif ($self->{etc} =~ /\[O\]/) {
|
||||
print "output";
|
||||
print "output";
|
||||
} else {
|
||||
print "reg";
|
||||
print "reg";
|
||||
}
|
||||
p "\t";
|
||||
{
|
||||
local $Avoid_Hex=1;
|
||||
t1;
|
||||
local $Avoid_Hex=1;
|
||||
t1;
|
||||
}
|
||||
p "\t";
|
||||
a1;
|
||||
if (exists2()) {
|
||||
p " = ";
|
||||
t2;
|
||||
p " = ";
|
||||
t2;
|
||||
}
|
||||
p ";";
|
||||
nl;
|
||||
@@ -295,10 +295,10 @@ sub p_var {
|
||||
sub p_const {
|
||||
my $v = $Code_Self->{args}[0];
|
||||
if ($v =~ /\?32\?h(.*)$/
|
||||
|| ($Avoid_Hex && $v =~ /^[0-9?]*h(.*)$/)) {
|
||||
print hex $1;
|
||||
|| ($Avoid_Hex && $v =~ /^[0-9?]*h(.*)$/)) {
|
||||
print hex $1;
|
||||
} else {
|
||||
print $v;
|
||||
print $v;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-9
@@ -558,19 +558,20 @@ int AstNodeDType::widthPow2() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variable (or const) this dereferences?
|
||||
AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variable (or const) this dereferences?
|
||||
// Else AstArraySel etc; search for the base
|
||||
while (nodep) {
|
||||
if (VN_IS(nodep, ArraySel)) { nodep=VN_CAST(nodep, ArraySel)->fromp(); continue; }
|
||||
else if (VN_IS(nodep, Sel)) { nodep=VN_CAST(nodep, Sel)->fromp(); continue; }
|
||||
// AstNodeSelPre stashes the associated variable under an ATTROF of AstAttrType::VAR_BASE/MEMBER_BASE so it isn't constified
|
||||
else if (VN_IS(nodep, AttrOf)) { nodep=VN_CAST(nodep, AttrOf)->fromp(); continue; }
|
||||
if (VN_IS(nodep, ArraySel)) { nodep = VN_CAST(nodep, ArraySel)->fromp(); continue; }
|
||||
else if (VN_IS(nodep, Sel)) { nodep = VN_CAST(nodep, Sel)->fromp(); continue; }
|
||||
// AstNodeSelPre stashes the associated variable under an ATTROF
|
||||
// of AstAttrType::VAR_BASE/MEMBER_BASE so it isn't constified
|
||||
else if (VN_IS(nodep, AttrOf)) { nodep = VN_CAST(nodep, AttrOf)->fromp(); continue; }
|
||||
else if (VN_IS(nodep, NodePreSel)) {
|
||||
if (VN_CAST(nodep, NodePreSel)->attrp()) {
|
||||
nodep=VN_CAST(nodep, NodePreSel)->attrp();
|
||||
} else {
|
||||
nodep=VN_CAST(nodep, NodePreSel)->lhsp();
|
||||
}
|
||||
nodep = VN_CAST(nodep, NodePreSel)->attrp();
|
||||
} else {
|
||||
nodep = VN_CAST(nodep, NodePreSel)->lhsp();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else break;
|
||||
|
||||
+95
-59
@@ -927,7 +927,7 @@ class AstSelPlus : public AstNodePreSel {
|
||||
// Gets replaced during link with AstSel
|
||||
public:
|
||||
AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
|
||||
:AstNodePreSel(fl, fromp, bitp, widthp) {}
|
||||
: AstNodePreSel(fl, fromp, bitp, widthp) {}
|
||||
ASTNODE_NODE_FUNCS(SelPlus)
|
||||
AstNode* bitp() const { return rhsp(); }
|
||||
AstNode* widthp() const { return thsp(); }
|
||||
@@ -938,7 +938,7 @@ class AstSelMinus : public AstNodePreSel {
|
||||
// Gets replaced during link with AstSel
|
||||
public:
|
||||
AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
|
||||
:AstNodePreSel(fl, fromp, bitp, widthp) {}
|
||||
: AstNodePreSel(fl, fromp, bitp, widthp) {}
|
||||
ASTNODE_NODE_FUNCS(SelMinus)
|
||||
AstNode* bitp() const { return rhsp(); }
|
||||
AstNode* widthp() const { return thsp(); }
|
||||
@@ -955,8 +955,8 @@ private:
|
||||
int m_declElWidth; // If a packed array, the number of bits per element
|
||||
public:
|
||||
AstSel(FileLine* fl, AstNode* fromp, AstNode* lsbp, AstNode* widthp)
|
||||
:AstNodeTriop(fl, fromp, lsbp, widthp) {
|
||||
m_declElWidth = 1;
|
||||
: AstNodeTriop(fl, fromp, lsbp, widthp) {
|
||||
m_declElWidth = 1;
|
||||
if (VN_IS(widthp, Const)) {
|
||||
dtypeSetLogicSized(VN_CAST(widthp, Const)->toUInt(),
|
||||
VN_CAST(widthp, Const)->toUInt(),
|
||||
@@ -964,9 +964,9 @@ public:
|
||||
}
|
||||
}
|
||||
AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth)
|
||||
:AstNodeTriop(fl, fromp,
|
||||
new AstConst(fl,lsb), new AstConst(fl,bitwidth)) {
|
||||
m_declElWidth = 1;
|
||||
: AstNodeTriop(fl, fromp,
|
||||
new AstConst(fl,lsb), new AstConst(fl,bitwidth)) {
|
||||
m_declElWidth = 1;
|
||||
dtypeSetLogicSized(bitwidth,bitwidth,AstNumeric::UNSIGNED);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Sel)
|
||||
@@ -1076,9 +1076,9 @@ public:
|
||||
addNOp2p(pinsp);
|
||||
}
|
||||
AstMethodSel(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp)
|
||||
:AstNode(fl), m_name(name) {
|
||||
setOp1p(fromp);
|
||||
addNOp2p(pinsp);
|
||||
: AstNode(fl), m_name(name) {
|
||||
setOp1p(fromp);
|
||||
addNOp2p(pinsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(MethodSel)
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
@@ -1144,9 +1144,9 @@ private:
|
||||
}
|
||||
public:
|
||||
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp)
|
||||
:AstNode(fl)
|
||||
, m_name(name), m_origName(name) {
|
||||
init();
|
||||
: AstNode(fl)
|
||||
, m_name(name), m_origName(name) {
|
||||
init();
|
||||
combineType(type);
|
||||
childDTypep(dtp); // Only for parser
|
||||
dtypep(NULL); // V3Width will resolve
|
||||
@@ -1154,9 +1154,9 @@ public:
|
||||
else m_declKwd = AstBasicDTypeKwd::LOGIC;
|
||||
}
|
||||
AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtp)
|
||||
:AstNode(fl)
|
||||
, m_name(name), m_origName(name) {
|
||||
init();
|
||||
: AstNode(fl)
|
||||
, m_name(name), m_origName(name) {
|
||||
init();
|
||||
combineType(type);
|
||||
UASSERT(dtp,"AstVar created with no dtype");
|
||||
dtypep(dtp);
|
||||
@@ -1164,24 +1164,24 @@ public:
|
||||
else m_declKwd = AstBasicDTypeKwd::LOGIC;
|
||||
}
|
||||
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagLogicPacked, int wantwidth)
|
||||
:AstNode(fl)
|
||||
, m_name(name), m_origName(name) {
|
||||
init();
|
||||
combineType(type);
|
||||
dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED);
|
||||
: AstNode(fl)
|
||||
, m_name(name), m_origName(name) {
|
||||
init();
|
||||
combineType(type);
|
||||
dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED);
|
||||
m_declKwd = AstBasicDTypeKwd::LOGIC;
|
||||
}
|
||||
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagBitPacked, int wantwidth)
|
||||
:AstNode(fl)
|
||||
, m_name(name), m_origName(name) {
|
||||
init();
|
||||
combineType(type);
|
||||
dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED);
|
||||
: AstNode(fl)
|
||||
, m_name(name), m_origName(name) {
|
||||
init();
|
||||
combineType(type);
|
||||
dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED);
|
||||
m_declKwd = AstBasicDTypeKwd::BIT;
|
||||
}
|
||||
AstVar(FileLine* fl, AstVarType type, const string& name, AstVar* examplep)
|
||||
:AstNode(fl)
|
||||
, m_name(name), m_origName(name) {
|
||||
: AstNode(fl)
|
||||
, m_name(name), m_origName(name) {
|
||||
init();
|
||||
combineType(type);
|
||||
if (examplep->childDTypep()) {
|
||||
@@ -1396,9 +1396,9 @@ private:
|
||||
AstNodeModule* m_modp; // Module scope corresponds to
|
||||
public:
|
||||
AstScope(FileLine* fl, AstNodeModule* modp, const string& name,
|
||||
AstScope* aboveScopep, AstCell* aboveCellp)
|
||||
:AstNode(fl)
|
||||
,m_name(name) ,m_aboveScopep(aboveScopep) ,m_aboveCellp(aboveCellp), m_modp(modp) {}
|
||||
AstScope* aboveScopep, AstCell* aboveCellp)
|
||||
: AstNode(fl)
|
||||
,m_name(name) ,m_aboveScopep(aboveScopep) ,m_aboveCellp(aboveCellp), m_modp(modp) {}
|
||||
ASTNODE_NODE_FUNCS(Scope)
|
||||
virtual void cloneRelink();
|
||||
virtual const char* broken() const;
|
||||
@@ -1426,8 +1426,8 @@ class AstTopScope : public AstNode {
|
||||
// Children: SCOPEs
|
||||
public:
|
||||
AstTopScope(FileLine* fl, AstScope* ascopep)
|
||||
:AstNode(fl)
|
||||
{addNOp2p(ascopep);}
|
||||
: AstNode(fl)
|
||||
{addNOp2p(ascopep);}
|
||||
ASTNODE_NODE_FUNCS(TopScope)
|
||||
AstNode* stmtsp() const { return op1p(); }
|
||||
void addStmtsp(AstNode* nodep) { addOp1p(nodep); }
|
||||
@@ -1446,9 +1446,9 @@ private:
|
||||
bool m_trace:1; // Tracing is turned on for this scope
|
||||
public:
|
||||
AstVarScope(FileLine* fl, AstScope* scopep, AstVar* varp)
|
||||
:AstNode(fl)
|
||||
, m_scopep(scopep), m_varp(varp) {
|
||||
m_circular = false;
|
||||
: AstNode(fl)
|
||||
, m_scopep(scopep), m_varp(varp) {
|
||||
m_circular = false;
|
||||
m_trace = true;
|
||||
dtypeFrom(varp);
|
||||
}
|
||||
@@ -1517,10 +1517,10 @@ private:
|
||||
string m_inlinedDots; // Dotted hierarchy flattened out
|
||||
public:
|
||||
AstVarXRef(FileLine* fl, const string& name, const string& dotted, bool lvalue)
|
||||
:AstNodeVarRef(fl, name, NULL, lvalue)
|
||||
, m_dotted(dotted) { }
|
||||
: AstNodeVarRef(fl, name, NULL, lvalue)
|
||||
, m_dotted(dotted) { }
|
||||
AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, bool lvalue)
|
||||
:AstNodeVarRef(fl, varp->name(), varp, lvalue)
|
||||
: AstNodeVarRef(fl, varp->name(), varp, lvalue)
|
||||
, m_dotted(dotted) {
|
||||
dtypeFrom(varp);
|
||||
}
|
||||
@@ -1555,16 +1555,16 @@ private:
|
||||
bool m_svImplicit; // Pin is SystemVerilog .name'ed
|
||||
public:
|
||||
AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp)
|
||||
:AstNode(fl)
|
||||
,m_name(name), m_param(false), m_svImplicit(false) {
|
||||
m_pinNum = pinNum;
|
||||
m_modVarp = NULL;
|
||||
m_modPTypep = NULL;
|
||||
setNOp1p(exprp);
|
||||
: AstNode(fl)
|
||||
,m_name(name), m_param(false), m_svImplicit(false) {
|
||||
m_pinNum = pinNum;
|
||||
m_modVarp = NULL;
|
||||
m_modPTypep = NULL;
|
||||
setNOp1p(exprp);
|
||||
}
|
||||
AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp)
|
||||
:AstNode(fl), m_param(false), m_svImplicit(false) {
|
||||
m_name = varname->name();
|
||||
: AstNode(fl), m_param(false), m_svImplicit(false) {
|
||||
m_name = varname->name();
|
||||
m_pinNum = pinNum;
|
||||
m_modVarp = NULL;
|
||||
m_modPTypep = NULL;
|
||||
@@ -1903,8 +1903,8 @@ private:
|
||||
string m_name; // Name of pin
|
||||
public:
|
||||
AstPort(FileLine* fl, int pinnum, const string& name)
|
||||
:AstNode(fl)
|
||||
,m_pinNum(pinnum) ,m_name(name) {}
|
||||
: AstNode(fl)
|
||||
,m_pinNum(pinnum) ,m_name(name) {}
|
||||
ASTNODE_NODE_FUNCS(Port)
|
||||
virtual string name() const { return m_name; } // * = Port name
|
||||
int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation
|
||||
@@ -1939,7 +1939,7 @@ private:
|
||||
string m_name;
|
||||
public:
|
||||
AstParseRef(FileLine* fl, AstParseRefExp expect, const string& name, AstNode* lhsp, AstNodeFTaskRef* ftaskrefp)
|
||||
:AstNode(fl), m_expect(expect), m_name(name) { setNOp1p(lhsp); setNOp2p(ftaskrefp); }
|
||||
: AstNode(fl), m_expect(expect), m_name(name) { setNOp1p(lhsp); setNOp2p(ftaskrefp); }
|
||||
ASTNODE_NODE_FUNCS(ParseRef)
|
||||
virtual void dump(std::ostream& str);
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
@@ -1984,7 +1984,7 @@ class AstDot : public AstNode {
|
||||
// These are eliminated in the link stage
|
||||
public:
|
||||
AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
:AstNode(fl) { setOp1p(lhsp); setOp2p(rhsp); }
|
||||
: AstNode(fl) { setOp1p(lhsp); setOp2p(rhsp); }
|
||||
ASTNODE_NODE_FUNCS(Dot)
|
||||
static AstNode* newIfPkg(FileLine*fl, AstPackage* packagep, AstNode* rhsp) { // For parser, make only if non-null package
|
||||
if (!packagep) return rhsp;
|
||||
@@ -2003,7 +2003,7 @@ class AstTask : public AstNodeFTask {
|
||||
// A task inside a module
|
||||
public:
|
||||
AstTask(FileLine* fl, const string& name, AstNode* stmtp)
|
||||
:AstNodeFTask(fl, name, stmtp) {}
|
||||
: AstNodeFTask(fl, name, stmtp) {}
|
||||
ASTNODE_NODE_FUNCS(Task)
|
||||
};
|
||||
|
||||
@@ -2011,8 +2011,8 @@ class AstFunc : public AstNodeFTask {
|
||||
// A function inside a module
|
||||
public:
|
||||
AstFunc(FileLine* fl, const string& name, AstNode* stmtp, AstNode* fvarsp)
|
||||
:AstNodeFTask(fl, name, stmtp) {
|
||||
addNOp1p(fvarsp);
|
||||
: AstNodeFTask(fl, name, stmtp) {
|
||||
addNOp1p(fvarsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Func)
|
||||
virtual bool hasDType() const { return true; }
|
||||
@@ -2022,9 +2022,9 @@ class AstTaskRef : public AstNodeFTaskRef {
|
||||
// A reference to a task
|
||||
public:
|
||||
AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp)
|
||||
:AstNodeFTaskRef(fl, namep, pinsp) {}
|
||||
: AstNodeFTaskRef(fl, namep, pinsp) {}
|
||||
AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp)
|
||||
:AstNodeFTaskRef(fl, name, pinsp) {}
|
||||
: AstNodeFTaskRef(fl, name, pinsp) {}
|
||||
ASTNODE_NODE_FUNCS(TaskRef)
|
||||
virtual bool isStatement() const { return true; } // A statement, unlike FuncRef
|
||||
};
|
||||
@@ -2033,9 +2033,9 @@ class AstFuncRef : public AstNodeFTaskRef {
|
||||
// A reference to a function
|
||||
public:
|
||||
AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp)
|
||||
:AstNodeFTaskRef(fl, namep, pinsp) {}
|
||||
: AstNodeFTaskRef(fl, namep, pinsp) {}
|
||||
AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp)
|
||||
:AstNodeFTaskRef(fl, name, pinsp) {}
|
||||
: AstNodeFTaskRef(fl, name, pinsp) {}
|
||||
ASTNODE_NODE_FUNCS(FuncRef)
|
||||
virtual bool isStatement() const { return false; } // Not a statement, unlike TaskRef
|
||||
virtual bool hasDType() const { return true; }
|
||||
@@ -2050,7 +2050,7 @@ private:
|
||||
string m_cname; // Name of function on c side
|
||||
public:
|
||||
AstDpiExport(FileLine* fl, const string& vname, const string& cname)
|
||||
:AstNode(fl), m_name(vname), m_cname(cname) { }
|
||||
: AstNode(fl), m_name(vname), m_cname(cname) { }
|
||||
ASTNODE_NODE_FUNCS(DpiExport)
|
||||
virtual string name() const { return m_name; }
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
@@ -2741,6 +2741,42 @@ public:
|
||||
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
|
||||
};
|
||||
|
||||
class AstFRead : public AstNodeMath {
|
||||
// Parents: expr
|
||||
// Children: varrefs to load
|
||||
// Children: file which must be a varref
|
||||
// Children: low index
|
||||
// Children: count
|
||||
public:
|
||||
AstFRead(FileLine* fileline, AstNode* memp, AstNode* filep,
|
||||
AstNode* startp, AstNode* countp)
|
||||
: AstNodeMath(fileline) {
|
||||
setOp1p(memp);
|
||||
setOp2p(filep);
|
||||
setNOp3p(startp);
|
||||
setNOp4p(countp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(FRead)
|
||||
virtual string verilogKwd() const { return "$fread"; }
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual bool isPure() const { return false; } // SPECIAL: has 'visual' ordering
|
||||
virtual bool isOutputter() const { return true; } // SPECIAL: makes output
|
||||
virtual bool cleanOut() { return false; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
AstNode* memp() const { return op1p(); }
|
||||
void memp(AstNode* nodep) { setOp1p(nodep); }
|
||||
AstNode* filep() const { return op2p(); }
|
||||
void filep(AstNode* nodep) { setOp2p(nodep); }
|
||||
AstNode* startp() const { return op3p(); }
|
||||
void startp(AstNode* nodep) { setNOp3p(nodep); }
|
||||
AstNode* countp() const { return op4p(); }
|
||||
void countp(AstNode* nodep) { setNOp4p(nodep); }
|
||||
};
|
||||
|
||||
class AstFScanF : public AstNodeMath {
|
||||
// Parents: expr
|
||||
// Children: file which must be a varref
|
||||
|
||||
@@ -230,6 +230,10 @@ private:
|
||||
}
|
||||
insureCleanAndNext(nodep->bodysp());
|
||||
}
|
||||
virtual void visit(AstTraceDecl* nodep) {
|
||||
// No cleaning, or would loose pointer to enum
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstTraceInc* nodep) {
|
||||
iterateChildren(nodep);
|
||||
insureCleanAndNext(nodep->valuep());
|
||||
|
||||
+42
-3
@@ -387,6 +387,45 @@ public:
|
||||
puts(")); }\n");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstFRead* nodep) {
|
||||
puts("VL_FREAD_I(");
|
||||
puts(cvtToStr(nodep->memp()->widthMin())); // Need real storage width
|
||||
putbs(",");
|
||||
bool memory = false;
|
||||
uint32_t array_lsb = 0;
|
||||
uint32_t array_size = 0;
|
||||
{
|
||||
const AstVarRef* varrefp = VN_CAST(nodep->memp(), VarRef);
|
||||
if (!varrefp) { nodep->v3error(nodep->verilogKwd() << " loading non-variable"); }
|
||||
else if (VN_CAST(varrefp->varp()->dtypeSkipRefp(), BasicDType)) { }
|
||||
else if (const AstUnpackArrayDType* adtypep
|
||||
= VN_CAST(varrefp->varp()->dtypeSkipRefp(), UnpackArrayDType)) {
|
||||
memory = true;
|
||||
array_lsb = adtypep->lsb();
|
||||
array_size = adtypep->elementsConst();
|
||||
}
|
||||
else {
|
||||
nodep->v3error(nodep->verilogKwd()
|
||||
<< " loading other than unpacked-array variable");
|
||||
}
|
||||
}
|
||||
puts(cvtToStr(array_lsb));
|
||||
putbs(",");
|
||||
puts(cvtToStr(array_size));
|
||||
putbs(", ");
|
||||
if (!memory) puts("&(");
|
||||
iterateAndNextNull(nodep->memp());
|
||||
if (!memory) puts(")");
|
||||
putbs(", ");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
putbs(", ");
|
||||
if (nodep->startp()) iterateAndNextNull(nodep->startp());
|
||||
else puts(cvtToStr(array_lsb));
|
||||
putbs(", ");
|
||||
if (nodep->countp()) iterateAndNextNull(nodep->countp());
|
||||
else puts(cvtToStr(array_size));
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstSysFuncAsTask* nodep) {
|
||||
if (!nodep->lhsp()->isWide()) puts("(void)");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
@@ -2848,7 +2887,7 @@ class EmitCTrace : EmitCStmts {
|
||||
puts(",");
|
||||
putsQuoted(nodep->showname());
|
||||
// Direction
|
||||
if (v3Global.opt.traceFormat() == TraceFormat::FST) {
|
||||
if (v3Global.opt.traceFormat().fstFlavor()) {
|
||||
puts(","+cvtToStr(enumNum));
|
||||
// fstVarDir
|
||||
if (nodep->declDirection().isInoutish()) puts(",FST_VD_INOUT");
|
||||
@@ -2915,9 +2954,9 @@ class EmitCTrace : EmitCStmts {
|
||||
|
||||
int emitTraceDeclDType(AstNodeDType* nodep) {
|
||||
// Return enum number or -1 for none
|
||||
if (v3Global.opt.traceFormat() == TraceFormat::FST) {
|
||||
if (v3Global.opt.traceFormat().fstFlavor()) {
|
||||
// Skip over refs-to-refs, but stop before final ref so can get data type name
|
||||
// Alternatively back in V3Width we could have push enum names from upper typedefs
|
||||
// Alternatively back in V3Width we could push enum names from upper typedefs
|
||||
if (AstEnumDType* enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) {
|
||||
int enumNum = enump->user1();
|
||||
if (!enumNum) {
|
||||
|
||||
@@ -46,9 +46,11 @@ class EmitCInlines : EmitCBaseVisitor {
|
||||
v3Global.needHeavy(true);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstValuePlusArgs* nodep) {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
// NOPs
|
||||
virtual void visit(AstNodeStmt*) {}
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep) {
|
||||
iterateChildren(nodep);
|
||||
|
||||
@@ -61,6 +61,9 @@ public:
|
||||
of.puts("VM_THREADS = "); of.puts(cvtToStr(v3Global.opt.threads())); of.puts("\n");
|
||||
of.puts("# Tracing output mode? 0/1 (from --trace)\n");
|
||||
of.puts("VM_TRACE = "); of.puts(v3Global.opt.trace()?"1":"0"); of.puts("\n");
|
||||
of.puts("# Tracing threadeds output mode? 0/1 (from --trace-fst-thread)\n");
|
||||
of.puts("VM_TRACE_THREADED = "); of.puts(v3Global.opt.traceFormat().threaded()
|
||||
?"1":"0"); of.puts("\n");
|
||||
|
||||
of.puts("\n### Object file lists...\n");
|
||||
for (int support=0; support<3; support++) {
|
||||
|
||||
+10
-7
@@ -49,8 +49,9 @@ public:
|
||||
I_DEF_NETTYPE_WIRE, // `default_nettype is WIRE (false=NONE)
|
||||
// Error codes:
|
||||
E_DETECTARRAY, // Error: Unsupported: Can't detect changes on arrayed variable
|
||||
E_MULTITOP, // Error: Multiple top level modules
|
||||
E_TASKNSVAR, // Error: Task I/O not simple
|
||||
E_MULTITOP, // Error: Multiple top level modules
|
||||
E_PORTSHORT, // Error: Output port is connected to a constant, electrical short
|
||||
E_TASKNSVAR, // Error: Task I/O not simple
|
||||
//
|
||||
// Warning codes:
|
||||
EC_FIRST_WARN, // Just a code so the program knows where to start warnings
|
||||
@@ -77,7 +78,8 @@ public:
|
||||
ENDLABEL, // End lable name mismatch
|
||||
GENCLK, // Generated Clock
|
||||
IFDEPTH, // If statements too deep
|
||||
IMPERFECTSCH, // Imperfect schedule (disabled by default)
|
||||
IGNOREDRETURN, // Ignoring return value (funcation as task)
|
||||
IMPERFECTSCH, // Imperfect schedule (disabled by default)
|
||||
IMPLICIT, // Implicit wire
|
||||
IMPORTSTAR, // Import::* in $unit
|
||||
IMPURE, // Impure function not being inlined
|
||||
@@ -128,9 +130,9 @@ public:
|
||||
" MIN", " INFO", " FATAL", " FATALSRC", " ERROR",
|
||||
// Boolean
|
||||
" I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE",
|
||||
// Errors
|
||||
"DETECTARRAY", "MULTITOP", "TASKNSVAR",
|
||||
// Warnings
|
||||
// Errors
|
||||
"DETECTARRAY", "MULTITOP", "PORTSHORT", "TASKNSVAR",
|
||||
// Warnings
|
||||
" EC_FIRST_WARN",
|
||||
"ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN",
|
||||
"BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE",
|
||||
@@ -138,7 +140,8 @@ public:
|
||||
"CMPCONST", "COLONPLUS", "COMBDLY", "CONTASSREG",
|
||||
"DEFPARAM", "DECLFILENAME",
|
||||
"ENDLABEL", "GENCLK",
|
||||
"IFDEPTH", "IMPERFECTSCH", "IMPLICIT", "IMPORTSTAR", "IMPURE",
|
||||
"IFDEPTH", "IGNOREDRETURN",
|
||||
"IMPERFECTSCH", "IMPLICIT", "IMPORTSTAR", "IMPURE",
|
||||
"INCABSPATH", "INFINITELOOP", "INITIALDLY",
|
||||
"LITENDIAN", "MODDUP",
|
||||
"MULTIDRIVEN",
|
||||
|
||||
@@ -91,6 +91,7 @@ protected:
|
||||
friend class V3ParseImp;
|
||||
friend class V3PreLex;
|
||||
friend class V3PreProcImp;
|
||||
friend class V3PreShellImp;
|
||||
void lineno(int num) { m_lineno = num; }
|
||||
void language(V3LangCode lang) { singleton().numberToLang(m_filenameno, lang); }
|
||||
void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); }
|
||||
|
||||
+2
-5
@@ -550,14 +550,11 @@ private:
|
||||
AstVar* pinNewVarp = pinOldVarp->clonep();
|
||||
if (!pinNewVarp) pinOldVarp->v3fatalSrc("Cloning failed");
|
||||
|
||||
AstNode* connectRefp = pinp->exprp();
|
||||
AstNode* connectRefp = pinp->exprp();
|
||||
if (!VN_IS(connectRefp, Const) && !VN_IS(connectRefp, VarRef)) {
|
||||
pinp->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up");
|
||||
}
|
||||
if (pinNewVarp->direction() == VDirection::OUTPUT
|
||||
&& VN_IS(connectRefp, Const)) {
|
||||
pinp->v3error("Output port is connected to a constant pin, electrical short");
|
||||
}
|
||||
V3Inst::checkOutputShort(pinp);
|
||||
|
||||
// Propagate any attributes across the interconnect
|
||||
pinNewVarp->propagateAttrFrom(pinOldVarp);
|
||||
|
||||
+18
-7
@@ -68,10 +68,7 @@ private:
|
||||
UINFO(4," PIN "<<nodep<<endl);
|
||||
if (!nodep->exprp()) return; // No-connect
|
||||
if (debug()>=9) nodep->dumpTree(cout," Pin_oldb: ");
|
||||
if (nodep->modVarp()->direction() == VDirection::OUTPUT
|
||||
&& VN_IS(nodep->exprp(), Const)) {
|
||||
nodep->v3error("Output port is connected to a constant pin, electrical short");
|
||||
}
|
||||
V3Inst::checkOutputShort(nodep);
|
||||
// Use user1p on the PIN to indicate we created an assign for this pin
|
||||
if (!nodep->user1SetOnce()) {
|
||||
// Simplify it
|
||||
@@ -513,8 +510,9 @@ public:
|
||||
// Done. Constant.
|
||||
} else {
|
||||
// Make a new temp wire
|
||||
//if (1||debug()>=9) { pinp->dumpTree(cout,"-in_pin:"); }
|
||||
AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
|
||||
//if (1||debug()>=9) { pinp->dumpTree(cout,"-in_pin:"); }
|
||||
V3Inst::checkOutputShort(pinp);
|
||||
AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
|
||||
string newvarname = (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp")
|
||||
// Prevent name conflict if both tri & non-tri add signals
|
||||
+(forTristate?"t":"")
|
||||
@@ -555,10 +553,23 @@ public:
|
||||
// Inst class functions
|
||||
|
||||
AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp,
|
||||
bool forTristate, bool alwaysCvt) {
|
||||
bool forTristate, bool alwaysCvt) {
|
||||
return InstStatic::pinReconnectSimple(pinp, cellp, forTristate, alwaysCvt);
|
||||
}
|
||||
|
||||
void V3Inst::checkOutputShort(AstPin* nodep) {
|
||||
if (nodep->modVarp()->direction() == VDirection::OUTPUT) {
|
||||
if (VN_IS(nodep->exprp(), Const)
|
||||
|| VN_IS(nodep->exprp(), Extend)
|
||||
|| (VN_IS(nodep->exprp(), Concat)
|
||||
&& (VN_IS(VN_CAST(nodep->exprp(), Concat)->lhsp(), Const)))) {
|
||||
// Uses v3warn for error, as might be found multiple times
|
||||
nodep->v3warn(E_PORTSHORT, "Output port is connected to a constant pin,"
|
||||
" electrical short");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// Inst class visitor
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ public:
|
||||
static void dearrayAll(AstNetlist* nodep);
|
||||
static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp,
|
||||
bool forTristate, bool alwaysCvt=false);
|
||||
static void checkOutputShort(AstPin* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
@@ -131,6 +131,15 @@ private:
|
||||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstFRead* nodep) {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
iterateAndNextNull(nodep->memp());
|
||||
iterateAndNextNull(nodep->filep());
|
||||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstFScanF* nodep) {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
|
||||
@@ -210,6 +210,11 @@ private:
|
||||
} else if (AstEnumItemRef* fromp = VN_CAST(basefromp, EnumItemRef)) {
|
||||
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::ENUM_BASE,
|
||||
fromp->cloneTree(false)));
|
||||
} else if (VN_IS(basefromp, Replicate)) {
|
||||
// From {...}[...] syntax in IEEE 2017
|
||||
if (basefromp) { UINFO(1," Related node: "<<basefromp<<endl); }
|
||||
nodep->v3error("Unsupported: Select of concatenation");
|
||||
nodep = NULL;
|
||||
} else {
|
||||
if (basefromp) { UINFO(1," Related node: "<<basefromp<<endl); }
|
||||
nodep->v3fatalSrc("Illegal bit select; no signal/member being extracted from");
|
||||
@@ -362,6 +367,10 @@ private:
|
||||
iterateChildren(nodep);
|
||||
expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef));
|
||||
}
|
||||
virtual void visit(AstFRead* nodep) {
|
||||
iterateChildren(nodep);
|
||||
expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef));
|
||||
}
|
||||
virtual void visit(AstFScanF* nodep) {
|
||||
iterateChildren(nodep);
|
||||
expectFormat(nodep, nodep->text(), nodep->exprsp(), true);
|
||||
|
||||
+24
-14
@@ -153,18 +153,16 @@ V3Number::V3Number(FileLine* fileline, const char* sourcep) {
|
||||
got_01 = 1;
|
||||
break;
|
||||
}
|
||||
case 'z': case '?': {
|
||||
if (!m_sized) m_fileline->v3error("Unsized X/Z/? not legal in decimal constant: "<<*cp);
|
||||
setAllBitsZ();
|
||||
got_z = 1;
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
if (!m_sized) m_fileline->v3error("Unsized X/Z/? not legal in decimal constant: "<<*cp);
|
||||
got_x = 1;
|
||||
setAllBitsX();
|
||||
break;
|
||||
}
|
||||
case 'z': case '?': {
|
||||
got_z = 1;
|
||||
setAllBitsZ();
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
got_x = 1;
|
||||
setAllBitsX();
|
||||
break;
|
||||
}
|
||||
case '_': break;
|
||||
default: {
|
||||
m_fileline->v3error("Illegal character in decimal constant: "<<*cp);
|
||||
@@ -1658,8 +1656,20 @@ V3Number& V3Number::opAssign(const V3Number& lhs) {
|
||||
V3Number& V3Number::opExtendS(const V3Number& lhs, uint32_t lbits) {
|
||||
// Note may be a width change during the sign extension
|
||||
setZero();
|
||||
for(int bit=0; bit<this->width(); bit++) {
|
||||
setBit(bit,lhs.bitIsExtend(bit, lbits));
|
||||
for (int bit=0; bit < width(); bit++) {
|
||||
char extendWith = lhs.bitIsExtend(bit, lbits);
|
||||
setBit(bit, extendWith);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
V3Number& V3Number::opExtendXZ(const V3Number& lhs, uint32_t lbits) {
|
||||
// Note may be a width change during the X/Z extension
|
||||
setZero();
|
||||
for (int bit=0; bit < width(); bit++) {
|
||||
char extendWith = lhs.bitIsExtend(bit, lbits);
|
||||
if (extendWith == '1' || extendWith == 1) extendWith = 0;
|
||||
setBit(bit, lhs.bitIsExtend(bit, lbits));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
+4
-2
@@ -199,6 +199,7 @@ public:
|
||||
bool isLtXZ(const V3Number& rhs) const; // operator< with XZ compared
|
||||
void isSigned(bool ssigned) { m_signed=ssigned; }
|
||||
bool isUnknown() const;
|
||||
bool isMsbXZ() const { return bitIsXZ(m_width); }
|
||||
uint32_t toUInt() const;
|
||||
vlsint32_t toSInt() const;
|
||||
vluint64_t toUQuad() const;
|
||||
@@ -231,8 +232,9 @@ public:
|
||||
V3Number& opBitsZ (const V3Number& lhs); // Z->1, 0/1/X->0
|
||||
V3Number& opBitsNonZ(const V3Number& lhs); // Z->0, 0/1/X->1
|
||||
//
|
||||
V3Number& opAssign (const V3Number& lhs);
|
||||
V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension
|
||||
V3Number& opAssign (const V3Number& lhs);
|
||||
V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension
|
||||
V3Number& opExtendXZ(const V3Number& lhs, uint32_t lbits); // X/Z extension
|
||||
V3Number& opRedOr (const V3Number& lhs);
|
||||
V3Number& opRedAnd (const V3Number& lhs);
|
||||
V3Number& opRedXor (const V3Number& lhs);
|
||||
|
||||
+13
-4
@@ -699,10 +699,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
else if ( onoff (sw, "-stats-vars", flag/*ref*/) ) { m_statsVars = flag; m_stats |= flag; }
|
||||
else if ( !strcmp (sw, "-sv") ) { m_defaultLanguage = V3LangCode::L1800_2005; }
|
||||
else if ( onoff (sw, "-threads-coarsen", flag/*ref*/)) { m_threadsCoarsen = flag; } // Undocumented, debug
|
||||
else if ( onoff (sw, "-trace", flag/*ref*/) ) { m_trace = flag; }
|
||||
else if ( onoff (sw, "-trace-fst", flag/*ref*/) ) { m_trace = flag; m_traceFormat = TraceFormat::FST; addLdLibs("-lz"); }
|
||||
else if ( onoff (sw, "-trace-dups", flag/*ref*/) ) { m_traceDups = flag; }
|
||||
else if ( onoff (sw, "-trace-params", flag/*ref*/) ) { m_traceParams = flag; }
|
||||
else if ( onoff (sw, "-trace", flag/*ref*/) ) { m_trace = flag; }
|
||||
else if ( onoff (sw, "-trace-dups", flag/*ref*/) ) { m_traceDups = flag; }
|
||||
else if ( onoff (sw, "-trace-params", flag/*ref*/) ) { m_traceParams = flag; }
|
||||
else if ( onoff (sw, "-trace-structs", flag/*ref*/) ) { m_traceStructs = flag; }
|
||||
else if ( onoff (sw, "-trace-underscore", flag/*ref*/) ) { m_traceUnderscore = flag; }
|
||||
else if ( onoff (sw, "-underline-zero", flag/*ref*/) ) { m_underlineZero = flag; } // Undocumented, old Verilator-2
|
||||
@@ -869,6 +868,16 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
shift;
|
||||
m_outputSplitCTrace = atoi(argv[i]);
|
||||
}
|
||||
else if (!strcmp(sw, "-trace-fst")) {
|
||||
m_trace = true;
|
||||
m_traceFormat = TraceFormat::FST;
|
||||
addLdLibs("-lz");
|
||||
}
|
||||
else if (!strcmp(sw, "-trace-fst-thread")) {
|
||||
m_trace = true;
|
||||
m_traceFormat = TraceFormat::FST_THREAD;
|
||||
addLdLibs("-lz");
|
||||
}
|
||||
else if ( !strcmp (sw, "-trace-depth") && (i+1)<argc ) {
|
||||
shift;
|
||||
m_traceDepth = atoi(argv[i]);
|
||||
|
||||
+6
-1
@@ -41,14 +41,18 @@ class TraceFormat {
|
||||
public:
|
||||
enum en {
|
||||
VCD = 0,
|
||||
FST
|
||||
FST,
|
||||
FST_THREAD
|
||||
} m_e;
|
||||
inline TraceFormat(en _e = VCD) : m_e(_e) {}
|
||||
explicit inline TraceFormat(int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en() const { return m_e; }
|
||||
bool fstFlavor() const { return m_e == FST || m_e == FST_THREAD; }
|
||||
bool threaded() const { return m_e == FST_THREAD; }
|
||||
string classBase() const {
|
||||
static const char* const names[] = {
|
||||
"VerilatedVcd",
|
||||
"VerilatedFst",
|
||||
"VerilatedFst"
|
||||
};
|
||||
return names[m_e];
|
||||
@@ -56,6 +60,7 @@ public:
|
||||
string sourceName() const {
|
||||
static const char* const names[] = {
|
||||
"verilated_vcd",
|
||||
"verilated_fst",
|
||||
"verilated_fst"
|
||||
};
|
||||
return names[m_e];
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(WIN32) || defined(__MINGW32__)
|
||||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
# include <direct.h> // mkdir
|
||||
#endif
|
||||
|
||||
|
||||
+22
-14
@@ -271,21 +271,29 @@ private:
|
||||
|
||||
// Make sure all parameters are constantified
|
||||
virtual void visit(AstVar* nodep) {
|
||||
if (!nodep->user5SetOnce()) { // Process once
|
||||
if (!nodep->user5SetOnce()) { // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isParam()) {
|
||||
if (!nodep->valuep()) { nodep->v3fatalSrc("Parameter without initial value"); }
|
||||
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
|
||||
if (!VN_IS(nodep->valuep(), Const)) { // Complex init, like an array
|
||||
// Make a new INITIAL to set the value.
|
||||
// This allows the normal array/struct handling code to properly initialize the parameter
|
||||
nodep->addNext(new AstInitial(nodep->fileline(),
|
||||
new AstAssign(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
nodep->valuep()->cloneTree(true))));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodep->isParam()) {
|
||||
if (!nodep->valuep()) {
|
||||
nodep->v3error("Parameter without initial value is never given value"
|
||||
<<" (IEEE 1800-2017 6.20.1): "
|
||||
<<nodep->prettyName());
|
||||
} else {
|
||||
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
|
||||
if (!VN_IS(nodep->valuep(), Const)) { // Complex init, like an array
|
||||
// Make a new INITIAL to set the value.
|
||||
// This allows the normal array/struct handling code to properly
|
||||
// initialize the parameter.
|
||||
nodep->addNext(
|
||||
new AstInitial(nodep->fileline(),
|
||||
new AstAssign(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
nodep->valuep()->cloneTree(true))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Make sure varrefs cause vars to constify before things above
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
|
||||
@@ -115,17 +115,6 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
|
||||
m_fileline = new FileLine(fileline);
|
||||
m_inLibrary = inLibrary;
|
||||
|
||||
// Set language standard up front
|
||||
if (!v3Global.opt.preprocOnly()) {
|
||||
// Leting lex parse this saves us from having to specially en/decode
|
||||
// from the V3LangCode to the various Lex BEGIN states. The language
|
||||
// of this source file is updated here, in case there have been any
|
||||
// intervening +<lang>ext+ options since it was first ecountered.
|
||||
FileLine *modfileline = new FileLine(modfilename, 0);
|
||||
modfileline->language(v3Global.opt.fileLanguage(modfilename));
|
||||
ppPushText(string("`begin_keywords \"")+modfileline->language().ascii()+"\"\n");
|
||||
}
|
||||
|
||||
// Preprocess into m_ppBuffer
|
||||
bool ok = V3PreShell::preproc(fileline, modfilename, m_filterp, this, errmsg);
|
||||
if (!ok) {
|
||||
|
||||
+24
-8
@@ -102,8 +102,20 @@ protected:
|
||||
|
||||
// Preprocess
|
||||
s_filterp = filterp;
|
||||
bool ok = preprocOpen(fl, s_filterp, modname, "", errmsg);
|
||||
if (!ok) return false;
|
||||
string modfilename = preprocOpen(fl, s_filterp, modname, "", errmsg);
|
||||
if (modfilename.empty()) return false;
|
||||
|
||||
// Set language standard up front
|
||||
if (!v3Global.opt.preprocOnly()) {
|
||||
// Leting lex parse this saves us from having to specially en/decode
|
||||
// from the V3LangCode to the various Lex BEGIN states. The language
|
||||
// of this source file is updated here, in case there have been any
|
||||
// intervening +<lang>ext+ options since it was first ecountered.
|
||||
FileLine* modfileline = new FileLine(modfilename, 0);
|
||||
modfileline->language(v3Global.opt.fileLanguage(modfilename));
|
||||
V3Parse::ppPushText(parsep, (string("`begin_keywords \"")
|
||||
+modfileline->language().ascii()+"\"\n"));
|
||||
}
|
||||
|
||||
while (!s_preprocp->isEof()) {
|
||||
string line = s_preprocp->getline();
|
||||
@@ -116,12 +128,15 @@ protected:
|
||||
if (modname[0]=='/' || modname[0]=='\\') {
|
||||
fl->v3warn(INCABSPATH,"Suggest `include with absolute path be made relative, and use +include: "<<modname);
|
||||
}
|
||||
preprocOpen(fl, s_filterp, modname, V3Os::filenameDir(fl->filename()), "Cannot find include file: ");
|
||||
preprocOpen(fl, s_filterp, modname, V3Os::filenameDir(fl->filename()),
|
||||
"Cannot find include file: ");
|
||||
}
|
||||
|
||||
bool preprocOpen(FileLine* fl, V3InFilter* filterp, const string& modname, const string& lastpath,
|
||||
const string& errmsg) { // Error message or "" to suppress
|
||||
// Returns true if successful
|
||||
private:
|
||||
string preprocOpen(FileLine* fl, V3InFilter* filterp,
|
||||
const string& modname, const string& lastpath,
|
||||
const string& errmsg) { // Error message or "" to suppress
|
||||
// Returns filename if successful
|
||||
// Try a pure name in case user has a bogus `filename they don't expect
|
||||
string filename = v3Global.opt.filePath(fl, modname, lastpath, errmsg);
|
||||
if (filename=="") {
|
||||
@@ -131,13 +146,14 @@ protected:
|
||||
|
||||
filename = v3Global.opt.filePath(fl, ppmodname, lastpath, errmsg);
|
||||
}
|
||||
if (filename=="") return false; // Not found
|
||||
if (filename=="") return ""; // Not found
|
||||
|
||||
UINFO(2," Reading "<<filename<<endl);
|
||||
s_preprocp->openFile(fl, filterp, filename);
|
||||
return true;
|
||||
return filename;
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
V3PreShellImp() {}
|
||||
~V3PreShellImp() {}
|
||||
|
||||
+14
-6
@@ -226,7 +226,9 @@ private:
|
||||
}
|
||||
|
||||
void createTableVars(AstNode* nodep) {
|
||||
// Create table for each output
|
||||
// Create table for each output
|
||||
typedef std::map<string,int> NameCounts;
|
||||
NameCounts namecounts;
|
||||
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin(); it!=m_outVarps.end(); ++it) {
|
||||
AstVarScope* outvscp = *it;
|
||||
AstVar* outvarp = outvscp->varp();
|
||||
@@ -234,11 +236,17 @@ private:
|
||||
AstNodeArrayDType* dtypep
|
||||
= new AstUnpackArrayDType(fl, outvarp->dtypep(),
|
||||
new AstRange(fl, VL_MASK_I(m_inWidth), 0));
|
||||
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
|
||||
AstVar* tablevarp
|
||||
= new AstVar(fl, AstVarType::MODULETEMP,
|
||||
"__Vtable" + cvtToStr(m_modTables) +"_"+outvarp->name(),
|
||||
dtypep);
|
||||
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
|
||||
string name = "__Vtable"+cvtToStr(m_modTables)+"_"+outvarp->name();
|
||||
NameCounts::iterator nit = namecounts.find(name);
|
||||
if (nit != namecounts.end()) {
|
||||
// Multiple scopes can have same var name. We could append the
|
||||
// scope name but that is very long, so just deduplicate.
|
||||
name += "__dedup"+cvtToStr(++nit->second);
|
||||
} else {
|
||||
namecounts[name] = 0;
|
||||
}
|
||||
AstVar* tablevarp = new AstVar(fl, AstVarType::MODULETEMP, name, dtypep);
|
||||
tablevarp->isConst(true);
|
||||
tablevarp->isStatic(true);
|
||||
tablevarp->valuep(new AstInitArray(nodep->fileline(), dtypep, NULL));
|
||||
|
||||
+9
-5
@@ -1170,11 +1170,15 @@ private:
|
||||
nodep->replaceWith(outrefp);
|
||||
// Insert new statements
|
||||
visitp = insertBeforeStmt(nodep, beginp);
|
||||
} else {
|
||||
// outvscp maybe non-NULL if calling a function in a taskref,
|
||||
// but if so we want to simply ignore the function result
|
||||
nodep->replaceWith(beginp);
|
||||
}
|
||||
} else {
|
||||
if (nodep->taskp()->isFunction()) {
|
||||
nodep->v3warn(IGNOREDRETURN,
|
||||
"Ignoring return value of non-void function (IEEE 2017 13.4.1)");
|
||||
}
|
||||
// outvscp maybe non-NULL if calling a function in a taskref,
|
||||
// but if so we want to simply ignore the function result
|
||||
nodep->replaceWith(beginp);
|
||||
}
|
||||
// Cleanup
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
UINFO(4," FTask REF Done.\n");
|
||||
|
||||
+1
-1
@@ -511,7 +511,7 @@ private:
|
||||
}
|
||||
} else {
|
||||
AstNode* clrp = new AstAssign(fl, new AstVarRef(fl, m_activityVscp, true),
|
||||
new AstConst(fl, V3Number(fl, m_activityVscp->width())));
|
||||
new AstConst(fl, V3Number(fl, m_activityVscp->width(), 0)));
|
||||
m_fullFuncp->addFinalsp(clrp->cloneTree(true));
|
||||
m_chgFuncp->addFinalsp(clrp);
|
||||
}
|
||||
|
||||
+45
-2
@@ -2232,6 +2232,19 @@ private:
|
||||
userIterateAndNext(nodep->strgp(), WidthVP(SELF,BOTH).p());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstFRead* nodep) {
|
||||
if (m_vup->prelim()) {
|
||||
nodep->dtypeSetSigned32(); // Spec says integer return
|
||||
userIterateAndNext(nodep->memp(), WidthVP(SELF,BOTH).p());
|
||||
iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
|
||||
if (nodep->startp()) {
|
||||
iterateCheckSigned32(nodep, "$fread start", nodep->startp(), BOTH);
|
||||
}
|
||||
if (nodep->countp()) {
|
||||
iterateCheckSigned32(nodep, "$fread count", nodep->countp(), BOTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstFScanF* nodep) {
|
||||
if (m_vup->prelim()) {
|
||||
nodep->dtypeSetSigned32(); // Spec says integer return
|
||||
@@ -3157,8 +3170,26 @@ private:
|
||||
nodepr = newp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // No change
|
||||
// X/Z also upper bit extend. In pre-SV only to 32-bits, SV forever.
|
||||
else if (!constp->num().sized()
|
||||
// Make it the proper size. Careful of proper extension of 0's/1's
|
||||
&& expWidth > 32 && constp->num().isMsbXZ()) {
|
||||
constp->v3warn(WIDTH, "Unsized constant being X/Z extended to "
|
||||
<<expWidth<<" bits: "<<constp->prettyName());
|
||||
V3Number num (constp->fileline(), expWidth);
|
||||
num.opExtendXZ(constp->num(), constp->width());
|
||||
AstNode* newp = new AstConst(constp->fileline(), num);
|
||||
// Spec says always unsigned with proper width
|
||||
if (debug()>4) constp->dumpTree(cout," fixUnszExtend_old: ");
|
||||
if (debug()>4) newp->dumpTree(cout," _new: ");
|
||||
constp->replaceWith(newp);
|
||||
constp->deleteTree(); VL_DANGLING(constp);
|
||||
// Tell caller the new constp, and that we changed it.
|
||||
nodepr = newp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // No change
|
||||
}
|
||||
|
||||
bool similarDTypeRecurse(AstNodeDType* node1p, AstNodeDType* node2p) {
|
||||
@@ -3172,6 +3203,18 @@ private:
|
||||
underp = iterateCheck(nodep,"file_descriptor",underp,SELF,FINAL,expDTypep,EXTEND_EXP);
|
||||
if (underp) {} // cppcheck
|
||||
}
|
||||
void iterateCheckSigned32(AstNode* nodep, const char* side, AstNode* underp, Stage stage) {
|
||||
// Coerce child to signed32 if not already. Child is self-determined
|
||||
// underp may change as a result of replacement
|
||||
if (stage & PRELIM) {
|
||||
underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, PRELIM).p());
|
||||
}
|
||||
if (stage & FINAL) {
|
||||
AstNodeDType* expDTypep = nodep->findSigned32DType();
|
||||
underp = iterateCheck(nodep, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP);
|
||||
}
|
||||
if (underp) {} // cppcheck
|
||||
}
|
||||
void iterateCheckReal(AstNode* nodep, const char* side, AstNode* underp, Stage stage) {
|
||||
// Coerce child to real if not already. Child is self-determined
|
||||
// e.g. nodep=ADDD, underp=ADD in ADDD(ADD(a,b), real-CONST)
|
||||
|
||||
+58
-58
@@ -32,35 +32,35 @@
|
||||
class VlcBuckets {
|
||||
private:
|
||||
// MEMBERS
|
||||
vluint64_t* m_datap; ///< Pointer to first bucket (dynamically allocated)
|
||||
vluint64_t m_dataSize; ///< Current entries in m_datap
|
||||
vluint64_t m_bucketsCovered; ///< Num buckets with sufficient coverage
|
||||
vluint64_t* m_datap; ///< Pointer to first bucket (dynamically allocated)
|
||||
vluint64_t m_dataSize; ///< Current entries in m_datap
|
||||
vluint64_t m_bucketsCovered; ///< Num buckets with sufficient coverage
|
||||
|
||||
private:
|
||||
static inline vluint64_t covBit(vluint64_t point) { return 1ULL<<(point & 63); }
|
||||
inline vluint64_t allocSize() const { return sizeof(vluint64_t) * m_dataSize / 64; }
|
||||
void allocate(vluint64_t point) {
|
||||
vluint64_t oldsize = m_dataSize;
|
||||
if (m_dataSize<point) m_dataSize=(point+64) & ~63ULL; // Keep power of two
|
||||
m_dataSize *= 2;
|
||||
vluint64_t oldsize = m_dataSize;
|
||||
if (m_dataSize<point) m_dataSize=(point+64) & ~63ULL; // Keep power of two
|
||||
m_dataSize *= 2;
|
||||
//UINFO(9, "Realloc "<<allocSize()<<" for "<<point<<" "<<cvtToHex(m_datap)<<endl);
|
||||
vluint64_t* newp = (vluint64_t*)realloc(m_datap, allocSize());
|
||||
if (!newp) { free(m_datap); v3fatal("Out of memory increasing buckets"); }
|
||||
m_datap = newp;
|
||||
for (vluint64_t i=oldsize; i<m_dataSize; i+=64) m_datap[i/64] = 0;
|
||||
vluint64_t* newp = (vluint64_t*)realloc(m_datap, allocSize());
|
||||
if (!newp) { free(m_datap); v3fatal("Out of memory increasing buckets"); }
|
||||
m_datap = newp;
|
||||
for (vluint64_t i=oldsize; i<m_dataSize; i+=64) m_datap[i/64] = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlcBuckets() {
|
||||
m_dataSize = 0;
|
||||
m_datap = NULL;
|
||||
m_bucketsCovered = 0;
|
||||
allocate(1024);
|
||||
m_dataSize = 0;
|
||||
m_datap = NULL;
|
||||
m_bucketsCovered = 0;
|
||||
allocate(1024);
|
||||
}
|
||||
~VlcBuckets() {
|
||||
m_dataSize = 0;
|
||||
free(m_datap); m_datap=NULL;
|
||||
m_dataSize = 0;
|
||||
free(m_datap); m_datap=NULL;
|
||||
}
|
||||
|
||||
// ACCESSORS
|
||||
@@ -69,66 +69,66 @@ public:
|
||||
|
||||
// METHODS
|
||||
void addData(vluint64_t point, vluint64_t hits) {
|
||||
if (hits >= sufficient()) {
|
||||
//UINFO(9," addData "<<point<<" "<<hits<<" size="<<m_dataSize<<endl);
|
||||
if (point >= m_dataSize) allocate(point);
|
||||
m_datap[point/64] |= covBit(point);
|
||||
m_bucketsCovered++;
|
||||
}
|
||||
if (hits >= sufficient()) {
|
||||
//UINFO(9," addData "<<point<<" "<<hits<<" size="<<m_dataSize<<endl);
|
||||
if (point >= m_dataSize) allocate(point);
|
||||
m_datap[point/64] |= covBit(point);
|
||||
m_bucketsCovered++;
|
||||
}
|
||||
}
|
||||
void clearHits(vluint64_t point) const {
|
||||
if (point >= m_dataSize) {
|
||||
return;
|
||||
} else {
|
||||
m_datap[point/64] &= ~covBit(point);
|
||||
}
|
||||
if (point >= m_dataSize) {
|
||||
return;
|
||||
} else {
|
||||
m_datap[point/64] &= ~covBit(point);
|
||||
}
|
||||
}
|
||||
bool exists(vluint64_t point) const {
|
||||
if (point >= m_dataSize) {
|
||||
return false;
|
||||
} else {
|
||||
return (m_datap[point/64] & covBit(point)) ? 1:0;
|
||||
}
|
||||
if (point >= m_dataSize) {
|
||||
return false;
|
||||
} else {
|
||||
return (m_datap[point/64] & covBit(point)) ? 1:0;
|
||||
}
|
||||
}
|
||||
vluint64_t hits(vluint64_t point) const {
|
||||
if (point >= m_dataSize) {
|
||||
return 0;
|
||||
} else {
|
||||
return (m_datap[point/64] & covBit(point)) ? 1:0;
|
||||
}
|
||||
if (point >= m_dataSize) {
|
||||
return 0;
|
||||
} else {
|
||||
return (m_datap[point/64] & covBit(point)) ? 1:0;
|
||||
}
|
||||
}
|
||||
vluint64_t popCount() const {
|
||||
vluint64_t pop = 0;
|
||||
for (vluint64_t i=0; i<m_dataSize; i++) {
|
||||
if (hits(i)) pop++;
|
||||
}
|
||||
return pop;
|
||||
vluint64_t pop = 0;
|
||||
for (vluint64_t i=0; i<m_dataSize; i++) {
|
||||
if (hits(i)) pop++;
|
||||
}
|
||||
return pop;
|
||||
}
|
||||
vluint64_t dataPopCount(const VlcBuckets& remaining) {
|
||||
vluint64_t pop = 0;
|
||||
for (vluint64_t i=0; i<m_dataSize; i++) {
|
||||
if (hits(i) && remaining.hits(i)) pop++;
|
||||
}
|
||||
return pop;
|
||||
vluint64_t pop = 0;
|
||||
for (vluint64_t i=0; i<m_dataSize; i++) {
|
||||
if (hits(i) && remaining.hits(i)) pop++;
|
||||
}
|
||||
return pop;
|
||||
}
|
||||
void orData(const VlcBuckets& ordata) {
|
||||
for (vluint64_t i=0; i<m_dataSize; i++) {
|
||||
if (hits(i) && ordata.hits(i)) {
|
||||
clearHits(i);
|
||||
}
|
||||
}
|
||||
for (vluint64_t i=0; i<m_dataSize; i++) {
|
||||
if (hits(i) && ordata.hits(i)) {
|
||||
clearHits(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump() const {
|
||||
cout<<"# ";
|
||||
for (vluint64_t i=0; i<m_dataSize; i++) {
|
||||
if (hits(i)) cout<<","<<i;
|
||||
}
|
||||
cout<<endl;
|
||||
cout<<"# ";
|
||||
for (vluint64_t i=0; i<m_dataSize; i++) {
|
||||
if (hits(i)) cout<<","<<i;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//######################################################################
|
||||
|
||||
#endif // guard
|
||||
#endif // guard
|
||||
|
||||
+67
-68
@@ -43,7 +43,7 @@
|
||||
|
||||
void VlcOptions::addReadFile(const string& filename) {
|
||||
if (m_readFiles.find(filename) == m_readFiles.end()) {
|
||||
m_readFiles.insert(filename);
|
||||
m_readFiles.insert(filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,9 +59,9 @@ bool VlcOptions::onoff(const char* sw, const char* arg, bool& flag) {
|
||||
// if sw=="-noarg", then return true (found it), and flag=false
|
||||
// else return false
|
||||
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.");
|
||||
if (0==strcmp(sw,arg)) { flag=true; return true; }
|
||||
else if (0==strncmp(sw,"-no",3) && (0==strcmp(sw+3,arg+1))) { flag=false; return true; }
|
||||
else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag=false; return true; }
|
||||
if (0==strcmp(sw,arg)) { flag = true; return true; }
|
||||
else if (0==strncmp(sw,"-no",3) && (0==strcmp(sw+3,arg+1))) { flag = false; return true; }
|
||||
else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag = false; return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -71,58 +71,58 @@ void VlcOptions::parseOptsList(int argc, char** argv) {
|
||||
// May be called recursively when there are -f files.
|
||||
#define shift { ++i; }
|
||||
for (int i=0; i<argc; ) {
|
||||
UINFO(9, " Option: "<<argv[i]<<endl);
|
||||
if (argv[i][0]=='-') {
|
||||
const char *sw = argv[i];
|
||||
bool flag = true;
|
||||
// Allow gnu -- switches
|
||||
if (sw[0]=='-' && sw[1]=='-') ++sw;
|
||||
if (0) {}
|
||||
// Single switches
|
||||
else if ( onoff (sw, "-annotate-all", flag/*ref*/) ) { m_annotateAll = flag; }
|
||||
else if ( onoff (sw, "-rank", flag/*ref*/) ) { m_rank = flag; }
|
||||
else if ( onoff (sw, "-unlink", flag/*ref*/) ) { m_unlink = flag; }
|
||||
// Parameterized switches
|
||||
UINFO(9, " Option: "<<argv[i]<<endl);
|
||||
if (argv[i][0]=='-') {
|
||||
const char *sw = argv[i];
|
||||
bool flag = true;
|
||||
// Allow gnu -- switches
|
||||
if (sw[0]=='-' && sw[1]=='-') ++sw;
|
||||
if (0) {}
|
||||
// Single switches
|
||||
else if ( onoff (sw, "-annotate-all", flag/*ref*/) ) { m_annotateAll = flag; }
|
||||
else if ( onoff (sw, "-rank", flag/*ref*/) ) { m_rank = flag; }
|
||||
else if ( onoff (sw, "-unlink", flag/*ref*/) ) { m_unlink = flag; }
|
||||
// Parameterized switches
|
||||
else if ( !strcmp (sw, "-annotate-min") && (i+1)<argc ) {
|
||||
shift;
|
||||
m_annotateMin = atoi(argv[i]);
|
||||
}
|
||||
else if ( !strcmp (sw, "-annotate") && (i+1)<argc ) {
|
||||
shift;
|
||||
m_annotateOut = argv[i];
|
||||
}
|
||||
else if ( !strcmp (sw, "-debug") ) {
|
||||
V3Error::debugDefault(3);
|
||||
}
|
||||
else if ( !strcmp (sw, "-debugi") && (i+1)<argc ) {
|
||||
shift;
|
||||
V3Error::debugDefault(atoi(argv[i]));
|
||||
}
|
||||
else if ( !strcmp (sw, "-V") ) {
|
||||
showVersion(true);
|
||||
exit(0);
|
||||
}
|
||||
else if ( !strcmp (sw, "-version") ) {
|
||||
showVersion(false);
|
||||
exit(0);
|
||||
}
|
||||
else if ( !strcmp (sw, "-write") && (i+1)<argc ) {
|
||||
shift;
|
||||
m_writeFile = argv[i];
|
||||
}
|
||||
else {
|
||||
else if ( !strcmp (sw, "-annotate") && (i+1)<argc ) {
|
||||
shift;
|
||||
m_annotateOut = argv[i];
|
||||
}
|
||||
else if ( !strcmp (sw, "-debug") ) {
|
||||
V3Error::debugDefault(3);
|
||||
}
|
||||
else if ( !strcmp (sw, "-debugi") && (i+1)<argc ) {
|
||||
shift;
|
||||
V3Error::debugDefault(atoi(argv[i]));
|
||||
}
|
||||
else if ( !strcmp (sw, "-V") ) {
|
||||
showVersion(true);
|
||||
exit(0);
|
||||
}
|
||||
else if ( !strcmp (sw, "-version") ) {
|
||||
showVersion(false);
|
||||
exit(0);
|
||||
}
|
||||
else if ( !strcmp (sw, "-write") && (i+1)<argc ) {
|
||||
shift;
|
||||
m_writeFile = argv[i];
|
||||
}
|
||||
else {
|
||||
v3fatal("Invalid option: "<<argv[i]);
|
||||
}
|
||||
shift;
|
||||
} // - options
|
||||
else if (1) {
|
||||
addReadFile(argv[i]);
|
||||
shift;
|
||||
}
|
||||
else {
|
||||
}
|
||||
shift;
|
||||
} // - options
|
||||
else if (1) {
|
||||
addReadFile(argv[i]);
|
||||
shift;
|
||||
}
|
||||
else {
|
||||
v3fatal("Invalid argument: "<<argv[i]);
|
||||
shift;
|
||||
}
|
||||
shift;
|
||||
}
|
||||
}
|
||||
#undef shift
|
||||
}
|
||||
@@ -154,20 +154,20 @@ int main(int argc, char** argv, char** env) {
|
||||
top.opt.parseOptsList(argc-1, argv+1);
|
||||
|
||||
if (top.opt.readFiles().empty()) {
|
||||
top.opt.addReadFile("vlt_coverage.dat");
|
||||
top.opt.addReadFile("vlt_coverage.dat");
|
||||
}
|
||||
|
||||
{
|
||||
const VlStringSet& readFiles = top.opt.readFiles();
|
||||
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
|
||||
string filename = *it;
|
||||
top.readCoverage(filename);
|
||||
}
|
||||
const VlStringSet& readFiles = top.opt.readFiles();
|
||||
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
|
||||
string filename = *it;
|
||||
top.readCoverage(filename);
|
||||
}
|
||||
}
|
||||
|
||||
if (debug() >= 9) {
|
||||
top.tests().dump(true);
|
||||
top.points().dump();
|
||||
top.tests().dump(true);
|
||||
top.points().dump();
|
||||
}
|
||||
|
||||
V3Error::abortIfWarnings();
|
||||
@@ -176,19 +176,19 @@ int main(int argc, char** argv, char** env) {
|
||||
}
|
||||
|
||||
if (top.opt.rank()) {
|
||||
top.rank();
|
||||
top.tests().dump(false);
|
||||
top.rank();
|
||||
top.tests().dump(false);
|
||||
}
|
||||
|
||||
if (!top.opt.writeFile().empty()) {
|
||||
top.writeCoverage(top.opt.writeFile());
|
||||
V3Error::abortIfWarnings();
|
||||
top.writeCoverage(top.opt.writeFile());
|
||||
V3Error::abortIfWarnings();
|
||||
if (top.opt.unlink()) {
|
||||
const VlStringSet& readFiles = top.opt.readFiles();
|
||||
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
|
||||
string filename = *it;
|
||||
unlink(filename.c_str());
|
||||
}
|
||||
const VlStringSet& readFiles = top.opt.readFiles();
|
||||
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
|
||||
string filename = *it;
|
||||
unlink(filename.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,4 +201,3 @@ int main(int argc, char** argv, char** env) {
|
||||
// Local Variables:
|
||||
// compile-command: "v4make bin/verilator_coverage --debugi 9 test_regress/t/t_vlcov_data_*.dat"
|
||||
// End:
|
||||
|
||||
|
||||
+12
-12
@@ -38,13 +38,13 @@ typedef std::set<string> VlStringSet;
|
||||
|
||||
class VlcOptions {
|
||||
// MEMBERS (general options)
|
||||
string m_annotateOut; // main switch: --annotate I<output_directory>
|
||||
bool m_annotateAll; // main switch: --annotate-all
|
||||
int m_annotateMin; // main switch: --annotate-min I<count>
|
||||
VlStringSet m_readFiles; // main switch: --read
|
||||
bool m_rank; // main switch: --rank
|
||||
bool m_unlink; // main switch: --unlink
|
||||
string m_writeFile; // main switch: --write
|
||||
string m_annotateOut; // main switch: --annotate I<output_directory>
|
||||
bool m_annotateAll; // main switch: --annotate-all
|
||||
int m_annotateMin; // main switch: --annotate-min I<count>
|
||||
VlStringSet m_readFiles; // main switch: --read
|
||||
bool m_rank; // main switch: --rank
|
||||
bool m_unlink; // main switch: --unlink
|
||||
string m_writeFile; // main switch: --write
|
||||
|
||||
private:
|
||||
// METHODS
|
||||
@@ -54,10 +54,10 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlcOptions() {
|
||||
m_annotateAll = false;
|
||||
m_annotateMin = 10;
|
||||
m_rank = false;
|
||||
m_unlink = false;
|
||||
m_annotateAll = false;
|
||||
m_annotateMin = 10;
|
||||
m_rank = false;
|
||||
m_unlink = false;
|
||||
}
|
||||
~VlcOptions() {}
|
||||
void setDebugMode(int level);
|
||||
@@ -81,4 +81,4 @@ public:
|
||||
|
||||
//######################################################################
|
||||
|
||||
#endif // guard
|
||||
#endif // guard
|
||||
|
||||
+49
-49
@@ -36,18 +36,18 @@
|
||||
class VlcPoint {
|
||||
private:
|
||||
// MEMBERS
|
||||
string m_name; //< Name of the point
|
||||
vluint64_t m_pointNum; //< Point number
|
||||
vluint64_t m_testsCovering;//< Number tests with non-zero coverage of this point
|
||||
vluint64_t m_count; //< Count of hits across all tests
|
||||
string m_name; //< Name of the point
|
||||
vluint64_t m_pointNum; //< Point number
|
||||
vluint64_t m_testsCovering; //< Number tests with non-zero coverage of this point
|
||||
vluint64_t m_count; //< Count of hits across all tests
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlcPoint(const string& name, int pointNum) {
|
||||
m_name = name;
|
||||
m_pointNum = pointNum;
|
||||
m_testsCovering = 0;
|
||||
m_count = 0;
|
||||
m_name = name;
|
||||
m_pointNum = pointNum;
|
||||
m_testsCovering = 0;
|
||||
m_count = 0;
|
||||
}
|
||||
~VlcPoint() {}
|
||||
// ACCESSORS
|
||||
@@ -66,31 +66,31 @@ public:
|
||||
int column() const { return atoi(keyExtract(VL_CIK_COLUMN).c_str()); }
|
||||
// METHODS
|
||||
string keyExtract(const char* shortKey) const {
|
||||
// Hot function
|
||||
size_t shortLen = strlen(shortKey);
|
||||
const string namestr = name();
|
||||
for (const char* cp = namestr.c_str(); *cp; ++cp) {
|
||||
if (*cp == '\001') {
|
||||
if (0==strncmp(cp+1, shortKey, shortLen)
|
||||
&& cp[shortLen+1] == '\002') {
|
||||
cp += shortLen+2; // Skip \001+short+\002
|
||||
const char* ep = cp;
|
||||
while (*ep && *ep != '\001') ++ep;
|
||||
return string(cp, ep-cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
// Hot function
|
||||
size_t shortLen = strlen(shortKey);
|
||||
const string namestr = name();
|
||||
for (const char* cp = namestr.c_str(); *cp; ++cp) {
|
||||
if (*cp == '\001') {
|
||||
if (0==strncmp(cp+1, shortKey, shortLen)
|
||||
&& cp[shortLen+1] == '\002') {
|
||||
cp += shortLen+2; // Skip \001+short+\002
|
||||
const char* ep = cp;
|
||||
while (*ep && *ep != '\001') ++ep;
|
||||
return string(cp, ep-cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
static void dumpHeader() {
|
||||
cout<<"Points:\n";
|
||||
cout<<" Num, TestsCover, Count, Name"<<endl;
|
||||
cout<<"Points:\n";
|
||||
cout<<" Num, TestsCover, Count, Name"<<endl;
|
||||
}
|
||||
void dump() const {
|
||||
cout<<" "<<std::setw(8)<<std::setfill('0')<<pointNum()
|
||||
<<", "<<std::setw(7)<<std::setfill(' ')<<testsCovering()
|
||||
<<", "<<std::setw(7)<<std::setfill(' ')<<count()
|
||||
<<", \""<<name()<<"\""<<endl;
|
||||
<<", \""<<name()<<"\""<<endl;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -115,40 +115,40 @@ public:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlcPoints() {
|
||||
m_numPoints = 0;
|
||||
m_numPoints = 0;
|
||||
}
|
||||
~VlcPoints() {}
|
||||
|
||||
// METHODS
|
||||
void dump() {
|
||||
UINFO(2,"dumpPoints...\n");
|
||||
VlcPoint::dumpHeader();
|
||||
for (VlcPoints::ByName::iterator it=begin(); it!=end(); ++it) {
|
||||
const VlcPoint& point = pointNumber(it->second);
|
||||
point.dump();
|
||||
}
|
||||
UINFO(2,"dumpPoints...\n");
|
||||
VlcPoint::dumpHeader();
|
||||
for (VlcPoints::ByName::iterator it=begin(); it!=end(); ++it) {
|
||||
const VlcPoint& point = pointNumber(it->second);
|
||||
point.dump();
|
||||
}
|
||||
}
|
||||
VlcPoint& pointNumber(vluint64_t num) {
|
||||
return m_points[num];
|
||||
return m_points[num];
|
||||
}
|
||||
vluint64_t findAddPoint(const string& name, vluint64_t count) {
|
||||
vluint64_t pointnum;
|
||||
NameMap::iterator iter = m_nameMap.find(name);
|
||||
if (iter != m_nameMap.end()) {
|
||||
pointnum = iter->second;
|
||||
m_points[pointnum].countInc(count);
|
||||
}
|
||||
else {
|
||||
pointnum = m_numPoints++;
|
||||
VlcPoint point (name, pointnum);
|
||||
point.countInc(count);
|
||||
m_points.push_back(point);
|
||||
m_nameMap.insert(make_pair(point.name(), point.pointNum()));
|
||||
}
|
||||
return pointnum;
|
||||
vluint64_t pointnum;
|
||||
NameMap::iterator iter = m_nameMap.find(name);
|
||||
if (iter != m_nameMap.end()) {
|
||||
pointnum = iter->second;
|
||||
m_points[pointnum].countInc(count);
|
||||
}
|
||||
else {
|
||||
pointnum = m_numPoints++;
|
||||
VlcPoint point (name, pointnum);
|
||||
point.countInc(count);
|
||||
m_points.push_back(point);
|
||||
m_nameMap.insert(make_pair(point.name(), point.pointNum()));
|
||||
}
|
||||
return pointnum;
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
#endif // guard
|
||||
#endif // guard
|
||||
|
||||
+36
-36
@@ -33,18 +33,18 @@
|
||||
class VlcSourceCount {
|
||||
private:
|
||||
// MEMBERS
|
||||
int m_lineno; ///< Line number
|
||||
int m_column; ///< Column number
|
||||
vluint64_t m_count; ///< Count
|
||||
bool m_ok; ///< Coverage is above threshold
|
||||
int m_lineno; ///< Line number
|
||||
int m_column; ///< Column number
|
||||
vluint64_t m_count; ///< Count
|
||||
bool m_ok; ///< Coverage is above threshold
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlcSourceCount(int lineno, int column) {
|
||||
m_lineno = lineno;
|
||||
m_column = column;
|
||||
m_count = 0;
|
||||
m_ok = false;
|
||||
m_lineno = lineno;
|
||||
m_column = column;
|
||||
m_count = 0;
|
||||
m_ok = false;
|
||||
}
|
||||
~VlcSourceCount() {}
|
||||
|
||||
@@ -56,8 +56,8 @@ public:
|
||||
|
||||
// METHODS
|
||||
void incCount(vluint64_t count, bool ok) {
|
||||
m_count += count;
|
||||
if (ok) m_ok = true;
|
||||
m_count += count;
|
||||
if (ok) m_ok = true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -72,15 +72,15 @@ public:
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
string m_name; //< Name of the source file
|
||||
bool m_needed; //< Need to annotate; has low coverage
|
||||
LinenoMap m_lines; //< Map of each annotated line
|
||||
string m_name; //< Name of the source file
|
||||
bool m_needed; //< Need to annotate; has low coverage
|
||||
LinenoMap m_lines; //< Map of each annotated line
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit VlcSource(const string& name) {
|
||||
m_name = name;
|
||||
m_needed = false;
|
||||
m_name = name;
|
||||
m_needed = false;
|
||||
}
|
||||
~VlcSource() {}
|
||||
|
||||
@@ -92,17 +92,17 @@ public:
|
||||
|
||||
// METHODS
|
||||
void incCount(int lineno, int column, vluint64_t count, bool ok) {
|
||||
LinenoMap::iterator lit = m_lines.find(lineno);
|
||||
if (lit == m_lines.end()) {
|
||||
lit = m_lines.insert(make_pair(lineno,ColumnMap())).first;
|
||||
}
|
||||
ColumnMap& cmap = lit->second;
|
||||
ColumnMap::iterator cit = cmap.find(column);
|
||||
if (cit == cmap.end()) {
|
||||
cit = cmap.insert(make_pair(column,VlcSourceCount(lineno, column))).first;
|
||||
}
|
||||
VlcSourceCount& sc = cit->second;
|
||||
sc.incCount(count,ok);
|
||||
LinenoMap::iterator lit = m_lines.find(lineno);
|
||||
if (lit == m_lines.end()) {
|
||||
lit = m_lines.insert(make_pair(lineno, ColumnMap())).first;
|
||||
}
|
||||
ColumnMap& cmap = lit->second;
|
||||
ColumnMap::iterator cit = cmap.find(column);
|
||||
if (cit == cmap.end()) {
|
||||
cit = cmap.insert(make_pair(column, VlcSourceCount(lineno, column))).first;
|
||||
}
|
||||
VlcSourceCount& sc = cit->second;
|
||||
sc.incCount(count, ok);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -115,7 +115,7 @@ public:
|
||||
typedef std::map<string,VlcSource> NameMap;
|
||||
private:
|
||||
// MEMBERS
|
||||
NameMap m_sources; //< List of all sources
|
||||
NameMap m_sources; //< List of all sources
|
||||
|
||||
public:
|
||||
// ITERATORS
|
||||
@@ -130,17 +130,17 @@ public:
|
||||
|
||||
// METHODS
|
||||
VlcSource& findNewSource(const string& name) {
|
||||
NameMap::iterator iter = m_sources.find(name);
|
||||
if (iter != m_sources.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
else {
|
||||
iter = m_sources.insert(make_pair(name, VlcSource(name))).first;
|
||||
return iter->second;
|
||||
}
|
||||
NameMap::iterator iter = m_sources.find(name);
|
||||
if (iter != m_sources.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
else {
|
||||
iter = m_sources.insert(make_pair(name, VlcSource(name))).first;
|
||||
return iter->second;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
#endif // Guard
|
||||
#endif // Guard
|
||||
|
||||
+36
-36
@@ -36,23 +36,23 @@
|
||||
class VlcTest {
|
||||
private:
|
||||
// MEMBERS
|
||||
string m_name; //< Name of the test
|
||||
double m_computrons; //< Runtime for the test
|
||||
vluint64_t m_testrun; //< Test run number, for database use
|
||||
vluint64_t m_rank; //< Execution rank suggestion
|
||||
vluint64_t m_rankPoints; //< Ranked additional points
|
||||
vluint64_t m_user; //< User data for algorithms (not persisted in .dat file)
|
||||
VlcBuckets m_buckets; //< Coverage data for each coverage point
|
||||
string m_name; //< Name of the test
|
||||
double m_computrons; //< Runtime for the test
|
||||
vluint64_t m_testrun; //< Test run number, for database use
|
||||
vluint64_t m_rank; //< Execution rank suggestion
|
||||
vluint64_t m_rankPoints; //< Ranked additional points
|
||||
vluint64_t m_user; //< User data for algorithms (not persisted in .dat file)
|
||||
VlcBuckets m_buckets; //< Coverage data for each coverage point
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlcTest(const string& name, vluint64_t testrun, double comp) {
|
||||
m_name = name;
|
||||
m_computrons = comp;
|
||||
m_testrun = testrun;
|
||||
m_rank = 0;
|
||||
m_rankPoints = 0;
|
||||
m_user = 0;
|
||||
m_name = name;
|
||||
m_computrons = comp;
|
||||
m_testrun = testrun;
|
||||
m_rank = 0;
|
||||
m_rankPoints = 0;
|
||||
m_user = 0;
|
||||
}
|
||||
~VlcTest() {}
|
||||
|
||||
@@ -71,20 +71,20 @@ public:
|
||||
|
||||
// METHODS
|
||||
static void dumpHeader() {
|
||||
cout<<"Tests:\n";
|
||||
//cout<<" Testrun, Computrons,"; // Currently not loaded
|
||||
cout<<" Covered, Rank, RankPts, Filename"<<endl;
|
||||
cout<<"Tests:\n";
|
||||
//cout<<" Testrun, Computrons,"; // Currently not loaded
|
||||
cout<<" Covered, Rank, RankPts, Filename"<<endl;
|
||||
}
|
||||
void dump(bool bucketsToo) {
|
||||
if (testrun() || computrons()!=0.0) {
|
||||
if (testrun() || computrons()!=0.0) {
|
||||
cout<<" "<<std::setw(8)<<std::setfill('0')<<testrun()
|
||||
<<", "<<std::setw(7)<<std::setfill(' ')<<computrons()<<",";
|
||||
}
|
||||
}
|
||||
cout<<" "<<std::setw(7)<<std::setfill(' ')<<bucketsCovered()
|
||||
<<", "<<std::setw(7)<<std::setfill(' ')<<rank()
|
||||
<<", "<<std::setw(7)<<std::setfill(' ')<<rankPoints()
|
||||
<<", \""<<name()<<"\""<<endl;
|
||||
if (bucketsToo) m_buckets.dump();
|
||||
<<", \""<<name()<<"\""<<endl;
|
||||
if (bucketsToo) m_buckets.dump();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
typedef std::vector<VlcTest*> ByName;
|
||||
private:
|
||||
// MEMBERS
|
||||
ByName m_tests; //< List of all tests
|
||||
ByName m_tests; //< List of all tests
|
||||
|
||||
public:
|
||||
// ITERATORS
|
||||
@@ -109,31 +109,31 @@ public:
|
||||
// CONSTRUCTORS
|
||||
VlcTests() {}
|
||||
~VlcTests() {
|
||||
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
|
||||
delete *it; *it=NULL;
|
||||
}
|
||||
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
|
||||
delete *it; *it=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// METHODS
|
||||
void dump(bool bucketsToo) {
|
||||
UINFO(2,"dumpTests...\n");
|
||||
VlcTest::dumpHeader();
|
||||
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
|
||||
(*it)->dump(bucketsToo);
|
||||
}
|
||||
UINFO(2,"dumpTests...\n");
|
||||
VlcTest::dumpHeader();
|
||||
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
|
||||
(*it)->dump(bucketsToo);
|
||||
}
|
||||
}
|
||||
VlcTest* newTest(const string& name, vluint64_t testrun, double comp) {
|
||||
VlcTest* testp = new VlcTest(name, testrun, comp);
|
||||
m_tests.push_back(testp);
|
||||
return testp;
|
||||
VlcTest* testp = new VlcTest(name, testrun, comp);
|
||||
m_tests.push_back(testp);
|
||||
return testp;
|
||||
}
|
||||
void clearUser() {
|
||||
for (ByName::iterator it = m_tests.begin(); it != m_tests.end(); ++it) {
|
||||
(*it)->user(0);
|
||||
}
|
||||
for (ByName::iterator it = m_tests.begin(); it != m_tests.end(); ++it) {
|
||||
(*it)->user(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
#endif // Guard
|
||||
#endif // Guard
|
||||
|
||||
+122
-122
@@ -34,8 +34,8 @@ void VlcTop::readCoverage(const string& filename, bool nonfatal) {
|
||||
|
||||
std::ifstream is(filename.c_str());
|
||||
if (!is) {
|
||||
if (!nonfatal) v3fatal("Can't read "<<filename);
|
||||
return;
|
||||
if (!nonfatal) v3fatal("Can't read "<<filename);
|
||||
return;
|
||||
}
|
||||
|
||||
// Testrun and computrons argument unsupported as yet
|
||||
@@ -45,23 +45,23 @@ void VlcTop::readCoverage(const string& filename, bool nonfatal) {
|
||||
string line = V3Os::getline(is);
|
||||
//UINFO(9," got "<<line<<endl);
|
||||
if (line[0] == 'C') {
|
||||
string::size_type secspace=3;
|
||||
for (; secspace<line.length(); secspace++) {
|
||||
if (line[secspace]=='\'' && line[secspace+1]==' ') break;
|
||||
}
|
||||
string point = line.substr(3,secspace-3);
|
||||
vluint64_t hits = atoll(line.c_str()+secspace+1);
|
||||
//UINFO(9," point '"<<point<<"'"<<" "<<hits<<endl);
|
||||
string::size_type secspace = 3;
|
||||
for (; secspace<line.length(); secspace++) {
|
||||
if (line[secspace]=='\'' && line[secspace+1]==' ') break;
|
||||
}
|
||||
string point = line.substr(3, secspace-3);
|
||||
vluint64_t hits = atoll(line.c_str()+secspace+1);
|
||||
//UINFO(9," point '"<<point<<"'"<<" "<<hits<<endl);
|
||||
|
||||
vluint64_t pointnum = points().findAddPoint(point, hits);
|
||||
if (pointnum) {} // Prevent unused
|
||||
if (opt.rank()) { // Only if ranking - uses a lot of memory
|
||||
if (hits >= VlcBuckets::sufficient()) {
|
||||
points().pointNumber(pointnum).testsCoveringInc();
|
||||
testp->buckets().addData(pointnum, hits);
|
||||
}
|
||||
}
|
||||
}
|
||||
vluint64_t pointnum = points().findAddPoint(point, hits);
|
||||
if (pointnum) {} // Prevent unused
|
||||
if (opt.rank()) { // Only if ranking - uses a lot of memory
|
||||
if (hits >= VlcBuckets::sufficient()) {
|
||||
points().pointNumber(pointnum).testsCoveringInc();
|
||||
testp->buckets().addData(pointnum, hits);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,14 +70,14 @@ void VlcTop::writeCoverage(const string& filename) {
|
||||
|
||||
std::ofstream os(filename.c_str());
|
||||
if (!os) {
|
||||
v3fatal("Can't write "<<filename);
|
||||
return;
|
||||
v3fatal("Can't write "<<filename);
|
||||
return;
|
||||
}
|
||||
|
||||
os << "# SystemC::Coverage-3" << endl;
|
||||
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
|
||||
const VlcPoint& point = m_points.pointNumber(it->second);
|
||||
os <<"C '"<<point.name()<<"' " << point.count()<<endl;
|
||||
const VlcPoint& point = m_points.pointNumber(it->second);
|
||||
os <<"C '"<<point.name()<<"' " << point.count()<<endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,32 +85,32 @@ void VlcTop::writeCoverage(const string& filename) {
|
||||
|
||||
struct CmpComputrons {
|
||||
inline bool operator() (const VlcTest* lhsp, const VlcTest* rhsp) const {
|
||||
if (lhsp->computrons() != rhsp->computrons()) {
|
||||
return lhsp->computrons() < rhsp->computrons();
|
||||
}
|
||||
return lhsp->bucketsCovered() > rhsp->bucketsCovered();
|
||||
if (lhsp->computrons() != rhsp->computrons()) {
|
||||
return lhsp->computrons() < rhsp->computrons();
|
||||
}
|
||||
return lhsp->bucketsCovered() > rhsp->bucketsCovered();
|
||||
}
|
||||
};
|
||||
|
||||
void VlcTop::rank() {
|
||||
UINFO(2,"rank...\n");
|
||||
vluint64_t nextrank=1;
|
||||
vluint64_t nextrank = 1;
|
||||
|
||||
// Sort by computrons, so fast tests get selected first
|
||||
std::vector<VlcTest*> bytime;
|
||||
for (VlcTests::ByName::iterator it=m_tests.begin(); it!=m_tests.end(); ++it) {
|
||||
VlcTest* testp = *it;
|
||||
if (testp->bucketsCovered()) { // else no points, so can't help us
|
||||
bytime.push_back(*it);
|
||||
}
|
||||
VlcTest* testp = *it;
|
||||
if (testp->bucketsCovered()) { // else no points, so can't help us
|
||||
bytime.push_back(*it);
|
||||
}
|
||||
}
|
||||
sort(bytime.begin(), bytime.end(), CmpComputrons()); // Sort the vector
|
||||
sort(bytime.begin(), bytime.end(), CmpComputrons()); // Sort the vector
|
||||
|
||||
VlcBuckets remaining;
|
||||
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
|
||||
VlcPoint* pointp = &points().pointNumber(it->second);
|
||||
// If any tests hit this point, then we'll need to cover it.
|
||||
if (pointp->testsCovering()) { remaining.addData(pointp->pointNum(), 1); }
|
||||
VlcPoint* pointp = &points().pointNumber(it->second);
|
||||
// If any tests hit this point, then we'll need to cover it.
|
||||
if (pointp->testsCovering()) { remaining.addData(pointp->pointNum(), 1); }
|
||||
}
|
||||
|
||||
// Additional Greedy algorithm
|
||||
@@ -118,26 +118,26 @@ void VlcTop::rank() {
|
||||
// then hierarchically solve a small subset of tests, and take resulting
|
||||
// solution and move up to larger subset of tests. (Aka quick sort.)
|
||||
while (1) {
|
||||
if (debug()) { UINFO(9,"Left on iter"<<nextrank<<": "); remaining.dump(); }
|
||||
VlcTest* bestTestp = NULL;
|
||||
vluint64_t bestRemain = 0;
|
||||
if (debug()) { UINFO(9,"Left on iter"<<nextrank<<": "); remaining.dump(); }
|
||||
VlcTest* bestTestp = NULL;
|
||||
vluint64_t bestRemain = 0;
|
||||
for (std::vector<VlcTest*>::iterator it=bytime.begin(); it!=bytime.end(); ++it) {
|
||||
VlcTest* testp = *it;
|
||||
if (!testp->rank()) {
|
||||
vluint64_t remain = testp->buckets().dataPopCount(remaining);
|
||||
if (remain > bestRemain) {
|
||||
bestTestp = testp;
|
||||
bestRemain = remain;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (VlcTest* testp = bestTestp) {
|
||||
testp->rank(nextrank++);
|
||||
testp->rankPoints(bestRemain);
|
||||
remaining.orData(bestTestp->buckets());
|
||||
} else {
|
||||
break; // No test covering more stuff found
|
||||
}
|
||||
VlcTest* testp = *it;
|
||||
if (!testp->rank()) {
|
||||
vluint64_t remain = testp->buckets().dataPopCount(remaining);
|
||||
if (remain > bestRemain) {
|
||||
bestTestp = testp;
|
||||
bestRemain = remain;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (VlcTest* testp = bestTestp) {
|
||||
testp->rank(nextrank++);
|
||||
testp->rankPoints(bestRemain);
|
||||
remaining.orData(bestTestp->buckets());
|
||||
} else {
|
||||
break; // No test covering more stuff found
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,18 +146,18 @@ void VlcTop::rank() {
|
||||
void VlcTop::annotateCalc() {
|
||||
// Calculate per-line information into filedata structure
|
||||
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
|
||||
const VlcPoint& point = m_points.pointNumber(it->second);
|
||||
string filename = point.filename();
|
||||
int lineno = point.lineno();
|
||||
const VlcPoint& point = m_points.pointNumber(it->second);
|
||||
string filename = point.filename();
|
||||
int lineno = point.lineno();
|
||||
if (!filename.empty() && lineno!=0) {
|
||||
int column = point.column();
|
||||
VlcSource& source = sources().findNewSource(filename);
|
||||
string threshStr = point.thresh();
|
||||
int column = point.column();
|
||||
VlcSource& source = sources().findNewSource(filename);
|
||||
string threshStr = point.thresh();
|
||||
unsigned thresh = (!threshStr.empty()) ? atoi(threshStr.c_str()) : opt.annotateMin();
|
||||
bool ok = (point.count() >= thresh);
|
||||
UINFO(9, "AnnoCalc count "<<filename<<" "<<lineno<<" "<<point.count()<<endl);
|
||||
source.incCount(lineno, column, point.count(), ok);
|
||||
}
|
||||
bool ok = (point.count() >= thresh);
|
||||
UINFO(9, "AnnoCalc count "<<filename<<" "<<lineno<<" "<<point.count()<<endl);
|
||||
source.incCount(lineno, column, point.count(), ok);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,23 +167,23 @@ void VlcTop::annotateCalcNeeded() {
|
||||
int totCases = 0;
|
||||
int totOk = 0;
|
||||
for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
|
||||
VlcSource& source = sit->second;
|
||||
//UINFO(1,"Source "<<source.name()<<endl);
|
||||
if (opt.annotateAll()) source.needed(true);
|
||||
VlcSource::LinenoMap& lines = source.lines();
|
||||
for (VlcSource::LinenoMap::iterator lit=lines.begin(); lit!=lines.end(); ++lit) {
|
||||
VlcSource::ColumnMap& cmap = lit->second;
|
||||
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
|
||||
VlcSourceCount& col = cit->second;
|
||||
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
|
||||
++totCases;
|
||||
if (col.ok()) {
|
||||
++totOk;
|
||||
} else {
|
||||
source.needed(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
VlcSource& source = sit->second;
|
||||
//UINFO(1,"Source "<<source.name()<<endl);
|
||||
if (opt.annotateAll()) source.needed(true);
|
||||
VlcSource::LinenoMap& lines = source.lines();
|
||||
for (VlcSource::LinenoMap::iterator lit=lines.begin(); lit!=lines.end(); ++lit) {
|
||||
VlcSource::ColumnMap& cmap = lit->second;
|
||||
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
|
||||
VlcSourceCount& col = cit->second;
|
||||
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
|
||||
++totCases;
|
||||
if (col.ok()) {
|
||||
++totOk;
|
||||
} else {
|
||||
source.needed(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
float pct = totCases ? (100*totOk / totCases) : 0;
|
||||
cout<<"Total coverage ("<<totOk<<"/"<<totCases<<") "
|
||||
@@ -195,60 +195,61 @@ void VlcTop::annotateOutputFiles(const string& dirname) {
|
||||
// Create if uncreated, ignore errors
|
||||
V3Os::createDir(dirname);
|
||||
for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
|
||||
VlcSource& source = sit->second;
|
||||
if (!source.needed()) continue;
|
||||
string filename = source.name();
|
||||
string outfilename = dirname+"/"+V3Os::filenameNonDir(filename);
|
||||
VlcSource& source = sit->second;
|
||||
if (!source.needed()) continue;
|
||||
string filename = source.name();
|
||||
string outfilename = dirname+"/"+V3Os::filenameNonDir(filename);
|
||||
|
||||
UINFO(1,"annotateOutputFile "<<filename<<" -> "<<outfilename<<endl);
|
||||
UINFO(1,"annotateOutputFile "<<filename<<" -> "<<outfilename<<endl);
|
||||
|
||||
std::ifstream is(filename.c_str());
|
||||
if (!is) {
|
||||
v3error("Can't read "<<filename);
|
||||
return;
|
||||
}
|
||||
if (!is) {
|
||||
v3error("Can't read "<<filename);
|
||||
return;
|
||||
}
|
||||
|
||||
std::ofstream os(outfilename.c_str());
|
||||
if (!os) {
|
||||
v3fatal("Can't write "<<outfilename);
|
||||
return;
|
||||
}
|
||||
if (!os) {
|
||||
v3fatal("Can't write "<<outfilename);
|
||||
return;
|
||||
}
|
||||
|
||||
os << "\t// verilator_coverage annotation"<<endl;
|
||||
os << "\t// verilator_coverage annotation"<<endl;
|
||||
|
||||
int lineno = 0;
|
||||
while (!is.eof()) {
|
||||
int lineno = 0;
|
||||
while (!is.eof()) {
|
||||
lineno++;
|
||||
string line = V3Os::getline(is);
|
||||
|
||||
bool first = true;
|
||||
bool first = true;
|
||||
|
||||
VlcSource::LinenoMap& lines = source.lines();
|
||||
VlcSource::LinenoMap::iterator lit=lines.find(lineno);
|
||||
if (lit != lines.end()) {
|
||||
VlcSource::ColumnMap& cmap = lit->second;
|
||||
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
|
||||
VlcSourceCount& col = cit->second;
|
||||
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
|
||||
os<<(col.ok()?" ":"%")
|
||||
VlcSource::LinenoMap& lines = source.lines();
|
||||
VlcSource::LinenoMap::iterator lit=lines.find(lineno);
|
||||
if (lit != lines.end()) {
|
||||
VlcSource::ColumnMap& cmap = lit->second;
|
||||
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
|
||||
VlcSourceCount& col = cit->second;
|
||||
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
|
||||
os<<(col.ok()?" ":"%")
|
||||
<<std::setfill('0')<<std::setw(6)<<col.count()
|
||||
<<"\t"<<line<<endl;
|
||||
if (first) {
|
||||
first = false;
|
||||
// Multiple columns on same line; print line just once
|
||||
<<"\t"<<line<<endl;
|
||||
if (first) {
|
||||
first = false;
|
||||
// Multiple columns on same line; print line just once
|
||||
string indent;
|
||||
for (string::const_iterator pos=line.begin(); pos!=line.end() && isspace(*pos); ++pos) {
|
||||
indent += *pos;
|
||||
}
|
||||
line = indent + "verilator_coverage: (next point on previous line)\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
for (string::const_iterator pos=line.begin();
|
||||
pos!=line.end() && isspace(*pos); ++pos) {
|
||||
indent += *pos;
|
||||
}
|
||||
line = indent + "verilator_coverage: (next point on previous line)\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (first) {
|
||||
os<<"\t"<<line<<endl;
|
||||
}
|
||||
}
|
||||
if (first) {
|
||||
os<<"\t"<<line<<endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,4 +259,3 @@ void VlcTop::annotate(const string& dirname) {
|
||||
annotateCalcNeeded();
|
||||
annotateOutputFiles(dirname);
|
||||
}
|
||||
|
||||
|
||||
+291
-291
@@ -7,7 +7,7 @@ use Getopt::Long;
|
||||
use IO::File;
|
||||
use Pod::Usage;
|
||||
use strict;
|
||||
use vars qw ($Debug @Types %Classes %Children %ClassRefs %Stages);
|
||||
use vars qw($Debug @Types %Classes %Children %ClassRefs %Stages);
|
||||
|
||||
#======================================================================
|
||||
# main
|
||||
@@ -17,8 +17,8 @@ my $opt_classes;
|
||||
my $opt_report;
|
||||
my @Opt_Cpt;
|
||||
my @Opt_I;
|
||||
Getopt::Long::config ("pass_through", "no_auto_abbrev");
|
||||
if (! GetOptions (
|
||||
Getopt::Long::config("pass_through", "no_auto_abbrev");
|
||||
if (! GetOptions(
|
||||
"help" => \&usage,
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"classes!" => \$opt_classes,
|
||||
@@ -51,17 +51,17 @@ foreach my $cpt (@Opt_Cpt) {
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
exit (1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sub parameter {
|
||||
my $param = shift;
|
||||
if ($param =~ /^-+I(\S+)/) {
|
||||
push @Opt_I, $1;
|
||||
push @Opt_I, $1;
|
||||
} elsif ($param =~ s/\.cpp$//) {
|
||||
push @Opt_Cpt, $param;
|
||||
push @Opt_Cpt, $param;
|
||||
} else {
|
||||
die "%Error: Unknown parameter: $param,";
|
||||
die "%Error: Unknown parameter: $param,";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,21 +72,21 @@ sub read_types {
|
||||
|
||||
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
||||
while (defined (my $line = $fh->getline())) {
|
||||
$line =~ s/\/\/.*$//;
|
||||
next if $line =~ /^\s*$/;
|
||||
if ($line =~ /^\s*(class|struct)\s*(\S+)/) {
|
||||
my $class = $2;
|
||||
my $inh = "";
|
||||
$inh = $1 if ($line =~ /:\s*public\s+(\S+)/);
|
||||
print "class $class : $inh\n" if $Debug;
|
||||
$inh = "" if $class eq "AstNode";
|
||||
if ($inh =~ /Ast/ || $class eq "AstNode") {
|
||||
$class =~ s/^Ast//;
|
||||
$inh =~ s/^Ast//;
|
||||
$Classes{$class} = $inh;
|
||||
$Children{$inh}{$class} = 1;
|
||||
}
|
||||
}
|
||||
$line =~ s/\/\/.*$//;
|
||||
next if $line =~ /^\s*$/;
|
||||
if ($line =~ /^\s*(class|struct)\s*(\S+)/) {
|
||||
my $class = $2;
|
||||
my $inh = "";
|
||||
$inh = $1 if ($line =~ /:\s*public\s+(\S+)/);
|
||||
print "class $class : $inh\n" if $Debug;
|
||||
$inh = "" if $class eq "AstNode";
|
||||
if ($inh =~ /Ast/ || $class eq "AstNode") {
|
||||
$class =~ s/^Ast//;
|
||||
$inh =~ s/^Ast//;
|
||||
$Classes{$class} = $inh;
|
||||
$Children{$inh}{$class} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,14 +96,14 @@ sub read_stages {
|
||||
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
||||
my $n = 0;
|
||||
while (defined (my $line = $fh->getline())) {
|
||||
$line =~ s/\/\/.*$//;
|
||||
next if $line =~ /^\s*$/;
|
||||
if ($line =~ /^\s*([A-Za-z0-9]+)::/) {
|
||||
my $stage = $1.".cpp";
|
||||
if (!defined ($Stages{$stage})) {
|
||||
$Stages{$stage} = $n++;
|
||||
}
|
||||
}
|
||||
$line =~ s/\/\/.*$//;
|
||||
next if $line =~ /^\s*$/;
|
||||
if ($line =~ /^\s*([A-Za-z0-9]+)::/) {
|
||||
my $stage = $1.".cpp";
|
||||
if (!defined ($Stages{$stage})) {
|
||||
$Stages{$stage} = $n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,17 +111,17 @@ sub read_refs {
|
||||
my @filenames = @_;
|
||||
|
||||
foreach my $filename (@filenames) {
|
||||
(my $basename = $filename) =~ s!.*/!!;
|
||||
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
||||
while (defined (my $line = $fh->getline())) {
|
||||
$line =~ s/\/\/.*$//;
|
||||
while ($line =~ /\bnew\s*(Ast[A-Za-z0-9_]+)/g) {
|
||||
$ClassRefs{$1}{newed}{$basename} = 1;
|
||||
}
|
||||
while ($line =~ /\b(Ast[A-Za-z0-9_]+)/g) {
|
||||
$ClassRefs{$1}{used}{$basename} = 1;
|
||||
}
|
||||
}
|
||||
(my $basename = $filename) =~ s!.*/!!;
|
||||
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
||||
while (defined (my $line = $fh->getline())) {
|
||||
$line =~ s/\/\/.*$//;
|
||||
while ($line =~ /\bnew\s*(Ast[A-Za-z0-9_]+)/g) {
|
||||
$ClassRefs{$1}{newed}{$basename} = 1;
|
||||
}
|
||||
while ($line =~ /\b(Ast[A-Za-z0-9_]+)/g) {
|
||||
$ClassRefs{$1}{used}{$basename} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#use Data::Dumper;print Dumper(\%ClassRefs);
|
||||
}
|
||||
@@ -142,8 +142,8 @@ sub subclasses_of {
|
||||
|
||||
my @cllist;
|
||||
for (my $subclass = $::Classes{$type}; $subclass; ) {
|
||||
push @cllist, $subclass;
|
||||
$subclass = $::Classes{$subclass};
|
||||
push @cllist, $subclass;
|
||||
$subclass = $::Classes{$subclass};
|
||||
}
|
||||
|
||||
return (reverse @cllist);
|
||||
@@ -156,10 +156,10 @@ sub children_of {
|
||||
my @todo;
|
||||
push @todo, $type;
|
||||
while (my $subclass = shift @todo) {
|
||||
foreach my $child (sort keys %{$::Children{$subclass}}) {
|
||||
push @todo, $child;
|
||||
push @cllist, $child;
|
||||
}
|
||||
foreach my $child (sort keys %{$::Children{$subclass}}) {
|
||||
push @todo, $child;
|
||||
push @cllist, $child;
|
||||
}
|
||||
}
|
||||
|
||||
return (@cllist);
|
||||
@@ -173,39 +173,39 @@ sub write_report {
|
||||
|
||||
$fh->print("Processing stages (approximate, based on order in Verilator.cpp):\n");
|
||||
foreach my $class (sort {$Stages{$a} <=> $Stages{$b}} keys %Stages) {
|
||||
$fh->print("\t$class\n");
|
||||
$fh->print("\t$class\n");
|
||||
}
|
||||
|
||||
$fh->print("\nProcessing stages (approximate, based on order in Verilator.cpp):\n");
|
||||
foreach my $type (sort (keys %Classes)) {
|
||||
printf $fh " class %-20s\n", "Ast${type}";
|
||||
$fh->print("\tparent:\t");
|
||||
foreach my $subclass (subclasses_of($type)) {
|
||||
next if $subclass eq 'Node';
|
||||
printf $fh "Ast%-12s ",$subclass;
|
||||
}
|
||||
printf $fh "\n";
|
||||
$fh->print("\tchilds:\t");
|
||||
foreach my $subclass (children_of($type)) {
|
||||
next if $subclass eq 'Node';
|
||||
printf $fh "Ast%-12s ",$subclass;
|
||||
}
|
||||
printf $fh "\n";
|
||||
if (my $refs = $ClassRefs{"Ast${type}"}) {
|
||||
$fh->print("\tnewed:\t");
|
||||
foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)}
|
||||
keys %{$refs->{newed}}) {
|
||||
$fh->print($stage." ");
|
||||
}
|
||||
$fh->print("\n");
|
||||
$fh->print("\tused:\t");
|
||||
foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)}
|
||||
keys %{$refs->{used}}) {
|
||||
$fh->print($stage." ");
|
||||
}
|
||||
$fh->print("\n");
|
||||
}
|
||||
$fh->print("\n");
|
||||
printf $fh " class %-20s\n", "Ast${type}";
|
||||
$fh->print("\tparent:\t");
|
||||
foreach my $subclass (subclasses_of($type)) {
|
||||
next if $subclass eq 'Node';
|
||||
printf $fh "Ast%-12s ",$subclass;
|
||||
}
|
||||
printf $fh "\n";
|
||||
$fh->print("\tchilds:\t");
|
||||
foreach my $subclass (children_of($type)) {
|
||||
next if $subclass eq 'Node';
|
||||
printf $fh "Ast%-12s ",$subclass;
|
||||
}
|
||||
printf $fh "\n";
|
||||
if (my $refs = $ClassRefs{"Ast${type}"}) {
|
||||
$fh->print("\tnewed:\t");
|
||||
foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)}
|
||||
keys %{$refs->{newed}}) {
|
||||
$fh->print($stage." ");
|
||||
}
|
||||
$fh->print("\n");
|
||||
$fh->print("\tused:\t");
|
||||
foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)}
|
||||
keys %{$refs->{used}}) {
|
||||
$fh->print($stage." ");
|
||||
}
|
||||
$fh->print("\n");
|
||||
}
|
||||
$fh->print("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,11 +213,11 @@ sub write_classes {
|
||||
my $fh = open_file(@_);
|
||||
printf $fh "class AstNode;\n";
|
||||
foreach my $type (sort (keys %Classes)) {
|
||||
printf $fh "class %-20s // ", "Ast${type};";
|
||||
foreach my $subclass (subclasses_of($type)) {
|
||||
printf $fh "Ast%-12s ",$subclass;
|
||||
}
|
||||
printf $fh "\n";
|
||||
printf $fh "class %-20s // ", "Ast${type};";
|
||||
foreach my $subclass (subclasses_of($type)) {
|
||||
printf $fh "Ast%-12s ",$subclass;
|
||||
}
|
||||
printf $fh "\n";
|
||||
}
|
||||
$fh->close();
|
||||
}
|
||||
@@ -225,12 +225,12 @@ sub write_classes {
|
||||
sub write_visitor {
|
||||
my $fh = open_file(@_);
|
||||
foreach my $type (sort (keys %Classes)) {
|
||||
my $base = $Classes{$type};
|
||||
if ($base) {
|
||||
printf $fh " virtual void visit(Ast${type}* nodep) { visit((Ast${base}*)(nodep)); }\n";
|
||||
} else {
|
||||
printf $fh " virtual void visit(Ast${type}*) = 0;\n";
|
||||
}
|
||||
my $base = $Classes{$type};
|
||||
if ($base) {
|
||||
printf $fh " virtual void visit(Ast${type}* nodep) { visit((Ast${base}*)(nodep)); }\n";
|
||||
} else {
|
||||
printf $fh " virtual void visit(Ast${type}*) = 0;\n";
|
||||
}
|
||||
}
|
||||
$fh->close();
|
||||
}
|
||||
@@ -262,11 +262,11 @@ sub write_impl {
|
||||
print $fh "\n";
|
||||
print $fh " // These for use by VN_IS macro only\n";
|
||||
foreach my $type (sort (keys %Classes)) {
|
||||
if (children_of($type)) {
|
||||
if (children_of($type)) {
|
||||
print $fh "inline bool AstNode::privateIs",$type,"(const AstNode* nodep) { return (bool)(dynamic_cast<const Ast",$type,"*>(nodep)); }\n";
|
||||
} else {
|
||||
} else {
|
||||
print $fh "inline bool AstNode::privateIs",$type,"(const AstNode* nodep) { return nodep && nodep->type() == AstType::at",$type,"; }\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $type (sort (keys %Classes)) {
|
||||
@@ -285,16 +285,16 @@ sub write_types {
|
||||
printf $fh " enum en {\n";
|
||||
# Add "at" prefix to avoid conflicting with FOPEN and other macros in include files
|
||||
foreach my $type (sort (keys %Classes)) {
|
||||
next if $type =~ /^Node/;
|
||||
print $fh "\tat",$type,",\n";
|
||||
next if $type =~ /^Node/;
|
||||
print $fh "\tat",$type,",\n";
|
||||
}
|
||||
printf $fh "\t_ENUM_END\n";
|
||||
printf $fh " };\n";
|
||||
printf $fh " const char* ascii() const {\n";
|
||||
printf $fh " const char* const names[] = {\n";
|
||||
foreach my $type (sort (keys %Classes)) {
|
||||
next if $type =~ /^Node/;
|
||||
print $fh "\t\"", uc $type, "\",\n";
|
||||
next if $type =~ /^Node/;
|
||||
print $fh "\t\"", uc $type, "\",\n";
|
||||
}
|
||||
printf $fh "\t\"_ENUM_END\"\n";
|
||||
printf $fh " };\n";
|
||||
@@ -332,11 +332,11 @@ sub _output_line {
|
||||
|
||||
sub process {
|
||||
my $self = {
|
||||
in_filename => undef,
|
||||
out_filename => undef,
|
||||
out_lines => [],
|
||||
out_linenum => 1,
|
||||
@_,
|
||||
in_filename => undef,
|
||||
out_filename => undef,
|
||||
out_lines => [],
|
||||
out_linenum => 1,
|
||||
@_,
|
||||
};
|
||||
bless $self, __PACKAGE__;
|
||||
|
||||
@@ -346,25 +346,25 @@ sub process {
|
||||
# Read the file and parse into list of functions that generate output
|
||||
my $fhi = IO::File->new($self->{in_filename}) or die "%Error: $! $self->{in_filename},";
|
||||
while (defined(my $line = $fhi->getline)) {
|
||||
if (!$didln) {
|
||||
$self->print("#line $. \"$self->{in_filename}\"\n");
|
||||
$didln = 1;
|
||||
}
|
||||
if ($line =~ /^\s+(TREE.*)$/) {
|
||||
my $func = $1;
|
||||
$self->{in_linenum} = $.;
|
||||
$self->print("//$line");
|
||||
$self->output_func(sub{my $self=shift; $self->_output_line(); });
|
||||
$self->tree_line ($func);
|
||||
$didln = 0;
|
||||
}
|
||||
elsif ($line !~ /^\s*\/[\/\*]\s*TREE/
|
||||
&& $line =~ /\s+TREE/) {
|
||||
$self->error("Unknown astgen line: $line");
|
||||
}
|
||||
else {
|
||||
$self->print($line);
|
||||
}
|
||||
if (!$didln) {
|
||||
$self->print("#line $. \"$self->{in_filename}\"\n");
|
||||
$didln = 1;
|
||||
}
|
||||
if ($line =~ /^\s+(TREE.*)$/) {
|
||||
my $func = $1;
|
||||
$self->{in_linenum} = $.;
|
||||
$self->print("//$line");
|
||||
$self->output_func(sub{my $self=shift; $self->_output_line(); });
|
||||
$self->tree_line($func);
|
||||
$didln = 0;
|
||||
}
|
||||
elsif ($line !~ /^\s*\/[\/\*]\s*TREE/
|
||||
&& $line =~ /\s+TREE/) {
|
||||
$self->error("Unknown astgen line: $line");
|
||||
}
|
||||
else {
|
||||
$self->print($line);
|
||||
}
|
||||
}
|
||||
$fhi->close;
|
||||
|
||||
@@ -373,16 +373,16 @@ sub process {
|
||||
my $fho = ::open_file($self->{out_filename});
|
||||
my @togen = @{$self->{out_lines}};
|
||||
foreach my $line (@togen) {
|
||||
if (ref $line) {
|
||||
$self->{out_lines} = [];
|
||||
&$line($self);
|
||||
} else {
|
||||
$self->{out_lines} = [$line];
|
||||
}
|
||||
foreach my $out (@{$self->{out_lines}}) {
|
||||
$self->{out_linenum}++ while ($out =~ /\n/smg);
|
||||
print $fho $out;
|
||||
}
|
||||
if (ref $line) {
|
||||
$self->{out_lines} = [];
|
||||
&$line($self);
|
||||
} else {
|
||||
$self->{out_lines} = [$line];
|
||||
}
|
||||
foreach my $out (@{$self->{out_lines}}) {
|
||||
$self->{out_linenum}++ while ($out =~ /\n/smg);
|
||||
print $fho $out;
|
||||
}
|
||||
}
|
||||
$fho->close;
|
||||
}
|
||||
@@ -396,64 +396,64 @@ sub tree_line {
|
||||
|
||||
# doflag "S" indicates an op specifying short-circuiting for a type.
|
||||
if ($func =~ /TREEOP(1?)([VCS]?)\s*\(\s* \"([^\"]*)\" \s*,\s* \"([^\"]*)\" \s*\)/sx) {
|
||||
my $order = $1; my $doflag = $2; my $from = $3; my $to = $4;
|
||||
#$self->print("// $from $to\n");
|
||||
if (!$self->{did_out_tree}) {
|
||||
$self->{did_out_tree} = 1;
|
||||
$self->output_func(sub{ my $self=shift;
|
||||
$self->tree_match();
|
||||
$self->tree_base();
|
||||
});
|
||||
}
|
||||
$from =~ /Ast([a-zA-Z0-9]+)\s*\{(.*)\}\s*$/
|
||||
or $self->error("Can't parse from function: $func");
|
||||
my $type = $1;
|
||||
my $subnodes = $2;
|
||||
(::subclasses_of($type)) or $self->error("Unknown AstNode type: $type: in $func");
|
||||
my $order = $1; my $doflag = $2; my $from = $3; my $to = $4;
|
||||
#$self->print("// $from $to\n");
|
||||
if (!$self->{did_out_tree}) {
|
||||
$self->{did_out_tree} = 1;
|
||||
$self->output_func(sub{ my $self=shift;
|
||||
$self->tree_match();
|
||||
$self->tree_base();
|
||||
});
|
||||
}
|
||||
$from =~ /Ast([a-zA-Z0-9]+)\s*\{(.*)\}\s*$/
|
||||
or $self->error("Can't parse from function: $func");
|
||||
my $type = $1;
|
||||
my $subnodes = $2;
|
||||
(::subclasses_of($type)) or $self->error("Unknown AstNode type: $type: in $func");
|
||||
|
||||
my $mif;
|
||||
if ($doflag eq '') { $mif = "m_doNConst"; }
|
||||
elsif ($doflag eq 'V') { $mif = "m_doV"; }
|
||||
elsif ($doflag eq 'C') { $mif = ""; }
|
||||
elsif ($doflag eq 'S') { $mif = "m_doNConst"; } # Not just for m_doGenerate
|
||||
else { die; }
|
||||
$subnodes =~ s/,,/__ESCAPEDCOMMA__/g;
|
||||
foreach my $subnode (split /\s*,\s*/, $subnodes) {
|
||||
$subnode =~ s/__ESCAPEDCOMMA__/,/g;
|
||||
next if $subnode =~ /^\$([a-z0-9]+)$/gi; # "$lhs" is just a comment that this op has a lhs
|
||||
$mif .= " && " if $mif;
|
||||
my $subnodeif = $subnode;
|
||||
my $mif;
|
||||
if ($doflag eq '') { $mif = "m_doNConst"; }
|
||||
elsif ($doflag eq 'V') { $mif = "m_doV"; }
|
||||
elsif ($doflag eq 'C') { $mif = ""; }
|
||||
elsif ($doflag eq 'S') { $mif = "m_doNConst"; } # Not just for m_doGenerate
|
||||
else { die; }
|
||||
$subnodes =~ s/,,/__ESCAPEDCOMMA__/g;
|
||||
foreach my $subnode (split /\s*,\s*/, $subnodes) {
|
||||
$subnode =~ s/__ESCAPEDCOMMA__/,/g;
|
||||
next if $subnode =~ /^\$([a-z0-9]+)$/gi; # "$lhs" is just a comment that this op has a lhs
|
||||
$mif .= " && " if $mif;
|
||||
my $subnodeif = $subnode;
|
||||
$subnodeif =~ s/\$([a-zA-Z0-9]+)\.cast([A-Z][A-Za-z0-9]+)$/VN_IS(nodep->$1(),$2)/g;
|
||||
$subnodeif =~ s/\$([a-zA-Z0-9]+)\.([a-zA-Z0-9]+)$/nodep->$1()->$2()/g;
|
||||
$subnodeif = add_nodep($subnodeif);
|
||||
$mif .= $subnodeif;
|
||||
}
|
||||
$subnodeif =~ s/\$([a-zA-Z0-9]+)\.([a-zA-Z0-9]+)$/nodep->$1()->$2()/g;
|
||||
$subnodeif = add_nodep($subnodeif);
|
||||
$mif .= $subnodeif;
|
||||
}
|
||||
|
||||
my $exec_func = treeop_exec_func($self, $to);
|
||||
my $exec_func = treeop_exec_func($self, $to);
|
||||
while ($exec_func =~ s/([-()a-zA-Z0-9_>]+)->cast([A-Z][A-Za-z0-9]+)\(\)/VN_CAST($1,$2)/) {}
|
||||
|
||||
$self->{treeop}{$type} ||= [];
|
||||
my $n = $#{$self->{treeop}{$type}} + 1;
|
||||
my $typefunc = {
|
||||
order => $order,
|
||||
comment => $func,
|
||||
match_func => "match_${type}_${n}",
|
||||
match_if => $mif,
|
||||
exec_func => $exec_func,
|
||||
uinfo_level => ($to =~ /^!/ ? 0:7),
|
||||
short_circuit => ($doflag eq 'S'),
|
||||
};
|
||||
$self->{treeop}{$type} ||= [];
|
||||
my $n = $#{$self->{treeop}{$type}} + 1;
|
||||
my $typefunc = {
|
||||
order => $order,
|
||||
comment => $func,
|
||||
match_func => "match_${type}_${n}",
|
||||
match_if => $mif,
|
||||
exec_func => $exec_func,
|
||||
uinfo_level => ($to =~ /^!/ ? 0:7),
|
||||
short_circuit => ($doflag eq 'S'),
|
||||
};
|
||||
|
||||
($typefunc->{uinfo} = $func) =~ s/[ \t\"\{\}]+/ /g;
|
||||
push @{$self->{treeop}{$type}}, $typefunc;
|
||||
($typefunc->{uinfo} = $func) =~ s/[ \t\"\{\}]+/ /g;
|
||||
push @{$self->{treeop}{$type}}, $typefunc;
|
||||
}
|
||||
elsif ($func =~ /TREE_SKIP_VISIT\s*\(\s* \"([^\"]*)\" \s*\)/sx) {
|
||||
my $type = $1;
|
||||
$self->{tree_skip_visit}{$type} = 1;
|
||||
$::Classes{$type} or $self->error("Unknown node type: $type");
|
||||
my $type = $1;
|
||||
$self->{tree_skip_visit}{$type} = 1;
|
||||
$::Classes{$type} or $self->error("Unknown node type: $type");
|
||||
}
|
||||
else {
|
||||
$self->error("Unknown astgen op: $func");
|
||||
$self->error("Unknown astgen op: $func");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,12 +468,12 @@ our $_Exec_Nsyms;
|
||||
sub _exec_syms_recurse {
|
||||
my $aref = shift;
|
||||
foreach my $sym (@{$aref}) {
|
||||
if (ref $sym) { _exec_syms_recurse($sym); }
|
||||
elsif ($sym =~ /^\$.*/) {
|
||||
if (!defined $_Exec_Syms{$sym}) {
|
||||
$_Exec_Syms{$sym} = "arg".(++$_Exec_Nsyms)."p";
|
||||
}
|
||||
}
|
||||
if (ref $sym) { _exec_syms_recurse($sym); }
|
||||
elsif ($sym =~ /^\$.*/) {
|
||||
if (!defined $_Exec_Syms{$sym}) {
|
||||
$_Exec_Syms{$sym} = "arg".(++$_Exec_Nsyms)."p";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,14 +482,14 @@ sub _exec_new_recurse {
|
||||
my $out = "new ".$aref->[0]."(nodep->fileline()";
|
||||
my $first = 1;
|
||||
foreach my $sym (@{$aref}) {
|
||||
if ($first) { $first=0; next; }
|
||||
$out .= ", ";
|
||||
if (ref $sym) { $out.=_exec_new_recurse($sym); }
|
||||
elsif ($sym =~ /^\$.*/) {
|
||||
$out .= $_Exec_Syms{$sym};
|
||||
} else {
|
||||
$out .= $sym;
|
||||
}
|
||||
if ($first) { $first=0; next; }
|
||||
$out .= ", ";
|
||||
if (ref $sym) { $out.=_exec_new_recurse($sym); }
|
||||
elsif ($sym =~ /^\$.*/) {
|
||||
$out .= $_Exec_Syms{$sym};
|
||||
} else {
|
||||
$out .= $sym;
|
||||
}
|
||||
}
|
||||
return $out.")";
|
||||
}
|
||||
@@ -500,142 +500,142 @@ sub treeop_exec_func {
|
||||
my $out = "";
|
||||
$func =~ s/^!//;
|
||||
if ($func =~ /^\s*[a-zA-Z0-9]+\s*\(/) { # Function call
|
||||
(my $outl = $func) =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g;
|
||||
$out .= $outl.";";
|
||||
(my $outl = $func) =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g;
|
||||
$out .= $outl.";";
|
||||
}
|
||||
elsif ($func =~ /^\s*Ast([a-zA-Z0-9]+) \s*\{\s* (.*) \s* \}$/x) {
|
||||
|
||||
my $nargs = 0;
|
||||
my %argnums; # Number for each argument name
|
||||
my $nargs = 0;
|
||||
my %argnums; # Number for each argument name
|
||||
|
||||
my $aref = undef; # Recursive array with structure to form
|
||||
my @astack;
|
||||
my $forming = "";
|
||||
my $argtext = $func . "\000"; # EOF character
|
||||
#print "FF $func\n" if $Debug;
|
||||
while ($argtext =~ s/^(.)//) {
|
||||
my $tok = $1;
|
||||
#print "TOK: $tok $forming\n" if $tok !~ /[a-zA-Z0-9]/;
|
||||
my $aref = undef; # Recursive array with structure to form
|
||||
my @astack;
|
||||
my $forming = "";
|
||||
my $argtext = $func . "\000"; # EOF character
|
||||
#print "FF $func\n" if $Debug;
|
||||
while ($argtext =~ s/^(.)//) {
|
||||
my $tok = $1;
|
||||
#print "TOK: $tok $forming\n" if $tok !~ /[a-zA-Z0-9]/;
|
||||
|
||||
if ($tok eq "\000") {
|
||||
} elsif ($tok =~ /\s+/) {
|
||||
} elsif ($tok eq "{") {
|
||||
my $newref = [$forming];
|
||||
push @{$aref}, $newref;
|
||||
push @astack, $aref if $aref;
|
||||
$aref = $newref;
|
||||
$forming = "";
|
||||
} elsif ($tok eq "}") {
|
||||
push @{$aref}, $forming if $forming;
|
||||
$aref = pop @astack;
|
||||
$aref or $self->error("Too many } in execution function: $func\n");
|
||||
$forming = "";
|
||||
} elsif ($tok eq ",") {
|
||||
push @{$aref}, $forming if $forming;
|
||||
$forming = "";
|
||||
} else {
|
||||
$forming .= $tok;
|
||||
}
|
||||
}
|
||||
($aref && ref $aref->[0] && !$aref->[1]) or $self->error("Badly formed execution function: $func\n");
|
||||
$aref = $aref->[0];
|
||||
#use Data::Dumper; print Dumper($aref),"\n";
|
||||
if ($tok eq "\000") {
|
||||
} elsif ($tok =~ /\s+/) {
|
||||
} elsif ($tok eq "{") {
|
||||
my $newref = [$forming];
|
||||
push @{$aref}, $newref;
|
||||
push @astack, $aref if $aref;
|
||||
$aref = $newref;
|
||||
$forming = "";
|
||||
} elsif ($tok eq "}") {
|
||||
push @{$aref}, $forming if $forming;
|
||||
$aref = pop @astack;
|
||||
$aref or $self->error("Too many } in execution function: $func\n");
|
||||
$forming = "";
|
||||
} elsif ($tok eq ",") {
|
||||
push @{$aref}, $forming if $forming;
|
||||
$forming = "";
|
||||
} else {
|
||||
$forming .= $tok;
|
||||
}
|
||||
}
|
||||
($aref && ref $aref->[0] && !$aref->[1]) or $self->error("Badly formed execution function: $func\n");
|
||||
$aref = $aref->[0];
|
||||
#use Data::Dumper; print Dumper($aref),"\n";
|
||||
|
||||
# Assign numbers to each $ symbol
|
||||
%_Exec_Syms = ();
|
||||
$_Exec_Nsyms = 0;
|
||||
_exec_syms_recurse($aref);
|
||||
# Assign numbers to each $ symbol
|
||||
%_Exec_Syms = ();
|
||||
$_Exec_Nsyms = 0;
|
||||
_exec_syms_recurse($aref);
|
||||
|
||||
foreach my $sym (sort {$_Exec_Syms{$a} cmp $_Exec_Syms{$b}} (keys %_Exec_Syms)) {
|
||||
my $argnp = $_Exec_Syms{$sym};
|
||||
my $arg = add_nodep($sym);
|
||||
$out .= "AstNode* ${argnp} = ${arg}->unlinkFrBack();\n";
|
||||
}
|
||||
foreach my $sym (sort {$_Exec_Syms{$a} cmp $_Exec_Syms{$b}} (keys %_Exec_Syms)) {
|
||||
my $argnp = $_Exec_Syms{$sym};
|
||||
my $arg = add_nodep($sym);
|
||||
$out .= "AstNode* ${argnp} = ${arg}->unlinkFrBack();\n";
|
||||
}
|
||||
|
||||
$out .= "AstNode* newp = " . _exec_new_recurse($aref).";\n";
|
||||
$out .= "nodep->replaceWith(newp);";
|
||||
$out .= "nodep->deleteTree(); VL_DANGLING(nodep);";
|
||||
#print "FF $out\n" if $Debug;
|
||||
$out .= "AstNode* newp = " . _exec_new_recurse($aref).";\n";
|
||||
$out .= "nodep->replaceWith(newp);";
|
||||
$out .= "nodep->deleteTree(); VL_DANGLING(nodep);";
|
||||
#print "FF $out\n" if $Debug;
|
||||
} elsif ($func eq "NEVER") {
|
||||
$out .= "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");";
|
||||
$out .= "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");";
|
||||
} elsif ($func eq "DONE") {
|
||||
} else {
|
||||
$self->error("Unknown execution function format: $func\n");
|
||||
$self->error("Unknown execution function format: $func\n");
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
sub tree_match {
|
||||
my $self = shift;
|
||||
$self->print (" // TREEOP functions, each return true if they matched & transformed\n");
|
||||
$self->print(" // TREEOP functions, each return true if they matched & transformed\n");
|
||||
#use Data::Dumper; print Dumper($self);
|
||||
foreach my $base (sort (keys %{$self->{treeop}})) {
|
||||
foreach my $typefunc (@{$self->{treeop}{$base}}) {
|
||||
$self->print(" // Generated by astgen\n");
|
||||
$self->print(" bool $typefunc->{match_func}(Ast${base}* nodep) {\n",
|
||||
"\t// $typefunc->{comment}\n",);
|
||||
$self->print( "\tif ($typefunc->{match_if}) {\n");
|
||||
foreach my $typefunc (@{$self->{treeop}{$base}}) {
|
||||
$self->print(" // Generated by astgen\n");
|
||||
$self->print(" bool $typefunc->{match_func}(Ast${base}* nodep) {\n",
|
||||
"\t// $typefunc->{comment}\n",);
|
||||
$self->print( "\tif ($typefunc->{match_if}) {\n");
|
||||
$self->print( "\t UINFO($typefunc->{uinfo_level},cvtToHex(nodep)"
|
||||
."<<\" $typefunc->{uinfo}\\n\");\n");
|
||||
$self->print( "\t $typefunc->{exec_func}\n");
|
||||
$self->print( "\t return true;\n");
|
||||
$self->print( "\t}\n");
|
||||
$self->print( "\treturn false;\n");
|
||||
$self->print(" }\n",);
|
||||
}
|
||||
$self->print( "\t $typefunc->{exec_func}\n");
|
||||
$self->print( "\t return true;\n");
|
||||
$self->print( "\t}\n");
|
||||
$self->print( "\treturn false;\n");
|
||||
$self->print(" }\n",);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub tree_base {
|
||||
my $self = shift;
|
||||
$self->print (" // TREEOP visitors, call each base type's match\n");
|
||||
$self->print (" // Bottom class up, as more simple transforms are generally better\n");
|
||||
$self->print(" // TREEOP visitors, call each base type's match\n");
|
||||
$self->print(" // Bottom class up, as more simple transforms are generally better\n");
|
||||
foreach my $type (sort (keys %::Classes)) {
|
||||
my $base = $::Classes{$type};
|
||||
my @out_for_type_sc;
|
||||
my @out_for_type;
|
||||
foreach my $base (::subclasses_of($type), $type) {
|
||||
foreach my $typefunc (@{$self->{treeop}{$base}}) {
|
||||
my $base = $::Classes{$type};
|
||||
my @out_for_type_sc;
|
||||
my @out_for_type;
|
||||
foreach my $base (::subclasses_of($type), $type) {
|
||||
foreach my $typefunc (@{$self->{treeop}{$base}}) {
|
||||
my @lines = (" if ($typefunc->{match_func}(nodep)) return;\n",);
|
||||
if ($typefunc->{short_circuit}) { # short-circuit match fn
|
||||
push @out_for_type_sc, @lines;
|
||||
} else { # Standard match fn
|
||||
if ($typefunc->{order}) {
|
||||
unshift @out_for_type, @lines; # TREEOP1's go in front of others
|
||||
} else {
|
||||
push @out_for_type, @lines;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($typefunc->{short_circuit}) { # short-circuit match fn
|
||||
push @out_for_type_sc, @lines;
|
||||
} else { # Standard match fn
|
||||
if ($typefunc->{order}) {
|
||||
unshift @out_for_type, @lines; # TREEOP1's go in front of others
|
||||
} else {
|
||||
push @out_for_type, @lines;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# We need to deal with two cases. For short circuited functions we
|
||||
# evaluate the LHS, then apply the short-circuit matches, then
|
||||
# evaluate the RHS and possibly THS (ternary operators may
|
||||
# short-circuit) and apply all the other matches.
|
||||
# We need to deal with two cases. For short circuited functions we
|
||||
# evaluate the LHS, then apply the short-circuit matches, then
|
||||
# evaluate the RHS and possibly THS (ternary operators may
|
||||
# short-circuit) and apply all the other matches.
|
||||
|
||||
# For types without short-circuits, we just use iterateChildren, which
|
||||
# saves one comparison.
|
||||
if ($out_for_type_sc[0]) { # Short-circuited types
|
||||
$self->print(" // Generated by astgen with short-circuiting\n",
|
||||
" virtual void visit(Ast${type}* nodep) {\n",
|
||||
# For types without short-circuits, we just use iterateChildren, which
|
||||
# saves one comparison.
|
||||
if ($out_for_type_sc[0]) { # Short-circuited types
|
||||
$self->print(" // Generated by astgen with short-circuiting\n",
|
||||
" virtual void visit(Ast${type}* nodep) {\n",
|
||||
" iterateAndNextNull(nodep->lhsp());\n",
|
||||
@out_for_type_sc);
|
||||
@out_for_type_sc);
|
||||
$self->print(" iterateAndNextNull(nodep->rhsp());\n",
|
||||
" AstNodeTriop *tnp = VN_CAST(nodep, NodeTriop);\n",
|
||||
" if (tnp && tnp->thsp()) iterateAndNextNull(tnp->thsp());\n",
|
||||
@out_for_type,
|
||||
" }\n") if ($out_for_type[0]);
|
||||
} elsif ($out_for_type[0]) { # Other types with something to print
|
||||
my $skip = $self->{tree_skip_visit}{$type};
|
||||
my $gen = $skip ? "Gen" : "";
|
||||
$self->print(" // Generated by astgen\n",
|
||||
" virtual void visit$gen(Ast${type}* nodep) {\n",
|
||||
($skip?"":
|
||||
@out_for_type,
|
||||
" }\n") if ($out_for_type[0]);
|
||||
} elsif ($out_for_type[0]) { # Other types with something to print
|
||||
my $skip = $self->{tree_skip_visit}{$type};
|
||||
my $gen = $skip ? "Gen" : "";
|
||||
$self->print(" // Generated by astgen\n",
|
||||
" virtual void visit$gen(Ast${type}* nodep) {\n",
|
||||
($skip?"":
|
||||
" iterateChildren(nodep);\n"),
|
||||
@out_for_type,
|
||||
" }\n");
|
||||
}
|
||||
@out_for_type,
|
||||
" }\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+237
-237
@@ -7,7 +7,7 @@ use Getopt::Long;
|
||||
use IO::File;
|
||||
use Pod::Usage;
|
||||
use strict;
|
||||
use vars qw ($Debug $VERSION);
|
||||
use vars qw($Debug $VERSION);
|
||||
|
||||
$VERSION = '3.404';
|
||||
|
||||
@@ -28,21 +28,21 @@ our $Opt_Input;
|
||||
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
Getopt::Long::config ("no_auto_abbrev");
|
||||
if (! GetOptions (
|
||||
# Local options
|
||||
"help" => \&usage,
|
||||
"version" => sub { print "Version $VERSION\n"; exit(0); },
|
||||
"yacc=s" => \$Opt_Yacc,
|
||||
# Passed to Bison
|
||||
"t|debug" => sub { $Opt_Debug = 1; },
|
||||
"b|file-prefix=s" => \$Opt_File_Prefix,
|
||||
"d" => \$Opt_Definitions,
|
||||
"k|token-table" => \$Opt_Token_Table,
|
||||
"o=s" => \$Opt_Output,
|
||||
"p|name-prefix=s" => \$Opt_Name_Prefix,
|
||||
"v|verbose" => \$Opt_Verbose,
|
||||
"<>" => \¶meter,
|
||||
Getopt::Long::config("no_auto_abbrev");
|
||||
if (! GetOptions(
|
||||
# Local options
|
||||
"help" => \&usage,
|
||||
"version" => sub { print "Version $VERSION\n"; exit(0); },
|
||||
"yacc=s" => \$Opt_Yacc,
|
||||
# Passed to Bison
|
||||
"t|debug" => sub { $Opt_Debug = 1; },
|
||||
"b|file-prefix=s" => \$Opt_File_Prefix,
|
||||
"d" => \$Opt_Definitions,
|
||||
"k|token-table" => \$Opt_Token_Table,
|
||||
"o=s" => \$Opt_Output,
|
||||
"p|name-prefix=s" => \$Opt_Name_Prefix,
|
||||
"v|verbose" => \$Opt_Verbose,
|
||||
"<>" => \¶meter,
|
||||
)) {
|
||||
die "%Error: Bad usage, try 'bisonpre --help'\n";
|
||||
}
|
||||
@@ -57,15 +57,15 @@ process();
|
||||
sub usage {
|
||||
print "Version $VERSION\n";
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT, -noperldoc=>1);
|
||||
exit (1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sub parameter {
|
||||
my $param = shift;
|
||||
if (!defined $Opt_Input) {
|
||||
$Opt_Input = $param;
|
||||
$Opt_Input = $param;
|
||||
} else {
|
||||
die "bisonpre: %Error: Unknown parameter: $param\n";
|
||||
die "bisonpre: %Error: Unknown parameter: $param\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,31 +81,31 @@ sub process {
|
||||
|
||||
# Run bison
|
||||
my $command = ($Opt_Yacc
|
||||
.($Opt_Debug?" -t":"")
|
||||
.($Opt_Definitions?" -d":"")
|
||||
.($Opt_Token_Table?" -k":"")
|
||||
.($Opt_Verbose?" -v":"")
|
||||
.(($Opt_Verbose && $supports_report)?" --report=itemset --report=lookahead":"")
|
||||
# -p required for GLR parsers; they write to -p basename, not -o
|
||||
.($Opt_Name_Prefix?" -p $Opt_Name_Prefix":"")
|
||||
." -b ".tmp_prefix()
|
||||
." -o ".tmp_prefix().".c"
|
||||
." ".tmp_prefix().".y" );
|
||||
.($Opt_Debug?" -t":"")
|
||||
.($Opt_Definitions?" -d":"")
|
||||
.($Opt_Token_Table?" -k":"")
|
||||
.($Opt_Verbose?" -v":"")
|
||||
.(($Opt_Verbose && $supports_report)?" --report=itemset --report=lookahead":"")
|
||||
# -p required for GLR parsers; they write to -p basename, not -o
|
||||
.($Opt_Name_Prefix?" -p $Opt_Name_Prefix":"")
|
||||
." -b ".tmp_prefix()
|
||||
." -o ".tmp_prefix().".c"
|
||||
." ".tmp_prefix().".y" );
|
||||
|
||||
print " $command\n";
|
||||
system $command;
|
||||
my $status = $?;
|
||||
if ($status != 0) {
|
||||
remove_outputs();
|
||||
my $v = bison_version_check();
|
||||
die "bisonpre: %Error: $Opt_Yacc version $v run failed due to errors\n";
|
||||
remove_outputs();
|
||||
my $v = bison_version_check();
|
||||
die "bisonpre: %Error: $Opt_Yacc version $v run failed due to errors\n";
|
||||
}
|
||||
|
||||
clean_output(tmp_prefix().".output",output_prefix().".output", 1,0);
|
||||
warning_check(output_prefix().".output");
|
||||
|
||||
clean_output(tmp_prefix().".c", output_prefix().".c", 0,1);
|
||||
clean_output(tmp_prefix().".h", output_prefix().".h", 0,1);
|
||||
clean_output(tmp_prefix().".c", output_prefix().".c", 0,1);
|
||||
clean_output(tmp_prefix().".h", output_prefix().".h", 0,1);
|
||||
remove_tmp();
|
||||
}
|
||||
|
||||
@@ -116,10 +116,10 @@ sub tmp_prefix {
|
||||
sub output_prefix {
|
||||
my $o;
|
||||
if ($Opt_Output) {
|
||||
(my $o = $Opt_Output) =~ s!\.[^.]*$!!;
|
||||
return $o;
|
||||
(my $o = $Opt_Output) =~ s!\.[^.]*$!!;
|
||||
return $o;
|
||||
} else {
|
||||
return $Opt_File_Prefix.".tab";
|
||||
return $Opt_File_Prefix.".tab";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,11 +139,11 @@ sub remove_outputs {
|
||||
sub bison_version_check {
|
||||
my $v = `$Opt_Yacc --version`;
|
||||
if ($v && $v =~ /([0-9]+\.[0-9]+)/) {
|
||||
my $v = $1;
|
||||
($v >= 1.875) or die "bisonpre: %Error: '$Opt_Yacc' is version $v; version 1.875 or newer is required\n";
|
||||
return $v;
|
||||
my $v = $1;
|
||||
($v >= 1.875) or die "bisonpre: %Error: '$Opt_Yacc' is version $v; version 1.875 or newer is required\n";
|
||||
return $v;
|
||||
} else {
|
||||
die "bisonpre: %Error: '$Opt_Yacc' is not installed, or not working\n";
|
||||
die "bisonpre: %Error: '$Opt_Yacc' is not installed, or not working\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,55 +164,55 @@ sub clean_output {
|
||||
$newbase =~ s/\.y/./;
|
||||
|
||||
if ($is_output) {
|
||||
my %state_line; my $l=0;
|
||||
foreach my $line (@lines) {
|
||||
$l++;
|
||||
# We add a colon so it's easy to search for the definition
|
||||
$state_line{$1} = $l if $line =~ s/^state (\d+)\s*$/state $1:/;
|
||||
}
|
||||
my @out;
|
||||
foreach my $line (@lines) {
|
||||
if ($line =~ /^State (\d+) (conflicts)/) {
|
||||
chomp $line;
|
||||
$line .= " // line $state_line{$1}" if $state_line{$1};
|
||||
$line .= "\n";
|
||||
}
|
||||
push @out, $line;
|
||||
}
|
||||
@lines = @out; @out = ();
|
||||
my %state_line; my $l=0;
|
||||
foreach my $line (@lines) {
|
||||
$l++;
|
||||
# We add a colon so it's easy to search for the definition
|
||||
$state_line{$1} = $l if $line =~ s/^state (\d+)\s*$/state $1:/;
|
||||
}
|
||||
my @out;
|
||||
foreach my $line (@lines) {
|
||||
if ($line =~ /^State (\d+) (conflicts)/) {
|
||||
chomp $line;
|
||||
$line .= " // line $state_line{$1}" if $state_line{$1};
|
||||
$line .= "\n";
|
||||
}
|
||||
push @out, $line;
|
||||
}
|
||||
@lines = @out; @out = ();
|
||||
}
|
||||
if ($is_c) {
|
||||
my %token_values;
|
||||
my $in_en=0;
|
||||
foreach my $line (@lines) {
|
||||
$in_en=1 if $line =~ /enum\s+yytokentype/;
|
||||
$in_en=0 if $line =~ /;/;
|
||||
$token_values{$2} = $1 if $in_en && $line =~ /\b(\S+) = (\d+)/;
|
||||
}
|
||||
my @out;
|
||||
foreach my $line (@lines) {
|
||||
if ($line =~ /BISONPRE_TOKEN_NAMES/) {
|
||||
push @out, $line;
|
||||
foreach my $tv (sort keys %token_values) {
|
||||
push @out, sprintf("\tcase %d: return \"%s\";\n",
|
||||
$tv, $token_values{$tv});
|
||||
}
|
||||
next;
|
||||
}
|
||||
push @out, $line;
|
||||
}
|
||||
@lines = @out; @out = ();
|
||||
my %token_values;
|
||||
my $in_en=0;
|
||||
foreach my $line (@lines) {
|
||||
$in_en=1 if $line =~ /enum\s+yytokentype/;
|
||||
$in_en=0 if $line =~ /;/;
|
||||
$token_values{$2} = $1 if $in_en && $line =~ /\b(\S+) = (\d+)/;
|
||||
}
|
||||
my @out;
|
||||
foreach my $line (@lines) {
|
||||
if ($line =~ /BISONPRE_TOKEN_NAMES/) {
|
||||
push @out, $line;
|
||||
foreach my $tv (sort keys %token_values) {
|
||||
push @out, sprintf("\tcase %d: return \"%s\";\n",
|
||||
$tv, $token_values{$tv});
|
||||
}
|
||||
next;
|
||||
}
|
||||
push @out, $line;
|
||||
}
|
||||
@lines = @out; @out = ();
|
||||
}
|
||||
|
||||
$fh = IO::File->new(">$outname") or die "%Error: $! writing $outname\n";
|
||||
foreach my $line (@lines) {
|
||||
# Fix filename refs
|
||||
$line =~ s!$basename!$newbase!g;
|
||||
# Fix bison 2.3 and GCC 4.2.1
|
||||
$line =~ s!\(YY_\("!(YY_((char*)"!g;
|
||||
# Fix bison 2.3 glr-parser warning about yyerrorloc.YYTYPE::yydummy uninit
|
||||
$line =~ s!(YYLTYPE yyerrloc;)!$1 yyerrloc.yydummy=0;/*bisonpre*/!g;
|
||||
$fh->write($line);
|
||||
# Fix filename refs
|
||||
$line =~ s!$basename!$newbase!g;
|
||||
# Fix bison 2.3 and GCC 4.2.1
|
||||
$line =~ s!\(YY_\("!(YY_((char*)"!g;
|
||||
# Fix bison 2.3 glr-parser warning about yyerrorloc.YYTYPE::yydummy uninit
|
||||
$line =~ s!(YYLTYPE yyerrloc;)!$1 yyerrloc.yydummy=0;/*bisonpre*/!g;
|
||||
$fh->write($line);
|
||||
}
|
||||
$fh->close;
|
||||
}
|
||||
@@ -222,9 +222,9 @@ sub warning_check {
|
||||
|
||||
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
|
||||
while (defined(my $line = $fh->getline)) {
|
||||
if ($line =~ /(conflicts|warning:|^useless)/i) {
|
||||
die "%Error: $filename:$.: $line\n";
|
||||
}
|
||||
if ($line =~ /(conflicts|warning:|^useless)/i) {
|
||||
die "%Error: $filename:$.: $line\n";
|
||||
}
|
||||
}
|
||||
$fh->close;
|
||||
}
|
||||
@@ -249,160 +249,160 @@ sub clean_input {
|
||||
my $last_rule;
|
||||
my $section = 1;
|
||||
{
|
||||
my @linesin = @lines; @lines=(); my $l=0;
|
||||
foreach my $line (@linesin) {
|
||||
$l++;
|
||||
# ^/ to prevent comments from matching
|
||||
$line =~ m!^[a-zA-Z0-9_<>]+:[^/]*[a-zA-Z]! and die "%Error: $filename:$l: Move text on rule line to next line: $line\n";
|
||||
if ($line =~ /^%%/) {
|
||||
$section++;
|
||||
if ($section==2) { $last_rule = undef; }
|
||||
}
|
||||
elsif ($line =~ s/^([a-zA-Z0-9_]+)<(\S*)>:/$1:/) {
|
||||
!$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n";
|
||||
$types{$2}{$1} = 1;
|
||||
$rules{$1}{name} = $1;
|
||||
$rules{$1}{type} = $2;
|
||||
!$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n";
|
||||
$last_rule = $1;
|
||||
} elsif ($line =~ /^([a-zA-Z0-9_]+):/) {
|
||||
!$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n";
|
||||
$rules{$1}{name} = $1;
|
||||
$rules{$1}{type} = "";
|
||||
!$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n";
|
||||
$last_rule = $1;
|
||||
}
|
||||
push @lines, $line;
|
||||
# Now clean the line and extract some more info
|
||||
(my $cline = $line) =~ s/\/\/.*$/\n/;
|
||||
(my $rline = $line) =~ s/\/\/.*$/\n/;
|
||||
if ($cline =~ /^\s*;/) {
|
||||
$last_rule or die "%Error: $filename:$l: Stray semicolon\n";
|
||||
$last_rule = undef;
|
||||
} elsif ($last_rule) {
|
||||
$rules{$last_rule}{rules_and_productions} .= $cline;
|
||||
}
|
||||
if ($cline =~ /^%token\s*<(\S+)>\s*(\S+)/) {
|
||||
!$tokens{$2} or die "%Error: $filename:$l: Redeclaring '$2': $line\n";
|
||||
$tokens{$2} = $1;
|
||||
}
|
||||
foreach my $tok (split /[^a-zA-Z0-9_]+/, $cline) {
|
||||
if ($last_rule && $tok=~/^[a-zA-Z]/) {
|
||||
#print "TT $last_rule $tok\n";
|
||||
$rules{$last_rule}{subrules}{$tok} = 1;
|
||||
$rules{$tok}{parentrules}{$last_rule} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
my @linesin = @lines; @lines=(); my $l=0;
|
||||
foreach my $line (@linesin) {
|
||||
$l++;
|
||||
# ^/ to prevent comments from matching
|
||||
$line =~ m!^[a-zA-Z0-9_<>]+:[^/]*[a-zA-Z]! and die "%Error: $filename:$l: Move text on rule line to next line: $line\n";
|
||||
if ($line =~ /^%%/) {
|
||||
$section++;
|
||||
if ($section==2) { $last_rule = undef; }
|
||||
}
|
||||
elsif ($line =~ s/^([a-zA-Z0-9_]+)<(\S*)>:/$1:/) {
|
||||
!$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n";
|
||||
$types{$2}{$1} = 1;
|
||||
$rules{$1}{name} = $1;
|
||||
$rules{$1}{type} = $2;
|
||||
!$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n";
|
||||
$last_rule = $1;
|
||||
} elsif ($line =~ /^([a-zA-Z0-9_]+):/) {
|
||||
!$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n";
|
||||
$rules{$1}{name} = $1;
|
||||
$rules{$1}{type} = "";
|
||||
!$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n";
|
||||
$last_rule = $1;
|
||||
}
|
||||
push @lines, $line;
|
||||
# Now clean the line and extract some more info
|
||||
(my $cline = $line) =~ s/\/\/.*$/\n/;
|
||||
(my $rline = $line) =~ s/\/\/.*$/\n/;
|
||||
if ($cline =~ /^\s*;/) {
|
||||
$last_rule or die "%Error: $filename:$l: Stray semicolon\n";
|
||||
$last_rule = undef;
|
||||
} elsif ($last_rule) {
|
||||
$rules{$last_rule}{rules_and_productions} .= $cline;
|
||||
}
|
||||
if ($cline =~ /^%token\s*<(\S+)>\s*(\S+)/) {
|
||||
!$tokens{$2} or die "%Error: $filename:$l: Redeclaring '$2': $line\n";
|
||||
$tokens{$2} = $1;
|
||||
}
|
||||
foreach my $tok (split /[^a-zA-Z0-9_]+/, $cline) {
|
||||
if ($last_rule && $tok=~/^[a-zA-Z]/) {
|
||||
#print "TT $last_rule $tok\n";
|
||||
$rules{$last_rule}{subrules}{$tok} = 1;
|
||||
$rules{$tok}{parentrules}{$last_rule} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#use Data::Dumper; print Dumper(\%rules);
|
||||
|
||||
# Replace BISONPRE_VERSION(ver,,...) with expanded list
|
||||
{
|
||||
my @linesin = @lines; @lines=(); my $l=0;
|
||||
foreach my $line (@linesin) {
|
||||
$l++;
|
||||
if ($line =~ /BISONPRE_VERSION/) {
|
||||
# 1 3 4
|
||||
($line =~ /BISONPRE_VERSION\((\S+)\s*,\s*((\S+)\s*,)?\s*([^\),]+)\)\s*$/)
|
||||
or die "%Error: $filename:$l: Bad form of BISONPRE_VERSION: $line\n";
|
||||
my $ver=$1; my $ver_max=$3; my $cmd=$4;
|
||||
if ($Self->{bison_version} >= $1
|
||||
&& (!$ver_max || $Self->{bison_version} <= $ver_max)) {
|
||||
$line = $cmd."\n";
|
||||
} else {
|
||||
$line = "//NOP: $line";
|
||||
}
|
||||
}
|
||||
push @lines, $line;
|
||||
}
|
||||
my @linesin = @lines; @lines=(); my $l=0;
|
||||
foreach my $line (@linesin) {
|
||||
$l++;
|
||||
if ($line =~ /BISONPRE_VERSION/) {
|
||||
# 1 3 4
|
||||
($line =~ /BISONPRE_VERSION\((\S+)\s*,\s*((\S+)\s*,)?\s*([^\),]+)\)\s*$/)
|
||||
or die "%Error: $filename:$l: Bad form of BISONPRE_VERSION: $line\n";
|
||||
my $ver=$1; my $ver_max=$3; my $cmd=$4;
|
||||
if ($Self->{bison_version} >= $1
|
||||
&& (!$ver_max || $Self->{bison_version} <= $ver_max)) {
|
||||
$line = $cmd."\n";
|
||||
} else {
|
||||
$line = "//NOP: $line";
|
||||
}
|
||||
}
|
||||
push @lines, $line;
|
||||
}
|
||||
}
|
||||
|
||||
# Replace BISONPRE_NOT(type,...) with expanded list
|
||||
{
|
||||
my @linesin = @lines; @lines=(); my $l=0;
|
||||
foreach my $line (@linesin) {
|
||||
$l++;
|
||||
if ($line =~ /BISONPRE_NOT/) {
|
||||
($line =~ s/BISONPRE_NOT\((\S+)\)\s*({[^}]+})\s*$//)
|
||||
or die "%Error: $filename:$l: Bad form of BISONPRE_NOT: $line\n";
|
||||
my $endtok = $1; my $action = $2;
|
||||
my @endtoks = split (/,/, $endtok);
|
||||
map { $tokens{$_} or die "%Error: $filename:$l: Can't find definition for token: $_\n"
|
||||
} @endtoks;
|
||||
# Push it all onto one line to avoid error messages changing
|
||||
my $bar = "";
|
||||
tok:
|
||||
foreach my $tok (sort keys %tokens) {
|
||||
foreach (@endtoks) {
|
||||
next tok if $tok eq $_;
|
||||
}
|
||||
if ($endtok ne $tok) {
|
||||
$line .= "\t$bar $tok $action";
|
||||
$bar = "|";
|
||||
}
|
||||
}
|
||||
$line .= "\n";
|
||||
}
|
||||
push @lines, $line;
|
||||
}
|
||||
my @linesin = @lines; @lines=(); my $l=0;
|
||||
foreach my $line (@linesin) {
|
||||
$l++;
|
||||
if ($line =~ /BISONPRE_NOT/) {
|
||||
($line =~ s/BISONPRE_NOT\((\S+)\)\s*(\{[^}]+})\s*$//)
|
||||
or die "%Error: $filename:$l: Bad form of BISONPRE_NOT: $line\n";
|
||||
my $endtok = $1; my $action = $2;
|
||||
my @endtoks = split(/,/, $endtok);
|
||||
map { $tokens{$_} or die "%Error: $filename:$l: Can't find definition for token: $_\n"
|
||||
} @endtoks;
|
||||
# Push it all onto one line to avoid error messages changing
|
||||
my $bar = "";
|
||||
tok:
|
||||
foreach my $tok (sort keys %tokens) {
|
||||
foreach (@endtoks) {
|
||||
next tok if $tok eq $_;
|
||||
}
|
||||
if ($endtok ne $tok) {
|
||||
$line .= "\t$bar $tok $action";
|
||||
$bar = "|";
|
||||
}
|
||||
}
|
||||
$line .= "\n";
|
||||
}
|
||||
push @lines, $line;
|
||||
}
|
||||
}
|
||||
|
||||
# Replace BISONPRE_COPY(type,{code})
|
||||
{
|
||||
my @linesin = @lines; @lines=(); my $l=0;
|
||||
foreach my $line (@linesin) {
|
||||
$l++;
|
||||
if ($line =~ /BISONPRE_COPY/) {
|
||||
$line = _bisonpre_copy($line,$l,0);
|
||||
}
|
||||
push @lines, $line;
|
||||
}
|
||||
my @linesin = @lines; @lines=(); my $l=0;
|
||||
foreach my $line (@linesin) {
|
||||
$l++;
|
||||
if ($line =~ /BISONPRE_COPY/) {
|
||||
$line = _bisonpre_copy($line,$l,0);
|
||||
}
|
||||
push @lines, $line;
|
||||
}
|
||||
}
|
||||
|
||||
# Replace ~[x]~ - must be after BISONPRE_COPY expansion
|
||||
{
|
||||
my @linesin = @lines; @lines=(); my $l=0;
|
||||
foreach my $line (@linesin) {
|
||||
$l++;
|
||||
$line =~ s/~[a-zA-Z0-9_]+~//g;
|
||||
push @lines, $line;
|
||||
}
|
||||
my @linesin = @lines; @lines=(); my $l=0;
|
||||
foreach my $line (@linesin) {
|
||||
$l++;
|
||||
$line =~ s/~[a-zA-Z0-9_]+~//g;
|
||||
push @lines, $line;
|
||||
}
|
||||
}
|
||||
|
||||
# Find "BISONPRE_TYPES"
|
||||
{
|
||||
my @linesin = @lines; @lines=(); my $l=0;
|
||||
my $needmore = 0;
|
||||
foreach my $line (@linesin) {
|
||||
$l++;
|
||||
if ($line =~ m!//BISONPRE_TYPES!) {
|
||||
push @lines, $line;
|
||||
foreach my $type (sort keys %types) {
|
||||
next if !$type;
|
||||
my $line = "%type<$type>\t";
|
||||
foreach my $rule (sort keys %{$types{$type}}) {
|
||||
$line.=" ".$rule;
|
||||
}
|
||||
$line .= "\n";
|
||||
push @lines, $line;
|
||||
$needmore++
|
||||
}
|
||||
} elsif ($needmore) {
|
||||
# Bison doesn't have a #line directive, so we need somewhere to insert into
|
||||
$line =~ s!^\s*//.*$!!;
|
||||
($line =~ m/^\s*$/) or die "%Error: $filename:$l: Need $needmore more blank lines to insure line numbers are constant\n";
|
||||
$needmore--;
|
||||
} else {
|
||||
push @lines, $line;
|
||||
}
|
||||
}
|
||||
my @linesin = @lines; @lines=(); my $l=0;
|
||||
my $needmore = 0;
|
||||
foreach my $line (@linesin) {
|
||||
$l++;
|
||||
if ($line =~ m!//BISONPRE_TYPES!) {
|
||||
push @lines, $line;
|
||||
foreach my $type (sort keys %types) {
|
||||
next if !$type;
|
||||
my $line = "%type<$type>\t";
|
||||
foreach my $rule (sort keys %{$types{$type}}) {
|
||||
$line.=" ".$rule;
|
||||
}
|
||||
$line .= "\n";
|
||||
push @lines, $line;
|
||||
$needmore++
|
||||
}
|
||||
} elsif ($needmore) {
|
||||
# Bison doesn't have a #line directive, so we need somewhere to insert into
|
||||
$line =~ s!^\s*//.*$!!;
|
||||
($line =~ m/^\s*$/) or die "%Error: $filename:$l: Need $needmore more blank lines to insure line numbers are constant\n";
|
||||
$needmore--;
|
||||
} else {
|
||||
push @lines, $line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$fh = IO::File->new(">$outname") or die "%Error: $! writing $outname\n";
|
||||
foreach my $line (@lines) {
|
||||
$fh->write($line);
|
||||
$fh->write($line);
|
||||
}
|
||||
$fh->close;
|
||||
}
|
||||
@@ -412,28 +412,28 @@ sub _bisonpre_copy {
|
||||
my $l = shift;
|
||||
my $depth = shift;
|
||||
while ($text =~ /BISONPRE_COPY/) {
|
||||
($text =~ s/BISONPRE_COPY(_ONCE)?\((\S+)\s*,\s*{([^}]*)}\s*\)/{HERE}/)
|
||||
or die "%Error: $Self->{filename}:$l: Bad form of BISONPRE_NOT: $text\n";
|
||||
my $once = $1; my $rule = $2; my $code = $3;
|
||||
$Self->{rules}{$rule} or die "%Error: $Self->{filename}:$l: Can't find definition for rule: $rule\n";
|
||||
if ($depth > 0 && $once) {
|
||||
# _ONCE means don't inherit
|
||||
$text =~ s/\|[ \t]+{HERE}//; # Don't OR in nothing
|
||||
$text =~ s/{HERE}//;
|
||||
} else {
|
||||
# Push it all onto one line to avoid error messages changing
|
||||
my $insert = $Self->{rules}{$rule}{rules_and_productions};
|
||||
$insert =~ s/^\S+://g; # Strip rule name
|
||||
# Recurse so BISONPRE under B
|
||||
#print "COPY $l code $code\n";
|
||||
#print "COPY $l in $insert\n";
|
||||
$_=$insert; eval("$code; \$_;"); $insert = $_;
|
||||
#print "COPY $l out $insert\n";
|
||||
while ($insert =~ s/[ \t\n]+\n/\n/go) {}
|
||||
while ($insert =~ s/\n/ /go) {} # Optional - preserve line numbering
|
||||
$text =~ s/{HERE}/$insert/;
|
||||
}
|
||||
$depth++;
|
||||
($text =~ s/BISONPRE_COPY(_ONCE)?\((\S+)\s*,\s*\{([^}]*)}\s*\)/{HERE}/)
|
||||
or die "%Error: $Self->{filename}:$l: Bad form of BISONPRE_NOT: $text\n";
|
||||
my $once = $1; my $rule = $2; my $code = $3;
|
||||
$Self->{rules}{$rule} or die "%Error: $Self->{filename}:$l: Can't find definition for rule: $rule\n";
|
||||
if ($depth > 0 && $once) {
|
||||
# _ONCE means don't inherit
|
||||
$text =~ s/\|[ \t]+{HERE}//; # Don't OR in nothing
|
||||
$text =~ s/{HERE}//;
|
||||
} else {
|
||||
# Push it all onto one line to avoid error messages changing
|
||||
my $insert = $Self->{rules}{$rule}{rules_and_productions};
|
||||
$insert =~ s/^\S+://g; # Strip rule name
|
||||
# Recurse so BISONPRE under B
|
||||
#print "COPY $l code $code\n";
|
||||
#print "COPY $l in $insert\n";
|
||||
$_=$insert; eval("$code; \$_;"); $insert = $_;
|
||||
#print "COPY $l out $insert\n";
|
||||
while ($insert =~ s/[ \t\n]+\n/\n/go) {}
|
||||
while ($insert =~ s/\n/ /go) {} # Optional - preserve line numbering
|
||||
$text =~ s/{HERE}/$insert/;
|
||||
}
|
||||
$depth++;
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
+90
-90
@@ -7,7 +7,7 @@ use Getopt::Long;
|
||||
use IO::File;
|
||||
use Pod::Usage;
|
||||
use strict;
|
||||
use vars qw ($Debug $VERSION);
|
||||
use vars qw($Debug $VERSION);
|
||||
|
||||
$VERSION = '3.881';
|
||||
|
||||
@@ -23,12 +23,12 @@ our $Opt_Debug;
|
||||
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
Getopt::Long::config ("no_auto_abbrev","pass_through");
|
||||
Getopt::Long::config("no_auto_abbrev","pass_through");
|
||||
our @Opt_Args = ("cppcheck", @ARGV);
|
||||
if (! GetOptions (
|
||||
# Local options
|
||||
"help" => \&usage,
|
||||
"version" => sub { print "Version $VERSION\n"; system("cppcheck","--version"); exit(0); },
|
||||
if (! GetOptions(
|
||||
# Local options
|
||||
"help" => \&usage,
|
||||
"version" => sub { print "Version $VERSION\n"; system("cppcheck","--version"); exit(0); },
|
||||
)) {
|
||||
die "%Error: Bad usage, try 'cppcheck_filtered --help'\n";
|
||||
}
|
||||
@@ -40,7 +40,7 @@ process();
|
||||
sub usage {
|
||||
print "Version $VERSION\n";
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT, -noperldoc=>1);
|
||||
exit (1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
@@ -54,72 +54,72 @@ sub process {
|
||||
my %errs;
|
||||
my $last_error = "";
|
||||
while (defined(my $line = $fh->getline())) {
|
||||
$line =~ s/^\s+//;
|
||||
$line =~ s/Checking usage of global functions\.+//; # Sometimes tacked at end-of-line
|
||||
# General gunk
|
||||
next if $uniq{$line}++;
|
||||
next if $line =~ m!^<\?xml version!;
|
||||
next if $line =~ m!^<cppcheck!;
|
||||
next if $line =~ m!^<results!;
|
||||
next if $line =~ m!^</results>!;
|
||||
next if $line =~ m!^<errors!;
|
||||
next if $line =~ m!^</error>!;
|
||||
next if $line =~ m!^</errors>!;
|
||||
next if $line =~ m!^<error.*id="unmatchedSuppression"!; # --suppress=unmatchedSuppression doesn't work
|
||||
next if $line =~ m!Cppcheck cannot find all the include files!; # An earlier id line is more specific
|
||||
next if $line =~ m!^Checking !;
|
||||
next if $line =~ m!^make.*Entering directory !;
|
||||
next if $line =~ m!^make.*Leaving directory !;
|
||||
next if $line =~ m!^\s+$!g;
|
||||
$line =~ s/^\s+//;
|
||||
$line =~ s/Checking usage of global functions\.+//; # Sometimes tacked at end-of-line
|
||||
# General gunk
|
||||
next if $uniq{$line}++;
|
||||
next if $line =~ m!^<\?xml version!;
|
||||
next if $line =~ m!^<cppcheck!;
|
||||
next if $line =~ m!^<results!;
|
||||
next if $line =~ m!^</results>!;
|
||||
next if $line =~ m!^<errors!;
|
||||
next if $line =~ m!^</error>!;
|
||||
next if $line =~ m!^</errors>!;
|
||||
next if $line =~ m!^<error.*id="unmatchedSuppression"!; # --suppress=unmatchedSuppression doesn't work
|
||||
next if $line =~ m!Cppcheck cannot find all the include files!; # An earlier id line is more specific
|
||||
next if $line =~ m!^Checking !;
|
||||
next if $line =~ m!^make.*Entering directory !;
|
||||
next if $line =~ m!^make.*Leaving directory !;
|
||||
next if $line =~ m!^\s+$!g;
|
||||
|
||||
# Specific suppressions (see _suppress also)
|
||||
next if $line =~ m!id="unusedPrivateFunction" .*::debug!; # Doesn't know UINFO will use it
|
||||
|
||||
# Output
|
||||
if ($line =~ /^cppcheck --/) {
|
||||
print $line if $Debug;
|
||||
} elsif ($line =~ m!^\d+/\d+ files checked!) {
|
||||
print $line;
|
||||
} else {
|
||||
my $suppress;
|
||||
# --xml-format=1
|
||||
if ($line =~ /file="([^"]+)"\s+line="(\d+)"\s+id="([^"]+)"/) {
|
||||
my $file = $1; my $linenum = $2; my $id = $3;
|
||||
$suppress = 1 if _suppress($file,$linenum,$id);
|
||||
}
|
||||
# --xml-format=2
|
||||
if ($line =~ /<error id.*/) {
|
||||
$last_error = $line;
|
||||
chomp $last_error;
|
||||
$suppress = 1;
|
||||
}
|
||||
elsif ($line =~ /<location.* file="([^"]+)"\s+line="(\d+)"/) {
|
||||
my $file = $1; my $linenum = $2; my $id;
|
||||
if ($last_error =~ / id="([^"]+)"/) {
|
||||
$id = $1;
|
||||
} else {
|
||||
$id = "?";
|
||||
}
|
||||
$suppress = 1 if _suppress($file,$linenum,$id);
|
||||
$suppress = 1 if $file eq "*";
|
||||
if (!$suppress) {
|
||||
chomp $line;
|
||||
print "$file:$linenum: ".$last_error."\n";
|
||||
$suppress = 1;
|
||||
}
|
||||
}
|
||||
if (!$suppress) {
|
||||
my $eline = "%Error: cppcheck: $line";
|
||||
print $eline;
|
||||
$errs{$eline}++;
|
||||
}
|
||||
}
|
||||
# Output
|
||||
if ($line =~ /^cppcheck --/) {
|
||||
print $line if $Debug;
|
||||
} elsif ($line =~ m!^\d+/\d+ files checked!) {
|
||||
print $line;
|
||||
} else {
|
||||
my $suppress;
|
||||
# --xml-format=1
|
||||
if ($line =~ /file="([^"]+)"\s+line="(\d+)"\s+id="([^"]+)"/) {
|
||||
my $file = $1; my $linenum = $2; my $id = $3;
|
||||
$suppress = 1 if _suppress($file,$linenum,$id);
|
||||
}
|
||||
# --xml-format=2
|
||||
if ($line =~ /<error id.*/) {
|
||||
$last_error = $line;
|
||||
chomp $last_error;
|
||||
$suppress = 1;
|
||||
}
|
||||
elsif ($line =~ /<location.* file="([^"]+)"\s+line="(\d+)"/) {
|
||||
my $file = $1; my $linenum = $2; my $id;
|
||||
if ($last_error =~ / id="([^"]+)"/) {
|
||||
$id = $1;
|
||||
} else {
|
||||
$id = "?";
|
||||
}
|
||||
$suppress = 1 if _suppress($file,$linenum,$id);
|
||||
$suppress = 1 if $file eq "*";
|
||||
if (!$suppress) {
|
||||
chomp $line;
|
||||
print "$file:$linenum: ".$last_error."\n";
|
||||
$suppress = 1;
|
||||
}
|
||||
}
|
||||
if (!$suppress) {
|
||||
my $eline = "%Error: cppcheck: $line";
|
||||
print $eline;
|
||||
$errs{$eline}++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (scalar(keys %errs)) {
|
||||
#my $all = join('',sort(keys %errs));
|
||||
#$Self->error("Cppcheck errors:\n$all");
|
||||
#die "%Error: cppcheck_filtered found errors\n";
|
||||
exit(1);
|
||||
#my $all = join('',sort(keys %errs));
|
||||
#$Self->error("Cppcheck errors:\n$all");
|
||||
#die "%Error: cppcheck_filtered found errors\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,32 +143,32 @@ sub _suppress {
|
||||
|
||||
my $fh = IO::File->new("<$filename");
|
||||
if (!$fh) {
|
||||
warn "%Warning: $! $filename,";
|
||||
return undef;
|
||||
warn "%Warning: $! $filename,";
|
||||
return undef;
|
||||
}
|
||||
my $l = 0;
|
||||
while (defined(my $line = $fh->getline())) {
|
||||
++$l;
|
||||
if ($l+1 == $linenum) {
|
||||
if ($line =~ /cppcheck-suppress((\s+\S+)+)/) {
|
||||
my $supids = $1;
|
||||
foreach my $supid (split /\s+/, $supids) {
|
||||
if ($supid eq $id
|
||||
|| $supid eq ($SuppressMap{$id}||'')) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
warn "%Warning: $filename: $l: Found suppress for ids='$supids', not expected id='$id'\n";
|
||||
}
|
||||
}
|
||||
if ($l == $linenum) {
|
||||
if (0 && # We now use VL_DANGLING instead of this rule
|
||||
$id eq "uselessAssignmentPtrArg"
|
||||
&& $line =~ /(delete|Delete|Edit).*p *= *(NULL|nullptr);/) {
|
||||
# delete(nodep); nodep=NULL; # This is ok, it's how we prevent later using nodep
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
++$l;
|
||||
if ($l+1 == $linenum) {
|
||||
if ($line =~ /cppcheck-suppress((\s+\S+)+)/) {
|
||||
my $supids = $1;
|
||||
foreach my $supid (split /\s+/, $supids) {
|
||||
if ($supid eq $id
|
||||
|| $supid eq ($SuppressMap{$id}||'')) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
warn "%Warning: $filename: $l: Found suppress for ids='$supids', not expected id='$id'\n";
|
||||
}
|
||||
}
|
||||
if ($l == $linenum) {
|
||||
if (0 && # We now use VL_DANGLING instead of this rule
|
||||
$id eq "uselessAssignmentPtrArg"
|
||||
&& $line =~ /(delete|Delete|Edit).*p *= *(NULL|nullptr);/) {
|
||||
# delete(nodep); nodep=NULL; # This is ok, it's how we prevent later using nodep
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
@@ -227,6 +227,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"$finish" { FL; return yD_FINISH; }
|
||||
"$floor" { FL; return yD_FLOOR; }
|
||||
"$fopen" { FL; return yD_FOPEN; }
|
||||
"$fread" { FL; return yD_FREAD; }
|
||||
"$fscanf" { FL; return yD_FSCANF; }
|
||||
"$fullskew" { FL; return yaTIMINGSPEC; }
|
||||
"$fwrite" { FL; return yD_FWRITE; }
|
||||
|
||||
+31
-11
@@ -475,6 +475,7 @@ class AstSenTree;
|
||||
%token<fl> yD_FINISH "$finish"
|
||||
%token<fl> yD_FLOOR "$floor"
|
||||
%token<fl> yD_FOPEN "$fopen"
|
||||
%token<fl> yD_FREAD "$fread"
|
||||
%token<fl> yD_FSCANF "$fscanf"
|
||||
%token<fl> yD_FWRITE "$fwrite"
|
||||
%token<fl> yD_HIGH "$high"
|
||||
@@ -2084,7 +2085,9 @@ param_assignment<varp>: // ==IEEE: param_assignment
|
||||
id/*new-parameter*/ variable_dimensionListE sigAttrListE '=' exprOrDataType
|
||||
/**/ { $$ = VARDONEA($<fl>1,*$1, $2, $3); $$->valuep($5); }
|
||||
| id/*new-parameter*/ variable_dimensionListE sigAttrListE
|
||||
/**/ { $$ = VARDONEA($<fl>1,*$1, $2, $3); }
|
||||
/**/ { $$ = VARDONEA($<fl>1,*$1, $2, $3);
|
||||
if ($<fl>1->language() < V3LangCode::L1800_2009) {
|
||||
$<fl>1->v3error("Parameter requires default value, or use IEEE 1800-2009 or later."); } }
|
||||
;
|
||||
|
||||
list_of_param_assignments<varp>: // ==IEEE: list_of_param_assignments
|
||||
@@ -2390,8 +2393,21 @@ statement_item<nodep>: // IEEE: statement_item
|
||||
// // Below under expr
|
||||
//
|
||||
// // IEEE: subroutine_call_statement
|
||||
//UNSUP yVOID yP_TICK '(' function_subroutine_callNoMethod ')' ';' { }
|
||||
//UNSUP yVOID yP_TICK '(' expr '.' function_subroutine_callNoMethod ')' ';' { }
|
||||
// // IEEE says we then expect a function call
|
||||
// // (function_subroutine_callNoMethod), but rest of
|
||||
// // the code expects an AstTask when used as a statement,
|
||||
// // so parse as if task
|
||||
// // Alternative would be shim with new AstVoidStmt.
|
||||
| yVOID yP_TICK '(' task_subroutine_callNoMethod ')' ';'
|
||||
{ $$ = $4;
|
||||
FileLine* newfl = new FileLine($$->fileline());
|
||||
newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true);
|
||||
$$->fileline(newfl); }
|
||||
| yVOID yP_TICK '(' expr '.' task_subroutine_callNoMethod ')' ';'
|
||||
{ $$ = new AstDot($5, $4, $6);
|
||||
FileLine* newfl = new FileLine($6->fileline());
|
||||
newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true);
|
||||
$6->fileline(newfl); }
|
||||
// // Expr included here to resolve our not knowing what is a method call
|
||||
// // Expr here must result in a subroutine_call
|
||||
| task_subroutine_callNoMethod ';' { $$ = $1; }
|
||||
@@ -2815,6 +2831,9 @@ system_f_call_or_t<nodep>: // IEEE: part of system_tf_call (can be task or func)
|
||||
| yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); }
|
||||
| yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); }
|
||||
| yD_FGETS '(' idClassSel ',' expr ')' { $$ = new AstFGetS($1,$3,$5); }
|
||||
| yD_FREAD '(' idClassSel ',' expr ')' { $$ = new AstFRead($1,$3,$5,NULL,NULL); }
|
||||
| yD_FREAD '(' idClassSel ',' expr ',' expr ')' { $$ = new AstFRead($1,$3,$5,$7,NULL); }
|
||||
| yD_FREAD '(' idClassSel ',' expr ',' expr ',' expr ')' { $$ = new AstFRead($1,$3,$5,$7,$9); }
|
||||
| yD_FLOOR '(' expr ')' { $$ = new AstFloorD($1,$3); }
|
||||
| yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); }
|
||||
| yD_HIGH '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_HIGH,$3,NULL); }
|
||||
@@ -3278,6 +3297,13 @@ exprOkLvalue<nodep>: // expression that's also OK to use as a variable_lvalue
|
||||
// // IEEE: concatenation/constant_concatenation
|
||||
// // Replicate(1) required as otherwise "{a}" would not be self-determined
|
||||
| '{' cateList '}' { $$ = new AstReplicate($1,$2,1); }
|
||||
| '{' cateList '}' '[' expr ']' { $$ = new AstSelBit($4, new AstReplicate($1,$2,1), $5); }
|
||||
| '{' cateList '}' '[' constExpr ':' constExpr ']'
|
||||
{ $$ = new AstSelExtract($4, new AstReplicate($1,$2,1), $5, $7); }
|
||||
| '{' cateList '}' '[' expr yP_PLUSCOLON constExpr ']'
|
||||
{ $$ = new AstSelPlus($4, new AstReplicate($1,$2,1), $5, $7); }
|
||||
| '{' cateList '}' '[' expr yP_MINUSCOLON constExpr ']'
|
||||
{ $$ = new AstSelMinus($4, new AstReplicate($1,$2,1), $5, $7); }
|
||||
// // IEEE: assignment_pattern_expression
|
||||
// // IEEE: [ assignment_pattern_expression_type ] == [ ps_type_id /ps_paremeter_id/data_type]
|
||||
// // We allow more here than the spec requires
|
||||
@@ -3961,14 +3987,8 @@ void V3ParseGrammar::argWrapList(AstNodeFTaskRef* nodep) {
|
||||
}
|
||||
|
||||
AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, string name, int value) {
|
||||
FileLine* newfl = new FileLine (fileline);
|
||||
newfl->warnOff(V3ErrorCode::WIDTH, true);
|
||||
AstNode* nodep = new AstConst(newfl, V3Number(newfl));
|
||||
// Adding a NOT is less work than figuring out how wide to make it
|
||||
if (value) nodep = new AstNot(newfl, nodep);
|
||||
nodep = new AstAssignW(newfl, new AstVarRef(fileline, name, true),
|
||||
nodep);
|
||||
return nodep;
|
||||
return new AstAssignW(fileline, new AstVarRef(fileline, name, true),
|
||||
new AstConst(fileline, V3Number(fileline, (value ? "'1" : "'0"))));
|
||||
}
|
||||
|
||||
AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) {
|
||||
|
||||
+52
-52
@@ -7,7 +7,7 @@ use Getopt::Long;
|
||||
use IO::File;
|
||||
use Pod::Usage;
|
||||
use strict;
|
||||
use vars qw ($Debug);
|
||||
use vars qw($Debug);
|
||||
|
||||
our @Items;
|
||||
|
||||
@@ -16,12 +16,12 @@ our @Items;
|
||||
|
||||
$Debug = 0;
|
||||
my $Opt_Srcdir = ".";
|
||||
Getopt::Long::config ("pass_through", "no_auto_abbrev");
|
||||
if (! GetOptions (
|
||||
"help" => \&usage,
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"srcdir=s" => \$Opt_Srcdir,
|
||||
"<>" => sub { die "%Error: Unknown parameter: $_[0],"; },
|
||||
Getopt::Long::config("pass_through", "no_auto_abbrev");
|
||||
if (! GetOptions(
|
||||
"help" => \&usage,
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"srcdir=s" => \$Opt_Srcdir,
|
||||
"<>" => sub { die "%Error: Unknown parameter: $_[0],"; },
|
||||
)) {
|
||||
usage();
|
||||
}
|
||||
@@ -34,7 +34,7 @@ write_keys("$Opt_Srcdir/../include/verilated_cov_key.h");
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
exit (1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
@@ -44,17 +44,17 @@ sub read_keys {
|
||||
|
||||
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
|
||||
while (defined (my $line = $fh->getline())) {
|
||||
$line =~ s/\/\/.*$//;
|
||||
next if $line =~ /^\s*$/;
|
||||
if ($line =~ /^\s*VLCOVGEN_ITEM/) {
|
||||
$line =~ /^\s*VLCOVGEN_ITEM *\( *"([^"]+)" *\)/
|
||||
or die "%Error: $filename:$.: Misformed VLCOVGEN_ITEM line,";
|
||||
my @data;
|
||||
my $code = "\@data = ($1);";
|
||||
eval $code;
|
||||
die "%Error: $filename:$.: Parsing '$code': $@," if $@;
|
||||
push @Items, {@data};
|
||||
}
|
||||
$line =~ s/\/\/.*$//;
|
||||
next if $line =~ /^\s*$/;
|
||||
if ($line =~ /^\s*VLCOVGEN_ITEM/) {
|
||||
$line =~ /^\s*VLCOVGEN_ITEM *\( *"([^"]+)" *\)/
|
||||
or die "%Error: $filename:$.: Misformed VLCOVGEN_ITEM line,";
|
||||
my @data;
|
||||
my $code = "\@data = ($1);";
|
||||
eval $code;
|
||||
die "%Error: $filename:$.: Parsing '$code': $@," if $@;
|
||||
push @Items, {@data};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,11 +64,11 @@ sub lint {
|
||||
my %shorts;
|
||||
my $ok = 1;
|
||||
foreach my $itemref (@Items) {
|
||||
if ($shorts{$itemref->{short}}) {
|
||||
warn "%Error: Duplicate short code: $itemref->{short},";
|
||||
$ok = 0;
|
||||
}
|
||||
$shorts{$itemref->{short}} = 1;
|
||||
if ($shorts{$itemref->{short}}) {
|
||||
warn "%Error: Duplicate short code: $itemref->{short},";
|
||||
$ok = 0;
|
||||
}
|
||||
$shorts{$itemref->{short}} = 1;
|
||||
}
|
||||
return $ok;
|
||||
}
|
||||
@@ -82,40 +82,40 @@ sub write_keys {
|
||||
my @out;
|
||||
my $deleting;
|
||||
while (defined(my $line = $fh->getline)) {
|
||||
push @in, $line;
|
||||
if ($line =~ /VLCOVGEN_CIK_AUTO_EDIT_BEGIN/) {
|
||||
$deleting = 1;
|
||||
push @out, $line;
|
||||
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
|
||||
push @out, sprintf("#define VL_CIK_%s \"%s\"\n",
|
||||
uc $keyref->{name}, $keyref->{short});
|
||||
}
|
||||
}
|
||||
elsif ($line =~ /VLCOVGEN_SHORT_AUTO_EDIT_BEGIN/) {
|
||||
$deleting = 1;
|
||||
push @out, $line;
|
||||
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
|
||||
push @in, $line;
|
||||
if ($line =~ /VLCOVGEN_CIK_AUTO_EDIT_BEGIN/) {
|
||||
$deleting = 1;
|
||||
push @out, $line;
|
||||
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
|
||||
push @out, sprintf("#define VL_CIK_%s \"%s\"\n",
|
||||
uc $keyref->{name}, $keyref->{short});
|
||||
}
|
||||
}
|
||||
elsif ($line =~ /VLCOVGEN_SHORT_AUTO_EDIT_BEGIN/) {
|
||||
$deleting = 1;
|
||||
push @out, $line;
|
||||
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
|
||||
push @out, sprintf(" if (key == \"%s\") return VL_CIK_%s;\n",
|
||||
$keyref->{name}, uc $keyref->{name});
|
||||
}
|
||||
}
|
||||
elsif ($line =~ /VLCOVGEN_.*AUTO_EDIT_END/) {
|
||||
$deleting = 0;
|
||||
push @out, $line;
|
||||
}
|
||||
elsif ($deleting) {
|
||||
}
|
||||
else {
|
||||
push @out, $line;
|
||||
}
|
||||
$keyref->{name}, uc $keyref->{name});
|
||||
}
|
||||
}
|
||||
elsif ($line =~ /VLCOVGEN_.*AUTO_EDIT_END/) {
|
||||
$deleting = 0;
|
||||
push @out, $line;
|
||||
}
|
||||
elsif ($deleting) {
|
||||
}
|
||||
else {
|
||||
push @out, $line;
|
||||
}
|
||||
}
|
||||
$fh->close;
|
||||
|
||||
my $ok = join("", @out) eq join("", @in);
|
||||
if (!$ok) {
|
||||
my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename\n";
|
||||
$fh->print(join "", @out);
|
||||
$fh->close;
|
||||
my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename\n";
|
||||
$fh->print(join "", @out);
|
||||
$fh->close;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+652
-637
File diff suppressed because it is too large
Load Diff
@@ -19,34 +19,35 @@
|
||||
class TestSimulator {
|
||||
private:
|
||||
struct SimTypes {
|
||||
int verilator;
|
||||
int icarus;
|
||||
int mti;
|
||||
int ncsim;
|
||||
int vcs;
|
||||
int verilator;
|
||||
int icarus;
|
||||
int mti;
|
||||
int ncsim;
|
||||
int vcs;
|
||||
};
|
||||
s_vpi_vlog_info m_info;
|
||||
SimTypes m_simulators;
|
||||
s_vpi_vlog_info m_info;
|
||||
SimTypes m_simulators;
|
||||
public:
|
||||
TestSimulator() {
|
||||
vpi_get_vlog_info(&m_info);
|
||||
if (0 == strcmp(m_info.product, "Verilator")) {
|
||||
m_simulators.verilator = true;
|
||||
} else if (0 == strcmp(m_info.product, "Verilator")) {
|
||||
m_simulators.icarus = true;
|
||||
} else if (0 == strncmp(m_info.product, "Chronologic Simulation VCS", strlen("Chronologic Simulation VCS"))) {
|
||||
m_simulators.vcs = true;
|
||||
} else {
|
||||
printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n",
|
||||
__FILE__, __LINE__, m_info.product);
|
||||
}
|
||||
vpi_get_vlog_info(&m_info);
|
||||
if (0 == strcmp(m_info.product, "Verilator")) {
|
||||
m_simulators.verilator = true;
|
||||
} else if (0 == strcmp(m_info.product, "Verilator")) {
|
||||
m_simulators.icarus = true;
|
||||
} else if (0 == strncmp(m_info.product, "Chronologic Simulation VCS",
|
||||
strlen("Chronologic Simulation VCS"))) {
|
||||
m_simulators.vcs = true;
|
||||
} else {
|
||||
printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n",
|
||||
__FILE__, __LINE__, m_info.product);
|
||||
}
|
||||
}
|
||||
~TestSimulator() { }
|
||||
// METHORS
|
||||
private:
|
||||
static TestSimulator& singleton() {
|
||||
static TestSimulator s_singleton;
|
||||
return s_singleton;
|
||||
static TestSimulator s_singleton;
|
||||
return s_singleton;
|
||||
}
|
||||
static const SimTypes& simulators() { return singleton().m_simulators; }
|
||||
public:
|
||||
@@ -62,19 +63,19 @@ public:
|
||||
static bool has_get_scalar() { return !simulators().icarus; }
|
||||
// return test level scope
|
||||
static const char* top() {
|
||||
if (simulators().verilator) {
|
||||
return "t";
|
||||
} else {
|
||||
return "top.t";
|
||||
}
|
||||
if (simulators().verilator) {
|
||||
return "t";
|
||||
} else {
|
||||
return "top.t";
|
||||
}
|
||||
}
|
||||
// return absolute scope of obj
|
||||
static const char* rooted(const char *obj) {
|
||||
static string buf;
|
||||
ostringstream os;
|
||||
os<<top()<<"."<<obj;
|
||||
buf = os.str();
|
||||
return buf.c_str();
|
||||
static string buf;
|
||||
ostringstream os;
|
||||
os<<top()<<"."<<obj;
|
||||
buf = os.str();
|
||||
return buf.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ class TestVpiHandle {
|
||||
public:
|
||||
TestVpiHandle() : m_handle(NULL), m_free(true) { }
|
||||
TestVpiHandle(vpiHandle h) : m_handle(h), m_free(true) { }
|
||||
~TestVpiHandle() { if (m_handle && m_free) { vpi_free_object(m_handle); m_handle=NULL; } } // icarus has yet to catch up with 1800-2009
|
||||
~TestVpiHandle() { if (m_handle && m_free) { vpi_free_object(m_handle); m_handle=NULL; } }
|
||||
operator vpiHandle() const { return m_handle; }
|
||||
inline TestVpiHandle& operator= (vpiHandle h) { m_handle = h; return *this; }
|
||||
TestVpiHandle& nofree() {
|
||||
|
||||
@@ -14,7 +14,7 @@ compile(
|
||||
);
|
||||
|
||||
if ($Self->{vlt_all}) {
|
||||
file_grep ($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
|
||||
file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
|
||||
}
|
||||
|
||||
execute(
|
||||
|
||||
@@ -14,7 +14,7 @@ compile(
|
||||
);
|
||||
|
||||
if ($Self->{vlt_all}) {
|
||||
file_grep ($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
|
||||
file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
|
||||
}
|
||||
|
||||
execute(
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
%Error: t/t_array_pattern_bad.v:23: Assignment pattern key 'valids' not found as member
|
||||
%Error: Exiting due to
|
||||
@@ -11,9 +11,7 @@ scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => 1,
|
||||
expect =>
|
||||
q{%Error: t/t_array_pattern_bad.v:23: Assignment pattern key 'valids' not found as member
|
||||
.*%Error: Exiting due to.*},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
|
||||
@@ -23,7 +23,7 @@ execute(
|
||||
fails => $Self->{vlt_all},
|
||||
);
|
||||
|
||||
file_grep ("$Self->{obj_dir}/vlt_compile.log",
|
||||
file_grep("$Self->{obj_dir}/vlt_compile.log",
|
||||
qr/%Warning-USERFATAL: Parameter 5 is invalid...string and constant both work/);
|
||||
|
||||
ok(1);
|
||||
|
||||
@@ -20,9 +20,9 @@ execute(
|
||||
fails => 1
|
||||
);
|
||||
|
||||
file_grep ($Self->{run_log_filename}, qr/'assert property' failed/);
|
||||
file_grep($Self->{run_log_filename}, qr/'assert property' failed/);
|
||||
# We expect to get a message when this assert fires:
|
||||
file_grep ($Self->{run_log_filename}, qr/cyc != 3/);
|
||||
file_grep($Self->{run_log_filename}, qr/cyc != 3/);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
@@ -20,7 +20,7 @@ execute(
|
||||
fails => 1
|
||||
);
|
||||
|
||||
file_grep ($Self->{run_log_filename}, qr/'assert property' failed/);
|
||||
file_grep($Self->{run_log_filename}, qr/'assert property' failed/);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
@@ -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
|
||||
@@ -12,9 +12,7 @@ scenarios(simulator => 1);
|
||||
compile(
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails => 1,
|
||||
expect =>
|
||||
'%Error: t/t_bitsel_const_bad.v:\d+: Illegal bit or array select; type does not have a bit range, or bad dimension: type is logic
|
||||
.*%Error: Exiting due to.*',
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
|
||||
@@ -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
|
||||
@@ -12,9 +12,7 @@ scenarios(simulator => 1);
|
||||
compile(
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails => 1,
|
||||
expect =>
|
||||
'%Error: t/t_case_genx_bad.v:\d+: Use of x/\? constant in generate case statement, \(no such thing as \'generate casez\'\)
|
||||
%Error: Exiting due to.*',
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
|
||||
@@ -15,8 +15,8 @@ compile(
|
||||
verilator_flags2 => ["--stats --prof-cfuncs -CFLAGS '-pg' -LDFLAGS '-pg'"],
|
||||
);
|
||||
|
||||
file_grep ($Self->{stats}, qr/Optimizations, Tables created\s+(\d+)/i, 10);
|
||||
file_grep ($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 10);
|
||||
file_grep($Self->{stats}, qr/Optimizations, Tables created\s+(\d+)/i, 10);
|
||||
file_grep($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 10);
|
||||
|
||||
unlink $_ foreach (glob "$Self->{obj_dir}/gmon.out.*");
|
||||
$ENV{GMON_OUT_PREFIX} = "$Self->{obj_dir}/gmon.out";
|
||||
@@ -36,7 +36,7 @@ run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{VM_PREFIX} $gmon_base > gprof.
|
||||
run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc gprof.out > cfuncs.out"],
|
||||
check_finished => 0);
|
||||
|
||||
file_grep ("$Self->{obj_dir}/cfuncs.out", qr/Overall summary by/);
|
||||
file_grep("$Self->{obj_dir}/cfuncs.out", qr/Overall summary by/);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
@@ -15,8 +15,8 @@ module t (/*AUTOARG*/
|
||||
input clk;
|
||||
|
||||
reg [63:0] crc;
|
||||
`verilator_file_descriptor fd;
|
||||
`verilator_file_descriptor fdtmp;
|
||||
integer fd;
|
||||
integer fdtmp;
|
||||
|
||||
t_case_write1_tasks tasks ();
|
||||
|
||||
@@ -33,14 +33,14 @@ module t (/*AUTOARG*/
|
||||
cyc <= cyc + 1;
|
||||
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||
if (cyc==1) begin
|
||||
crc <= 64'h00000000_00000097;
|
||||
crc <= 64'h00000000_00000097;
|
||||
$write("%s", {"Open ", `STRINGIFY(`TEST_OBJ_DIR), "/t_case_write1_logger.log\n"});
|
||||
fdtmp = $fopen({`STRINGIFY(`TEST_OBJ_DIR), "/t_case_write1_logger.log"}, "w");
|
||||
fd <= fdtmp;
|
||||
end
|
||||
if (cyc==90) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ module t (/*AUTOARG*/
|
||||
input clk;
|
||||
|
||||
reg [63:0] crc;
|
||||
`verilator_file_descriptor fd;
|
||||
`verilator_file_descriptor fdtmp;
|
||||
integer fd;
|
||||
integer fdtmp;
|
||||
|
||||
t_case_write2_tasks tasks ();
|
||||
|
||||
@@ -33,14 +33,14 @@ module t (/*AUTOARG*/
|
||||
cyc <= cyc + 1;
|
||||
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||
if (cyc==1) begin
|
||||
crc <= 64'h00000000_00000097;
|
||||
crc <= 64'h00000000_00000097;
|
||||
$write("%s", {"Open ", `STRINGIFY(`TEST_OBJ_DIR), "/t_case_write2_logger.log\n"});
|
||||
fdtmp = $fopen({`STRINGIFY(`TEST_OBJ_DIR), "/t_case_write2_logger.log"}, "w");
|
||||
fd <= fdtmp;
|
||||
end
|
||||
if (cyc==90) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ compile(
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
file_grep ("$Self->{obj_dir}/V$Self->{name}__cdc.txt", qr/CDC Report/);
|
||||
file_grep("$Self->{obj_dir}/V$Self->{name}__cdc.txt", qr/CDC Report/);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
@@ -18,7 +18,7 @@ execute(
|
||||
);
|
||||
|
||||
if ($Self->{vlt_all}) {
|
||||
file_grep ($Self->{stats}, qr/Optimizations, Gate assign merged\s+(\d+)/i, 28);
|
||||
file_grep($Self->{stats}, qr/Optimizations, Gate assign merged\s+(\d+)/i, 28);
|
||||
};
|
||||
|
||||
ok(1);
|
||||
|
||||
@@ -38,16 +38,16 @@ int main(int argc, char *argv[]) {
|
||||
Verilated::debug(0);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
clockit(0, 0);
|
||||
clockit(0, 1);
|
||||
clockit(1, 1);
|
||||
clockit(0, 0);
|
||||
clockit(1, 1);
|
||||
clockit(1, 0);
|
||||
clockit(0, 0);
|
||||
clockit(0, 1);
|
||||
clockit(1, 0);
|
||||
clockit(0, 0);
|
||||
clockit(0, 0);
|
||||
clockit(0, 1);
|
||||
clockit(1, 1);
|
||||
clockit(0, 0);
|
||||
clockit(1, 1);
|
||||
clockit(1, 0);
|
||||
clockit(0, 0);
|
||||
clockit(0, 1);
|
||||
clockit(1, 0);
|
||||
clockit(0, 0);
|
||||
}
|
||||
topp->check = 1;
|
||||
clockit(0,0);
|
||||
|
||||
@@ -17,7 +17,7 @@ execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
vcd_identical("$Self->{obj_dir}/simx.vcd", "t/$Self->{name}.out");
|
||||
vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename});
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
@@ -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
|
||||
@@ -12,10 +12,7 @@ scenarios(simulator => 1);
|
||||
compile(
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails => 1,
|
||||
expect =>
|
||||
'%Warning-WIDTHCONCAT: t/t_concat_large_bad.v:\d+: More than a 8k bit replication is probably wrong: 32768
|
||||
%Warning-WIDTHCONCAT: Use .*
|
||||
%Error: Exiting due to.*',
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
|
||||
Executable
+20
@@ -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;
|
||||
@@ -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
|
||||
@@ -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
|
||||
Executable
+22
@@ -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;
|
||||
@@ -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
|
||||
@@ -20,7 +20,7 @@ execute(
|
||||
# Read the input .v file and do any CHECK_COVER requests
|
||||
inline_checks();
|
||||
|
||||
file_grep ($Self->{stats}, qr/Coverage, Toggle points joined\s+(\d+)/i, 25)
|
||||
file_grep($Self->{stats}, qr/Coverage, Toggle points joined\s+(\d+)/i, 25)
|
||||
if $Self->{vlt_all};
|
||||
|
||||
ok(1);
|
||||
|
||||
@@ -14,7 +14,7 @@ compile(
|
||||
);
|
||||
|
||||
if ($Self->{vlt_all}) {
|
||||
file_grep ($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 4);
|
||||
file_grep($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 4);
|
||||
}
|
||||
|
||||
ok(1);
|
||||
|
||||
@@ -14,7 +14,7 @@ compile(
|
||||
);
|
||||
|
||||
if ($Self->{vlt_all}) {
|
||||
file_grep ($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 6);
|
||||
file_grep($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 6);
|
||||
}
|
||||
|
||||
ok(1);
|
||||
|
||||
@@ -18,8 +18,8 @@ execute(
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}__stats.txt",
|
||||
qr/Node count, DISPLAY \s+ 32 \s+ 25 \s+ 25 \s+ 25/);
|
||||
file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}__stats.txt",
|
||||
qr/Node count, DISPLAY \s+ 32 \s+ 25 \s+ 25 \s+ 25/);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
@@ -27,7 +27,8 @@ if (!-r "$root/.git") {
|
||||
my $lineno = 0;
|
||||
foreach my $line ((split /\n/, $diff), "+++ b/_the_end") {
|
||||
if ($line =~ m!^\+\+\+ b/(.*)!) {
|
||||
if ($file && !$atab && $btab) {
|
||||
if ($file && !$atab && $btab
|
||||
&& $file !~ /\.out$/) {
|
||||
$summary = "File modifications adds new tabs (please untabify the patch):";
|
||||
$warns{$file} = "File modification adds new tabs (please untabify the patch): $file";
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user