mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +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!
|
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
|
* Verilator 4.010 2019-01-27
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
\.clang-tidy
|
\.clang-tidy
|
||||||
\.git/
|
\.git/
|
||||||
|
\.git$
|
||||||
\.svn/
|
\.svn/
|
||||||
\.(bak|old)/
|
\.(bak|old)/
|
||||||
\.(bak|old)$
|
\.(bak|old)$
|
||||||
|
|||||||
+71
-39
@@ -58,17 +58,17 @@ foreach my $sw (@ARGV) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Getopt::Long::config("no_auto_abbrev","pass_through");
|
Getopt::Long::config("no_auto_abbrev","pass_through");
|
||||||
if (! GetOptions (
|
if (! GetOptions(
|
||||||
# Major operating modes
|
# Major operating modes
|
||||||
"help" => \&usage,
|
"help" => \&usage,
|
||||||
"debug:s" => \&debug,
|
"debug:s" => \&debug,
|
||||||
# "version!" => \&version, # Also passthru'ed
|
# "version!" => \&version, # Also passthru'ed
|
||||||
# Switches
|
# Switches
|
||||||
"gdb!" => \$opt_gdb,
|
"gdb!" => \$opt_gdb,
|
||||||
"gdbbt!" => \$opt_gdbbt,
|
"gdbbt!" => \$opt_gdbbt,
|
||||||
# Additional parameters
|
# Additional parameters
|
||||||
"<>" => sub {}, # Ignored
|
"<>" => sub {}, # Ignored
|
||||||
)) {
|
)) {
|
||||||
pod2usage(-exitstatus=>2, -verbose=>0);
|
pod2usage(-exitstatus=>2, -verbose=>0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ if ($opt_gdbbt && !gdb_works()) {
|
|||||||
my @quoted_sw = map {sh_escape($_)} @Opt_Verilator_Sw;
|
my @quoted_sw = map {sh_escape($_)} @Opt_Verilator_Sw;
|
||||||
if ($opt_gdb) {
|
if ($opt_gdb) {
|
||||||
# Generic GDB interactive
|
# Generic GDB interactive
|
||||||
run (("gdb"||$ENV{VERILATOR_GDB})
|
run (($ENV{VERILATOR_GDB}||"gdb")
|
||||||
." ".verilator_bin()
|
." ".verilator_bin()
|
||||||
# Note, uncomment to set breakpoints before running:
|
# Note, uncomment to set breakpoints before running:
|
||||||
# ." -ex 'break main'"
|
# ." -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
|
--top-module <topname> Name of top level input module
|
||||||
--trace Enable waveform creation
|
--trace Enable waveform creation
|
||||||
--trace-fst Enable FST waveform creation
|
--trace-fst Enable FST waveform creation
|
||||||
|
--trace-fst-thread Enable FST threaded waveform creation
|
||||||
--trace-depth <levels> Depth of tracing
|
--trace-depth <levels> Depth of tracing
|
||||||
--trace-max-array <depth> Maximum bit width for tracing
|
--trace-max-array <depth> Maximum bit width for tracing
|
||||||
--trace-max-width <width> Maximum array depth for tracing
|
--trace-max-width <width> Maximum array depth for tracing
|
||||||
@@ -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+file+I<filename> Set profile filename
|
||||||
+verilator+prof+threads+start+I<value> Set profile starting point
|
+verilator+prof+threads+start+I<value> Set profile starting point
|
||||||
+verilator+prof+threads+window+I<value> Set profile duration
|
+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+V Verbose version and config
|
||||||
+verilator+version Show version and exit
|
+verilator+version Show version and exit
|
||||||
|
|
||||||
@@ -1290,7 +1292,14 @@ even when waveforms are not turned on during model execution.
|
|||||||
|
|
||||||
=item --trace-fst
|
=item --trace-fst
|
||||||
|
|
||||||
Enable FST waveform tracing in the model. This overrides C<--trace>.
|
Enable FST waveform tracing in the model. This overrides C<--trace> and
|
||||||
|
C<--trace-fst-thread>. See also C<--trace-fst-thread>.
|
||||||
|
|
||||||
|
=item --trace-fst-thread
|
||||||
|
|
||||||
|
Enable FST waveform tracing in the model, using a separate thread. This is
|
||||||
|
typically faster in runtime but slower in total computes than
|
||||||
|
C<--trace-fst>. This overrides C<--trace> and C<--trace-fst>.
|
||||||
|
|
||||||
=item --trace-depth I<levels>
|
=item --trace-depth I<levels>
|
||||||
|
|
||||||
@@ -1455,10 +1464,10 @@ Enable all code style related warning messages. This is equivalent to
|
|||||||
=item --x-assign unique
|
=item --x-assign unique
|
||||||
|
|
||||||
Controls the two-state value that is replaced when an assignment to X is
|
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
|
encountered. C<--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.
|
best for performance. C<--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
|
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. --x-assign=unique
|
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
|
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
|
all Xs to find reset bugs and is the slowest, but safest for finding reset
|
||||||
bugs in code.
|
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
|
Controls the two-state value that is used to initialize variables that are
|
||||||
not otherwise initialized.
|
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
|
which determines the value to use each initialization. This gives greatest
|
||||||
flexibility and allows finding reset bugs. See L</"Unknown states">.
|
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
|
a state Verilator determines is optimal. This may allow further code
|
||||||
optimizations, but will likely hide any code bugs relating to missing
|
optimizations, but will likely hide any code bugs relating to missing
|
||||||
resets.
|
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 =
|
initialization technique. 0 = Reset to zeros. 1 = Reset to all-ones. 2 =
|
||||||
Randomize. See L</"Unknown states">.
|
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
|
=item +verilator+V
|
||||||
|
|
||||||
Shows the verbose version, including configuration information.
|
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"
|
#include "Vour.h"
|
||||||
int sc_main(int argc, char **argv) {
|
int sc_main(int argc, char **argv) {
|
||||||
Verilated::commandArgs(argc, argv);
|
Verilated::commandArgs(argc, argv);
|
||||||
sc_clock clk ("clk",10, 0.5, 3, true);
|
sc_clock clk ("clk", 10, 0.5, 3, true);
|
||||||
Vour* top;
|
Vour* top;
|
||||||
top = new Vour("top");
|
top = new Vour("top");
|
||||||
top->clk(clk);
|
top->clk(clk);
|
||||||
@@ -1759,8 +1773,8 @@ the examples directory in the distribution.
|
|||||||
=head1 BENCHMARKING & OPTIMIZATION
|
=head1 BENCHMARKING & OPTIMIZATION
|
||||||
|
|
||||||
For best performance, run Verilator with the "-O3 --x-assign=fast
|
For best performance, run Verilator with the "-O3 --x-assign=fast
|
||||||
--x-initial=fast --noassert" flags. The -O3 flag will require longer
|
--x-initial fast --noassert" flags. The -O3 flag will require longer
|
||||||
compile times, and --x-assign=fast --x-initial=fast may increase the risk
|
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
|
of reset bugs in trade for performance; see the above documentation for
|
||||||
these flags.
|
these flags.
|
||||||
|
|
||||||
@@ -2068,7 +2082,7 @@ command line, or the link), you'd then:
|
|||||||
|
|
||||||
#include "svdpi.h"
|
#include "svdpi.h"
|
||||||
#include "Vour__Dpi.h"
|
#include "Vour__Dpi.h"
|
||||||
int add (int a, int b) { return a+b; }
|
int add(int a, int b) { return a+b; }
|
||||||
|
|
||||||
=head2 DPI System Task/Functions
|
=head2 DPI System Task/Functions
|
||||||
|
|
||||||
@@ -2118,7 +2132,7 @@ respect to that top level module, then the scope could be set with
|
|||||||
|
|
||||||
#include "svdpi.h"
|
#include "svdpi.h"
|
||||||
...
|
...
|
||||||
svSetScope (svGetScopeFromName ("dut"));
|
svSetScope(svGetScopeFromName("dut"));
|
||||||
|
|
||||||
(Remember that Verilator adds a "V" to the top of the module hierarchy.)
|
(Remember that Verilator adds a "V" to the top of the module hierarchy.)
|
||||||
|
|
||||||
@@ -2132,7 +2146,7 @@ comments within the svdpi.h header for more information.
|
|||||||
Verilator allows writing $display like functions using this syntax:
|
Verilator allows writing $display like functions using this syntax:
|
||||||
|
|
||||||
import "DPI-C" function void
|
import "DPI-C" function void
|
||||||
\$my_display (input string formatted /*verilator sformat*/ );
|
\$my_display(input string formatted /*verilator sformat*/ );
|
||||||
|
|
||||||
The /*verilator sformat*/ indicates that this function accepts a $display
|
The /*verilator sformat*/ indicates that this function accepts a $display
|
||||||
like format specifier followed by any number of arguments to satisfy the
|
like format specifier followed by any number of arguments to satisfy the
|
||||||
@@ -2240,7 +2254,7 @@ accesses the above signal "readme" would be:
|
|||||||
#include "verilated_vpi.h" // Required to get definitions
|
#include "verilated_vpi.h" // Required to get definitions
|
||||||
|
|
||||||
vluint64_t main_time = 0; // See comments in first example
|
vluint64_t main_time = 0; // See comments in first example
|
||||||
double sc_time_stamp () { return main_time; }
|
double sc_time_stamp() { return main_time; }
|
||||||
|
|
||||||
void read_and_check() {
|
void read_and_check() {
|
||||||
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"TOP.our.readme", NULL);
|
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"TOP.our.readme", NULL);
|
||||||
@@ -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
|
performance to be far worse than it would be with proper stoichiometry of
|
||||||
threads and CPU cores.
|
threads and CPU cores.
|
||||||
|
|
||||||
|
With --trace-fst-thread, tracing occurs in a separate thread from the main
|
||||||
|
simulation thread(s). This option is orthogonal to --threads.
|
||||||
|
|
||||||
The remainder of this section describe behavior with --threads 1 or
|
The remainder of this section describe behavior with --threads 1 or
|
||||||
--threads N (not --no-threads).
|
--threads N (not --no-threads).
|
||||||
|
|
||||||
@@ -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.
|
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
|
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
|
value (see the --x-assign switch and +verilator+rand+reset runtime switch.)
|
||||||
random value should cause downstream errors. Integers also randomize, even
|
Thus if the value is actually used, the random value should cause
|
||||||
though the Verilog 2001 specification says they initialize to zero.
|
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
|
All variables, depending on --x-initial setting, are typically randomly
|
||||||
initialized using a function. By running several random simulation runs
|
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)
|
always @ (posedge clk)
|
||||||
if (~reset_l) begin
|
if (~reset_l) begin
|
||||||
for (i=0; i<`ARRAY_SIZE; i++) begin
|
for (i=0; i<`ARRAY_SIZE; i++) begin
|
||||||
array[i] = 0; // Non-delayed for verilator
|
array[i] = 0; // Non-delayed for verilator
|
||||||
end
|
end
|
||||||
|
|
||||||
This message is only seen on large or complicated loops because Verilator
|
This message is only seen on large or complicated loops because Verilator
|
||||||
@@ -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
|
Disabled by default as this is a code style warning; it will simulate
|
||||||
correctly.
|
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
|
=item IMPERFECTSCH
|
||||||
|
|
||||||
Warns that the scheduling of the model is not absolutely perfect, and some
|
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
|
synthesis which analyzes interconnection per-bit, but is circular to
|
||||||
simulation which analyzes per-bus:
|
simulation which analyzes per-bus:
|
||||||
|
|
||||||
wire [2:0] x = {x[1:0],shift_in};
|
wire [2:0] x = {x[1:0], shift_in};
|
||||||
|
|
||||||
This statement needs to be evaluated multiple times, as a change in
|
This statement needs to be evaluated multiple times, as a change in
|
||||||
"shift_in" requires "x" to be computed 3 times before it becomes stable.
|
"shift_in" requires "x" to be computed 3 times before it becomes stable.
|
||||||
@@ -3872,12 +3903,12 @@ causes the warning.
|
|||||||
|
|
||||||
For significantly better performance, split this into 2 separate signals:
|
For significantly better performance, split this into 2 separate signals:
|
||||||
|
|
||||||
wire [2:0] xout = {x[1:0],shift_in};
|
wire [2:0] xout = {x[1:0], shift_in};
|
||||||
|
|
||||||
and change all receiving logic to instead receive "xout". Alternatively,
|
and change all receiving logic to instead receive "xout". Alternatively,
|
||||||
change it to
|
change it to
|
||||||
|
|
||||||
wire [2:0] x = {xin[1:0],shift_in};
|
wire [2:0] x = {xin[1:0], shift_in};
|
||||||
|
|
||||||
and change all driving logic to instead drive "xin".
|
and change all driving logic to instead drive "xin".
|
||||||
|
|
||||||
@@ -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:
|
The best fix, which clarifies intent and will also make all tools happy is:
|
||||||
|
|
||||||
wire [5:0] plus_one = from[5:0] + 6'd1 + {5'd0,carry[0]};
|
wire [5:0] plus_one = from[5:0] + 6'd1 + {5'd0, carry[0]};
|
||||||
|
|
||||||
Ignoring this warning will only suppress the lint check, it will simulate
|
Ignoring this warning will only suppress the lint check, it will simulate
|
||||||
correctly.
|
correctly.
|
||||||
@@ -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
|
that widths inside concatenates and replicates must be sized, and should be
|
||||||
fixed in the code.
|
fixed in the code.
|
||||||
|
|
||||||
wire [63:0] concat = {1,2};
|
wire [63:0] concat = {1, 2};
|
||||||
|
|
||||||
An example where this is technically legal (though still bad form) is:
|
An example where this is technically legal (though still bad form) is:
|
||||||
|
|
||||||
parameter PAR = 1;
|
parameter PAR = 1;
|
||||||
wire [63:0] concat = {PAR,PAR};
|
wire [63:0] concat = {PAR, PAR};
|
||||||
|
|
||||||
The correct fix is to either size the 1 ("32'h1"), or add the width to the
|
The correct fix is to either size the 1 ("32'h1"), or add the width to the
|
||||||
parameter definition ("parameter [31:0]"), or add the width to the
|
parameter definition ("parameter [31:0]"), or add the width to the
|
||||||
@@ -4213,7 +4244,8 @@ trace file if you want all data to land in the same output file.
|
|||||||
|
|
||||||
FST a format by GTKWave.
|
FST a format by GTKWave.
|
||||||
This version provides a basic FST support.
|
This version provides a basic FST support.
|
||||||
To dump FST format, add the --trace switch to Verilator and change the include path in the testbench to:
|
To dump FST format, add the --trace-fst switch to Verilator and change the include
|
||||||
|
path in the testbench to:
|
||||||
|
|
||||||
#include "verilated_fst_c.h"
|
#include "verilated_fst_c.h"
|
||||||
VerilatedFstC* tfp = new VerilatedFstC;
|
VerilatedFstC* tfp = new VerilatedFstC;
|
||||||
|
|||||||
+38
-38
@@ -19,8 +19,8 @@ require 5.006_001;
|
|||||||
use warnings;
|
use warnings;
|
||||||
BEGIN {
|
BEGIN {
|
||||||
if ($ENV{DIRPROJECT} && $ENV{DIRPROJECT_PERL_BOOT}) {
|
if ($ENV{DIRPROJECT} && $ENV{DIRPROJECT_PERL_BOOT}) {
|
||||||
# Magic to allow author testing of perl packages in local directory
|
# Magic to allow author testing of perl packages in local directory
|
||||||
require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
|
require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,12 +56,12 @@ foreach my $sw (@ARGV) {
|
|||||||
|
|
||||||
Getopt::Long::config("no_auto_abbrev","pass_through");
|
Getopt::Long::config("no_auto_abbrev","pass_through");
|
||||||
if (! GetOptions (
|
if (! GetOptions (
|
||||||
# Major operating modes
|
# Major operating modes
|
||||||
"help" => \&usage,
|
"help" => \&usage,
|
||||||
"debug:s" => \&debug,
|
"debug:s" => \&debug,
|
||||||
# "version!" => \&version, # Also passthru'ed
|
# "version!" => \&version, # Also passthru'ed
|
||||||
# Additional parameters
|
# Additional parameters
|
||||||
"<>" => sub {}, # Ignored
|
"<>" => sub {}, # Ignored
|
||||||
)) {
|
)) {
|
||||||
pod2usage(-exitstatus=>2, -verbose=>0);
|
pod2usage(-exitstatus=>2, -verbose=>0);
|
||||||
}
|
}
|
||||||
@@ -90,25 +90,25 @@ sub verilator_coverage_bin {
|
|||||||
my $bin = "";
|
my $bin = "";
|
||||||
# Use VERILATOR_ROOT if defined, else assume verilator_bin is in the search path
|
# Use VERILATOR_ROOT if defined, else assume verilator_bin is in the search path
|
||||||
my $basename = ($ENV{VERILATOR_COVERAGE_BIN}
|
my $basename = ($ENV{VERILATOR_COVERAGE_BIN}
|
||||||
|| "verilator_coverage_bin_dbg");
|
|| "verilator_coverage_bin_dbg");
|
||||||
if (defined($ENV{VERILATOR_ROOT})) {
|
if (defined($ENV{VERILATOR_ROOT})) {
|
||||||
my $dir = $ENV{VERILATOR_ROOT};
|
my $dir = $ENV{VERILATOR_ROOT};
|
||||||
if (-x "$dir/bin/$basename"
|
if (-x "$dir/bin/$basename"
|
||||||
|| -x "$dir/bin/$basename.exe") { # From a "make install" into VERILATOR_ROOT
|
|| -x "$dir/bin/$basename.exe") { # From a "make install" into VERILATOR_ROOT
|
||||||
$bin = "$dir/bin/$basename";
|
$bin = "$dir/bin/$basename";
|
||||||
} else {
|
} else {
|
||||||
$bin = "$dir/$basename"; # From pointing to kit directory
|
$bin = "$dir/$basename"; # From pointing to kit directory
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (-x "$RealBin/$basename"
|
if (-x "$RealBin/$basename"
|
||||||
|| -x "$RealBin/$basename.exe") {
|
|| -x "$RealBin/$basename.exe") {
|
||||||
$bin = "$RealBin/$basename"; # From path/to/verilator with verilator_bin installed
|
$bin = "$RealBin/$basename"; # From path/to/verilator with verilator_bin installed
|
||||||
} else {
|
} else {
|
||||||
$bin = $basename; # Find in PATH
|
$bin = $basename; # Find in PATH
|
||||||
}
|
}
|
||||||
# Note we don't look under bin/$basename which would be right if running
|
# Note we don't look under bin/$basename which would be right if running
|
||||||
# in the kit dir. Running that would likely break, since
|
# in the kit dir. Running that would likely break, since
|
||||||
# VERILATOR_ROOT wouldn't be set and Verilator won't find internal files.
|
# VERILATOR_ROOT wouldn't be set and Verilator won't find internal files.
|
||||||
}
|
}
|
||||||
return $bin;
|
return $bin;
|
||||||
}
|
}
|
||||||
@@ -125,23 +125,23 @@ sub run {
|
|||||||
system($command);
|
system($command);
|
||||||
my $status = $?;
|
my $status = $?;
|
||||||
if ($status) {
|
if ($status) {
|
||||||
if ($! =~ /no such file or directory/i) {
|
if ($! =~ /no such file or directory/i) {
|
||||||
warn "%Error: verilator_coverage: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
|
warn "%Error: verilator_coverage: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
|
||||||
}
|
}
|
||||||
if ($Debug) { # For easy rerunning
|
if ($Debug) { # For easy rerunning
|
||||||
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
|
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
|
||||||
warn "%Error: $command\n";
|
warn "%Error: $command\n";
|
||||||
}
|
}
|
||||||
if ($status & 127) {
|
if ($status & 127) {
|
||||||
if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
|
if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
|
||||||
warn "%Error: Verilator_coverage internal fault, sorry.\n" if !$Debug;
|
warn "%Error: Verilator_coverage internal fault, sorry.\n" if !$Debug;
|
||||||
} elsif (($status & 127) == 6) { # SIGABRT
|
} elsif (($status & 127) == 6) { # SIGABRT
|
||||||
warn "%Error: Verilator_coverage aborted.\n" if !$Debug;
|
warn "%Error: Verilator_coverage aborted.\n" if !$Debug;
|
||||||
} else {
|
} else {
|
||||||
warn "%Error: Verilator_coverage threw signal $status.\n" if !$Debug;
|
warn "%Error: Verilator_coverage threw signal $status.\n" if !$Debug;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
die "%Error: Command Failed $command\n";
|
die "%Error: Command Failed $command\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+52
-52
@@ -38,11 +38,11 @@ my $Opt_Lineno = 1;
|
|||||||
autoflush STDOUT 1;
|
autoflush STDOUT 1;
|
||||||
autoflush STDERR 1;
|
autoflush STDERR 1;
|
||||||
Getopt::Long::config("no_auto_abbrev");
|
Getopt::Long::config("no_auto_abbrev");
|
||||||
if (! GetOptions (
|
if (! GetOptions(
|
||||||
"help" => \&usage,
|
"help" => \&usage,
|
||||||
"debug" => \&debug,
|
"debug" => \&debug,
|
||||||
"<>" => \¶meter,
|
"<>" => \¶meter,
|
||||||
"lineno!" => \$Opt_Lineno,
|
"lineno!" => \$Opt_Lineno,
|
||||||
)) {
|
)) {
|
||||||
die "%Error: Bad usage, try 'verilator_difftree --help'\n";
|
die "%Error: Bad usage, try 'verilator_difftree --help'\n";
|
||||||
}
|
}
|
||||||
@@ -68,22 +68,22 @@ sub diff_dir {
|
|||||||
my %files;
|
my %files;
|
||||||
|
|
||||||
foreach my $fn (glob("$a/*.tree")) {
|
foreach my $fn (glob("$a/*.tree")) {
|
||||||
(my $base = $fn) =~ s!.*/!!;
|
(my $base = $fn) =~ s!.*/!!;
|
||||||
$files{$base}{a} = $fn;
|
$files{$base}{a} = $fn;
|
||||||
}
|
}
|
||||||
foreach my $fn (glob("$b/*.tree")) {
|
foreach my $fn (glob("$b/*.tree")) {
|
||||||
(my $base = $fn) =~ s!.*/!!;
|
(my $base = $fn) =~ s!.*/!!;
|
||||||
$files{$base}{b} = $fn;
|
$files{$base}{b} = $fn;
|
||||||
}
|
}
|
||||||
my $any;
|
my $any;
|
||||||
foreach my $base (sort (keys %files)) {
|
foreach my $base (sort (keys %files)) {
|
||||||
my $a = $files{$base}{a};
|
my $a = $files{$base}{a};
|
||||||
my $b = $files{$base}{b};
|
my $b = $files{$base}{b};
|
||||||
next if !$a || !$b;
|
next if !$a || !$b;
|
||||||
print "="x70,"\n";
|
print "="x70,"\n";
|
||||||
print "= $a <-> $b\n";
|
print "= $a <-> $b\n";
|
||||||
diff_file($a,$b);
|
diff_file($a,$b);
|
||||||
$any = 1;
|
$any = 1;
|
||||||
}
|
}
|
||||||
$any or warn("%Warning: No .tree files found that have similar base names:\n "
|
$any or warn("%Warning: No .tree files found that have similar base names:\n "
|
||||||
.join("\n ", sort keys %files),"\n");
|
.join("\n ", sort keys %files),"\n");
|
||||||
@@ -101,7 +101,7 @@ sub diff_file {
|
|||||||
my $vera = version_from($a);
|
my $vera = version_from($a);
|
||||||
my $verb = version_from($b);
|
my $verb = version_from($b);
|
||||||
my $verCvt = (($vera < 0x3900 && $verb >= 0x3900)
|
my $verCvt = (($vera < 0x3900 && $verb >= 0x3900)
|
||||||
|| ($vera >= 0x3900 && $verb < 0x3900));
|
|| ($vera >= 0x3900 && $verb < 0x3900));
|
||||||
|
|
||||||
filter($a, $tmp_a, $verCvt);
|
filter($a, $tmp_a, $verCvt);
|
||||||
filter($b, $tmp_b, $verCvt);
|
filter($b, $tmp_b, $verCvt);
|
||||||
@@ -115,8 +115,8 @@ sub version_from {
|
|||||||
# Return dump format
|
# Return dump format
|
||||||
my $f1 = IO::File->new ($fn) or die "%Error: $! $fn,";
|
my $f1 = IO::File->new ($fn) or die "%Error: $! $fn,";
|
||||||
while (defined (my $line=$f1->getline())) {
|
while (defined (my $line=$f1->getline())) {
|
||||||
last if $. > 10;
|
last if $. > 10;
|
||||||
return hex $1 if $line =~ /\(format (0x[0-9.]+)\)/;
|
return hex $1 if $line =~ /\(format (0x[0-9.]+)\)/;
|
||||||
}
|
}
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
@@ -130,36 +130,36 @@ sub filter {
|
|||||||
my $f2 = IO::File->new ($fn2,"w") or die "%Error: $! $fn2,";
|
my $f2 = IO::File->new ($fn2,"w") or die "%Error: $! $fn2,";
|
||||||
while (defined (my $line=$f1->getline())) {
|
while (defined (my $line=$f1->getline())) {
|
||||||
same_line:
|
same_line:
|
||||||
next if $line =~ / This=/;
|
next if $line =~ / This=/;
|
||||||
$line =~ s/0x[a-f0-9]+/0x/g;
|
$line =~ s/0x[a-f0-9]+/0x/g;
|
||||||
$line =~ s/<e[0-9]+\#?>/<e>/g;
|
$line =~ s/<e[0-9]+\#?>/<e>/g;
|
||||||
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
|
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
|
||||||
if ($verCvt) {
|
if ($verCvt) {
|
||||||
next if $line =~ /^ NETLIST/;
|
next if $line =~ /^ NETLIST/;
|
||||||
$line =~ s!\@dt=0x\(G?/?([^)]+)\)!$1!g; # NEW: @dt -> OLD: non @dt format
|
$line =~ s!\@dt=0x\(G?/?([^)]+)\)!$1!g; # NEW: @dt -> OLD: non @dt format
|
||||||
# # Below Ver1_Non_Dtyped may replace above further
|
# # Below Ver1_Non_Dtyped may replace above further
|
||||||
if ($line =~ /: ([A-Z]+) /) {
|
if ($line =~ /: ([A-Z]+) /) {
|
||||||
my $type = $1;
|
my $type = $1;
|
||||||
next if $type =~ 'DTYPE';
|
next if $type =~ 'DTYPE';
|
||||||
if ($type eq 'TYPETABLE' || $type eq 'RANGE') {
|
if ($type eq 'TYPETABLE' || $type eq 'RANGE') {
|
||||||
$line =~ /^(\s+\S+:) /; my $prefix = $1;
|
$line =~ /^(\s+\S+:) /; my $prefix = $1;
|
||||||
while (defined ($line=$f1->getline())) {
|
while (defined ($line=$f1->getline())) {
|
||||||
next if $line =~ /^\s+[a-z]/; # Table body
|
next if $line =~ /^\s+[a-z]/; # Table body
|
||||||
next if $line =~ /^${prefix}[0-9]:/;
|
next if $line =~ /^${prefix}[0-9]:/;
|
||||||
goto same_line;
|
goto same_line;
|
||||||
}
|
}
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
if ($Ver1_Non_Dtyped{$type}) {
|
if ($Ver1_Non_Dtyped{$type}) {
|
||||||
$line =~ s! w[0-9]+!!g;
|
$line =~ s! w[0-9]+!!g;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$line =~ s!\@dt=0$!NoW!g; # NEW: dt=null -> common format
|
$line =~ s!\@dt=0$!NoW!g; # NEW: dt=null -> common format
|
||||||
$line =~ s!\@dt=0 !NoW !g; # NEW: dt=null -> common format
|
$line =~ s!\@dt=0 !NoW !g; # NEW: dt=null -> common format
|
||||||
$line =~ s! s?w0$! NoW!g; # OLD: no width -> common format
|
$line =~ s! s?w0$! NoW!g; # OLD: no width -> common format
|
||||||
$line =~ s! s?w0 ! NoW !g; # OLD: no width -> common format
|
$line =~ s! s?w0 ! NoW !g; # OLD: no width -> common format
|
||||||
}
|
}
|
||||||
print $f2 $line;
|
print $f2 $line;
|
||||||
}
|
}
|
||||||
$f1->close;
|
$f1->close;
|
||||||
$f2->close;
|
$f2->close;
|
||||||
@@ -179,11 +179,11 @@ sub debug {
|
|||||||
sub parameter {
|
sub parameter {
|
||||||
my $param = shift;
|
my $param = shift;
|
||||||
if (!defined $Opt_A) {
|
if (!defined $Opt_A) {
|
||||||
$Opt_A = $param;
|
$Opt_A = $param;
|
||||||
} elsif (!defined $Opt_B) {
|
} elsif (!defined $Opt_B) {
|
||||||
$Opt_B = $param;
|
$Opt_B = $param;
|
||||||
} else {
|
} else {
|
||||||
die "%Error: Unknown parameter: $param\n";
|
die "%Error: Unknown parameter: $param\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+84
-84
@@ -24,11 +24,11 @@ my $Opt_File;
|
|||||||
autoflush STDOUT 1;
|
autoflush STDOUT 1;
|
||||||
autoflush STDERR 1;
|
autoflush STDERR 1;
|
||||||
Getopt::Long::config("no_auto_abbrev");
|
Getopt::Long::config("no_auto_abbrev");
|
||||||
if (! GetOptions (
|
if (! GetOptions(
|
||||||
"help" => \&usage,
|
"help" => \&usage,
|
||||||
"debug" => \&debug,
|
"debug" => \&debug,
|
||||||
"<>" => \¶meter,
|
"<>" => \¶meter,
|
||||||
)) {
|
)) {
|
||||||
die "%Error: Bad usage, try 'verilator_profcfunc --help'\n";
|
die "%Error: Bad usage, try 'verilator_profcfunc --help'\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,9 +50,9 @@ sub debug {
|
|||||||
sub parameter {
|
sub parameter {
|
||||||
my $param = shift;
|
my $param = shift;
|
||||||
if (!defined $Opt_File) {
|
if (!defined $Opt_File) {
|
||||||
$Opt_File = $param;
|
$Opt_File = $param;
|
||||||
} else {
|
} else {
|
||||||
die "%Error: Unknown parameter: $param\n";
|
die "%Error: Unknown parameter: $param\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,13 +66,13 @@ sub profcfunc {
|
|||||||
my %funcs;
|
my %funcs;
|
||||||
|
|
||||||
while (defined (my $line=$fh->getline())) {
|
while (defined (my $line=$fh->getline())) {
|
||||||
# %time cumesec selfsec calls {stuff} name
|
# %time cumesec selfsec calls {stuff} name
|
||||||
if ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
|
if ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
|
||||||
my $pct=$1; my $sec=$2; my $calls=$3; my $func=$4;
|
my $pct=$1; my $sec=$2; my $calls=$3; my $func=$4;
|
||||||
$funcs{$func}{pct} += $pct;
|
$funcs{$func}{pct} += $pct;
|
||||||
$funcs{$func}{sec} += $sec;
|
$funcs{$func}{sec} += $sec;
|
||||||
$funcs{$func}{calls} += $calls;
|
$funcs{$func}{calls} += $calls;
|
||||||
}
|
}
|
||||||
# Older gprofs have no call column for single-call functions
|
# Older gprofs have no call column for single-call functions
|
||||||
# %time cumesec selfsec {stuff} name
|
# %time cumesec selfsec {stuff} name
|
||||||
elsif ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
|
elsif ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
|
||||||
@@ -88,10 +88,10 @@ sub profcfunc {
|
|||||||
my %pointer_mods;
|
my %pointer_mods;
|
||||||
my %verilated_mods;
|
my %verilated_mods;
|
||||||
foreach my $func (keys %funcs) {
|
foreach my $func (keys %funcs) {
|
||||||
if ($func =~ /(.*)::_eval\(([a-zA-Z_0-9]+__Syms).*\)$/) {
|
if ($func =~ /(.*)::_eval\(([a-zA-Z_0-9]+__Syms).*\)$/) {
|
||||||
$verilated_mods{$1} = qr/^$1/;
|
$verilated_mods{$1} = qr/^$1/;
|
||||||
$pointer_mods{$2} = $1;
|
$pointer_mods{$2} = $1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#print Dumper(\%pointer_mods, \%verilated_mods);
|
#print Dumper(\%pointer_mods, \%verilated_mods);
|
||||||
|
|
||||||
@@ -99,72 +99,72 @@ sub profcfunc {
|
|||||||
my %vfuncs;
|
my %vfuncs;
|
||||||
my %groups;
|
my %groups;
|
||||||
foreach my $func (keys %funcs) {
|
foreach my $func (keys %funcs) {
|
||||||
my $pct = $funcs{$func}{pct};
|
my $pct = $funcs{$func}{pct};
|
||||||
my $vfunc = $func;
|
my $vfunc = $func;
|
||||||
my $design;
|
my $design;
|
||||||
|
|
||||||
if ($func =~ /\(([a-zA-Z_0-9]+__Syms)/) {
|
if ($func =~ /\(([a-zA-Z_0-9]+__Syms)/) {
|
||||||
$design = $pointer_mods{$1};
|
$design = $pointer_mods{$1};
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $vde (keys %verilated_mods) {
|
foreach my $vde (keys %verilated_mods) {
|
||||||
last if $design;
|
last if $design;
|
||||||
if ($func =~ /$verilated_mods{$vde}/) {
|
if ($func =~ /$verilated_mods{$vde}/) {
|
||||||
$design=$vde;
|
$design=$vde;
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($vfunc =~ /__PROF__([a-zA-Z_0-9]+)__l?([0-9]+)\(/) {
|
if ($vfunc =~ /__PROF__([a-zA-Z_0-9]+)__l?([0-9]+)\(/) {
|
||||||
$vfunc = sprintf("VBlock %s:%d", $1, $2);
|
$vfunc = sprintf("VBlock %s:%d", $1, $2);
|
||||||
$groups{type}{"Verilog Blocks under $design"} += $pct;
|
$groups{type}{"Verilog Blocks under $design"} += $pct;
|
||||||
$groups{design}{$design} += $pct;
|
$groups{design}{$design} += $pct;
|
||||||
$groups{module}{$1} += $pct;
|
$groups{module}{$1} += $pct;
|
||||||
} else {
|
} else {
|
||||||
if ($design) {
|
if ($design) {
|
||||||
$vfunc = sprintf("VCommon %s", $func);
|
$vfunc = sprintf("VCommon %s", $func);
|
||||||
$groups{type}{"Common code under $design"} += $pct;
|
$groups{type}{"Common code under $design"} += $pct;
|
||||||
$groups{design}{$design} += $pct;
|
$groups{design}{$design} += $pct;
|
||||||
$groups{module}{$design." common code"} += $pct;
|
$groups{module}{$design." common code"} += $pct;
|
||||||
} elsif ($func =~ /^VL_[A-Z0-9_]+/
|
} elsif ($func =~ /^VL_[A-Z0-9_]+/
|
||||||
|| $func =~ /^_?vl_[a-zA-Z0-9_]+/
|
|| $func =~ /^_?vl_[a-zA-Z0-9_]+/
|
||||||
|| $func =~ /^verilated/i) {
|
|| $func =~ /^verilated/i) {
|
||||||
$vfunc = sprintf("VLib %s", $func);
|
$vfunc = sprintf("VLib %s", $func);
|
||||||
$groups{type}{'VLib'} += $pct;
|
$groups{type}{'VLib'} += $pct;
|
||||||
$groups{design}{'VLib'} += $pct;
|
$groups{design}{'VLib'} += $pct;
|
||||||
$groups{module}{'VLib'} += $pct;
|
$groups{module}{'VLib'} += $pct;
|
||||||
} elsif ($func =~ /^_mcount_private/) {
|
} elsif ($func =~ /^_mcount_private/) {
|
||||||
$vfunc = sprintf("Prof %s", $func);
|
$vfunc = sprintf("Prof %s", $func);
|
||||||
$groups{type}{'Prof'} += $pct;
|
$groups{type}{'Prof'} += $pct;
|
||||||
$groups{design}{'Prof'} += $pct;
|
$groups{design}{'Prof'} += $pct;
|
||||||
$groups{module}{'Prof'} += $pct;
|
$groups{module}{'Prof'} += $pct;
|
||||||
} else {
|
} else {
|
||||||
$vfunc = sprintf("C++ %s", $func);
|
$vfunc = sprintf("C++ %s", $func);
|
||||||
$groups{type}{'C++'} += $pct;
|
$groups{type}{'C++'} += $pct;
|
||||||
$groups{design}{'C++'} += $pct;
|
$groups{design}{'C++'} += $pct;
|
||||||
$groups{module}{'C++'} += $pct;
|
$groups{module}{'C++'} += $pct;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$vfuncs{$vfunc} = $funcs{$func};
|
$vfuncs{$vfunc} = $funcs{$func};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach my $type (qw(type design module)) {
|
foreach my $type (qw(type design module)) {
|
||||||
my $missing = 100;
|
my $missing = 100;
|
||||||
foreach (sort (keys %{$groups{$type}})) {
|
foreach (sort (keys %{$groups{$type}})) {
|
||||||
$missing -= $groups{$type}{$_};
|
$missing -= $groups{$type}{$_};
|
||||||
}
|
}
|
||||||
if ($missing) {
|
if ($missing) {
|
||||||
$groups{$type}{"\377Unaccounted for/rounding error"} = $missing;
|
$groups{$type}{"\377Unaccounted for/rounding error"} = $missing;
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Overall summary by $type:\n");
|
print("Overall summary by $type:\n");
|
||||||
printf(" %-6s %s\n","% time",$type);
|
printf(" %-6s %s\n","% time",$type);
|
||||||
foreach my $what (sort (keys %{$groups{$type}})) {
|
foreach my $what (sort (keys %{$groups{$type}})) {
|
||||||
(my $pwhat = $what) =~ s/^\377//; # Just used to establish sort order
|
(my $pwhat = $what) =~ s/^\377//; # Just used to establish sort order
|
||||||
printf(" %6.2f %s\n", $groups{$type}{$what}, $pwhat);
|
printf(" %6.2f %s\n", $groups{$type}{$what}, $pwhat);
|
||||||
}
|
}
|
||||||
print("\n");
|
print("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Verilog code profile:\n");
|
print("Verilog code profile:\n");
|
||||||
@@ -181,14 +181,14 @@ sub profcfunc {
|
|||||||
|
|
||||||
my $cume = 0;
|
my $cume = 0;
|
||||||
foreach my $func (sort {$vfuncs{$b}{sec} <=> $vfuncs{$a}{sec}
|
foreach my $func (sort {$vfuncs{$b}{sec} <=> $vfuncs{$a}{sec}
|
||||||
|| $a cmp $b}
|
|| $a cmp $b}
|
||||||
(keys %vfuncs)) {
|
(keys %vfuncs)) {
|
||||||
$cume += $vfuncs{$func}{sec};
|
$cume += $vfuncs{$func}{sec};
|
||||||
printf +("%6.2f %9.2f %8.2f %8d %s\n",
|
printf +("%6.2f %9.2f %8.2f %8d %s\n",
|
||||||
$vfuncs{$func}{pct},
|
$vfuncs{$func}{pct},
|
||||||
$cume, $vfuncs{$func}{sec},
|
$cume, $vfuncs{$func}{sec},
|
||||||
$vfuncs{$func}{calls},
|
$vfuncs{$func}{calls},
|
||||||
$func);
|
$func);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||||
#AC_INIT([Verilator],[#.### devel])
|
#AC_INIT([Verilator],[#.### devel])
|
||||||
AC_INIT([Verilator],[4.010 2019-01-27],
|
AC_INIT([Verilator],[4.014 2019-05-08],
|
||||||
[https://www.veripool.org/verilator],
|
[https://www.veripool.org/verilator],
|
||||||
[verilator],[https://www.veripool.org/verilator])
|
[verilator],[https://www.veripool.org/verilator])
|
||||||
# When releasing, also update header of Changes file
|
# When releasing, also update header of Changes file
|
||||||
|
|||||||
@@ -27,17 +27,21 @@ int main(int argc, char** argv, char** env) {
|
|||||||
|
|
||||||
// Prevent unused variable warnings
|
// Prevent unused variable warnings
|
||||||
if (0 && argc && argv && env) {}
|
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
|
// Set debug level, 0 is off, 9 is highest presently used
|
||||||
|
// May be overridden by commandArgs
|
||||||
Verilated::debug(0);
|
Verilated::debug(0);
|
||||||
|
|
||||||
// Randomization reset policy
|
// Randomization reset policy
|
||||||
|
// May be overridden by commandArgs
|
||||||
Verilated::randReset(2);
|
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"
|
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
||||||
Vtop* top = new Vtop; // Or use a const unique_ptr, or the VL_UNIQUE_PTR wrapper
|
Vtop* top = new Vtop; // Or use a const unique_ptr, or the VL_UNIQUE_PTR wrapper
|
||||||
|
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
// If verilator was invoked with --trace argument,
|
// If verilator was invoked with --trace argument,
|
||||||
@@ -90,14 +94,14 @@ int main(int argc, char** argv, char** env) {
|
|||||||
|
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
// Dump trace data for this cycle
|
// Dump trace data for this cycle
|
||||||
if (tfp) tfp->dump (main_time);
|
if (tfp) tfp->dump(main_time);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Read outputs
|
// Read outputs
|
||||||
VL_PRINTF ("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
|
VL_PRINTF("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
|
||||||
" -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n",
|
" -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n",
|
||||||
main_time, top->clk, top->reset_l, top->in_quad,
|
main_time, top->clk, top->reset_l, top->in_quad,
|
||||||
top->out_quad, top->out_wide[2], top->out_wide[1], top->out_wide[0]);
|
top->out_quad, top->out_wide[2], top->out_wide[1], top->out_wide[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final model cleanup
|
// Final model cleanup
|
||||||
|
|||||||
@@ -24,15 +24,19 @@ int sc_main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
// Prevent unused variable warnings
|
// Prevent unused variable warnings
|
||||||
if (0 && argc && argv) {}
|
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
|
// Set debug level, 0 is off, 9 is highest presently used
|
||||||
|
// May be overridden by commandArgs
|
||||||
Verilated::debug(0);
|
Verilated::debug(0);
|
||||||
|
|
||||||
// Randomization reset policy
|
// Randomization reset policy
|
||||||
|
// May be overridden by commandArgs
|
||||||
Verilated::randReset(2);
|
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
|
// General logfile
|
||||||
ios::sync_with_stdio();
|
ios::sync_with_stdio();
|
||||||
|
|
||||||
@@ -111,9 +115,9 @@ int sc_main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
// Apply inputs
|
// Apply inputs
|
||||||
if (VL_TIME_Q() > 1 && VL_TIME_Q() < 10) {
|
if (VL_TIME_Q() > 1 && VL_TIME_Q() < 10) {
|
||||||
reset_l = !1; // Assert reset
|
reset_l = !1; // Assert reset
|
||||||
} else if (VL_TIME_Q() > 1) {
|
} else if (VL_TIME_Q() > 1) {
|
||||||
reset_l = !0; // Deassert reset
|
reset_l = !0; // Deassert reset
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simulate 1ns
|
// Simulate 1ns
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ module sub
|
|||||||
|
|
||||||
// An example assertion
|
// An example assertion
|
||||||
always_ff @ (posedge clk) begin
|
always_ff @ (posedge clk) begin
|
||||||
AssertionExample: assert (!reset_l || count_c<100);
|
AssertionExample: assert(!reset_l || count_c<100);
|
||||||
end
|
end
|
||||||
|
|
||||||
// And example coverage analysis
|
// And example coverage analysis
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ static const int LZ4_minLength = (MFLIMIT+1);
|
|||||||
/**************************************
|
/**************************************
|
||||||
* Common functions
|
* Common functions
|
||||||
**************************************/
|
**************************************/
|
||||||
static unsigned LZ4_NbCommonBytes (register size_t val)
|
static unsigned LZ4_NbCommonBytes (size_t val)
|
||||||
{
|
{
|
||||||
if (LZ4_isLittleEndian())
|
if (LZ4_isLittleEndian())
|
||||||
{
|
{
|
||||||
|
|||||||
+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),0)
|
||||||
ifneq ($(VM_THREADS),)
|
ifneq ($(VM_THREADS),)
|
||||||
|
CPPFLAGS += -DVL_THREADED
|
||||||
|
VK_LIBS_THREADED=1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(VM_TRACE_THREADED),0)
|
||||||
|
ifneq ($(VM_TRACE_THREADED),)
|
||||||
|
CPPFLAGS += -DVL_TRACE_THREADED
|
||||||
|
VK_LIBS_THREADED=1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(VK_LIBS_THREADED),0)
|
||||||
|
ifneq ($(VK_LIBS_THREADED),)
|
||||||
# Need C++11 at least, so always default to newest
|
# Need C++11 at least, so always default to newest
|
||||||
CPPFLAGS += -DVL_THREADED $(CFG_CXXFLAGS_STD_NEWEST)
|
CPPFLAGS += $(CFG_CXXFLAGS_STD_NEWEST)
|
||||||
LDLIBS += $(CFG_LDLIBS_THREADS)
|
LDLIBS += $(CFG_LDLIBS_THREADS)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|||||||
+236
-236
@@ -50,10 +50,10 @@ public: // But only local to this file
|
|||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
// Derived classes should call zero() in their constructor
|
// Derived classes should call zero() in their constructor
|
||||||
VerilatedCovImpItem() {
|
VerilatedCovImpItem() {
|
||||||
for (int i=0; i<MAX_KEYS; ++i) {
|
for (int i=0; i<MAX_KEYS; ++i) {
|
||||||
m_keys[i]=KEY_UNDEF;
|
m_keys[i] = KEY_UNDEF;
|
||||||
m_vals[i]=0;
|
m_vals[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual ~VerilatedCovImpItem() {}
|
virtual ~VerilatedCovImpItem() {}
|
||||||
virtual vluint64_t count() const = 0;
|
virtual vluint64_t count() const = 0;
|
||||||
@@ -96,7 +96,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
VerilatedMutex m_mutex; ///< Protects all members, when VL_THREADED. Wrapper deals with setting it.
|
VerilatedMutex m_mutex; ///< Protects all members, when VL_THREADED. Wrapper deals with setting it.
|
||||||
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
|
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
|
||||||
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
|
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
|
||||||
ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items
|
ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items
|
||||||
@@ -107,294 +107,294 @@ private:
|
|||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VerilatedCovImp() {
|
VerilatedCovImp() {
|
||||||
m_insertp = NULL;
|
m_insertp = NULL;
|
||||||
m_insertFilenamep = NULL;
|
m_insertFilenamep = NULL;
|
||||||
m_insertLineno = 0;
|
m_insertLineno = 0;
|
||||||
}
|
}
|
||||||
VL_UNCOPYABLE(VerilatedCovImp);
|
VL_UNCOPYABLE(VerilatedCovImp);
|
||||||
public:
|
public:
|
||||||
~VerilatedCovImp() { clearGuts(); }
|
~VerilatedCovImp() { clearGuts(); }
|
||||||
static VerilatedCovImp& imp() VL_MT_SAFE {
|
static VerilatedCovImp& imp() VL_MT_SAFE {
|
||||||
static VerilatedCovImp s_singleton;
|
static VerilatedCovImp s_singleton;
|
||||||
return s_singleton;
|
return s_singleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// PRIVATE METHODS
|
// PRIVATE METHODS
|
||||||
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
|
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
|
||||||
static int nextIndex = KEY_UNDEF+1;
|
static int nextIndex = KEY_UNDEF+1;
|
||||||
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
|
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
|
||||||
if (iter != m_valueIndexes.end()) return iter->second;
|
if (iter != m_valueIndexes.end()) return iter->second;
|
||||||
nextIndex++; assert(nextIndex>0);
|
nextIndex++; assert(nextIndex>0);
|
||||||
m_valueIndexes.insert(std::make_pair(value, nextIndex));
|
m_valueIndexes.insert(std::make_pair(value, nextIndex));
|
||||||
m_indexValues.insert(std::make_pair(nextIndex, value));
|
m_indexValues.insert(std::make_pair(nextIndex, value));
|
||||||
return nextIndex;
|
return nextIndex;
|
||||||
}
|
}
|
||||||
static std::string dequote(const std::string& text) VL_PURE {
|
static std::string dequote(const std::string& text) VL_PURE {
|
||||||
// Quote any special characters
|
// Quote any special characters
|
||||||
std::string rtn;
|
std::string rtn;
|
||||||
for (const char* pos = text.c_str(); *pos; ++pos) {
|
for (const char* pos = text.c_str(); *pos; ++pos) {
|
||||||
if (!isprint(*pos) || *pos=='%' || *pos=='"') {
|
if (!isprint(*pos) || *pos=='%' || *pos=='"') {
|
||||||
char hex[10]; sprintf(hex,"%%%02X",pos[0]);
|
char hex[10]; sprintf(hex, "%%%02X", pos[0]);
|
||||||
rtn += hex;
|
rtn += hex;
|
||||||
} else {
|
} else {
|
||||||
rtn += *pos;
|
rtn += *pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
static bool legalKey(const std::string& key) VL_PURE {
|
static bool legalKey(const std::string& key) VL_PURE {
|
||||||
// Because we compress long keys to a single letter, and
|
// Because we compress long keys to a single letter, and
|
||||||
// don't want applications to either get confused if they use
|
// don't want applications to either get confused if they use
|
||||||
// a letter differently, nor want them to rely on our compression...
|
// a letter differently, nor want them to rely on our compression...
|
||||||
// (Considered using numeric keys, but will remain back compatible.)
|
// (Considered using numeric keys, but will remain back compatible.)
|
||||||
if (key.length()<2) return false;
|
if (key.length()<2) return false;
|
||||||
if (key.length()==2 && isdigit(key[1])) return false;
|
if (key.length()==2 && isdigit(key[1])) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
static std::string keyValueFormatter(const std::string& key, const std::string& value) VL_PURE {
|
static std::string keyValueFormatter(const std::string& key, const std::string& value) VL_PURE {
|
||||||
std::string name;
|
std::string name;
|
||||||
if (key.length()==1 && isalpha(key[0])) {
|
if (key.length()==1 && isalpha(key[0])) {
|
||||||
name += std::string("\001")+key;
|
name += std::string("\001")+key;
|
||||||
} else {
|
} else {
|
||||||
name += std::string("\001")+dequote(key);
|
name += std::string("\001")+dequote(key);
|
||||||
}
|
}
|
||||||
name += std::string("\002")+dequote(value);
|
name += std::string("\002")+dequote(value);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
static std::string combineHier(const std::string& old, const std::string& add) VL_PURE {
|
static std::string combineHier(const std::string& old, const std::string& add) VL_PURE {
|
||||||
// (foo.a.x, foo.b.x) => foo.*.x
|
// (foo.a.x, foo.b.x) => foo.*.x
|
||||||
// (foo.a.x, foo.b.y) => foo.*
|
// (foo.a.x, foo.b.y) => foo.*
|
||||||
// (foo.a.x, foo.b) => foo.*
|
// (foo.a.x, foo.b) => foo.*
|
||||||
if (old == add) return add;
|
if (old == add) return add;
|
||||||
if (old.empty()) return add;
|
if (old.empty()) return add;
|
||||||
if (add.empty()) return old;
|
if (add.empty()) return old;
|
||||||
|
|
||||||
const char* a = old.c_str();
|
const char* a = old.c_str();
|
||||||
const char* b = add.c_str();
|
const char* b = add.c_str();
|
||||||
|
|
||||||
// Scan forward to first mismatch
|
// Scan forward to first mismatch
|
||||||
const char* apre = a;
|
const char* apre = a;
|
||||||
const char* bpre = b;
|
const char* bpre = b;
|
||||||
while (*apre == *bpre) { apre++; bpre++; }
|
while (*apre == *bpre) { apre++; bpre++; }
|
||||||
|
|
||||||
// We used to backup and split on only .'s but it seems better to be verbose
|
// We used to backup and split on only .'s but it seems better to be verbose
|
||||||
// and not assume . is the separator
|
// and not assume . is the separator
|
||||||
std::string prefix = std::string(a,apre-a);
|
std::string prefix = std::string(a, apre-a);
|
||||||
|
|
||||||
// Scan backward to last mismatch
|
// Scan backward to last mismatch
|
||||||
const char* apost = a+strlen(a)-1;
|
const char* apost = a+strlen(a)-1;
|
||||||
const char* bpost = b+strlen(b)-1;
|
const char* bpost = b+strlen(b)-1;
|
||||||
while (*apost == *bpost
|
while (*apost == *bpost
|
||||||
&& apost>apre && bpost>bpre) { apost--; bpost--; }
|
&& apost>apre && bpost>bpre) { apost--; bpost--; }
|
||||||
|
|
||||||
// Forward to . so we have a whole word
|
// Forward to . so we have a whole word
|
||||||
std::string suffix = *bpost ? std::string(bpost+1) : "";
|
std::string suffix = *bpost ? std::string(bpost+1) : "";
|
||||||
|
|
||||||
std::string out = prefix+"*"+suffix;
|
std::string out = prefix+"*"+suffix;
|
||||||
|
|
||||||
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
|
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match) VL_REQUIRES(m_mutex) {
|
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match) VL_REQUIRES(m_mutex) {
|
||||||
for (int i=0; i<MAX_KEYS; ++i) {
|
for (int i=0; i<MAX_KEYS; ++i) {
|
||||||
if (itemp->m_keys[i] != KEY_UNDEF) {
|
if (itemp->m_keys[i] != KEY_UNDEF) {
|
||||||
// We don't compare keys, only values
|
// We don't compare keys, only values
|
||||||
std::string val = m_indexValues[itemp->m_vals[i]];
|
std::string val = m_indexValues[itemp->m_vals[i]];
|
||||||
if (std::string::npos != val.find(match)) { // Found
|
if (std::string::npos != val.find(match)) { // Found
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
static void selftest() VL_MT_SAFE {
|
static void selftest() VL_MT_SAFE {
|
||||||
// Little selftest
|
// Little selftest
|
||||||
if (combineHier ("a.b.c","a.b.c") !="a.b.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
if (combineHier("a.b.c","a.b.c") !="a.b.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||||
if (combineHier ("a.b.c","a.b") !="a.b*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
if (combineHier("a.b.c","a.b") !="a.b*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||||
if (combineHier ("a.x.c","a.y.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
if (combineHier("a.x.c","a.y.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||||
if (combineHier ("a.z.z.z.c","a.b.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
if (combineHier("a.z.z.z.c","a.b.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||||
if (combineHier ("z","a") !="*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
if (combineHier("z","a") !="*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||||
if (combineHier ("q.a","q.b") !="q.*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
if (combineHier("q.a","q.b") !="q.*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||||
if (combineHier ("q.za","q.zb") !="q.z*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
if (combineHier("q.za","q.zb") !="q.z*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||||
if (combineHier ("1.2.3.a","9.8.7.a") !="*.a") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
if (combineHier("1.2.3.a","9.8.7.a") !="*.a") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||||
}
|
}
|
||||||
void clearGuts() VL_REQUIRES(m_mutex) {
|
void clearGuts() VL_REQUIRES(m_mutex) {
|
||||||
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||||
VerilatedCovImpItem* itemp = *(it);
|
VerilatedCovImpItem* itemp = *(it);
|
||||||
delete itemp;
|
delete itemp;
|
||||||
}
|
}
|
||||||
m_items.clear();
|
m_items.clear();
|
||||||
m_indexValues.clear();
|
m_indexValues.clear();
|
||||||
m_valueIndexes.clear();
|
m_valueIndexes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// PUBLIC METHODS
|
// PUBLIC METHODS
|
||||||
void clear() VL_EXCLUDES(m_mutex) {
|
void clear() VL_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
VerilatedLockGuard lock(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
clearGuts();
|
clearGuts();
|
||||||
}
|
}
|
||||||
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
|
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
VerilatedLockGuard lock(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
if (matchp && matchp[0]) {
|
if (matchp && matchp[0]) {
|
||||||
ItemList newlist;
|
ItemList newlist;
|
||||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||||
VerilatedCovImpItem* itemp = *(it);
|
VerilatedCovImpItem* itemp = *(it);
|
||||||
if (!itemMatchesString(itemp, matchp)) {
|
if (!itemMatchesString(itemp, matchp)) {
|
||||||
delete itemp;
|
delete itemp;
|
||||||
} else {
|
} else {
|
||||||
newlist.push_back(itemp);
|
newlist.push_back(itemp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_items = newlist;
|
m_items = newlist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void zero() VL_EXCLUDES(m_mutex) {
|
void zero() VL_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
VerilatedLockGuard lock(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||||
(*it)->zero();
|
(*it)->zero();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We assume there's always call to i/f/p in that order
|
// We assume there's always call to i/f/p in that order
|
||||||
void inserti(VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
|
void inserti(VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
assert(!m_insertp);
|
assert(!m_insertp);
|
||||||
m_insertp = itemp;
|
m_insertp = itemp;
|
||||||
}
|
}
|
||||||
void insertf(const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
|
void insertf(const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
m_insertFilenamep = filenamep;
|
m_insertFilenamep = filenamep;
|
||||||
m_insertLineno = lineno;
|
m_insertLineno = lineno;
|
||||||
}
|
}
|
||||||
void insertp(const char* ckeyps[MAX_KEYS],
|
void insertp(const char* ckeyps[MAX_KEYS],
|
||||||
const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
|
const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
assert(m_insertp);
|
assert(m_insertp);
|
||||||
// First two key/vals are filename
|
// First two key/vals are filename
|
||||||
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
|
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
|
||||||
std::string linestr = vlCovCvtToStr(m_insertLineno);
|
std::string linestr = vlCovCvtToStr(m_insertLineno);
|
||||||
ckeyps[1]="lineno"; valps[1]=linestr.c_str();
|
ckeyps[1]="lineno"; valps[1]=linestr.c_str();
|
||||||
// Default page if not specified
|
// Default page if not specified
|
||||||
const char* fnstartp = m_insertFilenamep;
|
const char* fnstartp = m_insertFilenamep;
|
||||||
while (const char* foundp = strchr(fnstartp,'/')) fnstartp=foundp+1;
|
while (const char* foundp = strchr(fnstartp,'/')) fnstartp = foundp+1;
|
||||||
const char* fnendp = fnstartp;
|
const char* fnendp = fnstartp;
|
||||||
while (*fnendp && *fnendp!='.') fnendp++;
|
while (*fnendp && *fnendp!='.') fnendp++;
|
||||||
std::string page_default = "sp_user/"+std::string(fnstartp,fnendp-fnstartp);
|
std::string page_default = "sp_user/"+std::string(fnstartp, fnendp-fnstartp);
|
||||||
ckeyps[2]="page"; valps[2]=page_default.c_str();
|
ckeyps[2]="page"; valps[2]=page_default.c_str();
|
||||||
|
|
||||||
// Keys -> strings
|
// Keys -> strings
|
||||||
std::string keys[MAX_KEYS];
|
std::string keys[MAX_KEYS];
|
||||||
for (int i=0; i<MAX_KEYS; ++i) {
|
for (int i=0; i<MAX_KEYS; ++i) {
|
||||||
if (ckeyps[i] && ckeyps[i][0]) {
|
if (ckeyps[i] && ckeyps[i][0]) {
|
||||||
keys[i] = ckeyps[i];
|
keys[i] = ckeyps[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Ignore empty keys
|
// Ignore empty keys
|
||||||
for (int i=0; i<MAX_KEYS; ++i) {
|
for (int i=0; i<MAX_KEYS; ++i) {
|
||||||
if (!keys[i].empty()) {
|
if (!keys[i].empty()) {
|
||||||
for (int j=i+1; j<MAX_KEYS; ++j) {
|
for (int j=i+1; j<MAX_KEYS; ++j) {
|
||||||
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
|
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
|
||||||
keys[i] = "";
|
keys[i] = "";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Insert the values
|
// Insert the values
|
||||||
int addKeynum=0;
|
int addKeynum = 0;
|
||||||
for (int i=0; i<MAX_KEYS; ++i) {
|
for (int i=0; i<MAX_KEYS; ++i) {
|
||||||
const std::string key = keys[i];
|
const std::string key = keys[i];
|
||||||
if (!keys[i].empty()) {
|
if (!keys[i].empty()) {
|
||||||
const std::string val = valps[i];
|
const std::string val = valps[i];
|
||||||
//cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
|
//cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
|
||||||
m_insertp->m_keys[addKeynum] = valueIndex(key);
|
m_insertp->m_keys[addKeynum] = valueIndex(key);
|
||||||
m_insertp->m_vals[addKeynum] = valueIndex(val);
|
m_insertp->m_vals[addKeynum] = valueIndex(val);
|
||||||
addKeynum++;
|
addKeynum++;
|
||||||
if (!legalKey(key)) {
|
if (!legalKey(key)) {
|
||||||
std::string msg = "%Error: Coverage keys of one character, or letter+digit are illegal: "+key;
|
std::string msg = "%Error: Coverage keys of one character, or letter+digit are illegal: "+key;
|
||||||
VL_FATAL_MT("",0,"",msg.c_str());
|
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_items.push_back(m_insertp);
|
m_items.push_back(m_insertp);
|
||||||
// Prepare for next
|
// Prepare for next
|
||||||
m_insertp = NULL;
|
m_insertp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
VerilatedLockGuard lock(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
#ifndef VM_COVERAGE
|
#ifndef VM_COVERAGE
|
||||||
VL_FATAL_MT("",0,"","%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
VL_FATAL_MT("", 0, "", "%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
||||||
#endif
|
#endif
|
||||||
selftest();
|
selftest();
|
||||||
|
|
||||||
std::ofstream os(filename);
|
std::ofstream os(filename);
|
||||||
if (os.fail()) {
|
if (os.fail()) {
|
||||||
std::string msg = std::string("%Error: Can't write '")+filename+"'";
|
std::string msg = std::string("%Error: Can't write '")+filename+"'";
|
||||||
VL_FATAL_MT("",0,"",msg.c_str());
|
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
os << "# SystemC::Coverage-3\n";
|
os << "# SystemC::Coverage-3\n";
|
||||||
|
|
||||||
// Build list of events; totalize if collapsing hierarchy
|
// Build list of events; totalize if collapsing hierarchy
|
||||||
typedef std::map<std::string,std::pair<std::string,vluint64_t> > EventMap;
|
typedef std::map<std::string,std::pair<std::string,vluint64_t> > EventMap;
|
||||||
EventMap eventCounts;
|
EventMap eventCounts;
|
||||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||||
VerilatedCovImpItem* itemp = *(it);
|
VerilatedCovImpItem* itemp = *(it);
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string hier;
|
std::string hier;
|
||||||
bool per_instance = false;
|
bool per_instance = false;
|
||||||
|
|
||||||
for (int i=0; i<MAX_KEYS; ++i) {
|
for (int i=0; i<MAX_KEYS; ++i) {
|
||||||
if (itemp->m_keys[i] != KEY_UNDEF) {
|
if (itemp->m_keys[i] != KEY_UNDEF) {
|
||||||
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
|
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
|
||||||
std::string val = m_indexValues[itemp->m_vals[i]];
|
std::string val = m_indexValues[itemp->m_vals[i]];
|
||||||
if (key == VL_CIK_PER_INSTANCE) {
|
if (key == VL_CIK_PER_INSTANCE) {
|
||||||
if (val != "0") per_instance = true;
|
if (val != "0") per_instance = true;
|
||||||
}
|
}
|
||||||
if (key == VL_CIK_HIER) {
|
if (key == VL_CIK_HIER) {
|
||||||
hier = val;
|
hier = val;
|
||||||
} else {
|
} else {
|
||||||
// Print it
|
// Print it
|
||||||
name += keyValueFormatter(key,val);
|
name += keyValueFormatter(key, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (per_instance) { // Not collapsing hierarchies
|
if (per_instance) { // Not collapsing hierarchies
|
||||||
name += keyValueFormatter(VL_CIK_HIER,hier);
|
name += keyValueFormatter(VL_CIK_HIER, hier);
|
||||||
hier = "";
|
hier = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group versus point labels don't matter here, downstream
|
// Group versus point labels don't matter here, downstream
|
||||||
// deals with it. Seems bad for sizing though and doesn't
|
// deals with it. Seems bad for sizing though and doesn't
|
||||||
// allow easy addition of new group codes (would be
|
// allow easy addition of new group codes (would be
|
||||||
// inefficient)
|
// inefficient)
|
||||||
|
|
||||||
// Find or insert the named event
|
// Find or insert the named event
|
||||||
EventMap::iterator cit = eventCounts.find(name);
|
EventMap::iterator cit = eventCounts.find(name);
|
||||||
if (cit != eventCounts.end()) {
|
if (cit != eventCounts.end()) {
|
||||||
const std::string& oldhier = cit->second.first;
|
const std::string& oldhier = cit->second.first;
|
||||||
cit->second.second += itemp->count();
|
cit->second.second += itemp->count();
|
||||||
cit->second.first = combineHier(oldhier, hier);
|
cit->second.first = combineHier(oldhier, hier);
|
||||||
} else {
|
} else {
|
||||||
eventCounts.insert(std::make_pair(name, make_pair(hier,itemp->count())));
|
eventCounts.insert(std::make_pair(name, make_pair(hier, itemp->count())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output body
|
// Output body
|
||||||
for (EventMap::const_iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
|
for (EventMap::const_iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
|
||||||
os<<"C '"<<std::dec;
|
os<<"C '"<<std::dec;
|
||||||
os<<it->first;
|
os<<it->first;
|
||||||
if (!it->second.first.empty()) os<<keyValueFormatter(VL_CIK_HIER,it->second.first);
|
if (!it->second.first.empty()) os<<keyValueFormatter(VL_CIK_HIER, it->second.first);
|
||||||
os<<"' "<<it->second.second;
|
os<<"' "<<it->second.second;
|
||||||
os<<std::endl;
|
os<<std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -420,7 +420,7 @@ void VerilatedCov::_inserti(vluint64_t* itemp) VL_MT_SAFE {
|
|||||||
VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint64_t>(itemp));
|
VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint64_t>(itemp));
|
||||||
}
|
}
|
||||||
void VerilatedCov::_insertf(const char* filename, int lineno) VL_MT_SAFE {
|
void VerilatedCov::_insertf(const char* filename, int lineno) VL_MT_SAFE {
|
||||||
VerilatedCovImp::imp().insertf(filename,lineno);
|
VerilatedCovImp::imp().insertf(filename, lineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define K(n) const char* key ## n
|
#define K(n) const char* key ## n
|
||||||
@@ -446,14 +446,14 @@ void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
|
|||||||
// And versions with fewer arguments (oh for a language with named parameters!)
|
// And versions with fewer arguments (oh for a language with named parameters!)
|
||||||
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)) VL_MT_SAFE {
|
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)) VL_MT_SAFE {
|
||||||
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
|
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
|
||||||
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
|
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
|
||||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||||
}
|
}
|
||||||
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
|
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
|
||||||
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)) VL_MT_SAFE {
|
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)) VL_MT_SAFE {
|
||||||
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
|
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
|
||||||
C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19),
|
C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19),
|
||||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||||
}
|
}
|
||||||
// Backward compatibility for Verilator
|
// Backward compatibility for Verilator
|
||||||
void VerilatedCov::_insertp(A(0), A(1), K(2),int val2, K(3),int val3,
|
void VerilatedCov::_insertp(A(0), A(1), K(2),int val2, K(3),int val3,
|
||||||
@@ -461,10 +461,10 @@ void VerilatedCov::_insertp(A(0), A(1), K(2),int val2, K(3),int val3,
|
|||||||
std::string val2str = vlCovCvtToStr(val2);
|
std::string val2str = vlCovCvtToStr(val2);
|
||||||
std::string val3str = vlCovCvtToStr(val3);
|
std::string val3str = vlCovCvtToStr(val3);
|
||||||
_insertp(C(0),C(1),
|
_insertp(C(0),C(1),
|
||||||
key2,val2str.c_str(), key3,val3str.c_str(), key4, val4.c_str(),
|
key2,val2str.c_str(), key3,val3str.c_str(), key4, val4.c_str(),
|
||||||
C(5),C(6),N(7),N(8),N(9),
|
C(5),C(6),N(7),N(8),N(9),
|
||||||
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
|
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
|
||||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||||
}
|
}
|
||||||
#undef A
|
#undef A
|
||||||
#undef C
|
#undef C
|
||||||
|
|||||||
+19
-19
@@ -44,31 +44,31 @@
|
|||||||
/// The value may be a string, or another type which will be auto-converted to a string.
|
/// The value may be a string, or another type which will be auto-converted to a string.
|
||||||
///
|
///
|
||||||
/// Some typical keys:
|
/// Some typical keys:
|
||||||
/// filename File the recording occurs in. Defaults to __FILE__
|
/// filename File the recording occurs in. Defaults to __FILE__
|
||||||
/// lineno Line number the recording occurs in. Defaults to __LINE__
|
/// lineno Line number the recording occurs in. Defaults to __LINE__
|
||||||
/// column Column number (or occurrence# for dup file/lines). Defaults to undef.
|
/// column Column number (or occurrence# for dup file/lines). Defaults to undef.
|
||||||
/// hier Hierarchical name. Defaults to name()
|
/// hier Hierarchical name. Defaults to name()
|
||||||
/// type Type of coverage. Defaults to "user"
|
/// type Type of coverage. Defaults to "user"
|
||||||
/// Other types are 'block', 'fsm', 'toggle'.
|
/// Other types are 'block', 'fsm', 'toggle'.
|
||||||
/// comment Description of the coverage event. Should be set by the user.
|
/// comment Description of the coverage event. Should be set by the user.
|
||||||
/// Comments for type==block: 'if', 'else', 'elsif', 'case'
|
/// Comments for type==block: 'if', 'else', 'elsif', 'case'
|
||||||
/// thresh Threshold to consider fully covered.
|
/// thresh Threshold to consider fully covered.
|
||||||
/// If unspecified, downstream tools will determine it.
|
/// If unspecified, downstream tools will determine it.
|
||||||
///
|
///
|
||||||
/// Examples:
|
/// Examples:
|
||||||
///
|
///
|
||||||
/// vluint32_t m_cases[10];
|
/// vluint32_t m_cases[10];
|
||||||
/// constructor {
|
/// constructor {
|
||||||
/// for (int i=0; i<10; ++i) { m_cases[i]=0; }
|
/// for (int i=0; i<10; ++i) { m_cases[i]=0; }
|
||||||
|
/// }
|
||||||
|
/// for (int i=0; i<10; ++i) {
|
||||||
|
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
|
||||||
/// }
|
/// }
|
||||||
/// for (int i=0; i<10; ++i) {
|
|
||||||
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
|
|
||||||
/// }
|
|
||||||
|
|
||||||
#define VL_COVER_INSERT(countp,args...) \
|
#define VL_COVER_INSERT(countp,args...) \
|
||||||
VL_IF_COVER(VerilatedCov::_inserti(countp); \
|
VL_IF_COVER(VerilatedCov::_inserti(countp); \
|
||||||
VerilatedCov::_insertf(__FILE__,__LINE__); \
|
VerilatedCov::_insertf(__FILE__,__LINE__); \
|
||||||
VerilatedCov::_insertp("hier", name(), args))
|
VerilatedCov::_insertp("hier", name(), args))
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
/// Convert VL_COVER_INSERT value arguments to strings
|
/// Convert VL_COVER_INSERT value arguments to strings
|
||||||
|
|||||||
@@ -24,6 +24,12 @@
|
|||||||
#include "verilated.h"
|
#include "verilated.h"
|
||||||
#include "verilated_fst_c.h"
|
#include "verilated_fst_c.h"
|
||||||
|
|
||||||
|
// GTKWave configuration
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
# define HAVE_LIBPTHREAD
|
||||||
|
# define FST_WRITER_PARALLEL
|
||||||
|
#endif
|
||||||
|
|
||||||
// Include the GTKWave implementation directly
|
// Include the GTKWave implementation directly
|
||||||
#include "gtkwave/fastlz.c"
|
#include "gtkwave/fastlz.c"
|
||||||
#include "gtkwave/fstapi.c"
|
#include "gtkwave/fstapi.c"
|
||||||
@@ -72,6 +78,10 @@ VerilatedFst::VerilatedFst(void* fst)
|
|||||||
void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
|
void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
|
||||||
m_assertOne.check();
|
m_assertOne.check();
|
||||||
m_fst = fstWriterCreate(filename, 1);
|
m_fst = fstWriterCreate(filename, 1);
|
||||||
|
fstWriterSetPackType(m_fst, FST_WR_PT_LZ4);
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
fstWriterSetParallelMode(m_fst, 1);
|
||||||
|
#endif
|
||||||
m_curScope.clear();
|
m_curScope.clear();
|
||||||
|
|
||||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
|
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
|
||||||
|
|||||||
+149
-145
@@ -92,32 +92,32 @@ public:
|
|||||||
// METHODS
|
// METHODS
|
||||||
//// Add message to queue (called by producer)
|
//// Add message to queue (called by producer)
|
||||||
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
|
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
m_queue.insert(msg); // Pass by value to copy the message into queue
|
m_queue.insert(msg); // Pass by value to copy the message into queue
|
||||||
++m_depth;
|
++m_depth;
|
||||||
}
|
}
|
||||||
/// Service queue until completion (called by consumer)
|
/// Service queue until completion (called by consumer)
|
||||||
void process() VL_EXCLUDES(m_mutex) {
|
void process() VL_EXCLUDES(m_mutex) {
|
||||||
// Tracking m_depth is redundant to e.g. getting the mutex and looking at queue size,
|
// Tracking m_depth is redundant to e.g. getting the mutex and looking at queue size,
|
||||||
// but on the reader side it's 4x faster to test an atomic then getting a mutex
|
// but on the reader side it's 4x faster to test an atomic then getting a mutex
|
||||||
while (m_depth) {
|
while (m_depth) {
|
||||||
// Wait for a message to be added to the queue
|
// Wait for a message to be added to the queue
|
||||||
// We don't use unique_lock as want to unlock with the message copy still in scope
|
// We don't use unique_lock as want to unlock with the message copy still in scope
|
||||||
m_mutex.lock();
|
m_mutex.lock();
|
||||||
assert(!m_queue.empty()); // Otherwise m_depth is wrong
|
assert(!m_queue.empty()); // Otherwise m_depth is wrong
|
||||||
// Unfortunately to release the lock we need to copy the message
|
// Unfortunately to release the lock we need to copy the message
|
||||||
// (Or have the message be a pointer, but then new/delete cost on each message)
|
// (Or have the message be a pointer, but then new/delete cost on each message)
|
||||||
// We assume messages are small, so copy
|
// We assume messages are small, so copy
|
||||||
auto it = m_queue.begin();
|
auto it = m_queue.begin();
|
||||||
const VerilatedMsg msg = *(it);
|
const VerilatedMsg msg = *(it);
|
||||||
m_queue.erase(it);
|
m_queue.erase(it);
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
m_depth--; // Ok if outside critical section as only this code checks the value
|
m_depth--; // Ok if outside critical section as only this code checks the value
|
||||||
{
|
{
|
||||||
VL_DEBUG_IF(VL_DBG_MSGF("Executing callback from mtaskId=%d\n", msg.mtaskId()););
|
VL_DEBUG_IF(VL_DBG_MSGF("Executing callback from mtaskId=%d\n", msg.mtaskId()););
|
||||||
msg.run();
|
msg.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -128,15 +128,15 @@ public:
|
|||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VerilatedThreadMsgQueue() { }
|
VerilatedThreadMsgQueue() { }
|
||||||
~VerilatedThreadMsgQueue() {
|
~VerilatedThreadMsgQueue() {
|
||||||
// The only call of this with a non-empty queue is a fatal error.
|
// The only call of this with a non-empty queue is a fatal error.
|
||||||
// So this does not flush the queue, as the destination queue is not known to this class.
|
// So this does not flush the queue, as the destination queue is not known to this class.
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
|
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
|
||||||
// METHODS
|
// METHODS
|
||||||
static VerilatedThreadMsgQueue& threadton() {
|
static VerilatedThreadMsgQueue& threadton() {
|
||||||
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
|
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
|
||||||
return t_s;
|
return t_s;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
/// Add message to queue, called by producer
|
/// Add message to queue, called by producer
|
||||||
@@ -153,11 +153,11 @@ public:
|
|||||||
}
|
}
|
||||||
/// Push all messages to the eval's queue
|
/// Push all messages to the eval's queue
|
||||||
static void flush(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
static void flush(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||||
while (!threadton().m_queue.empty()) {
|
while (!threadton().m_queue.empty()) {
|
||||||
evalMsgQp->post(threadton().m_queue.front());
|
evalMsgQp->post(threadton().m_queue.front());
|
||||||
threadton().m_queue.pop();
|
threadton().m_queue.pop();
|
||||||
Verilated::endOfEvalReqdDec();
|
Verilated::endOfEvalReqdDec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif // VL_THREADED
|
#endif // VL_THREADED
|
||||||
@@ -200,11 +200,11 @@ class VerilatedImp {
|
|||||||
public: // But only for verilated*.cpp
|
public: // But only for verilated*.cpp
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VerilatedImp()
|
VerilatedImp()
|
||||||
: m_argVecLoaded(false), m_exportNext(0) {
|
: m_argVecLoaded(false), m_exportNext(0) {
|
||||||
m_fdps.resize(3);
|
m_fdps.resize(3);
|
||||||
m_fdps[0] = stdin;
|
m_fdps[0] = stdin;
|
||||||
m_fdps[1] = stdout;
|
m_fdps[1] = stdout;
|
||||||
m_fdps[2] = stderr;
|
m_fdps[2] = stderr;
|
||||||
}
|
}
|
||||||
~VerilatedImp() {}
|
~VerilatedImp() {}
|
||||||
private:
|
private:
|
||||||
@@ -219,21 +219,21 @@ public:
|
|||||||
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
|
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
|
||||||
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
|
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
|
||||||
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
|
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
|
||||||
VerilatedLockGuard lock(s_s.m_argMutex);
|
VerilatedLockGuard lock(s_s.m_argMutex);
|
||||||
// Note prefixp does not include the leading "+"
|
// Note prefixp does not include the leading "+"
|
||||||
size_t len = strlen(prefixp);
|
size_t len = strlen(prefixp);
|
||||||
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
|
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
|
||||||
s_s.m_argVecLoaded = true; // Complain only once
|
s_s.m_argVecLoaded = true; // Complain only once
|
||||||
VL_FATAL_MT("unknown",0,"",
|
VL_FATAL_MT("unknown", 0, "",
|
||||||
"%Error: Verilog called $test$plusargs or $value$plusargs without"
|
"%Error: Verilog called $test$plusargs or $value$plusargs without"
|
||||||
" testbench C first calling Verilated::commandArgs(argc,argv).");
|
" testbench C first calling Verilated::commandArgs(argc,argv).");
|
||||||
}
|
}
|
||||||
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
||||||
if ((*it)[0]=='+') {
|
if ((*it)[0]=='+') {
|
||||||
if (0==strncmp(prefixp, it->c_str()+1, len)) return *it;
|
if (0==strncmp(prefixp, it->c_str()+1, len)) return *it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex);
|
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex);
|
||||||
@@ -247,75 +247,77 @@ public:
|
|||||||
// There's often many more scopes than userdata's and thus having a ~48byte
|
// There's often many more scopes than userdata's and thus having a ~48byte
|
||||||
// per map overhead * N scopes would take much more space and cache thrashing.
|
// per map overhead * N scopes would take much more space and cache thrashing.
|
||||||
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
|
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||||
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
|
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep, userKey));
|
||||||
if (it != s_s.m_userMap.end()) it->second = userData;
|
if (it != s_s.m_userMap.end()) it->second = userData;
|
||||||
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
|
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
|
||||||
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep,userKey),userData));
|
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData));
|
||||||
}
|
}
|
||||||
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
|
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||||
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
|
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep, userKey));
|
||||||
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
|
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
|
||||||
else return NULL;
|
else return NULL;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
/// Symbol table destruction cleans up the entries for each scope.
|
/// Symbol table destruction cleans up the entries for each scope.
|
||||||
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
|
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||||
// Slow ok - called once/scope on destruction, so we simply iterate.
|
// Slow ok - called once/scope on destruction, so we simply iterate.
|
||||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||||
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
|
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
|
||||||
if (it->first.first == scopep) {
|
if (it->first.first == scopep) {
|
||||||
s_s.m_userMap.erase(it++);
|
s_s.m_userMap.erase(it++);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void userDump() VL_MT_SAFE {
|
static void userDump() VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
|
VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
|
for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
|
||||||
if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; }
|
if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; }
|
||||||
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n",
|
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n",
|
||||||
it->first.first, it->first.second, it->second);
|
it->first.first, it->first.second, it->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public: // But only for verilated*.cpp
|
public: // But only for verilated*.cpp
|
||||||
// METHODS - scope name
|
// METHODS - scope name
|
||||||
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
|
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||||
// Slow ok - called once/scope at construction
|
// Slow ok - called once/scope at construction
|
||||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||||
if (it == s_s.m_nameMap.end()) {
|
if (it == s_s.m_nameMap.end()) {
|
||||||
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(),scopep));
|
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
|
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(s_s.m_nameMutex); // If too slow, can assume this is only VL_MT_SAFE_POSINIT
|
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||||
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
|
// If too slow, can assume this is only VL_MT_SAFE_POSINIT
|
||||||
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
|
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
|
||||||
else return NULL;
|
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
|
||||||
|
else return NULL;
|
||||||
}
|
}
|
||||||
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
|
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||||
// Slow ok - called once/scope at destruction
|
// Slow ok - called once/scope at destruction
|
||||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||||
userEraseScope(scopep);
|
userEraseScope(scopep);
|
||||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||||
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
||||||
}
|
}
|
||||||
static void scopesDump() VL_MT_SAFE {
|
static void scopesDump() VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||||
VL_PRINTF_MT(" scopesDump:\n");
|
VL_PRINTF_MT(" scopesDump:\n");
|
||||||
for (VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) {
|
for (VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.begin();
|
||||||
const VerilatedScope* scopep = it->second;
|
it!=s_s.m_nameMap.end(); ++it) {
|
||||||
scopep->scopeDump();
|
const VerilatedScope* scopep = it->second;
|
||||||
}
|
scopep->scopeDump();
|
||||||
VL_PRINTF_MT("\n");
|
}
|
||||||
|
VL_PRINTF_MT("\n");
|
||||||
}
|
}
|
||||||
static const VerilatedScopeNameMap* scopeNameMap() VL_MT_SAFE_POSTINIT {
|
static const VerilatedScopeNameMap* scopeNameMap() VL_MT_SAFE_POSTINIT {
|
||||||
// Thread save only assuming this is called only after model construction completed
|
// Thread save only assuming this is called only after model construction completed
|
||||||
return &s_s.m_nameMap;
|
return &s_s.m_nameMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,40 +331,42 @@ public: // But only for verilated*.cpp
|
|||||||
// Rather than a 2D map, the integer scheme saves 500ish ns on a likely
|
// Rather than a 2D map, the integer scheme saves 500ish ns on a likely
|
||||||
// miss at the cost of a multiply, and all lookups move to slowpath.
|
// miss at the cost of a multiply, and all lookups move to slowpath.
|
||||||
static int exportInsert(const char* namep) VL_MT_SAFE {
|
static int exportInsert(const char* namep) VL_MT_SAFE {
|
||||||
// Slow ok - called once/function at creation
|
// Slow ok - called once/function at creation
|
||||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||||
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
|
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
|
||||||
if (it == s_s.m_exportMap.end()) {
|
if (it == s_s.m_exportMap.end()) {
|
||||||
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
|
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
|
||||||
return s_s.m_exportNext++;
|
return s_s.m_exportNext++;
|
||||||
} else {
|
} else {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static int exportFind(const char* namep) VL_MT_SAFE {
|
static int exportFind(const char* namep) VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||||
ExportNameMap::const_iterator it=s_s.m_exportMap.find(namep);
|
ExportNameMap::const_iterator it=s_s.m_exportMap.find(namep);
|
||||||
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
|
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
|
||||||
std::string msg = (std::string("%Error: Testbench C called ")+namep
|
std::string msg = (std::string("%Error: Testbench C called ")+namep
|
||||||
+" but no such DPI export function name exists in ANY model");
|
+" but no such DPI export function name exists in ANY model");
|
||||||
VL_FATAL_MT("unknown",0,"", msg.c_str());
|
VL_FATAL_MT("unknown", 0, "", msg.c_str());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
static const char* exportName(int funcnum) VL_MT_SAFE {
|
static const char* exportName(int funcnum) VL_MT_SAFE {
|
||||||
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
||||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||||
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin();
|
||||||
if (it->second == funcnum) return it->first;
|
it!=s_s.m_exportMap.end(); ++it) {
|
||||||
}
|
if (it->second == funcnum) return it->first;
|
||||||
return "*UNKNOWN*";
|
}
|
||||||
|
return "*UNKNOWN*";
|
||||||
}
|
}
|
||||||
static void exportsDump() VL_MT_SAFE {
|
static void exportsDump() VL_MT_SAFE {
|
||||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin();
|
||||||
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
|
it!=s_s.m_exportMap.end(); ++it) {
|
||||||
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
|
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
|
||||||
}
|
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// We don't free up m_exportMap until the end, because we can't be sure
|
// We don't free up m_exportMap until the end, because we can't be sure
|
||||||
// what other models are using the assigned funcnum's.
|
// what other models are using the assigned funcnum's.
|
||||||
@@ -370,32 +374,32 @@ public: // But only for verilated*.cpp
|
|||||||
public: // But only for verilated*.cpp
|
public: // But only for verilated*.cpp
|
||||||
// METHODS - file IO
|
// METHODS - file IO
|
||||||
static IData fdNew(FILE* fp) VL_MT_SAFE {
|
static IData fdNew(FILE* fp) VL_MT_SAFE {
|
||||||
if (VL_UNLIKELY(!fp)) return 0;
|
if (VL_UNLIKELY(!fp)) return 0;
|
||||||
// Bit 31 indicates it's a descriptor not a MCD
|
// Bit 31 indicates it's a descriptor not a MCD
|
||||||
VerilatedLockGuard lock(s_s.m_fdMutex);
|
VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||||
if (s_s.m_fdFree.empty()) {
|
if (s_s.m_fdFree.empty()) {
|
||||||
// Need to create more space in m_fdps and m_fdFree
|
// Need to create more space in m_fdps and m_fdFree
|
||||||
size_t start = s_s.m_fdps.size();
|
size_t start = s_s.m_fdps.size();
|
||||||
s_s.m_fdps.resize(start*2);
|
s_s.m_fdps.resize(start*2);
|
||||||
for (size_t i=start; i<start*2; ++i) s_s.m_fdFree.push_back(static_cast<IData>(i));
|
for (size_t i=start; i<start*2; ++i) s_s.m_fdFree.push_back(static_cast<IData>(i));
|
||||||
}
|
}
|
||||||
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
|
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
|
||||||
s_s.m_fdps[idx] = fp;
|
s_s.m_fdps[idx] = fp;
|
||||||
return (idx | (1UL<<31)); // bit 31 indicates not MCD
|
return (idx | (1UL<<31)); // bit 31 indicates not MCD
|
||||||
}
|
}
|
||||||
static void fdDelete(IData fdi) VL_MT_SAFE {
|
static void fdDelete(IData fdi) VL_MT_SAFE {
|
||||||
IData idx = VL_MASK_I(31) & fdi;
|
IData idx = VL_MASK_I(31) & fdi;
|
||||||
VerilatedLockGuard lock(s_s.m_fdMutex);
|
VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||||
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
|
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
|
||||||
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
|
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
|
||||||
s_s.m_fdps[idx] = NULL;
|
s_s.m_fdps[idx] = NULL;
|
||||||
s_s.m_fdFree.push_back(idx);
|
s_s.m_fdFree.push_back(idx);
|
||||||
}
|
}
|
||||||
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
|
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
|
||||||
IData idx = VL_MASK_I(31) & fdi;
|
IData idx = VL_MASK_I(31) & fdi;
|
||||||
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
|
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
|
||||||
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
|
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
|
||||||
return s_s.m_fdps[idx];
|
return s_s.m_fdps[idx];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+57
-59
@@ -56,17 +56,17 @@ bool VerilatedDeserialize::readDiffers(const void* __restrict datap, size_t size
|
|||||||
const vluint8_t* __restrict dp = static_cast<const vluint8_t* __restrict>(datap);
|
const vluint8_t* __restrict dp = static_cast<const vluint8_t* __restrict>(datap);
|
||||||
vluint8_t miss = 0;
|
vluint8_t miss = 0;
|
||||||
while (size--) {
|
while (size--) {
|
||||||
miss |= (*dp++ ^ *m_cp++);
|
miss |= (*dp++ ^ *m_cp++);
|
||||||
}
|
}
|
||||||
return (miss!=0);
|
return (miss!=0);
|
||||||
}
|
}
|
||||||
|
|
||||||
VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||||
if (VL_UNLIKELY(readDiffers(datap,size))) {
|
if (VL_UNLIKELY(readDiffers(datap, size))) {
|
||||||
std::string fn = filename();
|
std::string fn = filename();
|
||||||
std::string msg = std::string("Can't deserialize save-restore file as was made from different model");
|
std::string msg = std::string("Can't deserialize save-restore file as was made from different model");
|
||||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
return *this; // For function chaining
|
return *this; // For function chaining
|
||||||
}
|
}
|
||||||
@@ -84,10 +84,10 @@ void VerilatedSerialize::header() VL_MT_UNSAFE_ONE {
|
|||||||
void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
|
void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
|
||||||
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
||||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
|
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
|
||||||
std::string fn = filename();
|
std::string fn = filename();
|
||||||
std::string msg = std::string("Can't deserialize; file has wrong header signature");
|
std::string msg = std::string("Can't deserialize; file has wrong header signature");
|
||||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
|
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
|
||||||
}
|
}
|
||||||
@@ -101,10 +101,10 @@ void VerilatedSerialize::trailer() VL_MT_UNSAFE_ONE {
|
|||||||
void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
|
void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
|
||||||
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
||||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
|
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
|
||||||
std::string fn = filename();
|
std::string fn = filename();
|
||||||
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature");
|
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature");
|
||||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,19 +116,19 @@ void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
|
|||||||
void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
||||||
m_assertOne.check();
|
m_assertOne.check();
|
||||||
if (isOpen()) return;
|
if (isOpen()) return;
|
||||||
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n",filenamep););
|
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n", filenamep););
|
||||||
|
|
||||||
if (filenamep[0]=='|') {
|
if (filenamep[0]=='|') {
|
||||||
assert(0); // Not supported yet.
|
assert(0); // Not supported yet.
|
||||||
} else {
|
} else {
|
||||||
// cppcheck-suppress duplicateExpression
|
// cppcheck-suppress duplicateExpression
|
||||||
m_fd = ::open(filenamep, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK|O_CLOEXEC
|
m_fd = ::open(filenamep, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK|O_CLOEXEC
|
||||||
, 0666);
|
, 0666);
|
||||||
if (m_fd<0) {
|
if (m_fd<0) {
|
||||||
// User code can check isOpen()
|
// User code can check isOpen()
|
||||||
m_isOpen = false;
|
m_isOpen = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_isOpen = true;
|
m_isOpen = true;
|
||||||
m_filename = filenamep;
|
m_filename = filenamep;
|
||||||
@@ -139,19 +139,19 @@ void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
|||||||
void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
||||||
m_assertOne.check();
|
m_assertOne.check();
|
||||||
if (isOpen()) return;
|
if (isOpen()) return;
|
||||||
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n",filenamep););
|
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n", filenamep););
|
||||||
|
|
||||||
if (filenamep[0]=='|') {
|
if (filenamep[0]=='|') {
|
||||||
assert(0); // Not supported yet.
|
assert(0); // Not supported yet.
|
||||||
} else {
|
} else {
|
||||||
// cppcheck-suppress duplicateExpression
|
// cppcheck-suppress duplicateExpression
|
||||||
m_fd = ::open(filenamep, O_CREAT|O_RDONLY|O_LARGEFILE|O_CLOEXEC
|
m_fd = ::open(filenamep, O_CREAT|O_RDONLY|O_LARGEFILE|O_CLOEXEC
|
||||||
, 0666);
|
, 0666);
|
||||||
if (m_fd<0) {
|
if (m_fd<0) {
|
||||||
// User code can check isOpen()
|
// User code can check isOpen()
|
||||||
m_isOpen = false;
|
m_isOpen = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_isOpen = true;
|
m_isOpen = true;
|
||||||
m_filename = filenamep;
|
m_filename = filenamep;
|
||||||
@@ -184,21 +184,21 @@ void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
|
|||||||
if (VL_UNLIKELY(!isOpen())) return;
|
if (VL_UNLIKELY(!isOpen())) return;
|
||||||
vluint8_t* wp = m_bufp;
|
vluint8_t* wp = m_bufp;
|
||||||
while (1) {
|
while (1) {
|
||||||
ssize_t remaining = (m_cp - wp);
|
ssize_t remaining = (m_cp - wp);
|
||||||
if (remaining==0) break;
|
if (remaining==0) break;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ssize_t got = ::write(m_fd, wp, remaining);
|
ssize_t got = ::write(m_fd, wp, remaining);
|
||||||
if (got>0) {
|
if (got>0) {
|
||||||
wp += got;
|
wp += got;
|
||||||
} else if (got < 0) {
|
} else if (got < 0) {
|
||||||
if (errno != EAGAIN && errno != EINTR) {
|
if (errno != EAGAIN && errno != EINTR) {
|
||||||
// write failed, presume error (perhaps out of disk space)
|
// write failed, presume error (perhaps out of disk space)
|
||||||
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
||||||
VL_FATAL_MT("",0,"",msg.c_str());
|
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||||
close();
|
close();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_cp = m_bufp; // Reset buffer
|
m_cp = m_bufp; // Reset buffer
|
||||||
}
|
}
|
||||||
@@ -213,30 +213,28 @@ void VerilatedRestore::fill() VL_MT_UNSAFE_ONE {
|
|||||||
m_cp = m_bufp; // Reset buffer
|
m_cp = m_bufp; // Reset buffer
|
||||||
// Read into buffer starting at m_endp
|
// Read into buffer starting at m_endp
|
||||||
while (1) {
|
while (1) {
|
||||||
ssize_t remaining = (m_bufp+bufferSize() - m_endp);
|
ssize_t remaining = (m_bufp+bufferSize() - m_endp);
|
||||||
if (remaining==0) break;
|
if (remaining==0) break;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ssize_t got = ::read(m_fd, m_endp, remaining);
|
ssize_t got = ::read(m_fd, m_endp, remaining);
|
||||||
if (got>0) {
|
if (got>0) {
|
||||||
m_endp += got;
|
m_endp += got;
|
||||||
} else if (got < 0) {
|
} else if (got < 0) {
|
||||||
if (errno != EAGAIN && errno != EINTR) {
|
if (errno != EAGAIN && errno != EINTR) {
|
||||||
// write failed, presume error (perhaps out of disk space)
|
// write failed, presume error (perhaps out of disk space)
|
||||||
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
||||||
VL_FATAL_MT("",0,"",msg.c_str());
|
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||||
close();
|
close();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else { // got==0, EOF
|
} else { // got==0, EOF
|
||||||
// Fill buffer from here to end with NULLs so reader's don't
|
// Fill buffer from here to end with NULLs so reader's don't
|
||||||
// need to check eof each character.
|
// need to check eof each character.
|
||||||
while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0';
|
while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Serialization of types
|
// Serialization of types
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+55
-55
@@ -34,10 +34,10 @@ class VerilatedSerialize {
|
|||||||
protected:
|
protected:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
// For speed, keep m_cp as the first member of this structure
|
// For speed, keep m_cp as the first member of this structure
|
||||||
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
||||||
vluint8_t* m_bufp; ///< Output buffer
|
vluint8_t* m_bufp; ///< Output buffer
|
||||||
bool m_isOpen; ///< True indicates open file/stream
|
bool m_isOpen; ///< True indicates open file/stream
|
||||||
std::string m_filename; ///< Filename, for error messages
|
std::string m_filename; ///< Filename, for error messages
|
||||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||||
|
|
||||||
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
||||||
@@ -50,13 +50,13 @@ protected:
|
|||||||
VL_UNCOPYABLE(VerilatedSerialize);
|
VL_UNCOPYABLE(VerilatedSerialize);
|
||||||
public:
|
public:
|
||||||
VerilatedSerialize() {
|
VerilatedSerialize() {
|
||||||
m_isOpen = false;
|
m_isOpen = false;
|
||||||
m_bufp = new vluint8_t [bufferSize()];
|
m_bufp = new vluint8_t [bufferSize()];
|
||||||
m_cp = m_bufp;
|
m_cp = m_bufp;
|
||||||
}
|
}
|
||||||
virtual ~VerilatedSerialize() {
|
virtual ~VerilatedSerialize() {
|
||||||
close();
|
close();
|
||||||
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
||||||
}
|
}
|
||||||
// METHODS
|
// METHODS
|
||||||
bool isOpen() const { return m_isOpen; }
|
bool isOpen() const { return m_isOpen; }
|
||||||
@@ -64,24 +64,24 @@ public:
|
|||||||
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
|
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
|
||||||
virtual void flush() VL_MT_UNSAFE_ONE {}
|
virtual void flush() VL_MT_UNSAFE_ONE {}
|
||||||
inline VerilatedSerialize& write(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
inline VerilatedSerialize& write(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||||
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
|
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
|
||||||
while (size) {
|
while (size) {
|
||||||
bufferCheck();
|
bufferCheck();
|
||||||
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
||||||
const vluint8_t* __restrict maxp = dp + blk;
|
const vluint8_t* __restrict maxp = dp + blk;
|
||||||
while (dp < maxp) *m_cp++ = *dp++;
|
while (dp < maxp) *m_cp++ = *dp++;
|
||||||
size -= blk;
|
size -= blk;
|
||||||
}
|
}
|
||||||
return *this; // For function chaining
|
return *this; // For function chaining
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
VerilatedSerialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
VerilatedSerialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
||||||
// Flush the write buffer if there's not enough space left for new information
|
// Flush the write buffer if there's not enough space left for new information
|
||||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||||
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
|
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
return *this; // For function chaining
|
return *this; // For function chaining
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -93,12 +93,12 @@ class VerilatedDeserialize {
|
|||||||
protected:
|
protected:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
// For speed, keep m_cp as the first member of this structure
|
// For speed, keep m_cp as the first member of this structure
|
||||||
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
||||||
vluint8_t* m_bufp; ///< Output buffer
|
vluint8_t* m_bufp; ///< Output buffer
|
||||||
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
|
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
|
||||||
bool m_isOpen; ///< True indicates open file/stream
|
bool m_isOpen; ///< True indicates open file/stream
|
||||||
std::string m_filename; ///< Filename, for error messages
|
std::string m_filename; ///< Filename, for error messages
|
||||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||||
|
|
||||||
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
||||||
inline static size_t bufferInsertSize() { return 16*1024; }
|
inline static size_t bufferInsertSize() { return 16*1024; }
|
||||||
@@ -111,14 +111,14 @@ protected:
|
|||||||
VL_UNCOPYABLE(VerilatedDeserialize);
|
VL_UNCOPYABLE(VerilatedDeserialize);
|
||||||
public:
|
public:
|
||||||
VerilatedDeserialize() {
|
VerilatedDeserialize() {
|
||||||
m_isOpen = false;
|
m_isOpen = false;
|
||||||
m_bufp = new vluint8_t [bufferSize()];
|
m_bufp = new vluint8_t [bufferSize()];
|
||||||
m_cp = m_bufp;
|
m_cp = m_bufp;
|
||||||
m_endp = NULL;
|
m_endp = NULL;
|
||||||
}
|
}
|
||||||
virtual ~VerilatedDeserialize() {
|
virtual ~VerilatedDeserialize() {
|
||||||
close();
|
close();
|
||||||
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
||||||
}
|
}
|
||||||
// METHODS
|
// METHODS
|
||||||
bool isOpen() const { return m_isOpen; }
|
bool isOpen() const { return m_isOpen; }
|
||||||
@@ -126,15 +126,15 @@ public:
|
|||||||
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
|
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
|
||||||
virtual void flush() VL_MT_UNSAFE_ONE {}
|
virtual void flush() VL_MT_UNSAFE_ONE {}
|
||||||
inline VerilatedDeserialize& read(void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
inline VerilatedDeserialize& read(void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||||
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
|
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
|
||||||
while (size) {
|
while (size) {
|
||||||
bufferCheck();
|
bufferCheck();
|
||||||
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
||||||
const vluint8_t* __restrict maxp = dp + blk;
|
const vluint8_t* __restrict maxp = dp + blk;
|
||||||
while (dp < maxp) *dp++ = *m_cp++;
|
while (dp < maxp) *dp++ = *m_cp++;
|
||||||
size -= blk;
|
size -= blk;
|
||||||
}
|
}
|
||||||
return *this; // For function chaining
|
return *this; // For function chaining
|
||||||
}
|
}
|
||||||
// Read a datum and compare with expected value
|
// Read a datum and compare with expected value
|
||||||
VerilatedDeserialize& readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
VerilatedDeserialize& readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
||||||
@@ -143,12 +143,12 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
bool readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
||||||
VerilatedDeserialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
VerilatedDeserialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
||||||
// Flush the write buffer if there's not enough space left for new information
|
// Flush the write buffer if there's not enough space left for new information
|
||||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||||
if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
|
if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
|
||||||
fill();
|
fill();
|
||||||
}
|
}
|
||||||
return *this; // For function chaining
|
return *this; // For function chaining
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ private:
|
|||||||
|
|
||||||
class VerilatedSave : public VerilatedSerialize {
|
class VerilatedSave : public VerilatedSerialize {
|
||||||
private:
|
private:
|
||||||
int m_fd; ///< File descriptor we're writing to
|
int m_fd; ///< File descriptor we're writing to
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
@@ -177,7 +177,7 @@ public:
|
|||||||
|
|
||||||
class VerilatedRestore : public VerilatedDeserialize {
|
class VerilatedRestore : public VerilatedDeserialize {
|
||||||
private:
|
private:
|
||||||
int m_fd; ///< File descriptor we're writing to
|
int m_fd; ///< File descriptor we're writing to
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
@@ -237,12 +237,12 @@ inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, float& rhs) {
|
|||||||
return os.read(&rhs, sizeof(rhs));
|
return os.read(&rhs, sizeof(rhs));
|
||||||
}
|
}
|
||||||
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, std::string& rhs) {
|
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, std::string& rhs) {
|
||||||
vluint32_t len=rhs.length();
|
vluint32_t len = rhs.length();
|
||||||
os<<len;
|
os<<len;
|
||||||
return os.write(rhs.data(), len);
|
return os.write(rhs.data(), len);
|
||||||
}
|
}
|
||||||
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, std::string& rhs) {
|
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, std::string& rhs) {
|
||||||
vluint32_t len=0;
|
vluint32_t len = 0;
|
||||||
os>>len;
|
os>>len;
|
||||||
rhs.resize(len);
|
rhs.resize(len);
|
||||||
return os.read((void*)rhs.data(), len);
|
return os.read((void*)rhs.data(), len);
|
||||||
|
|||||||
@@ -134,17 +134,24 @@ private:
|
|||||||
// cppcheck-suppress functionConst
|
// cppcheck-suppress functionConst
|
||||||
void dumpDone();
|
void dumpDone();
|
||||||
inline void printCode(vluint32_t code) {
|
inline void printCode(vluint32_t code) {
|
||||||
if (code>=(94*94*94)) *m_writep++ = static_cast<char>((code/94/94/94)%94+33);
|
*m_writep++ = static_cast<char>('!' + code % 94);
|
||||||
if (code>=(94*94)) *m_writep++ = static_cast<char>((code/94/94)%94+33);
|
code /= 94;
|
||||||
if (code>=(94)) *m_writep++ = static_cast<char>((code/94)%94+33);
|
while (code) {
|
||||||
*m_writep++ = static_cast<char>((code)%94+33);
|
code--;
|
||||||
|
*m_writep++ = static_cast<char>('!' + code % 94);
|
||||||
|
code /= 94;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static std::string stringCode(vluint32_t code) VL_PURE {
|
static std::string stringCode(vluint32_t code) VL_PURE {
|
||||||
std::string out;
|
std::string out;
|
||||||
if (code>=(94*94*94)) out += static_cast<char>((code/94/94/94)%94+33);
|
out += static_cast<char>('!' + code % 94);
|
||||||
if (code>=(94*94)) out += static_cast<char>((code/94/94)%94+33);
|
code /= 94;
|
||||||
if (code>=(94)) out += static_cast<char>((code/94)%94+33);
|
while (code) {
|
||||||
return out + static_cast<char>((code)%94+33);
|
code--;
|
||||||
|
out += static_cast<char>('!' + code % 94);
|
||||||
|
code /= 94;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
|
|||||||
+547
-529
File diff suppressed because it is too large
Load Diff
+86
-86
@@ -16,11 +16,11 @@
|
|||||||
/// \file
|
/// \file
|
||||||
/// \brief Verilator: Common include for OS portability (verilated & verilator)
|
/// \brief Verilator: Common include for OS portability (verilated & verilator)
|
||||||
///
|
///
|
||||||
/// This header is used by both the Verilator source code (run on the
|
/// This header is used by both the Verilator source code (run on the
|
||||||
/// build and host system), and the Verilated output (run on the target
|
/// build and host system), and the Verilated output (run on the target
|
||||||
/// system). Code needed by only the host system goes into
|
/// system). Code needed by only the host system goes into
|
||||||
/// config_build.h.in, code needed by Verilated code only goes into
|
/// config_build.h.in, code needed by Verilated code only goes into
|
||||||
/// verilated.h, and code needed by both goes here (verilatedos.h).
|
/// verilated.h, and code needed by both goes here (verilatedos.h).
|
||||||
///
|
///
|
||||||
/// Code available from: http://www.veripool.org/verilator
|
/// Code available from: http://www.veripool.org/verilator
|
||||||
///
|
///
|
||||||
@@ -37,11 +37,7 @@
|
|||||||
# define VL_ATTR_ALIGNED(alignment) __attribute__ ((aligned (alignment)))
|
# define VL_ATTR_ALIGNED(alignment) __attribute__ ((aligned (alignment)))
|
||||||
# define VL_ATTR_ALWINLINE __attribute__ ((always_inline))
|
# define VL_ATTR_ALWINLINE __attribute__ ((always_inline))
|
||||||
# define VL_ATTR_NORETURN __attribute__ ((noreturn))
|
# define VL_ATTR_NORETURN __attribute__ ((noreturn))
|
||||||
# ifdef _WIN32
|
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, (fmtArgNum), (fmtArgNum)+1)))
|
||||||
# define VL_ATTR_PRINTF(fmtArgNum) // GCC with MS runtime will fool the print arg checker
|
|
||||||
# else
|
|
||||||
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, (fmtArgNum), (fmtArgNum)+1)))
|
|
||||||
# endif
|
|
||||||
# define VL_ATTR_PURE __attribute__ ((pure))
|
# define VL_ATTR_PURE __attribute__ ((pure))
|
||||||
# define VL_ATTR_UNUSED __attribute__ ((unused))
|
# define VL_ATTR_UNUSED __attribute__ ((unused))
|
||||||
# define VL_FUNC __func__
|
# define VL_FUNC __func__
|
||||||
@@ -58,8 +54,8 @@
|
|||||||
# define VL_EXCLUDES(x) __attribute__ ((locks_excluded(x)))
|
# define VL_EXCLUDES(x) __attribute__ ((locks_excluded(x)))
|
||||||
# define VL_SCOPED_CAPABILITY __attribute__ ((scoped_lockable))
|
# define VL_SCOPED_CAPABILITY __attribute__ ((scoped_lockable))
|
||||||
# endif
|
# endif
|
||||||
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
|
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||||
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||||
# define VL_UNREACHABLE __builtin_unreachable();
|
# define VL_UNREACHABLE __builtin_unreachable();
|
||||||
# define VL_PREFETCH_RD(p) __builtin_prefetch((p),0)
|
# define VL_PREFETCH_RD(p) __builtin_prefetch((p),0)
|
||||||
# define VL_PREFETCH_RW(p) __builtin_prefetch((p),1)
|
# define VL_PREFETCH_RW(p) __builtin_prefetch((p),1)
|
||||||
@@ -69,51 +65,51 @@
|
|||||||
|
|
||||||
// Defaults for unsupported compiler features
|
// Defaults for unsupported compiler features
|
||||||
#ifndef VL_ATTR_ALIGNED
|
#ifndef VL_ATTR_ALIGNED
|
||||||
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
|
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_ATTR_ALWINLINE
|
#ifndef VL_ATTR_ALWINLINE
|
||||||
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
|
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_ATTR_NORETURN
|
#ifndef VL_ATTR_NORETURN
|
||||||
# define VL_ATTR_NORETURN ///< Function does not ever return
|
# define VL_ATTR_NORETURN ///< Function does not ever return
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_ATTR_PRINTF
|
#ifndef VL_ATTR_PRINTF
|
||||||
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
|
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_ATTR_PURE
|
#ifndef VL_ATTR_PURE
|
||||||
# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE)
|
# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE)
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_ATTR_UNUSED
|
#ifndef VL_ATTR_UNUSED
|
||||||
# define VL_ATTR_UNUSED ///< Function that may be never used
|
# define VL_ATTR_UNUSED ///< Function that may be never used
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_FUNC
|
#ifndef VL_FUNC
|
||||||
# define VL_FUNC "__func__" ///< Name of current function for error macros
|
# define VL_FUNC "__func__" ///< Name of current function for error macros
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_CAPABILITY
|
#ifndef VL_CAPABILITY
|
||||||
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
|
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
|
||||||
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
|
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
|
||||||
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
|
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
|
||||||
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
|
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
|
||||||
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
|
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
|
||||||
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired a shared capability (-fthread-safety)
|
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired a shared capability (-fthread-safety)
|
||||||
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
|
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
|
||||||
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
|
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
|
||||||
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
|
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
|
||||||
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
|
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
|
||||||
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
|
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_LIKELY
|
#ifndef VL_LIKELY
|
||||||
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
|
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
|
||||||
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
|
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_UNREACHABLE
|
#ifndef VL_UNREACHABLE
|
||||||
# define VL_UNREACHABLE ///< Point that may never be reached
|
# define VL_UNREACHABLE ///< Point that may never be reached
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_PREFETCH_RD
|
#ifndef VL_PREFETCH_RD
|
||||||
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
|
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_PREFETCH_RW
|
#ifndef VL_PREFETCH_RW
|
||||||
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
|
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef VL_THREADED
|
#ifdef VL_THREADED
|
||||||
@@ -124,12 +120,12 @@
|
|||||||
# else
|
# else
|
||||||
# error "Unsupported compiler for VL_THREADED: No thread-local declarator"
|
# error "Unsupported compiler for VL_THREADED: No thread-local declarator"
|
||||||
# endif
|
# endif
|
||||||
# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread
|
# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread
|
||||||
#else
|
#else
|
||||||
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
|
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
|
||||||
#endif
|
#endif
|
||||||
#define VL_THREAD ///< Deprecated
|
#define VL_THREAD ///< Deprecated
|
||||||
#define VL_STATIC_OR_THREAD static ///< Deprecated
|
#define VL_STATIC_OR_THREAD static ///< Deprecated
|
||||||
|
|
||||||
#define VL_PURE ///< Comment tag that Function is pure (and thus also VL_MT_SAFE)
|
#define VL_PURE ///< Comment tag that Function is pure (and thus also VL_MT_SAFE)
|
||||||
#define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED
|
#define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED
|
||||||
@@ -138,18 +134,18 @@
|
|||||||
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED, protected to make sure single-caller
|
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED, protected to make sure single-caller
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# define VL_ULL(c) (c##ui64) ///< Add appropriate suffix to 64-bit constant
|
# define VL_ULL(c) (c##ui64) ///< Add appropriate suffix to 64-bit constant
|
||||||
#else
|
#else
|
||||||
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
|
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This is not necessarily the same as #UL, depending on what the IData typedef is.
|
// This is not necessarily the same as #UL, depending on what the IData typedef is.
|
||||||
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
|
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
|
||||||
|
|
||||||
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__)
|
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__)
|
||||||
# define VL_DANGLING(v)
|
# define VL_DANGLING(v)
|
||||||
#else
|
#else
|
||||||
# define VL_DANGLING(v) do { (v) = NULL; } while(0) ///< After e.g. delete, set variable to NULL to indicate must not use later
|
# define VL_DANGLING(v) do { (v) = NULL; } while(0) ///< After e.g. delete, set variable to NULL to indicate must not use later
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
@@ -180,7 +176,7 @@
|
|||||||
// Optimization
|
// Optimization
|
||||||
|
|
||||||
#ifndef VL_INLINE_OPT
|
#ifndef VL_INLINE_OPT
|
||||||
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
|
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
@@ -207,37 +203,37 @@
|
|||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
# include <sys/types.h> // __WORDSIZE
|
# include <sys/types.h> // __WORDSIZE
|
||||||
# include <unistd.h> // ssize_t
|
# include <unistd.h> // ssize_t
|
||||||
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||||
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||||
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
|
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
|
||||||
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
|
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
|
||||||
# if defined(__uint32_t_defined) || defined(___int32_t_defined) // Newer Cygwin uint32_t in stdint.h as an unsigned int
|
# if defined(__uint32_t_defined) || defined(___int32_t_defined) // Newer Cygwin uint32_t in stdint.h as an unsigned int
|
||||||
typedef int32_t vlsint32_t; ///< 32-bit signed type
|
typedef int32_t vlsint32_t; ///< 32-bit signed type
|
||||||
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
|
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
|
||||||
# else // Older Cygwin has long==uint32_t
|
# else // Older Cygwin has long==uint32_t
|
||||||
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||||
typedef long vlsint32_t; ///< 32-bit signed type
|
typedef long vlsint32_t; ///< 32-bit signed type
|
||||||
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
|
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
|
||||||
# endif
|
# endif
|
||||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||||
typedef long vlsint64_t; ///< 64-bit signed type
|
typedef long vlsint64_t; ///< 64-bit signed type
|
||||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||||
# else
|
# else
|
||||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#elif defined(_WIN32) && defined(_MSC_VER)
|
#elif defined(_WIN32) && defined(_MSC_VER)
|
||||||
|
|
||||||
typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||||
typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||||
typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||||
typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type
|
typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type
|
||||||
typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type
|
typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type
|
||||||
typedef signed __int32 vlsint32_t; ///< 32-bit signed type
|
typedef signed __int32 vlsint32_t; ///< 32-bit signed type
|
||||||
typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
|
typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
|
||||||
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
|
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
|
||||||
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
|
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
|
||||||
|
|
||||||
# ifndef _SSIZE_T_DEFINED
|
# ifndef _SSIZE_T_DEFINED
|
||||||
# ifdef _WIN64
|
# ifdef _WIN64
|
||||||
@@ -253,16 +249,16 @@ typedef signed __int32 ssize_t; ///< signed size_t; returned fro
|
|||||||
# include <stdint.h> // Linux and most flavors
|
# include <stdint.h> // Linux and most flavors
|
||||||
# include <sys/types.h> // __WORDSIZE
|
# include <sys/types.h> // __WORDSIZE
|
||||||
# include <unistd.h> // ssize_t
|
# include <unistd.h> // ssize_t
|
||||||
typedef uint8_t vluint8_t; ///< 32-bit unsigned type
|
typedef uint8_t vluint8_t; ///< 32-bit unsigned type
|
||||||
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
|
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
|
||||||
typedef int vlsint32_t; ///< 32-bit signed type
|
typedef int vlsint32_t; ///< 32-bit signed type
|
||||||
typedef uint32_t vluint32_t; ///< 32-bit signed type
|
typedef uint32_t vluint32_t; ///< 32-bit signed type
|
||||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||||
typedef long vlsint64_t; ///< 64-bit signed type
|
typedef long vlsint64_t; ///< 64-bit signed type
|
||||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||||
# else
|
# else
|
||||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -270,10 +266,14 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||||||
// Printing printf/scanf formats
|
// Printing printf/scanf formats
|
||||||
// Alas cinttypes isn't that standard yet
|
// Alas cinttypes isn't that standard yet
|
||||||
|
|
||||||
#ifdef _WIN32
|
// Use Microsoft-specific format specifiers for Microsoft Visual C++ only
|
||||||
# define __STDC_FORMAT_MACROS 1 // Otherwise MinGW doesn't get PRId64 for fstapi.c
|
#ifdef _MSC_VER
|
||||||
# define VL_PRI64 "I64"
|
# define VL_PRI64 "I64"
|
||||||
#else // Linux or compliant Unix flavors
|
#else // use standard C99 format specifiers
|
||||||
|
# ifdef __MINGW32__
|
||||||
|
# define __USE_MINGW_ANSI_STDIO 1 // Force old MinGW (GCC 5 and older) to use C99 formats
|
||||||
|
# define __STDC_FORMAT_MACROS 1 // Otherwise MinGW doesn't get PRId64 for fstapi.c
|
||||||
|
# endif
|
||||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||||
# define VL_PRI64 "l"
|
# define VL_PRI64 "l"
|
||||||
# else
|
# else
|
||||||
@@ -305,11 +305,11 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Integer size macros
|
// Integer size macros
|
||||||
|
|
||||||
#define VL_BYTESIZE 8 ///< Bits in a byte
|
#define VL_BYTESIZE 8 ///< Bits in a byte
|
||||||
#define VL_SHORTSIZE 16 ///< Bits in a short
|
#define VL_SHORTSIZE 16 ///< Bits in a short
|
||||||
#define VL_WORDSIZE 32 ///< Bits in a word
|
#define VL_WORDSIZE 32 ///< Bits in a word
|
||||||
#define VL_QUADSIZE 64 ///< Bits in a quadword
|
#define VL_QUADSIZE 64 ///< Bits in a quadword
|
||||||
#define VL_WORDSIZE_LOG2 5 ///< log2(VL_WORDSIZE)
|
#define VL_WORDSIZE_LOG2 5 ///< log2(VL_WORDSIZE)
|
||||||
|
|
||||||
/// Bytes this number of bits needs (1 bit=1 byte)
|
/// Bytes this number of bits needs (1 bit=1 byte)
|
||||||
#define VL_BYTES_I(nbits) (((nbits)+(VL_BYTESIZE-1))/VL_BYTESIZE)
|
#define VL_BYTES_I(nbits) (((nbits)+(VL_BYTESIZE-1))/VL_BYTESIZE)
|
||||||
@@ -327,21 +327,21 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Verilated function size macros
|
// Verilated function size macros
|
||||||
|
|
||||||
#define VL_MULS_MAX_WORDS 16 ///< Max size in words of MULS operation
|
#define VL_MULS_MAX_WORDS 16 ///< Max size in words of MULS operation
|
||||||
#define VL_TO_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
|
#define VL_TO_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Base macros
|
// Base macros
|
||||||
|
|
||||||
#define VL_SIZEBITS_I (VL_WORDSIZE-1) ///< Bit mask for bits in a word
|
#define VL_SIZEBITS_I (VL_WORDSIZE-1) ///< Bit mask for bits in a word
|
||||||
#define VL_SIZEBITS_Q (VL_QUADSIZE-1) ///< Bit mask for bits in a quad
|
#define VL_SIZEBITS_Q (VL_QUADSIZE-1) ///< Bit mask for bits in a quad
|
||||||
|
|
||||||
/// Mask for words with 1's where relevant bits are (0=all bits)
|
/// Mask for words with 1's where relevant bits are (0=all bits)
|
||||||
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) \
|
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) \
|
||||||
? ((1U << ((nbits) & VL_SIZEBITS_I) )-1) : ~0)
|
? ((1U << ((nbits) & VL_SIZEBITS_I) )-1) : ~0)
|
||||||
/// Mask for quads with 1's where relevant bits are (0=all bits)
|
/// Mask for quads with 1's where relevant bits are (0=all bits)
|
||||||
#define VL_MASK_Q(nbits) (((nbits) & VL_SIZEBITS_Q) \
|
#define VL_MASK_Q(nbits) (((nbits) & VL_SIZEBITS_Q) \
|
||||||
? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q) )-VL_ULL(1)) : VL_ULL(~0))
|
? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q) )-VL_ULL(1)) : VL_ULL(~0))
|
||||||
#define VL_BITWORD_I(bit) ((bit)/VL_WORDSIZE) ///< Word number for a wide quantity
|
#define VL_BITWORD_I(bit) ((bit)/VL_WORDSIZE) ///< Word number for a wide quantity
|
||||||
#define VL_BITBIT_I(bit) ((bit)&VL_SIZEBITS_I) ///< Bit number for a bit in a long
|
#define VL_BITBIT_I(bit) ((bit)&VL_SIZEBITS_I) ///< Bit number for a bit in a long
|
||||||
#define VL_BITBIT_Q(bit) ((bit)&VL_SIZEBITS_Q) ///< Bit number for a bit in a quad
|
#define VL_BITBIT_Q(bit) ((bit)&VL_SIZEBITS_Q) ///< Bit number for a bit in a quad
|
||||||
|
|||||||
+18
-18
@@ -23,9 +23,9 @@ our $Debug;
|
|||||||
our $Opt_Unsup;
|
our $Opt_Unsup;
|
||||||
|
|
||||||
if (! GetOptions (
|
if (! GetOptions (
|
||||||
#"help" => \&usage,
|
#"help" => \&usage,
|
||||||
"debug" => sub { $Debug = 1; },
|
"debug" => sub { $Debug = 1; },
|
||||||
"unsup!" => \$Opt_Unsup, # Ignore unsupported
|
"unsup!" => \$Opt_Unsup, # Ignore unsupported
|
||||||
)) {
|
)) {
|
||||||
die "usage();"
|
die "usage();"
|
||||||
}
|
}
|
||||||
@@ -59,24 +59,24 @@ sub prep {
|
|||||||
my $rule = "";
|
my $rule = "";
|
||||||
my $skip = 1;
|
my $skip = 1;
|
||||||
while (defined(my $line = $fh->getline)) {
|
while (defined(my $line = $fh->getline)) {
|
||||||
if ($skip == 1) {
|
if ($skip == 1) {
|
||||||
next if $line !~ /%token/;
|
next if $line !~ /%token/;
|
||||||
$skip = 2;
|
$skip = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Opt_Unsup) {
|
if ($Opt_Unsup) {
|
||||||
$line =~ s!//UNSUP!|!g;
|
$line =~ s!//UNSUP!|!g;
|
||||||
$line =~ s!(\s+)\|(\s+)!$1$2!g; # As "UNSUP" often replaces "|"
|
$line =~ s!(\s+)\|(\s+)!$1$2!g; # As "UNSUP" often replaces "|"
|
||||||
}
|
}
|
||||||
|
|
||||||
# %type<foo>
|
# %type<foo>
|
||||||
$line =~ s/^(%\S+)<(\S+)>/$1/;
|
$line =~ s/^(%\S+)<(\S+)>/$1/;
|
||||||
# rule<foo>
|
# rule<foo>
|
||||||
$line =~ s/^([a-zA-Z0-9_]+)<\S+>:/$1:/;
|
$line =~ s/^([a-zA-Z0-9_]+)<\S+>:/$1:/;
|
||||||
# Productions
|
# Productions
|
||||||
$line =~ s/[ \t]{[^}]*?}/\t{}/g;
|
$line =~ s/[ \t]{[^}]*?}/\t{}/g;
|
||||||
|
|
||||||
$fho->print($line);
|
$fho->print($line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-20
@@ -32,27 +32,27 @@ foreach my $line (<STDIN>) {
|
|||||||
$line =~ s!\s+! !g;
|
$line =~ s!\s+! !g;
|
||||||
next if $line eq '';
|
next if $line eq '';
|
||||||
if ($line =~ m!^\%\%!) {
|
if ($line =~ m!^\%\%!) {
|
||||||
$body++;
|
$body++;
|
||||||
} elsif ($body == 1) {
|
} elsif ($body == 1) {
|
||||||
$rule .= $line;
|
$rule .= $line;
|
||||||
if ($line =~ m!^\s*;\s*$!) {
|
if ($line =~ m!^\s*;\s*$!) {
|
||||||
#print "Rule: $rule\n";
|
#print "Rule: $rule\n";
|
||||||
($rule =~ /^([a-zA-Z0-9_]+)(<\S+>)?:(.*)$/) or die "%Error: No rule name: $1\n";
|
($rule =~ /^([a-zA-Z0-9_]+)(<\S+>)?:(.*)$/) or die "%Error: No rule name: $1\n";
|
||||||
my $rulename = $1; my $preaction = $3;
|
my $rulename = $1; my $preaction = $3;
|
||||||
$declared{$rulename} = $lineno;
|
$declared{$rulename} = $lineno;
|
||||||
$preaction =~ s/\{[^\}]*\}/ /g;
|
$preaction =~ s/\{[^\}]*\}/ /g;
|
||||||
#print "RULEN $rulename PA $preaction\n" if $Debug;
|
#print "RULEN $rulename PA $preaction\n" if $Debug;
|
||||||
$rule = '';
|
$rule = '';
|
||||||
foreach my $ref (split /\s+/, $preaction) {
|
foreach my $ref (split /\s+/, $preaction) {
|
||||||
next if $ref !~ /^[a-zA-Z]/;
|
next if $ref !~ /^[a-zA-Z]/;
|
||||||
next if $ref eq $rulename;
|
next if $ref eq $rulename;
|
||||||
if (!$used{$ref} && $declared{$ref}) {
|
if (!$used{$ref} && $declared{$ref}) {
|
||||||
print " %Warning: $lineno: $ref used by $rulename after declaration\n";
|
print " %Warning: $lineno: $ref used by $rulename after declaration\n";
|
||||||
}
|
}
|
||||||
$used{$ref} = $lineno;
|
$used{$ref} = $lineno;
|
||||||
print " ref $ref\n" if $Debug;
|
print " ref $ref\n" if $Debug;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+36
-36
@@ -24,11 +24,11 @@ $Debug = 0;
|
|||||||
my $opt_filename;
|
my $opt_filename;
|
||||||
autoflush STDOUT 1;
|
autoflush STDOUT 1;
|
||||||
autoflush STDERR 1;
|
autoflush STDERR 1;
|
||||||
if (! GetOptions (
|
if (! GetOptions(
|
||||||
"help" => \&usage,
|
"help" => \&usage,
|
||||||
"debug" => \&debug,
|
"debug" => \&debug,
|
||||||
"<>" => \¶meter,
|
"<>" => \¶meter,
|
||||||
)) {
|
)) {
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,9 +49,9 @@ sub debug {
|
|||||||
sub parameter {
|
sub parameter {
|
||||||
my $param = shift;
|
my $param = shift;
|
||||||
if (!$opt_filename) {
|
if (!$opt_filename) {
|
||||||
$opt_filename = $param;
|
$opt_filename = $param;
|
||||||
} else {
|
} else {
|
||||||
die "%Error: Unknown parameter: $param\n";
|
die "%Error: Unknown parameter: $param\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,30 +64,30 @@ sub dotread {
|
|||||||
my $header = 1;
|
my $header = 1;
|
||||||
my $vnum = 0;
|
my $vnum = 0;
|
||||||
while (defined (my $line = $fh->getline)) {
|
while (defined (my $line = $fh->getline)) {
|
||||||
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
|
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
|
||||||
next if $1 eq 'nTITLE';
|
next if $1 eq 'nTITLE';
|
||||||
$header = 0;
|
$header = 0;
|
||||||
$Vertexes{$1} = {num => $vnum++,
|
$Vertexes{$1} = {num => $vnum++,
|
||||||
line => $line,
|
line => $line,
|
||||||
name => $1,};
|
name => $1,};
|
||||||
}
|
}
|
||||||
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
|
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
|
||||||
my $from=$1; my $to=$2;
|
my $from=$1; my $to=$2;
|
||||||
my $weight = 1; $weight = $1 if $line =~ /weight=(\d+)/;
|
my $weight = 1; $weight = $1 if $line =~ /weight=(\d+)/;
|
||||||
my $cutable = undef; $cutable = $1 if $line =~ /style=(\S+)/;
|
my $cutable = undef; $cutable = $1 if $line =~ /style=(\S+)/;
|
||||||
my $edge = {num => $vnum++,
|
my $edge = {num => $vnum++,
|
||||||
line => $line,
|
line => $line,
|
||||||
weight => $weight,
|
weight => $weight,
|
||||||
cutable => $cutable,
|
cutable => $cutable,
|
||||||
from => $from,
|
from => $from,
|
||||||
to => $to,};
|
to => $to,};
|
||||||
push @Edges, $edge;
|
push @Edges, $edge;
|
||||||
$Edges{$from}{$to} = $edge;
|
$Edges{$from}{$to} = $edge;
|
||||||
}
|
}
|
||||||
elsif ($header) {
|
elsif ($header) {
|
||||||
push @Header, $line;
|
push @Header, $line;
|
||||||
print "IGNORE: $line";
|
print "IGNORE: $line";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,14 +100,14 @@ sub cwrite {
|
|||||||
$fh->print("void V3GraphTestImport::dotImport() {\n");
|
$fh->print("void V3GraphTestImport::dotImport() {\n");
|
||||||
$fh->print(" DfaGraph* gp = &m_graph;\n");
|
$fh->print(" DfaGraph* gp = &m_graph;\n");
|
||||||
foreach my $ver (sort {$a->{num} <=> $b->{num}} (values %Vertexes)) {
|
foreach my $ver (sort {$a->{num} <=> $b->{num}} (values %Vertexes)) {
|
||||||
$fh->printf(" V3GraphTestVertex* %s = new V3GraphTestVertex(gp, \"%s\"); if (%s) {}\n",
|
$fh->printf(" V3GraphTestVertex* %s = new V3GraphTestVertex(gp, \"%s\"); if (%s) {}\n",
|
||||||
$ver->{name}, $ver->{name}, $ver->{name});
|
$ver->{name}, $ver->{name}, $ver->{name});
|
||||||
}
|
}
|
||||||
$fh->print("\n");
|
$fh->print("\n");
|
||||||
foreach my $edge (@Edges) {
|
foreach my $edge (@Edges) {
|
||||||
$fh->printf(" new V3GraphEdge(gp, %s, %s, %s, %s);\n",
|
$fh->printf(" new V3GraphEdge(gp, %s, %s, %s, %s);\n",
|
||||||
$edge->{from}, $edge->{to},
|
$edge->{from}, $edge->{to},
|
||||||
$edge->{weight}, $edge->{cutable}?"true":"false");
|
$edge->{weight}, $edge->{cutable}?"true":"false");
|
||||||
}
|
}
|
||||||
$fh->print("}\n");
|
$fh->print("}\n");
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-35
@@ -26,12 +26,12 @@ my $opt_filename;
|
|||||||
my $opt_circle;
|
my $opt_circle;
|
||||||
autoflush STDOUT 1;
|
autoflush STDOUT 1;
|
||||||
autoflush STDERR 1;
|
autoflush STDERR 1;
|
||||||
if (! GetOptions (
|
if (! GetOptions(
|
||||||
"help" => \&usage,
|
"help" => \&usage,
|
||||||
"debug" => \&debug,
|
"debug" => \&debug,
|
||||||
"<>" => \¶meter,
|
"<>" => \¶meter,
|
||||||
"circle=s" => \$opt_circle,
|
"circle=s" => \$opt_circle,
|
||||||
)) {
|
)) {
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,9 +54,9 @@ sub debug {
|
|||||||
sub parameter {
|
sub parameter {
|
||||||
my $param = shift;
|
my $param = shift;
|
||||||
if (!$opt_filename) {
|
if (!$opt_filename) {
|
||||||
$opt_filename = $param;
|
$opt_filename = $param;
|
||||||
} else {
|
} else {
|
||||||
die "%Error: Unknown parameter: $param\n";
|
die "%Error: Unknown parameter: $param\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,16 +68,16 @@ sub dotread {
|
|||||||
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
||||||
my $header = 1;
|
my $header = 1;
|
||||||
while (defined (my $line = $fh->getline)) {
|
while (defined (my $line = $fh->getline)) {
|
||||||
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
|
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
|
||||||
$header = 0;
|
$header = 0;
|
||||||
$Vertexes{$1} = $2;
|
$Vertexes{$1} = $2;
|
||||||
}
|
}
|
||||||
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
|
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
|
||||||
$Edges{$1}{$2} = $3;
|
$Edges{$1}{$2} = $3;
|
||||||
}
|
}
|
||||||
elsif ($header) {
|
elsif ($header) {
|
||||||
push @Header, $line;
|
push @Header, $line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,12 +85,12 @@ sub dotread {
|
|||||||
|
|
||||||
sub simplify {
|
sub simplify {
|
||||||
foreach my $ver (sort (keys %Vertexes)) {
|
foreach my $ver (sort (keys %Vertexes)) {
|
||||||
$Vertexes{$ver} = _simplify($Vertexes{$ver});
|
$Vertexes{$ver} = _simplify($Vertexes{$ver});
|
||||||
}
|
}
|
||||||
foreach my $v1 (sort (keys %Edges)) {
|
foreach my $v1 (sort (keys %Edges)) {
|
||||||
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
|
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
|
||||||
$Edges{$v1}{$v2} = _simplify($Edges{$v1}{$v2});
|
$Edges{$v1}{$v2} = _simplify($Edges{$v1}{$v2});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,15 +103,15 @@ sub _simplify {
|
|||||||
|
|
||||||
sub dotwrite {
|
sub dotwrite {
|
||||||
foreach my $line (@Header) {
|
foreach my $line (@Header) {
|
||||||
print "$line";
|
print "$line";
|
||||||
}
|
}
|
||||||
foreach my $ver (sort (keys %Vertexes)) {
|
foreach my $ver (sort (keys %Vertexes)) {
|
||||||
print "\t$ver\t$Vertexes{$ver}\n";
|
print "\t$ver\t$Vertexes{$ver}\n";
|
||||||
}
|
}
|
||||||
foreach my $v1 (sort (keys %Edges)) {
|
foreach my $v1 (sort (keys %Edges)) {
|
||||||
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
|
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
|
||||||
print "\t$v1 -> $v2\t$Edges{$v1}{$v2}\n";
|
print "\t$v1 -> $v2\t$Edges{$v1}{$v2}\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print "}\n";
|
print "}\n";
|
||||||
}
|
}
|
||||||
@@ -125,15 +125,15 @@ sub circle {
|
|||||||
_circle_recurse($node, 1);
|
_circle_recurse($node, 1);
|
||||||
|
|
||||||
foreach my $ver (keys %Vertexes) {
|
foreach my $ver (keys %Vertexes) {
|
||||||
if (!$User{$ver}) {
|
if (!$User{$ver}) {
|
||||||
delete $Vertexes{$ver};
|
delete $Vertexes{$ver};
|
||||||
delete $Edges{$ver};
|
delete $Edges{$ver};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach my $v1 (sort (keys %Edges)) {
|
foreach my $v1 (sort (keys %Edges)) {
|
||||||
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
|
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
|
||||||
if (!$Vertexes{$v2}) { delete $Edges{$v1}{$v2}; }
|
if (!$Vertexes{$v2}) { delete $Edges{$v1}{$v2}; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ sub _circle_recurse {
|
|||||||
$User2{$node} = 1;
|
$User2{$node} = 1;
|
||||||
my $r = 0;
|
my $r = 0;
|
||||||
foreach my $v2 (keys %{$Edges{$node}}) {
|
foreach my $v2 (keys %{$Edges{$node}}) {
|
||||||
$r |= _circle_recurse($v2,$level++)||0;
|
$r |= _circle_recurse($v2,$level++)||0;
|
||||||
}
|
}
|
||||||
$User{$node} = 1 if $r;
|
$User{$node} = 1 if $r;
|
||||||
$User2{$node} = 2;
|
$User2{$node} = 2;
|
||||||
|
|||||||
+51
-51
@@ -18,11 +18,11 @@ our $Opt_Jobs = calc_jobs();
|
|||||||
autoflush STDOUT 1;
|
autoflush STDOUT 1;
|
||||||
autoflush STDERR 1;
|
autoflush STDERR 1;
|
||||||
Getopt::Long::config("no_auto_abbrev");
|
Getopt::Long::config("no_auto_abbrev");
|
||||||
if (! GetOptions (
|
if (! GetOptions(
|
||||||
"debug" => sub { $Debug = 1; },
|
"debug" => sub { $Debug = 1; },
|
||||||
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
|
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
|
||||||
"stage=i" => \$Opt_Stage,
|
"stage=i" => \$Opt_Stage,
|
||||||
"j=i" => \$Opt_Jobs,
|
"j=i" => \$Opt_Jobs,
|
||||||
)) {
|
)) {
|
||||||
die "%Error: Bad usage, try 'install_test --help'\n";
|
die "%Error: Bad usage, try 'install_test --help'\n";
|
||||||
}
|
}
|
||||||
@@ -46,51 +46,51 @@ sub test {
|
|||||||
my $testdirn= $srcdir."/test_regress/obj_dir/install_test_testn";
|
my $testdirn= $srcdir."/test_regress/obj_dir/install_test_testn";
|
||||||
|
|
||||||
if ($Opt_Stage <= 0) {
|
if ($Opt_Stage <= 0) {
|
||||||
run("/bin/rm -rf $blddir");
|
run("/bin/rm -rf $blddir");
|
||||||
run("/bin/mkdir -p $blddir");
|
run("/bin/mkdir -p $blddir");
|
||||||
run("cd $blddir && $srcdir/configure --prefix $prefix");
|
run("cd $blddir && $srcdir/configure --prefix $prefix");
|
||||||
run("cd $blddir && make -j $Opt_Jobs");
|
run("cd $blddir && make -j $Opt_Jobs");
|
||||||
}
|
}
|
||||||
|
|
||||||
# Install it under the prefix
|
# Install it under the prefix
|
||||||
if ($Opt_Stage <= 1) {
|
if ($Opt_Stage <= 1) {
|
||||||
run("/bin/rm -rf $prefix");
|
run("/bin/rm -rf $prefix");
|
||||||
run("/bin/mkdir -p $prefix");
|
run("/bin/mkdir -p $prefix");
|
||||||
run("cd $blddir && make install");
|
run("cd $blddir && make install");
|
||||||
run("test -e $prefix/share/man/man1/verilator.1");
|
run("test -e $prefix/share/man/man1/verilator.1");
|
||||||
run("test -e $prefix/share/verilator/examples/tracing_c/Makefile");
|
run("test -e $prefix/share/verilator/examples/tracing_c/Makefile");
|
||||||
run("test -e $prefix/share/verilator/include/verilated.h");
|
run("test -e $prefix/share/verilator/include/verilated.h");
|
||||||
run("test -e $prefix/bin/verilator");
|
run("test -e $prefix/bin/verilator");
|
||||||
run("test -e $prefix/bin/verilator_bin");
|
run("test -e $prefix/bin/verilator_bin");
|
||||||
run("test -e $prefix/bin/verilator_bin_dbg");
|
run("test -e $prefix/bin/verilator_bin_dbg");
|
||||||
run("test -e $prefix/bin/verilator_gantt");
|
run("test -e $prefix/bin/verilator_gantt");
|
||||||
run("test -e $prefix/bin/verilator_profcfunc");
|
run("test -e $prefix/bin/verilator_profcfunc");
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run a test using just the path
|
# Run a test using just the path
|
||||||
if ($Opt_Stage <= 2) {
|
if ($Opt_Stage <= 2) {
|
||||||
my $dir = $testdirp;
|
my $dir = $testdirp;
|
||||||
run("/bin/rm -rf $dir");
|
run("/bin/rm -rf $dir");
|
||||||
run("/bin/mkdir -p $dir");
|
run("/bin/mkdir -p $dir");
|
||||||
my $bin1 = $prefix."/bin";
|
my $bin1 = $prefix."/bin";
|
||||||
my $bin2 = $prefix."/share/bin";
|
my $bin2 = $prefix."/share/bin";
|
||||||
write_verilog($dir);
|
write_verilog($dir);
|
||||||
run("cd $dir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v --exe foo.cpp");
|
run("cd $dir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v --exe foo.cpp");
|
||||||
run("cd $dir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
|
run("cd $dir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
|
||||||
run("cd $dir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
|
run("cd $dir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run a test using exact path to binary
|
# Run a test using exact path to binary
|
||||||
if ($Opt_Stage <= 3) {
|
if ($Opt_Stage <= 3) {
|
||||||
my $dir = $testdirn;
|
my $dir = $testdirn;
|
||||||
run("/bin/rm -rf $dir");
|
run("/bin/rm -rf $dir");
|
||||||
run("/bin/mkdir -p $dir");
|
run("/bin/mkdir -p $dir");
|
||||||
write_verilog($dir);
|
write_verilog($dir);
|
||||||
my $bin1 = $prefix."/bin";
|
my $bin1 = $prefix."/bin";
|
||||||
my $bin2 = $prefix."/share/bin";
|
my $bin2 = $prefix."/share/bin";
|
||||||
run("cd $dir && $bin1/verilator --cc foo.v --exe foo.cpp");
|
run("cd $dir && $bin1/verilator --cc foo.v --exe foo.cpp");
|
||||||
run("cd $dir/obj_dir && make -f Vfoo.mk");
|
run("cd $dir/obj_dir && make -f Vfoo.mk");
|
||||||
run("cd $dir/obj_dir && ./Vfoo");
|
run("cd $dir/obj_dir && ./Vfoo");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Opt_Stage <= 9) {
|
if ($Opt_Stage <= 9) {
|
||||||
@@ -102,29 +102,29 @@ sub write_verilog {
|
|||||||
my $dir = shift;
|
my $dir = shift;
|
||||||
IO::File->new(">$dir/foo.v")->print('module t; initial begin $display("HELLO WORLD"); $finish; end endmodule'."\n");
|
IO::File->new(">$dir/foo.v")->print('module t; initial begin $display("HELLO WORLD"); $finish; end endmodule'."\n");
|
||||||
my $fh = IO::File->new(">$dir/foo.cpp");
|
my $fh = IO::File->new(">$dir/foo.cpp");
|
||||||
$fh->print('#include "Vfoo.h"' ,"\n");
|
$fh->print('#include "Vfoo.h"' ,"\n");
|
||||||
$fh->print('unsigned int main_time = 0;' ,"\n");
|
$fh->print('unsigned int main_time = 0;' ,"\n");
|
||||||
$fh->print('double sc_time_stamp() {' ,"\n");
|
$fh->print('double sc_time_stamp() {' ,"\n");
|
||||||
$fh->print(' return main_time;' ,"\n");
|
$fh->print(' return main_time;' ,"\n");
|
||||||
$fh->print('}' ,"\n");
|
$fh->print('}' ,"\n");
|
||||||
$fh->print('int main() {' ,"\n");
|
$fh->print('int main() {' ,"\n");
|
||||||
$fh->print(' Vfoo *top = new Vfoo;' ,"\n");
|
$fh->print(' Vfoo *top = new Vfoo;' ,"\n");
|
||||||
$fh->print(' while (!Verilated::gotFinish()) {',"\n");
|
$fh->print(' while (!Verilated::gotFinish()) {',"\n");
|
||||||
$fh->print(' top->eval();' ,"\n");
|
$fh->print(' top->eval();' ,"\n");
|
||||||
$fh->print(' main_time++;' ,"\n");
|
$fh->print(' main_time++;' ,"\n");
|
||||||
$fh->print(' }' ,"\n");
|
$fh->print(' }' ,"\n");
|
||||||
$fh->print(' top->final();' ,"\n");
|
$fh->print(' top->final();' ,"\n");
|
||||||
$fh->print('}' ,"\n");
|
$fh->print('}' ,"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
sub cleanenv {
|
sub cleanenv {
|
||||||
foreach my $var (keys %ENV) {
|
foreach my $var (keys %ENV) {
|
||||||
if ($var eq "VERILATOR_ROOT"
|
if ($var eq "VERILATOR_ROOT"
|
||||||
|| $var eq "VERILATOR_INCLUDE"
|
|| $var eq "VERILATOR_INCLUDE"
|
||||||
|| $var eq "VERILATOR_NO_OPT_BUILD") {
|
|| $var eq "VERILATOR_NO_OPT_BUILD") {
|
||||||
print "unset $var # Was '$ENV{$var}'\n";
|
print "unset $var # Was '$ENV{$var}'\n";
|
||||||
delete $ENV{$var}
|
delete $ENV{$var}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,8 +132,8 @@ sub cleanenv {
|
|||||||
|
|
||||||
sub calc_jobs {
|
sub calc_jobs {
|
||||||
my $ok = eval "
|
my $ok = eval "
|
||||||
use Unix::Processors;
|
use Unix::Processors;
|
||||||
return Unix::Processors->new->max_online;
|
return Unix::Processors->new->max_online;
|
||||||
";
|
";
|
||||||
$ok && !$@ or return 1;
|
$ok && !$@ or return 1;
|
||||||
print "driver.pl: Found $ok cores, using -j ",$ok+1,"\n" if $Debug;
|
print "driver.pl: Found $ok cores, using -j ",$ok+1,"\n" if $Debug;
|
||||||
|
|||||||
+143
-143
@@ -23,11 +23,11 @@ $Debug = 0;
|
|||||||
my $opt_filename;
|
my $opt_filename;
|
||||||
autoflush STDOUT 1;
|
autoflush STDOUT 1;
|
||||||
autoflush STDERR 1;
|
autoflush STDERR 1;
|
||||||
if (! GetOptions (
|
if (! GetOptions(
|
||||||
"help" => \&usage,
|
"help" => \&usage,
|
||||||
"debug" => \&debug,
|
"debug" => \&debug,
|
||||||
"<>" => \¶meter,
|
"<>" => \¶meter,
|
||||||
)) {
|
)) {
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,9 +51,9 @@ sub debug {
|
|||||||
sub parameter {
|
sub parameter {
|
||||||
my $param = shift;
|
my $param = shift;
|
||||||
if (!$opt_filename) {
|
if (!$opt_filename) {
|
||||||
$opt_filename = $param;
|
$opt_filename = $param;
|
||||||
} else {
|
} else {
|
||||||
die "%Error: Unknown parameter: $param\n";
|
die "%Error: Unknown parameter: $param\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,45 +64,45 @@ sub vread {
|
|||||||
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
||||||
my $lasthier="";
|
my $lasthier="";
|
||||||
$Tree = {
|
$Tree = {
|
||||||
op => 'NETLIST',
|
op => 'NETLIST',
|
||||||
t => [[],[],[],[],[],],
|
t => [[],[],[],[],[],],
|
||||||
};
|
};
|
||||||
my @stack;
|
my @stack;
|
||||||
$stack[1] = $Tree;
|
$stack[1] = $Tree;
|
||||||
while (defined (my $line = $fh->getline)) {
|
while (defined (my $line = $fh->getline)) {
|
||||||
if ($line =~ /^\s+(\S+):\s+(\S+)\s+0x\S+\s+{(\d+)}\s+w(\d+)\s+(.*)$/) {
|
if ($line =~ /^\s+(\S+):\s+(\S+)\s+0x\S+\s+{(\d+)}\s+w(\d+)\s+(.*)$/) {
|
||||||
my $hier = $1;
|
my $hier = $1;
|
||||||
my $op = $2;
|
my $op = $2;
|
||||||
my $lineno = $3;
|
my $lineno = $3;
|
||||||
my $width = $4;
|
my $width = $4;
|
||||||
my $etc = $5;
|
my $etc = $5;
|
||||||
|
|
||||||
$etc =~ s/__DOT__/./g;
|
$etc =~ s/__DOT__/./g;
|
||||||
$etc =~ s/__PVT__//g;
|
$etc =~ s/__PVT__//g;
|
||||||
|
|
||||||
my $self = {
|
my $self = {
|
||||||
op => $op,
|
op => $op,
|
||||||
#width => $width,
|
#width => $width,
|
||||||
#lineno => $lineno,
|
#lineno => $lineno,
|
||||||
#line => $line,
|
#line => $line,
|
||||||
etc => $etc,
|
etc => $etc,
|
||||||
args => [split(/[ \t]+/,$etc)],
|
args => [split(/[ \t]+/,$etc)],
|
||||||
t => [[],[],[],[],[],],
|
t => [[],[],[],[],[],],
|
||||||
};
|
};
|
||||||
|
|
||||||
my @hiers = (1,split(/:/,$hier));
|
my @hiers = (1,split(/:/,$hier));
|
||||||
my $depth = $#hiers+1;
|
my $depth = $#hiers+1;
|
||||||
my $newchild = $hiers[$#hiers];
|
my $newchild = $hiers[$#hiers];
|
||||||
|
|
||||||
#print "DD $depth $newchild $op\n";
|
#print "DD $depth $newchild $op\n";
|
||||||
|
|
||||||
push @{$stack[$depth-1]->{t}[$newchild]}, $self;
|
push @{$stack[$depth-1]->{t}[$newchild]}, $self;
|
||||||
$stack[$depth] = $self;
|
$stack[$depth] = $self;
|
||||||
|
|
||||||
$lasthier = $hier;
|
$lasthier = $hier;
|
||||||
#print " $lasthier\n";
|
#print " $lasthier\n";
|
||||||
#print Dumper($Tree);
|
#print Dumper($Tree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,125 +168,125 @@ sub nl { p "\n"," "x$Indent; }
|
|||||||
|
|
||||||
sub gentree {
|
sub gentree {
|
||||||
%OpMap = (
|
%OpMap = (
|
||||||
'NULLNODE' => sub { "" },
|
'NULLNODE' => sub { "" },
|
||||||
'NETLIST' => sub { nl;t1;t2;t3;t4;t5; },
|
'NETLIST' => sub { nl;t1;t2;t3;t4;t5; },
|
||||||
'ACTIVE' => sub { p "always_act @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
|
'ACTIVE' => sub { p "always_act @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
|
||||||
'ADD' => sub { p1;p " + ";p2; },
|
'ADD' => sub { p1;p " + ";p2; },
|
||||||
'ALWAYS' => sub { p "always @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
|
'ALWAYS' => sub { p "always @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
|
||||||
'ALWAYSPOST' => sub { p "ALWAYSPOST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'ALWAYSPOST' => sub { p "ALWAYSPOST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'AND' => sub { p1;p " & ";p2; },
|
'AND' => sub { p1;p " & ";p2; },
|
||||||
'ARRAYSEL' => sub { t1;p "[";t2;p "]"; },
|
'ARRAYSEL' => sub { t1;p "[";t2;p "]"; },
|
||||||
'ASSIGN' => sub { t2;p " = ";t1;p ";";nl; },
|
'ASSIGN' => sub { t2;p " = ";t1;p ";";nl; },
|
||||||
'ASSIGNDLY' => sub { t2;p " <= ";t1;p ";";nl; },
|
'ASSIGNDLY' => sub { t2;p " <= ";t1;p ";";nl; },
|
||||||
'ASSIGNPOST' => sub { p "ASSIGNPOST what{";t1;p " = ";t2;p ";";nl; },
|
'ASSIGNPOST' => sub { p "ASSIGNPOST what{";t1;p " = ";t2;p ";";nl; },
|
||||||
'ASSIGNPRE' => sub { p "ASSIGNPRE what{";t1;p " = ";t2;p ";";nl; },
|
'ASSIGNPRE' => sub { p "ASSIGNPRE what{";t1;p " = ";t2;p ";";nl; },
|
||||||
'ASSIGNW' => sub { p "assign ";t2;p " = ";t1;p ";";nl; },
|
'ASSIGNW' => sub { p "assign ";t2;p " = ";t1;p ";";nl; },
|
||||||
'ATTROF' => sub { p "ATTROF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'ATTROF' => sub { p "ATTROF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'BEGIN' => sub { p "begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
|
'BEGIN' => sub { p "begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
|
||||||
'BITSEL' => sub { t1;local $Avoid_Hex=1; p "[";t2;p "]"; },
|
'BITSEL' => sub { t1;local $Avoid_Hex=1; p "[";t2;p "]"; },
|
||||||
'CASE' => sub { p "CASE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'CASE' => sub { p "CASE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'CASEITEM' => sub { p "CASEITEM what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'CASEITEM' => sub { p "CASEITEM what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'CAST' => sub { p "CAST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'CAST' => sub { p "CAST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'CCALL' => sub { p "CCALL what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'CCALL' => sub { p "CCALL what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'CELL' => sub { a1;p " ";a7;p " (/*CELL*/);"; nl; },
|
'CELL' => sub { a1;p " ";a7;p " (/*CELL*/);"; nl; },
|
||||||
'CFUNC' => sub { p "CFUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'CFUNC' => sub { p "CFUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'CHANGEDET' => sub { p "CHANGEDET what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'CHANGEDET' => sub { p "CHANGEDET what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'CINCLUDE' => sub { p "CINCLUDE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'CINCLUDE' => sub { p "CINCLUDE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'COMMENT' => sub { p "//COMMENT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl;nl; },
|
'COMMENT' => sub { p "//COMMENT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl;nl; },
|
||||||
'CONCAT' => sub { p "{";p1;p ",";p2;p "}"; },
|
'CONCAT' => sub { p "{";p1;p ",";p2;p "}"; },
|
||||||
'CONDITIONAL' => sub { p1;p " ? ";p2;p " : ";p3; },
|
'CONDITIONAL' => sub { p1;p " ? ";p2;p " : ";p3; },
|
||||||
'CONST' => sub { p_const(); },
|
'CONST' => sub { p_const(); },
|
||||||
'COVER' => sub { p "COVER what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'COVER' => sub { p "COVER what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'CRETURN' => sub { p "CRETURN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'CRETURN' => sub { p "CRETURN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'CSTMT' => sub { p "CSTMT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'CSTMT' => sub { p "CSTMT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'DEFPARAM' => sub { p "defparam ";p1;p " = ";p2;p ";";nl; },
|
'DEFPARAM' => sub { p "defparam ";p1;p " = ";p2;p ";";nl; },
|
||||||
'DISPLAY' => sub { p '$write("';p1;p "\",";p2;p3;p4;p5;p ");";nl; },
|
'DISPLAY' => sub { p '$write("';p1;p "\",";p2;p3;p4;p5;p ");";nl; },
|
||||||
'DIV' => sub { p1;p " / ";p2; },
|
'DIV' => sub { p1;p " / ";p2; },
|
||||||
'EQ' => sub { p1;p " == ";p2; },
|
'EQ' => sub { p1;p " == ";p2; },
|
||||||
'EQCASE' => sub { p1;p " === ";p2; },
|
'EQCASE' => sub { p1;p " === ";p2; },
|
||||||
'EXTEND' => sub { t1; },
|
'EXTEND' => sub { t1; },
|
||||||
'EXTRACT' => sub { t1;local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
|
'EXTRACT' => sub { t1;local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
|
||||||
'FINISH' => sub { p '$finish;';nl },
|
'FINISH' => sub { p '$finish;';nl },
|
||||||
'FOR' => sub { p "for (";p1;p ",";p2;p ",";p3;p ") begin";indentInc;nl;p4;p5;indentDec;p "end";nl; },
|
'FOR' => sub { p "for (";p1;p ",";p2;p ",";p3;p ") begin";indentInc;nl;p4;p5;indentDec;p "end";nl; },
|
||||||
'FUNC' => sub { p "FUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'FUNC' => sub { p "FUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'FUNCREF' => sub { p "FUNCREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'FUNCREF' => sub { p "FUNCREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'GT' => sub { p1;p " > ";p2; },
|
'GT' => sub { p1;p " > ";p2; },
|
||||||
'GTE' => sub { p1;p " >= ";p2; },
|
'GTE' => sub { p1;p " >= ";p2; },
|
||||||
'IF' => sub { p "if (";p1;p ") begin";indentInc;nl;t2;indentDec;if (exists3) {p "end else begin";indentInc;nl;t3;indentDec;} p "end"; nl; },
|
'IF' => sub { p "if (";p1;p ") begin";indentInc;nl;t2;indentDec;if (exists3) {p "end else begin";indentInc;nl;t3;indentDec;} p "end"; nl; },
|
||||||
'INITARRAY' => sub { p "INITARRAY what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'INITARRAY' => sub { p "INITARRAY what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'INITIAL' => sub { p "initial begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
|
'INITIAL' => sub { p "initial begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
|
||||||
'LOGAND' => sub { p1;p " && ";p2; },
|
'LOGAND' => sub { p1;p " && ";p2; },
|
||||||
'LOGNOT' => sub { p1;p " || ";p2; },
|
'LOGNOT' => sub { p1;p " || ";p2; },
|
||||||
'LOGOR' => sub { p "!";p1; },
|
'LOGOR' => sub { p "!";p1; },
|
||||||
'LT' => sub { p1;p " < ";p2; },
|
'LT' => sub { p1;p " < ";p2; },
|
||||||
'LTE' => sub { p1;p " <= ";p2; },
|
'LTE' => sub { p1;p " <= ";p2; },
|
||||||
'MODDIV' => sub { p1;p " % ";p2; },
|
'MODDIV' => sub { p1;p " % ";p2; },
|
||||||
'MODULE' => sub { p "module ";a1;p " (/*AUTOARG*/);";indentInc;nl;t1;t2;t3;t4;t5;indentDec;nl;p "endmodule";nl; },
|
'MODULE' => sub { p "module ";a1;p " (/*AUTOARG*/);";indentInc;nl;t1;t2;t3;t4;t5;indentDec;nl;p "endmodule";nl; },
|
||||||
'MUL' => sub { p1;p " * ";p2; },
|
'MUL' => sub { p1;p " * ";p2; },
|
||||||
'NEQ' => sub { p1;p " != ";p2; },
|
'NEQ' => sub { p1;p " != ";p2; },
|
||||||
'NEQCASE' => sub { p1;p " !== ";p2; },
|
'NEQCASE' => sub { p1;p " !== ";p2; },
|
||||||
'NOT' => sub { p " ~";p1; },
|
'NOT' => sub { p " ~";p1; },
|
||||||
'OR' => sub { p1;p " | ";p2; },
|
'OR' => sub { p1;p " | ";p2; },
|
||||||
'PIN' => sub { p ";p ";p1;p " (";p2;p "),";nl; },
|
'PIN' => sub { p ";p ";p1;p " (";p2;p "),";nl; },
|
||||||
'PORT' => sub { p ""; },
|
'PORT' => sub { p ""; },
|
||||||
'PRAGMA' => sub { p "PRAGMA what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'PRAGMA' => sub { p "PRAGMA what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'RAND' => sub { p '$rand'; },
|
'RAND' => sub { p '$rand'; },
|
||||||
'RANGE' => sub { t1; local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
|
'RANGE' => sub { t1; local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
|
||||||
'REDAND' => sub { p "&(";p1;p ")"; },
|
'REDAND' => sub { p "&(";p1;p ")"; },
|
||||||
'REDOR' => sub { p "|(";p1;p ")"; },
|
'REDOR' => sub { p "|(";p1;p ")"; },
|
||||||
'REDXNOR' => sub { p "~|(";p1;p ")"; },
|
'REDXNOR' => sub { p "~|(";p1;p ")"; },
|
||||||
'REDXOR' => sub { p "~^(";p1;p ")"; },
|
'REDXOR' => sub { p "~^(";p1;p ")"; },
|
||||||
'REPLICATE' => sub { p "{";p1;p "{";p2;p "}}"; },
|
'REPLICATE' => sub { p "{";p1;p "{";p2;p "}}"; },
|
||||||
'SCCTOR' => sub { p "SCCTOR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'SCCTOR' => sub { p "SCCTOR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'SCHDR' => sub { p "SCHDR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'SCHDR' => sub { p "SCHDR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'SCIMP' => sub { p "SCIMP what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'SCIMP' => sub { p "SCIMP what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'SCINT' => sub { p "SCINT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'SCINT' => sub { p "SCINT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'SCOPE' => sub { t1;t2;t3;t4;t5; },
|
'SCOPE' => sub { t1;t2;t3;t4;t5; },
|
||||||
'SENITEM' => sub { a1;p " ";t1; },
|
'SENITEM' => sub { a1;p " ";t1; },
|
||||||
'SENTREE' => sub { t1;t2;t3;t4;t5; },
|
'SENTREE' => sub { t1;t2;t3;t4;t5; },
|
||||||
'SHIFTL' => sub { p1;p " << ";p2; },
|
'SHIFTL' => sub { p1;p " << ";p2; },
|
||||||
'SHIFTR' => sub { p1;p " >> ";p2; },
|
'SHIFTR' => sub { p1;p " >> ";p2; },
|
||||||
'STOP' => sub { p '$stop;';nl; },
|
'STOP' => sub { p '$stop;';nl; },
|
||||||
'SUB' => sub { p1;p " - ";p2; },
|
'SUB' => sub { p1;p " - ";p2; },
|
||||||
'TASK' => sub { p "TASK what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'TASK' => sub { p "TASK what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'TASKREF' => sub { p "TASKREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'TASKREF' => sub { p "TASKREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'TEXT' => sub { p "TEXT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'TEXT' => sub { p "TEXT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'TIME' => sub { p '$time'; },
|
'TIME' => sub { p '$time'; },
|
||||||
'TOPSCOPE' => sub { t1;t2;t3;t4;t5; },
|
'TOPSCOPE' => sub { t1;t2;t3;t4;t5; },
|
||||||
'TRACE' => sub { p "TRACE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'TRACE' => sub { p "TRACE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'UCFUNC' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ")"; },
|
'UCFUNC' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ")"; },
|
||||||
'UCSTMT' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ");";nl; },
|
'UCSTMT' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ");";nl; },
|
||||||
'NEGATE' => sub { p " -";p1; },
|
'NEGATE' => sub { p " -";p1; },
|
||||||
'VAR' => sub { p_var(); },
|
'VAR' => sub { p_var(); },
|
||||||
'VARPIN' => sub { p "VARPIN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
'VARPIN' => sub { p "VARPIN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||||
'VARREF' => sub { a1; },
|
'VARREF' => sub { a1; },
|
||||||
'VARSCOPE' => sub { },
|
'VARSCOPE' => sub { },
|
||||||
'WHILE' => sub { t1; p "while (";t2;p ") begin";indentInc;nl;t3;t4;indentDec;p "end";nl; },
|
'WHILE' => sub { t1; p "while (";t2;p ") begin";indentInc;nl;t3;t4;indentDec;p "end";nl; },
|
||||||
'WORDSEL' => sub { p1;p "[";p2;p ":";p3;p "]"; },
|
'WORDSEL' => sub { p1;p "[";p2;p ":";p3;p "]"; },
|
||||||
'XNOR' => sub { p1;p " ~^ ";p2; },
|
'XNOR' => sub { p1;p " ~^ ";p2; },
|
||||||
'XOR' => sub { p1;p " ^";p2; },
|
'XOR' => sub { p1;p " ^";p2; },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub p_var {
|
sub p_var {
|
||||||
my $self = $Code_Self;
|
my $self = $Code_Self;
|
||||||
if ($self->{etc} =~ /\[I\]/) {
|
if ($self->{etc} =~ /\[I\]/) {
|
||||||
print "input";
|
print "input";
|
||||||
} elsif ($self->{etc} =~ /\[O\]/) {
|
} elsif ($self->{etc} =~ /\[O\]/) {
|
||||||
print "output";
|
print "output";
|
||||||
} else {
|
} else {
|
||||||
print "reg";
|
print "reg";
|
||||||
}
|
}
|
||||||
p "\t";
|
p "\t";
|
||||||
{
|
{
|
||||||
local $Avoid_Hex=1;
|
local $Avoid_Hex=1;
|
||||||
t1;
|
t1;
|
||||||
}
|
}
|
||||||
p "\t";
|
p "\t";
|
||||||
a1;
|
a1;
|
||||||
if (exists2()) {
|
if (exists2()) {
|
||||||
p " = ";
|
p " = ";
|
||||||
t2;
|
t2;
|
||||||
}
|
}
|
||||||
p ";";
|
p ";";
|
||||||
nl;
|
nl;
|
||||||
@@ -295,10 +295,10 @@ sub p_var {
|
|||||||
sub p_const {
|
sub p_const {
|
||||||
my $v = $Code_Self->{args}[0];
|
my $v = $Code_Self->{args}[0];
|
||||||
if ($v =~ /\?32\?h(.*)$/
|
if ($v =~ /\?32\?h(.*)$/
|
||||||
|| ($Avoid_Hex && $v =~ /^[0-9?]*h(.*)$/)) {
|
|| ($Avoid_Hex && $v =~ /^[0-9?]*h(.*)$/)) {
|
||||||
print hex $1;
|
print hex $1;
|
||||||
} else {
|
} else {
|
||||||
print $v;
|
print $v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-9
@@ -558,19 +558,20 @@ int AstNodeDType::widthPow2() const {
|
|||||||
return 1;
|
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
|
// Else AstArraySel etc; search for the base
|
||||||
while (nodep) {
|
while (nodep) {
|
||||||
if (VN_IS(nodep, ArraySel)) { nodep=VN_CAST(nodep, ArraySel)->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; }
|
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
|
// AstNodeSelPre stashes the associated variable under an ATTROF
|
||||||
else if (VN_IS(nodep, AttrOf)) { nodep=VN_CAST(nodep, AttrOf)->fromp(); continue; }
|
// 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)) {
|
else if (VN_IS(nodep, NodePreSel)) {
|
||||||
if (VN_CAST(nodep, NodePreSel)->attrp()) {
|
if (VN_CAST(nodep, NodePreSel)->attrp()) {
|
||||||
nodep=VN_CAST(nodep, NodePreSel)->attrp();
|
nodep = VN_CAST(nodep, NodePreSel)->attrp();
|
||||||
} else {
|
} else {
|
||||||
nodep=VN_CAST(nodep, NodePreSel)->lhsp();
|
nodep = VN_CAST(nodep, NodePreSel)->lhsp();
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else break;
|
else break;
|
||||||
|
|||||||
+95
-59
@@ -927,7 +927,7 @@ class AstSelPlus : public AstNodePreSel {
|
|||||||
// Gets replaced during link with AstSel
|
// Gets replaced during link with AstSel
|
||||||
public:
|
public:
|
||||||
AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
|
AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
|
||||||
:AstNodePreSel(fl, fromp, bitp, widthp) {}
|
: AstNodePreSel(fl, fromp, bitp, widthp) {}
|
||||||
ASTNODE_NODE_FUNCS(SelPlus)
|
ASTNODE_NODE_FUNCS(SelPlus)
|
||||||
AstNode* bitp() const { return rhsp(); }
|
AstNode* bitp() const { return rhsp(); }
|
||||||
AstNode* widthp() const { return thsp(); }
|
AstNode* widthp() const { return thsp(); }
|
||||||
@@ -938,7 +938,7 @@ class AstSelMinus : public AstNodePreSel {
|
|||||||
// Gets replaced during link with AstSel
|
// Gets replaced during link with AstSel
|
||||||
public:
|
public:
|
||||||
AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
|
AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
|
||||||
:AstNodePreSel(fl, fromp, bitp, widthp) {}
|
: AstNodePreSel(fl, fromp, bitp, widthp) {}
|
||||||
ASTNODE_NODE_FUNCS(SelMinus)
|
ASTNODE_NODE_FUNCS(SelMinus)
|
||||||
AstNode* bitp() const { return rhsp(); }
|
AstNode* bitp() const { return rhsp(); }
|
||||||
AstNode* widthp() const { return thsp(); }
|
AstNode* widthp() const { return thsp(); }
|
||||||
@@ -955,8 +955,8 @@ private:
|
|||||||
int m_declElWidth; // If a packed array, the number of bits per element
|
int m_declElWidth; // If a packed array, the number of bits per element
|
||||||
public:
|
public:
|
||||||
AstSel(FileLine* fl, AstNode* fromp, AstNode* lsbp, AstNode* widthp)
|
AstSel(FileLine* fl, AstNode* fromp, AstNode* lsbp, AstNode* widthp)
|
||||||
:AstNodeTriop(fl, fromp, lsbp, widthp) {
|
: AstNodeTriop(fl, fromp, lsbp, widthp) {
|
||||||
m_declElWidth = 1;
|
m_declElWidth = 1;
|
||||||
if (VN_IS(widthp, Const)) {
|
if (VN_IS(widthp, Const)) {
|
||||||
dtypeSetLogicSized(VN_CAST(widthp, Const)->toUInt(),
|
dtypeSetLogicSized(VN_CAST(widthp, Const)->toUInt(),
|
||||||
VN_CAST(widthp, Const)->toUInt(),
|
VN_CAST(widthp, Const)->toUInt(),
|
||||||
@@ -964,9 +964,9 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth)
|
AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth)
|
||||||
:AstNodeTriop(fl, fromp,
|
: AstNodeTriop(fl, fromp,
|
||||||
new AstConst(fl,lsb), new AstConst(fl,bitwidth)) {
|
new AstConst(fl,lsb), new AstConst(fl,bitwidth)) {
|
||||||
m_declElWidth = 1;
|
m_declElWidth = 1;
|
||||||
dtypeSetLogicSized(bitwidth,bitwidth,AstNumeric::UNSIGNED);
|
dtypeSetLogicSized(bitwidth,bitwidth,AstNumeric::UNSIGNED);
|
||||||
}
|
}
|
||||||
ASTNODE_NODE_FUNCS(Sel)
|
ASTNODE_NODE_FUNCS(Sel)
|
||||||
@@ -1076,9 +1076,9 @@ public:
|
|||||||
addNOp2p(pinsp);
|
addNOp2p(pinsp);
|
||||||
}
|
}
|
||||||
AstMethodSel(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp)
|
AstMethodSel(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp)
|
||||||
:AstNode(fl), m_name(name) {
|
: AstNode(fl), m_name(name) {
|
||||||
setOp1p(fromp);
|
setOp1p(fromp);
|
||||||
addNOp2p(pinsp);
|
addNOp2p(pinsp);
|
||||||
}
|
}
|
||||||
ASTNODE_NODE_FUNCS(MethodSel)
|
ASTNODE_NODE_FUNCS(MethodSel)
|
||||||
virtual string name() const { return m_name; } // * = Var name
|
virtual string name() const { return m_name; } // * = Var name
|
||||||
@@ -1144,9 +1144,9 @@ private:
|
|||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp)
|
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp)
|
||||||
:AstNode(fl)
|
: AstNode(fl)
|
||||||
, m_name(name), m_origName(name) {
|
, m_name(name), m_origName(name) {
|
||||||
init();
|
init();
|
||||||
combineType(type);
|
combineType(type);
|
||||||
childDTypep(dtp); // Only for parser
|
childDTypep(dtp); // Only for parser
|
||||||
dtypep(NULL); // V3Width will resolve
|
dtypep(NULL); // V3Width will resolve
|
||||||
@@ -1154,9 +1154,9 @@ public:
|
|||||||
else m_declKwd = AstBasicDTypeKwd::LOGIC;
|
else m_declKwd = AstBasicDTypeKwd::LOGIC;
|
||||||
}
|
}
|
||||||
AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtp)
|
AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtp)
|
||||||
:AstNode(fl)
|
: AstNode(fl)
|
||||||
, m_name(name), m_origName(name) {
|
, m_name(name), m_origName(name) {
|
||||||
init();
|
init();
|
||||||
combineType(type);
|
combineType(type);
|
||||||
UASSERT(dtp,"AstVar created with no dtype");
|
UASSERT(dtp,"AstVar created with no dtype");
|
||||||
dtypep(dtp);
|
dtypep(dtp);
|
||||||
@@ -1164,24 +1164,24 @@ public:
|
|||||||
else m_declKwd = AstBasicDTypeKwd::LOGIC;
|
else m_declKwd = AstBasicDTypeKwd::LOGIC;
|
||||||
}
|
}
|
||||||
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagLogicPacked, int wantwidth)
|
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagLogicPacked, int wantwidth)
|
||||||
:AstNode(fl)
|
: AstNode(fl)
|
||||||
, m_name(name), m_origName(name) {
|
, m_name(name), m_origName(name) {
|
||||||
init();
|
init();
|
||||||
combineType(type);
|
combineType(type);
|
||||||
dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED);
|
dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED);
|
||||||
m_declKwd = AstBasicDTypeKwd::LOGIC;
|
m_declKwd = AstBasicDTypeKwd::LOGIC;
|
||||||
}
|
}
|
||||||
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagBitPacked, int wantwidth)
|
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagBitPacked, int wantwidth)
|
||||||
:AstNode(fl)
|
: AstNode(fl)
|
||||||
, m_name(name), m_origName(name) {
|
, m_name(name), m_origName(name) {
|
||||||
init();
|
init();
|
||||||
combineType(type);
|
combineType(type);
|
||||||
dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED);
|
dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED);
|
||||||
m_declKwd = AstBasicDTypeKwd::BIT;
|
m_declKwd = AstBasicDTypeKwd::BIT;
|
||||||
}
|
}
|
||||||
AstVar(FileLine* fl, AstVarType type, const string& name, AstVar* examplep)
|
AstVar(FileLine* fl, AstVarType type, const string& name, AstVar* examplep)
|
||||||
:AstNode(fl)
|
: AstNode(fl)
|
||||||
, m_name(name), m_origName(name) {
|
, m_name(name), m_origName(name) {
|
||||||
init();
|
init();
|
||||||
combineType(type);
|
combineType(type);
|
||||||
if (examplep->childDTypep()) {
|
if (examplep->childDTypep()) {
|
||||||
@@ -1396,9 +1396,9 @@ private:
|
|||||||
AstNodeModule* m_modp; // Module scope corresponds to
|
AstNodeModule* m_modp; // Module scope corresponds to
|
||||||
public:
|
public:
|
||||||
AstScope(FileLine* fl, AstNodeModule* modp, const string& name,
|
AstScope(FileLine* fl, AstNodeModule* modp, const string& name,
|
||||||
AstScope* aboveScopep, AstCell* aboveCellp)
|
AstScope* aboveScopep, AstCell* aboveCellp)
|
||||||
:AstNode(fl)
|
: AstNode(fl)
|
||||||
,m_name(name) ,m_aboveScopep(aboveScopep) ,m_aboveCellp(aboveCellp), m_modp(modp) {}
|
,m_name(name) ,m_aboveScopep(aboveScopep) ,m_aboveCellp(aboveCellp), m_modp(modp) {}
|
||||||
ASTNODE_NODE_FUNCS(Scope)
|
ASTNODE_NODE_FUNCS(Scope)
|
||||||
virtual void cloneRelink();
|
virtual void cloneRelink();
|
||||||
virtual const char* broken() const;
|
virtual const char* broken() const;
|
||||||
@@ -1426,8 +1426,8 @@ class AstTopScope : public AstNode {
|
|||||||
// Children: SCOPEs
|
// Children: SCOPEs
|
||||||
public:
|
public:
|
||||||
AstTopScope(FileLine* fl, AstScope* ascopep)
|
AstTopScope(FileLine* fl, AstScope* ascopep)
|
||||||
:AstNode(fl)
|
: AstNode(fl)
|
||||||
{addNOp2p(ascopep);}
|
{addNOp2p(ascopep);}
|
||||||
ASTNODE_NODE_FUNCS(TopScope)
|
ASTNODE_NODE_FUNCS(TopScope)
|
||||||
AstNode* stmtsp() const { return op1p(); }
|
AstNode* stmtsp() const { return op1p(); }
|
||||||
void addStmtsp(AstNode* nodep) { addOp1p(nodep); }
|
void addStmtsp(AstNode* nodep) { addOp1p(nodep); }
|
||||||
@@ -1446,9 +1446,9 @@ private:
|
|||||||
bool m_trace:1; // Tracing is turned on for this scope
|
bool m_trace:1; // Tracing is turned on for this scope
|
||||||
public:
|
public:
|
||||||
AstVarScope(FileLine* fl, AstScope* scopep, AstVar* varp)
|
AstVarScope(FileLine* fl, AstScope* scopep, AstVar* varp)
|
||||||
:AstNode(fl)
|
: AstNode(fl)
|
||||||
, m_scopep(scopep), m_varp(varp) {
|
, m_scopep(scopep), m_varp(varp) {
|
||||||
m_circular = false;
|
m_circular = false;
|
||||||
m_trace = true;
|
m_trace = true;
|
||||||
dtypeFrom(varp);
|
dtypeFrom(varp);
|
||||||
}
|
}
|
||||||
@@ -1517,10 +1517,10 @@ private:
|
|||||||
string m_inlinedDots; // Dotted hierarchy flattened out
|
string m_inlinedDots; // Dotted hierarchy flattened out
|
||||||
public:
|
public:
|
||||||
AstVarXRef(FileLine* fl, const string& name, const string& dotted, bool lvalue)
|
AstVarXRef(FileLine* fl, const string& name, const string& dotted, bool lvalue)
|
||||||
:AstNodeVarRef(fl, name, NULL, lvalue)
|
: AstNodeVarRef(fl, name, NULL, lvalue)
|
||||||
, m_dotted(dotted) { }
|
, m_dotted(dotted) { }
|
||||||
AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, bool lvalue)
|
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) {
|
, m_dotted(dotted) {
|
||||||
dtypeFrom(varp);
|
dtypeFrom(varp);
|
||||||
}
|
}
|
||||||
@@ -1555,16 +1555,16 @@ private:
|
|||||||
bool m_svImplicit; // Pin is SystemVerilog .name'ed
|
bool m_svImplicit; // Pin is SystemVerilog .name'ed
|
||||||
public:
|
public:
|
||||||
AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp)
|
AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp)
|
||||||
:AstNode(fl)
|
: AstNode(fl)
|
||||||
,m_name(name), m_param(false), m_svImplicit(false) {
|
,m_name(name), m_param(false), m_svImplicit(false) {
|
||||||
m_pinNum = pinNum;
|
m_pinNum = pinNum;
|
||||||
m_modVarp = NULL;
|
m_modVarp = NULL;
|
||||||
m_modPTypep = NULL;
|
m_modPTypep = NULL;
|
||||||
setNOp1p(exprp);
|
setNOp1p(exprp);
|
||||||
}
|
}
|
||||||
AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp)
|
AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp)
|
||||||
:AstNode(fl), m_param(false), m_svImplicit(false) {
|
: AstNode(fl), m_param(false), m_svImplicit(false) {
|
||||||
m_name = varname->name();
|
m_name = varname->name();
|
||||||
m_pinNum = pinNum;
|
m_pinNum = pinNum;
|
||||||
m_modVarp = NULL;
|
m_modVarp = NULL;
|
||||||
m_modPTypep = NULL;
|
m_modPTypep = NULL;
|
||||||
@@ -1903,8 +1903,8 @@ private:
|
|||||||
string m_name; // Name of pin
|
string m_name; // Name of pin
|
||||||
public:
|
public:
|
||||||
AstPort(FileLine* fl, int pinnum, const string& name)
|
AstPort(FileLine* fl, int pinnum, const string& name)
|
||||||
:AstNode(fl)
|
: AstNode(fl)
|
||||||
,m_pinNum(pinnum) ,m_name(name) {}
|
,m_pinNum(pinnum) ,m_name(name) {}
|
||||||
ASTNODE_NODE_FUNCS(Port)
|
ASTNODE_NODE_FUNCS(Port)
|
||||||
virtual string name() const { return m_name; } // * = Port name
|
virtual string name() const { return m_name; } // * = Port name
|
||||||
int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation
|
int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation
|
||||||
@@ -1939,7 +1939,7 @@ private:
|
|||||||
string m_name;
|
string m_name;
|
||||||
public:
|
public:
|
||||||
AstParseRef(FileLine* fl, AstParseRefExp expect, const string& name, AstNode* lhsp, AstNodeFTaskRef* ftaskrefp)
|
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)
|
ASTNODE_NODE_FUNCS(ParseRef)
|
||||||
virtual void dump(std::ostream& str);
|
virtual void dump(std::ostream& str);
|
||||||
virtual string name() const { return m_name; } // * = Var name
|
virtual string name() const { return m_name; } // * = Var name
|
||||||
@@ -1984,7 +1984,7 @@ class AstDot : public AstNode {
|
|||||||
// These are eliminated in the link stage
|
// These are eliminated in the link stage
|
||||||
public:
|
public:
|
||||||
AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||||
:AstNode(fl) { setOp1p(lhsp); setOp2p(rhsp); }
|
: AstNode(fl) { setOp1p(lhsp); setOp2p(rhsp); }
|
||||||
ASTNODE_NODE_FUNCS(Dot)
|
ASTNODE_NODE_FUNCS(Dot)
|
||||||
static AstNode* newIfPkg(FileLine*fl, AstPackage* packagep, AstNode* rhsp) { // For parser, make only if non-null package
|
static AstNode* newIfPkg(FileLine*fl, AstPackage* packagep, AstNode* rhsp) { // For parser, make only if non-null package
|
||||||
if (!packagep) return rhsp;
|
if (!packagep) return rhsp;
|
||||||
@@ -2003,7 +2003,7 @@ class AstTask : public AstNodeFTask {
|
|||||||
// A task inside a module
|
// A task inside a module
|
||||||
public:
|
public:
|
||||||
AstTask(FileLine* fl, const string& name, AstNode* stmtp)
|
AstTask(FileLine* fl, const string& name, AstNode* stmtp)
|
||||||
:AstNodeFTask(fl, name, stmtp) {}
|
: AstNodeFTask(fl, name, stmtp) {}
|
||||||
ASTNODE_NODE_FUNCS(Task)
|
ASTNODE_NODE_FUNCS(Task)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2011,8 +2011,8 @@ class AstFunc : public AstNodeFTask {
|
|||||||
// A function inside a module
|
// A function inside a module
|
||||||
public:
|
public:
|
||||||
AstFunc(FileLine* fl, const string& name, AstNode* stmtp, AstNode* fvarsp)
|
AstFunc(FileLine* fl, const string& name, AstNode* stmtp, AstNode* fvarsp)
|
||||||
:AstNodeFTask(fl, name, stmtp) {
|
: AstNodeFTask(fl, name, stmtp) {
|
||||||
addNOp1p(fvarsp);
|
addNOp1p(fvarsp);
|
||||||
}
|
}
|
||||||
ASTNODE_NODE_FUNCS(Func)
|
ASTNODE_NODE_FUNCS(Func)
|
||||||
virtual bool hasDType() const { return true; }
|
virtual bool hasDType() const { return true; }
|
||||||
@@ -2022,9 +2022,9 @@ class AstTaskRef : public AstNodeFTaskRef {
|
|||||||
// A reference to a task
|
// A reference to a task
|
||||||
public:
|
public:
|
||||||
AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp)
|
AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp)
|
||||||
:AstNodeFTaskRef(fl, namep, pinsp) {}
|
: AstNodeFTaskRef(fl, namep, pinsp) {}
|
||||||
AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp)
|
AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp)
|
||||||
:AstNodeFTaskRef(fl, name, pinsp) {}
|
: AstNodeFTaskRef(fl, name, pinsp) {}
|
||||||
ASTNODE_NODE_FUNCS(TaskRef)
|
ASTNODE_NODE_FUNCS(TaskRef)
|
||||||
virtual bool isStatement() const { return true; } // A statement, unlike FuncRef
|
virtual bool isStatement() const { return true; } // A statement, unlike FuncRef
|
||||||
};
|
};
|
||||||
@@ -2033,9 +2033,9 @@ class AstFuncRef : public AstNodeFTaskRef {
|
|||||||
// A reference to a function
|
// A reference to a function
|
||||||
public:
|
public:
|
||||||
AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp)
|
AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp)
|
||||||
:AstNodeFTaskRef(fl, namep, pinsp) {}
|
: AstNodeFTaskRef(fl, namep, pinsp) {}
|
||||||
AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp)
|
AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp)
|
||||||
:AstNodeFTaskRef(fl, name, pinsp) {}
|
: AstNodeFTaskRef(fl, name, pinsp) {}
|
||||||
ASTNODE_NODE_FUNCS(FuncRef)
|
ASTNODE_NODE_FUNCS(FuncRef)
|
||||||
virtual bool isStatement() const { return false; } // Not a statement, unlike TaskRef
|
virtual bool isStatement() const { return false; } // Not a statement, unlike TaskRef
|
||||||
virtual bool hasDType() const { return true; }
|
virtual bool hasDType() const { return true; }
|
||||||
@@ -2050,7 +2050,7 @@ private:
|
|||||||
string m_cname; // Name of function on c side
|
string m_cname; // Name of function on c side
|
||||||
public:
|
public:
|
||||||
AstDpiExport(FileLine* fl, const string& vname, const string& cname)
|
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)
|
ASTNODE_NODE_FUNCS(DpiExport)
|
||||||
virtual string name() const { return m_name; }
|
virtual string name() const { return m_name; }
|
||||||
virtual void name(const string& name) { m_name = name; }
|
virtual void name(const string& name) { m_name = name; }
|
||||||
@@ -2741,6 +2741,42 @@ public:
|
|||||||
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
|
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 {
|
class AstFScanF : public AstNodeMath {
|
||||||
// Parents: expr
|
// Parents: expr
|
||||||
// Children: file which must be a varref
|
// Children: file which must be a varref
|
||||||
|
|||||||
@@ -230,6 +230,10 @@ private:
|
|||||||
}
|
}
|
||||||
insureCleanAndNext(nodep->bodysp());
|
insureCleanAndNext(nodep->bodysp());
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstTraceDecl* nodep) {
|
||||||
|
// No cleaning, or would loose pointer to enum
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
virtual void visit(AstTraceInc* nodep) {
|
virtual void visit(AstTraceInc* nodep) {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
insureCleanAndNext(nodep->valuep());
|
insureCleanAndNext(nodep->valuep());
|
||||||
|
|||||||
+42
-3
@@ -387,6 +387,45 @@ public:
|
|||||||
puts(")); }\n");
|
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) {
|
virtual void visit(AstSysFuncAsTask* nodep) {
|
||||||
if (!nodep->lhsp()->isWide()) puts("(void)");
|
if (!nodep->lhsp()->isWide()) puts("(void)");
|
||||||
iterateAndNextNull(nodep->lhsp());
|
iterateAndNextNull(nodep->lhsp());
|
||||||
@@ -2848,7 +2887,7 @@ class EmitCTrace : EmitCStmts {
|
|||||||
puts(",");
|
puts(",");
|
||||||
putsQuoted(nodep->showname());
|
putsQuoted(nodep->showname());
|
||||||
// Direction
|
// Direction
|
||||||
if (v3Global.opt.traceFormat() == TraceFormat::FST) {
|
if (v3Global.opt.traceFormat().fstFlavor()) {
|
||||||
puts(","+cvtToStr(enumNum));
|
puts(","+cvtToStr(enumNum));
|
||||||
// fstVarDir
|
// fstVarDir
|
||||||
if (nodep->declDirection().isInoutish()) puts(",FST_VD_INOUT");
|
if (nodep->declDirection().isInoutish()) puts(",FST_VD_INOUT");
|
||||||
@@ -2915,9 +2954,9 @@ class EmitCTrace : EmitCStmts {
|
|||||||
|
|
||||||
int emitTraceDeclDType(AstNodeDType* nodep) {
|
int emitTraceDeclDType(AstNodeDType* nodep) {
|
||||||
// Return enum number or -1 for none
|
// Return enum number or -1 for none
|
||||||
if (v3Global.opt.traceFormat() == TraceFormat::FST) {
|
if (v3Global.opt.traceFormat().fstFlavor()) {
|
||||||
// Skip over refs-to-refs, but stop before final ref so can get data type name
|
// Skip over refs-to-refs, but stop before final ref so can get data type name
|
||||||
// Alternatively back in V3Width we could have push enum names from upper typedefs
|
// Alternatively back in V3Width we could push enum names from upper typedefs
|
||||||
if (AstEnumDType* enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) {
|
if (AstEnumDType* enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) {
|
||||||
int enumNum = enump->user1();
|
int enumNum = enump->user1();
|
||||||
if (!enumNum) {
|
if (!enumNum) {
|
||||||
|
|||||||
@@ -46,9 +46,11 @@ class EmitCInlines : EmitCBaseVisitor {
|
|||||||
v3Global.needHeavy(true);
|
v3Global.needHeavy(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstValuePlusArgs* nodep) {
|
||||||
|
v3Global.needHeavy(true);
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
// NOPs
|
|
||||||
virtual void visit(AstNodeStmt*) {}
|
|
||||||
// Default
|
// Default
|
||||||
virtual void visit(AstNode* nodep) {
|
virtual void visit(AstNode* nodep) {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ public:
|
|||||||
of.puts("VM_THREADS = "); of.puts(cvtToStr(v3Global.opt.threads())); of.puts("\n");
|
of.puts("VM_THREADS = "); of.puts(cvtToStr(v3Global.opt.threads())); of.puts("\n");
|
||||||
of.puts("# Tracing output mode? 0/1 (from --trace)\n");
|
of.puts("# Tracing output mode? 0/1 (from --trace)\n");
|
||||||
of.puts("VM_TRACE = "); of.puts(v3Global.opt.trace()?"1":"0"); of.puts("\n");
|
of.puts("VM_TRACE = "); of.puts(v3Global.opt.trace()?"1":"0"); of.puts("\n");
|
||||||
|
of.puts("# Tracing threadeds output mode? 0/1 (from --trace-fst-thread)\n");
|
||||||
|
of.puts("VM_TRACE_THREADED = "); of.puts(v3Global.opt.traceFormat().threaded()
|
||||||
|
?"1":"0"); of.puts("\n");
|
||||||
|
|
||||||
of.puts("\n### Object file lists...\n");
|
of.puts("\n### Object file lists...\n");
|
||||||
for (int support=0; support<3; support++) {
|
for (int support=0; support<3; support++) {
|
||||||
|
|||||||
+10
-7
@@ -49,8 +49,9 @@ public:
|
|||||||
I_DEF_NETTYPE_WIRE, // `default_nettype is WIRE (false=NONE)
|
I_DEF_NETTYPE_WIRE, // `default_nettype is WIRE (false=NONE)
|
||||||
// Error codes:
|
// Error codes:
|
||||||
E_DETECTARRAY, // Error: Unsupported: Can't detect changes on arrayed variable
|
E_DETECTARRAY, // Error: Unsupported: Can't detect changes on arrayed variable
|
||||||
E_MULTITOP, // Error: Multiple top level modules
|
E_MULTITOP, // Error: Multiple top level modules
|
||||||
E_TASKNSVAR, // Error: Task I/O not simple
|
E_PORTSHORT, // Error: Output port is connected to a constant, electrical short
|
||||||
|
E_TASKNSVAR, // Error: Task I/O not simple
|
||||||
//
|
//
|
||||||
// Warning codes:
|
// Warning codes:
|
||||||
EC_FIRST_WARN, // Just a code so the program knows where to start warnings
|
EC_FIRST_WARN, // Just a code so the program knows where to start warnings
|
||||||
@@ -77,7 +78,8 @@ public:
|
|||||||
ENDLABEL, // End lable name mismatch
|
ENDLABEL, // End lable name mismatch
|
||||||
GENCLK, // Generated Clock
|
GENCLK, // Generated Clock
|
||||||
IFDEPTH, // If statements too deep
|
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
|
IMPLICIT, // Implicit wire
|
||||||
IMPORTSTAR, // Import::* in $unit
|
IMPORTSTAR, // Import::* in $unit
|
||||||
IMPURE, // Impure function not being inlined
|
IMPURE, // Impure function not being inlined
|
||||||
@@ -128,9 +130,9 @@ public:
|
|||||||
" MIN", " INFO", " FATAL", " FATALSRC", " ERROR",
|
" MIN", " INFO", " FATAL", " FATALSRC", " ERROR",
|
||||||
// Boolean
|
// Boolean
|
||||||
" I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE",
|
" I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE",
|
||||||
// Errors
|
// Errors
|
||||||
"DETECTARRAY", "MULTITOP", "TASKNSVAR",
|
"DETECTARRAY", "MULTITOP", "PORTSHORT", "TASKNSVAR",
|
||||||
// Warnings
|
// Warnings
|
||||||
" EC_FIRST_WARN",
|
" EC_FIRST_WARN",
|
||||||
"ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN",
|
"ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN",
|
||||||
"BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE",
|
"BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE",
|
||||||
@@ -138,7 +140,8 @@ public:
|
|||||||
"CMPCONST", "COLONPLUS", "COMBDLY", "CONTASSREG",
|
"CMPCONST", "COLONPLUS", "COMBDLY", "CONTASSREG",
|
||||||
"DEFPARAM", "DECLFILENAME",
|
"DEFPARAM", "DECLFILENAME",
|
||||||
"ENDLABEL", "GENCLK",
|
"ENDLABEL", "GENCLK",
|
||||||
"IFDEPTH", "IMPERFECTSCH", "IMPLICIT", "IMPORTSTAR", "IMPURE",
|
"IFDEPTH", "IGNOREDRETURN",
|
||||||
|
"IMPERFECTSCH", "IMPLICIT", "IMPORTSTAR", "IMPURE",
|
||||||
"INCABSPATH", "INFINITELOOP", "INITIALDLY",
|
"INCABSPATH", "INFINITELOOP", "INITIALDLY",
|
||||||
"LITENDIAN", "MODDUP",
|
"LITENDIAN", "MODDUP",
|
||||||
"MULTIDRIVEN",
|
"MULTIDRIVEN",
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ protected:
|
|||||||
friend class V3ParseImp;
|
friend class V3ParseImp;
|
||||||
friend class V3PreLex;
|
friend class V3PreLex;
|
||||||
friend class V3PreProcImp;
|
friend class V3PreProcImp;
|
||||||
|
friend class V3PreShellImp;
|
||||||
void lineno(int num) { m_lineno = num; }
|
void lineno(int num) { m_lineno = num; }
|
||||||
void language(V3LangCode lang) { singleton().numberToLang(m_filenameno, lang); }
|
void language(V3LangCode lang) { singleton().numberToLang(m_filenameno, lang); }
|
||||||
void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); }
|
void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); }
|
||||||
|
|||||||
+2
-5
@@ -550,14 +550,11 @@ private:
|
|||||||
AstVar* pinNewVarp = pinOldVarp->clonep();
|
AstVar* pinNewVarp = pinOldVarp->clonep();
|
||||||
if (!pinNewVarp) pinOldVarp->v3fatalSrc("Cloning failed");
|
if (!pinNewVarp) pinOldVarp->v3fatalSrc("Cloning failed");
|
||||||
|
|
||||||
AstNode* connectRefp = pinp->exprp();
|
AstNode* connectRefp = pinp->exprp();
|
||||||
if (!VN_IS(connectRefp, Const) && !VN_IS(connectRefp, VarRef)) {
|
if (!VN_IS(connectRefp, Const) && !VN_IS(connectRefp, VarRef)) {
|
||||||
pinp->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up");
|
pinp->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up");
|
||||||
}
|
}
|
||||||
if (pinNewVarp->direction() == VDirection::OUTPUT
|
V3Inst::checkOutputShort(pinp);
|
||||||
&& VN_IS(connectRefp, Const)) {
|
|
||||||
pinp->v3error("Output port is connected to a constant pin, electrical short");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Propagate any attributes across the interconnect
|
// Propagate any attributes across the interconnect
|
||||||
pinNewVarp->propagateAttrFrom(pinOldVarp);
|
pinNewVarp->propagateAttrFrom(pinOldVarp);
|
||||||
|
|||||||
+18
-7
@@ -68,10 +68,7 @@ private:
|
|||||||
UINFO(4," PIN "<<nodep<<endl);
|
UINFO(4," PIN "<<nodep<<endl);
|
||||||
if (!nodep->exprp()) return; // No-connect
|
if (!nodep->exprp()) return; // No-connect
|
||||||
if (debug()>=9) nodep->dumpTree(cout," Pin_oldb: ");
|
if (debug()>=9) nodep->dumpTree(cout," Pin_oldb: ");
|
||||||
if (nodep->modVarp()->direction() == VDirection::OUTPUT
|
V3Inst::checkOutputShort(nodep);
|
||||||
&& VN_IS(nodep->exprp(), Const)) {
|
|
||||||
nodep->v3error("Output port is connected to a constant pin, electrical short");
|
|
||||||
}
|
|
||||||
// Use user1p on the PIN to indicate we created an assign for this pin
|
// Use user1p on the PIN to indicate we created an assign for this pin
|
||||||
if (!nodep->user1SetOnce()) {
|
if (!nodep->user1SetOnce()) {
|
||||||
// Simplify it
|
// Simplify it
|
||||||
@@ -513,8 +510,9 @@ public:
|
|||||||
// Done. Constant.
|
// Done. Constant.
|
||||||
} else {
|
} else {
|
||||||
// Make a new temp wire
|
// Make a new temp wire
|
||||||
//if (1||debug()>=9) { pinp->dumpTree(cout,"-in_pin:"); }
|
//if (1||debug()>=9) { pinp->dumpTree(cout,"-in_pin:"); }
|
||||||
AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
|
V3Inst::checkOutputShort(pinp);
|
||||||
|
AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
|
||||||
string newvarname = (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp")
|
string newvarname = (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp")
|
||||||
// Prevent name conflict if both tri & non-tri add signals
|
// Prevent name conflict if both tri & non-tri add signals
|
||||||
+(forTristate?"t":"")
|
+(forTristate?"t":"")
|
||||||
@@ -555,10 +553,23 @@ public:
|
|||||||
// Inst class functions
|
// Inst class functions
|
||||||
|
|
||||||
AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp,
|
AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp,
|
||||||
bool forTristate, bool alwaysCvt) {
|
bool forTristate, bool alwaysCvt) {
|
||||||
return InstStatic::pinReconnectSimple(pinp, cellp, forTristate, 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
|
// Inst class visitor
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public:
|
|||||||
static void dearrayAll(AstNetlist* nodep);
|
static void dearrayAll(AstNetlist* nodep);
|
||||||
static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp,
|
static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp,
|
||||||
bool forTristate, bool alwaysCvt=false);
|
bool forTristate, bool alwaysCvt=false);
|
||||||
|
static void checkOutputShort(AstPin* nodep);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|||||||
@@ -131,6 +131,15 @@ private:
|
|||||||
}
|
}
|
||||||
m_setRefLvalue = last_setRefLvalue;
|
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) {
|
virtual void visit(AstFScanF* nodep) {
|
||||||
bool last_setRefLvalue = m_setRefLvalue;
|
bool last_setRefLvalue = m_setRefLvalue;
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -210,6 +210,11 @@ private:
|
|||||||
} else if (AstEnumItemRef* fromp = VN_CAST(basefromp, EnumItemRef)) {
|
} else if (AstEnumItemRef* fromp = VN_CAST(basefromp, EnumItemRef)) {
|
||||||
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::ENUM_BASE,
|
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::ENUM_BASE,
|
||||||
fromp->cloneTree(false)));
|
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 {
|
} else {
|
||||||
if (basefromp) { UINFO(1," Related node: "<<basefromp<<endl); }
|
if (basefromp) { UINFO(1," Related node: "<<basefromp<<endl); }
|
||||||
nodep->v3fatalSrc("Illegal bit select; no signal/member being extracted from");
|
nodep->v3fatalSrc("Illegal bit select; no signal/member being extracted from");
|
||||||
@@ -362,6 +367,10 @@ private:
|
|||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef));
|
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) {
|
virtual void visit(AstFScanF* nodep) {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
expectFormat(nodep, nodep->text(), nodep->exprsp(), true);
|
expectFormat(nodep, nodep->text(), nodep->exprsp(), true);
|
||||||
|
|||||||
+24
-14
@@ -153,18 +153,16 @@ V3Number::V3Number(FileLine* fileline, const char* sourcep) {
|
|||||||
got_01 = 1;
|
got_01 = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'z': case '?': {
|
case 'z': case '?': {
|
||||||
if (!m_sized) m_fileline->v3error("Unsized X/Z/? not legal in decimal constant: "<<*cp);
|
got_z = 1;
|
||||||
setAllBitsZ();
|
setAllBitsZ();
|
||||||
got_z = 1;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
case 'x': {
|
||||||
case 'x': {
|
got_x = 1;
|
||||||
if (!m_sized) m_fileline->v3error("Unsized X/Z/? not legal in decimal constant: "<<*cp);
|
setAllBitsX();
|
||||||
got_x = 1;
|
break;
|
||||||
setAllBitsX();
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
case '_': break;
|
case '_': break;
|
||||||
default: {
|
default: {
|
||||||
m_fileline->v3error("Illegal character in decimal constant: "<<*cp);
|
m_fileline->v3error("Illegal character in decimal constant: "<<*cp);
|
||||||
@@ -1658,8 +1656,20 @@ V3Number& V3Number::opAssign(const V3Number& lhs) {
|
|||||||
V3Number& V3Number::opExtendS(const V3Number& lhs, uint32_t lbits) {
|
V3Number& V3Number::opExtendS(const V3Number& lhs, uint32_t lbits) {
|
||||||
// Note may be a width change during the sign extension
|
// Note may be a width change during the sign extension
|
||||||
setZero();
|
setZero();
|
||||||
for(int bit=0; bit<this->width(); bit++) {
|
for (int bit=0; bit < width(); bit++) {
|
||||||
setBit(bit,lhs.bitIsExtend(bit, lbits));
|
char extendWith = lhs.bitIsExtend(bit, lbits);
|
||||||
|
setBit(bit, extendWith);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
V3Number& V3Number::opExtendXZ(const V3Number& lhs, uint32_t lbits) {
|
||||||
|
// Note may be a width change during the X/Z extension
|
||||||
|
setZero();
|
||||||
|
for (int bit=0; bit < width(); bit++) {
|
||||||
|
char extendWith = lhs.bitIsExtend(bit, lbits);
|
||||||
|
if (extendWith == '1' || extendWith == 1) extendWith = 0;
|
||||||
|
setBit(bit, lhs.bitIsExtend(bit, lbits));
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -199,6 +199,7 @@ public:
|
|||||||
bool isLtXZ(const V3Number& rhs) const; // operator< with XZ compared
|
bool isLtXZ(const V3Number& rhs) const; // operator< with XZ compared
|
||||||
void isSigned(bool ssigned) { m_signed=ssigned; }
|
void isSigned(bool ssigned) { m_signed=ssigned; }
|
||||||
bool isUnknown() const;
|
bool isUnknown() const;
|
||||||
|
bool isMsbXZ() const { return bitIsXZ(m_width); }
|
||||||
uint32_t toUInt() const;
|
uint32_t toUInt() const;
|
||||||
vlsint32_t toSInt() const;
|
vlsint32_t toSInt() const;
|
||||||
vluint64_t toUQuad() const;
|
vluint64_t toUQuad() const;
|
||||||
@@ -231,8 +232,9 @@ public:
|
|||||||
V3Number& opBitsZ (const V3Number& lhs); // Z->1, 0/1/X->0
|
V3Number& opBitsZ (const V3Number& lhs); // Z->1, 0/1/X->0
|
||||||
V3Number& opBitsNonZ(const V3Number& lhs); // Z->0, 0/1/X->1
|
V3Number& opBitsNonZ(const V3Number& lhs); // Z->0, 0/1/X->1
|
||||||
//
|
//
|
||||||
V3Number& opAssign (const V3Number& lhs);
|
V3Number& opAssign (const V3Number& lhs);
|
||||||
V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension
|
V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension
|
||||||
|
V3Number& opExtendXZ(const V3Number& lhs, uint32_t lbits); // X/Z extension
|
||||||
V3Number& opRedOr (const V3Number& lhs);
|
V3Number& opRedOr (const V3Number& lhs);
|
||||||
V3Number& opRedAnd (const V3Number& lhs);
|
V3Number& opRedAnd (const V3Number& lhs);
|
||||||
V3Number& opRedXor (const V3Number& lhs);
|
V3Number& opRedXor (const V3Number& lhs);
|
||||||
|
|||||||
+13
-4
@@ -699,10 +699,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
|||||||
else if ( onoff (sw, "-stats-vars", flag/*ref*/) ) { m_statsVars = flag; m_stats |= flag; }
|
else if ( onoff (sw, "-stats-vars", flag/*ref*/) ) { m_statsVars = flag; m_stats |= flag; }
|
||||||
else if ( !strcmp (sw, "-sv") ) { m_defaultLanguage = V3LangCode::L1800_2005; }
|
else if ( !strcmp (sw, "-sv") ) { m_defaultLanguage = V3LangCode::L1800_2005; }
|
||||||
else if ( onoff (sw, "-threads-coarsen", flag/*ref*/)) { m_threadsCoarsen = flag; } // Undocumented, debug
|
else if ( onoff (sw, "-threads-coarsen", flag/*ref*/)) { m_threadsCoarsen = flag; } // Undocumented, debug
|
||||||
else if ( onoff (sw, "-trace", flag/*ref*/) ) { m_trace = flag; }
|
else if ( onoff (sw, "-trace", flag/*ref*/) ) { m_trace = flag; }
|
||||||
else if ( onoff (sw, "-trace-fst", flag/*ref*/) ) { m_trace = flag; m_traceFormat = TraceFormat::FST; addLdLibs("-lz"); }
|
else if ( onoff (sw, "-trace-dups", flag/*ref*/) ) { m_traceDups = flag; }
|
||||||
else if ( onoff (sw, "-trace-dups", flag/*ref*/) ) { m_traceDups = flag; }
|
else if ( onoff (sw, "-trace-params", flag/*ref*/) ) { m_traceParams = flag; }
|
||||||
else if ( onoff (sw, "-trace-params", flag/*ref*/) ) { m_traceParams = flag; }
|
|
||||||
else if ( onoff (sw, "-trace-structs", flag/*ref*/) ) { m_traceStructs = flag; }
|
else if ( onoff (sw, "-trace-structs", flag/*ref*/) ) { m_traceStructs = flag; }
|
||||||
else if ( onoff (sw, "-trace-underscore", flag/*ref*/) ) { m_traceUnderscore = flag; }
|
else if ( onoff (sw, "-trace-underscore", flag/*ref*/) ) { m_traceUnderscore = flag; }
|
||||||
else if ( onoff (sw, "-underline-zero", flag/*ref*/) ) { m_underlineZero = flag; } // Undocumented, old Verilator-2
|
else if ( onoff (sw, "-underline-zero", flag/*ref*/) ) { m_underlineZero = flag; } // Undocumented, old Verilator-2
|
||||||
@@ -869,6 +868,16 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
|||||||
shift;
|
shift;
|
||||||
m_outputSplitCTrace = atoi(argv[i]);
|
m_outputSplitCTrace = atoi(argv[i]);
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(sw, "-trace-fst")) {
|
||||||
|
m_trace = true;
|
||||||
|
m_traceFormat = TraceFormat::FST;
|
||||||
|
addLdLibs("-lz");
|
||||||
|
}
|
||||||
|
else if (!strcmp(sw, "-trace-fst-thread")) {
|
||||||
|
m_trace = true;
|
||||||
|
m_traceFormat = TraceFormat::FST_THREAD;
|
||||||
|
addLdLibs("-lz");
|
||||||
|
}
|
||||||
else if ( !strcmp (sw, "-trace-depth") && (i+1)<argc ) {
|
else if ( !strcmp (sw, "-trace-depth") && (i+1)<argc ) {
|
||||||
shift;
|
shift;
|
||||||
m_traceDepth = atoi(argv[i]);
|
m_traceDepth = atoi(argv[i]);
|
||||||
|
|||||||
+6
-1
@@ -41,14 +41,18 @@ class TraceFormat {
|
|||||||
public:
|
public:
|
||||||
enum en {
|
enum en {
|
||||||
VCD = 0,
|
VCD = 0,
|
||||||
FST
|
FST,
|
||||||
|
FST_THREAD
|
||||||
} m_e;
|
} m_e;
|
||||||
inline TraceFormat(en _e = VCD) : m_e(_e) {}
|
inline TraceFormat(en _e = VCD) : m_e(_e) {}
|
||||||
explicit inline TraceFormat(int _e) : m_e(static_cast<en>(_e)) {}
|
explicit inline TraceFormat(int _e) : m_e(static_cast<en>(_e)) {}
|
||||||
operator en() const { return m_e; }
|
operator en() const { return m_e; }
|
||||||
|
bool fstFlavor() const { return m_e == FST || m_e == FST_THREAD; }
|
||||||
|
bool threaded() const { return m_e == FST_THREAD; }
|
||||||
string classBase() const {
|
string classBase() const {
|
||||||
static const char* const names[] = {
|
static const char* const names[] = {
|
||||||
"VerilatedVcd",
|
"VerilatedVcd",
|
||||||
|
"VerilatedFst",
|
||||||
"VerilatedFst"
|
"VerilatedFst"
|
||||||
};
|
};
|
||||||
return names[m_e];
|
return names[m_e];
|
||||||
@@ -56,6 +60,7 @@ public:
|
|||||||
string sourceName() const {
|
string sourceName() const {
|
||||||
static const char* const names[] = {
|
static const char* const names[] = {
|
||||||
"verilated_vcd",
|
"verilated_vcd",
|
||||||
|
"verilated_fst",
|
||||||
"verilated_fst"
|
"verilated_fst"
|
||||||
};
|
};
|
||||||
return names[m_e];
|
return names[m_e];
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#if defined(WIN32) || defined(__MINGW32__)
|
#if defined(_WIN32) || defined(__MINGW32__)
|
||||||
# include <direct.h> // mkdir
|
# include <direct.h> // mkdir
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+22
-14
@@ -271,21 +271,29 @@ private:
|
|||||||
|
|
||||||
// Make sure all parameters are constantified
|
// Make sure all parameters are constantified
|
||||||
virtual void visit(AstVar* nodep) {
|
virtual void visit(AstVar* nodep) {
|
||||||
if (!nodep->user5SetOnce()) { // Process once
|
if (!nodep->user5SetOnce()) { // Process once
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
if (nodep->isParam()) {
|
if (nodep->isParam()) {
|
||||||
if (!nodep->valuep()) { nodep->v3fatalSrc("Parameter without initial value"); }
|
if (!nodep->valuep()) {
|
||||||
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
|
nodep->v3error("Parameter without initial value is never given value"
|
||||||
if (!VN_IS(nodep->valuep(), Const)) { // Complex init, like an array
|
<<" (IEEE 1800-2017 6.20.1): "
|
||||||
// Make a new INITIAL to set the value.
|
<<nodep->prettyName());
|
||||||
// This allows the normal array/struct handling code to properly initialize the parameter
|
} else {
|
||||||
nodep->addNext(new AstInitial(nodep->fileline(),
|
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
|
||||||
new AstAssign(nodep->fileline(),
|
if (!VN_IS(nodep->valuep(), Const)) { // Complex init, like an array
|
||||||
new AstVarRef(nodep->fileline(), nodep, true),
|
// Make a new INITIAL to set the value.
|
||||||
nodep->valuep()->cloneTree(true))));
|
// This allows the normal array/struct handling code to properly
|
||||||
}
|
// initialize the parameter.
|
||||||
}
|
nodep->addNext(
|
||||||
}
|
new AstInitial(nodep->fileline(),
|
||||||
|
new AstAssign(
|
||||||
|
nodep->fileline(),
|
||||||
|
new AstVarRef(nodep->fileline(), nodep, true),
|
||||||
|
nodep->valuep()->cloneTree(true))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Make sure varrefs cause vars to constify before things above
|
// Make sure varrefs cause vars to constify before things above
|
||||||
virtual void visit(AstVarRef* nodep) {
|
virtual void visit(AstVarRef* nodep) {
|
||||||
|
|||||||
@@ -115,17 +115,6 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
|
|||||||
m_fileline = new FileLine(fileline);
|
m_fileline = new FileLine(fileline);
|
||||||
m_inLibrary = inLibrary;
|
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
|
// Preprocess into m_ppBuffer
|
||||||
bool ok = V3PreShell::preproc(fileline, modfilename, m_filterp, this, errmsg);
|
bool ok = V3PreShell::preproc(fileline, modfilename, m_filterp, this, errmsg);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
|
|||||||
+24
-8
@@ -102,8 +102,20 @@ protected:
|
|||||||
|
|
||||||
// Preprocess
|
// Preprocess
|
||||||
s_filterp = filterp;
|
s_filterp = filterp;
|
||||||
bool ok = preprocOpen(fl, s_filterp, modname, "", errmsg);
|
string modfilename = preprocOpen(fl, s_filterp, modname, "", errmsg);
|
||||||
if (!ok) return false;
|
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()) {
|
while (!s_preprocp->isEof()) {
|
||||||
string line = s_preprocp->getline();
|
string line = s_preprocp->getline();
|
||||||
@@ -116,12 +128,15 @@ protected:
|
|||||||
if (modname[0]=='/' || modname[0]=='\\') {
|
if (modname[0]=='/' || modname[0]=='\\') {
|
||||||
fl->v3warn(INCABSPATH,"Suggest `include with absolute path be made relative, and use +include: "<<modname);
|
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,
|
private:
|
||||||
const string& errmsg) { // Error message or "" to suppress
|
string preprocOpen(FileLine* fl, V3InFilter* filterp,
|
||||||
// Returns true if successful
|
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
|
// Try a pure name in case user has a bogus `filename they don't expect
|
||||||
string filename = v3Global.opt.filePath(fl, modname, lastpath, errmsg);
|
string filename = v3Global.opt.filePath(fl, modname, lastpath, errmsg);
|
||||||
if (filename=="") {
|
if (filename=="") {
|
||||||
@@ -131,13 +146,14 @@ protected:
|
|||||||
|
|
||||||
filename = v3Global.opt.filePath(fl, ppmodname, lastpath, errmsg);
|
filename = v3Global.opt.filePath(fl, ppmodname, lastpath, errmsg);
|
||||||
}
|
}
|
||||||
if (filename=="") return false; // Not found
|
if (filename=="") return ""; // Not found
|
||||||
|
|
||||||
UINFO(2," Reading "<<filename<<endl);
|
UINFO(2," Reading "<<filename<<endl);
|
||||||
s_preprocp->openFile(fl, filterp, filename);
|
s_preprocp->openFile(fl, filterp, filename);
|
||||||
return true;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
V3PreShellImp() {}
|
V3PreShellImp() {}
|
||||||
~V3PreShellImp() {}
|
~V3PreShellImp() {}
|
||||||
|
|||||||
+14
-6
@@ -226,7 +226,9 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void createTableVars(AstNode* nodep) {
|
void createTableVars(AstNode* nodep) {
|
||||||
// Create table for each output
|
// Create table for each output
|
||||||
|
typedef std::map<string,int> NameCounts;
|
||||||
|
NameCounts namecounts;
|
||||||
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin(); it!=m_outVarps.end(); ++it) {
|
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin(); it!=m_outVarps.end(); ++it) {
|
||||||
AstVarScope* outvscp = *it;
|
AstVarScope* outvscp = *it;
|
||||||
AstVar* outvarp = outvscp->varp();
|
AstVar* outvarp = outvscp->varp();
|
||||||
@@ -234,11 +236,17 @@ private:
|
|||||||
AstNodeArrayDType* dtypep
|
AstNodeArrayDType* dtypep
|
||||||
= new AstUnpackArrayDType(fl, outvarp->dtypep(),
|
= new AstUnpackArrayDType(fl, outvarp->dtypep(),
|
||||||
new AstRange(fl, VL_MASK_I(m_inWidth), 0));
|
new AstRange(fl, VL_MASK_I(m_inWidth), 0));
|
||||||
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
|
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
|
||||||
AstVar* tablevarp
|
string name = "__Vtable"+cvtToStr(m_modTables)+"_"+outvarp->name();
|
||||||
= new AstVar(fl, AstVarType::MODULETEMP,
|
NameCounts::iterator nit = namecounts.find(name);
|
||||||
"__Vtable" + cvtToStr(m_modTables) +"_"+outvarp->name(),
|
if (nit != namecounts.end()) {
|
||||||
dtypep);
|
// Multiple scopes can have same var name. We could append the
|
||||||
|
// scope name but that is very long, so just deduplicate.
|
||||||
|
name += "__dedup"+cvtToStr(++nit->second);
|
||||||
|
} else {
|
||||||
|
namecounts[name] = 0;
|
||||||
|
}
|
||||||
|
AstVar* tablevarp = new AstVar(fl, AstVarType::MODULETEMP, name, dtypep);
|
||||||
tablevarp->isConst(true);
|
tablevarp->isConst(true);
|
||||||
tablevarp->isStatic(true);
|
tablevarp->isStatic(true);
|
||||||
tablevarp->valuep(new AstInitArray(nodep->fileline(), dtypep, NULL));
|
tablevarp->valuep(new AstInitArray(nodep->fileline(), dtypep, NULL));
|
||||||
|
|||||||
+9
-5
@@ -1170,11 +1170,15 @@ private:
|
|||||||
nodep->replaceWith(outrefp);
|
nodep->replaceWith(outrefp);
|
||||||
// Insert new statements
|
// Insert new statements
|
||||||
visitp = insertBeforeStmt(nodep, beginp);
|
visitp = insertBeforeStmt(nodep, beginp);
|
||||||
} else {
|
} else {
|
||||||
// outvscp maybe non-NULL if calling a function in a taskref,
|
if (nodep->taskp()->isFunction()) {
|
||||||
// but if so we want to simply ignore the function result
|
nodep->v3warn(IGNOREDRETURN,
|
||||||
nodep->replaceWith(beginp);
|
"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
|
// Cleanup
|
||||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||||
UINFO(4," FTask REF Done.\n");
|
UINFO(4," FTask REF Done.\n");
|
||||||
|
|||||||
+1
-1
@@ -511,7 +511,7 @@ private:
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AstNode* clrp = new AstAssign(fl, new AstVarRef(fl, m_activityVscp, true),
|
AstNode* clrp = new AstAssign(fl, new AstVarRef(fl, m_activityVscp, true),
|
||||||
new AstConst(fl, V3Number(fl, m_activityVscp->width())));
|
new AstConst(fl, V3Number(fl, m_activityVscp->width(), 0)));
|
||||||
m_fullFuncp->addFinalsp(clrp->cloneTree(true));
|
m_fullFuncp->addFinalsp(clrp->cloneTree(true));
|
||||||
m_chgFuncp->addFinalsp(clrp);
|
m_chgFuncp->addFinalsp(clrp);
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-2
@@ -2232,6 +2232,19 @@ private:
|
|||||||
userIterateAndNext(nodep->strgp(), WidthVP(SELF,BOTH).p());
|
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) {
|
virtual void visit(AstFScanF* nodep) {
|
||||||
if (m_vup->prelim()) {
|
if (m_vup->prelim()) {
|
||||||
nodep->dtypeSetSigned32(); // Spec says integer return
|
nodep->dtypeSetSigned32(); // Spec says integer return
|
||||||
@@ -3157,8 +3170,26 @@ private:
|
|||||||
nodepr = newp;
|
nodepr = newp;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
// X/Z also upper bit extend. In pre-SV only to 32-bits, SV forever.
|
||||||
return false; // No change
|
else if (!constp->num().sized()
|
||||||
|
// Make it the proper size. Careful of proper extension of 0's/1's
|
||||||
|
&& expWidth > 32 && constp->num().isMsbXZ()) {
|
||||||
|
constp->v3warn(WIDTH, "Unsized constant being X/Z extended to "
|
||||||
|
<<expWidth<<" bits: "<<constp->prettyName());
|
||||||
|
V3Number num (constp->fileline(), expWidth);
|
||||||
|
num.opExtendXZ(constp->num(), constp->width());
|
||||||
|
AstNode* newp = new AstConst(constp->fileline(), num);
|
||||||
|
// Spec says always unsigned with proper width
|
||||||
|
if (debug()>4) constp->dumpTree(cout," fixUnszExtend_old: ");
|
||||||
|
if (debug()>4) newp->dumpTree(cout," _new: ");
|
||||||
|
constp->replaceWith(newp);
|
||||||
|
constp->deleteTree(); VL_DANGLING(constp);
|
||||||
|
// Tell caller the new constp, and that we changed it.
|
||||||
|
nodepr = newp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false; // No change
|
||||||
}
|
}
|
||||||
|
|
||||||
bool similarDTypeRecurse(AstNodeDType* node1p, AstNodeDType* node2p) {
|
bool similarDTypeRecurse(AstNodeDType* node1p, AstNodeDType* node2p) {
|
||||||
@@ -3172,6 +3203,18 @@ private:
|
|||||||
underp = iterateCheck(nodep,"file_descriptor",underp,SELF,FINAL,expDTypep,EXTEND_EXP);
|
underp = iterateCheck(nodep,"file_descriptor",underp,SELF,FINAL,expDTypep,EXTEND_EXP);
|
||||||
if (underp) {} // cppcheck
|
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) {
|
void iterateCheckReal(AstNode* nodep, const char* side, AstNode* underp, Stage stage) {
|
||||||
// Coerce child to real if not already. Child is self-determined
|
// Coerce child to real if not already. Child is self-determined
|
||||||
// e.g. nodep=ADDD, underp=ADD in ADDD(ADD(a,b), real-CONST)
|
// e.g. nodep=ADDD, underp=ADD in ADDD(ADD(a,b), real-CONST)
|
||||||
|
|||||||
+58
-58
@@ -32,35 +32,35 @@
|
|||||||
class VlcBuckets {
|
class VlcBuckets {
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
vluint64_t* m_datap; ///< Pointer to first bucket (dynamically allocated)
|
vluint64_t* m_datap; ///< Pointer to first bucket (dynamically allocated)
|
||||||
vluint64_t m_dataSize; ///< Current entries in m_datap
|
vluint64_t m_dataSize; ///< Current entries in m_datap
|
||||||
vluint64_t m_bucketsCovered; ///< Num buckets with sufficient coverage
|
vluint64_t m_bucketsCovered; ///< Num buckets with sufficient coverage
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static inline vluint64_t covBit(vluint64_t point) { return 1ULL<<(point & 63); }
|
static inline vluint64_t covBit(vluint64_t point) { return 1ULL<<(point & 63); }
|
||||||
inline vluint64_t allocSize() const { return sizeof(vluint64_t) * m_dataSize / 64; }
|
inline vluint64_t allocSize() const { return sizeof(vluint64_t) * m_dataSize / 64; }
|
||||||
void allocate(vluint64_t point) {
|
void allocate(vluint64_t point) {
|
||||||
vluint64_t oldsize = m_dataSize;
|
vluint64_t oldsize = m_dataSize;
|
||||||
if (m_dataSize<point) m_dataSize=(point+64) & ~63ULL; // Keep power of two
|
if (m_dataSize<point) m_dataSize=(point+64) & ~63ULL; // Keep power of two
|
||||||
m_dataSize *= 2;
|
m_dataSize *= 2;
|
||||||
//UINFO(9, "Realloc "<<allocSize()<<" for "<<point<<" "<<cvtToHex(m_datap)<<endl);
|
//UINFO(9, "Realloc "<<allocSize()<<" for "<<point<<" "<<cvtToHex(m_datap)<<endl);
|
||||||
vluint64_t* newp = (vluint64_t*)realloc(m_datap, allocSize());
|
vluint64_t* newp = (vluint64_t*)realloc(m_datap, allocSize());
|
||||||
if (!newp) { free(m_datap); v3fatal("Out of memory increasing buckets"); }
|
if (!newp) { free(m_datap); v3fatal("Out of memory increasing buckets"); }
|
||||||
m_datap = newp;
|
m_datap = newp;
|
||||||
for (vluint64_t i=oldsize; i<m_dataSize; i+=64) m_datap[i/64] = 0;
|
for (vluint64_t i=oldsize; i<m_dataSize; i+=64) m_datap[i/64] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VlcBuckets() {
|
VlcBuckets() {
|
||||||
m_dataSize = 0;
|
m_dataSize = 0;
|
||||||
m_datap = NULL;
|
m_datap = NULL;
|
||||||
m_bucketsCovered = 0;
|
m_bucketsCovered = 0;
|
||||||
allocate(1024);
|
allocate(1024);
|
||||||
}
|
}
|
||||||
~VlcBuckets() {
|
~VlcBuckets() {
|
||||||
m_dataSize = 0;
|
m_dataSize = 0;
|
||||||
free(m_datap); m_datap=NULL;
|
free(m_datap); m_datap=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
@@ -69,66 +69,66 @@ public:
|
|||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
void addData(vluint64_t point, vluint64_t hits) {
|
void addData(vluint64_t point, vluint64_t hits) {
|
||||||
if (hits >= sufficient()) {
|
if (hits >= sufficient()) {
|
||||||
//UINFO(9," addData "<<point<<" "<<hits<<" size="<<m_dataSize<<endl);
|
//UINFO(9," addData "<<point<<" "<<hits<<" size="<<m_dataSize<<endl);
|
||||||
if (point >= m_dataSize) allocate(point);
|
if (point >= m_dataSize) allocate(point);
|
||||||
m_datap[point/64] |= covBit(point);
|
m_datap[point/64] |= covBit(point);
|
||||||
m_bucketsCovered++;
|
m_bucketsCovered++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void clearHits(vluint64_t point) const {
|
void clearHits(vluint64_t point) const {
|
||||||
if (point >= m_dataSize) {
|
if (point >= m_dataSize) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
m_datap[point/64] &= ~covBit(point);
|
m_datap[point/64] &= ~covBit(point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool exists(vluint64_t point) const {
|
bool exists(vluint64_t point) const {
|
||||||
if (point >= m_dataSize) {
|
if (point >= m_dataSize) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return (m_datap[point/64] & covBit(point)) ? 1:0;
|
return (m_datap[point/64] & covBit(point)) ? 1:0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vluint64_t hits(vluint64_t point) const {
|
vluint64_t hits(vluint64_t point) const {
|
||||||
if (point >= m_dataSize) {
|
if (point >= m_dataSize) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return (m_datap[point/64] & covBit(point)) ? 1:0;
|
return (m_datap[point/64] & covBit(point)) ? 1:0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vluint64_t popCount() const {
|
vluint64_t popCount() const {
|
||||||
vluint64_t pop = 0;
|
vluint64_t pop = 0;
|
||||||
for (vluint64_t i=0; i<m_dataSize; i++) {
|
for (vluint64_t i=0; i<m_dataSize; i++) {
|
||||||
if (hits(i)) pop++;
|
if (hits(i)) pop++;
|
||||||
}
|
}
|
||||||
return pop;
|
return pop;
|
||||||
}
|
}
|
||||||
vluint64_t dataPopCount(const VlcBuckets& remaining) {
|
vluint64_t dataPopCount(const VlcBuckets& remaining) {
|
||||||
vluint64_t pop = 0;
|
vluint64_t pop = 0;
|
||||||
for (vluint64_t i=0; i<m_dataSize; i++) {
|
for (vluint64_t i=0; i<m_dataSize; i++) {
|
||||||
if (hits(i) && remaining.hits(i)) pop++;
|
if (hits(i) && remaining.hits(i)) pop++;
|
||||||
}
|
}
|
||||||
return pop;
|
return pop;
|
||||||
}
|
}
|
||||||
void orData(const VlcBuckets& ordata) {
|
void orData(const VlcBuckets& ordata) {
|
||||||
for (vluint64_t i=0; i<m_dataSize; i++) {
|
for (vluint64_t i=0; i<m_dataSize; i++) {
|
||||||
if (hits(i) && ordata.hits(i)) {
|
if (hits(i) && ordata.hits(i)) {
|
||||||
clearHits(i);
|
clearHits(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump() const {
|
void dump() const {
|
||||||
cout<<"# ";
|
cout<<"# ";
|
||||||
for (vluint64_t i=0; i<m_dataSize; i++) {
|
for (vluint64_t i=0; i<m_dataSize; i++) {
|
||||||
if (hits(i)) cout<<","<<i;
|
if (hits(i)) cout<<","<<i;
|
||||||
}
|
}
|
||||||
cout<<endl;
|
cout<<endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
#endif // guard
|
#endif // guard
|
||||||
|
|||||||
+67
-68
@@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
void VlcOptions::addReadFile(const string& filename) {
|
void VlcOptions::addReadFile(const string& filename) {
|
||||||
if (m_readFiles.find(filename) == m_readFiles.end()) {
|
if (m_readFiles.find(filename) == m_readFiles.end()) {
|
||||||
m_readFiles.insert(filename);
|
m_readFiles.insert(filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,9 +59,9 @@ bool VlcOptions::onoff(const char* sw, const char* arg, bool& flag) {
|
|||||||
// if sw=="-noarg", then return true (found it), and flag=false
|
// if sw=="-noarg", then return true (found it), and flag=false
|
||||||
// else return false
|
// else return false
|
||||||
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.");
|
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.");
|
||||||
if (0==strcmp(sw,arg)) { flag=true; return true; }
|
if (0==strcmp(sw,arg)) { flag = true; return true; }
|
||||||
else if (0==strncmp(sw,"-no",3) && (0==strcmp(sw+3,arg+1))) { flag=false; return true; }
|
else if (0==strncmp(sw,"-no",3) && (0==strcmp(sw+3,arg+1))) { flag = false; return true; }
|
||||||
else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag=false; return true; }
|
else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag = false; return true; }
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,58 +71,58 @@ void VlcOptions::parseOptsList(int argc, char** argv) {
|
|||||||
// May be called recursively when there are -f files.
|
// May be called recursively when there are -f files.
|
||||||
#define shift { ++i; }
|
#define shift { ++i; }
|
||||||
for (int i=0; i<argc; ) {
|
for (int i=0; i<argc; ) {
|
||||||
UINFO(9, " Option: "<<argv[i]<<endl);
|
UINFO(9, " Option: "<<argv[i]<<endl);
|
||||||
if (argv[i][0]=='-') {
|
if (argv[i][0]=='-') {
|
||||||
const char *sw = argv[i];
|
const char *sw = argv[i];
|
||||||
bool flag = true;
|
bool flag = true;
|
||||||
// Allow gnu -- switches
|
// Allow gnu -- switches
|
||||||
if (sw[0]=='-' && sw[1]=='-') ++sw;
|
if (sw[0]=='-' && sw[1]=='-') ++sw;
|
||||||
if (0) {}
|
if (0) {}
|
||||||
// Single switches
|
// Single switches
|
||||||
else if ( onoff (sw, "-annotate-all", flag/*ref*/) ) { m_annotateAll = flag; }
|
else if ( onoff (sw, "-annotate-all", flag/*ref*/) ) { m_annotateAll = flag; }
|
||||||
else if ( onoff (sw, "-rank", flag/*ref*/) ) { m_rank = flag; }
|
else if ( onoff (sw, "-rank", flag/*ref*/) ) { m_rank = flag; }
|
||||||
else if ( onoff (sw, "-unlink", flag/*ref*/) ) { m_unlink = flag; }
|
else if ( onoff (sw, "-unlink", flag/*ref*/) ) { m_unlink = flag; }
|
||||||
// Parameterized switches
|
// Parameterized switches
|
||||||
else if ( !strcmp (sw, "-annotate-min") && (i+1)<argc ) {
|
else if ( !strcmp (sw, "-annotate-min") && (i+1)<argc ) {
|
||||||
shift;
|
shift;
|
||||||
m_annotateMin = atoi(argv[i]);
|
m_annotateMin = atoi(argv[i]);
|
||||||
}
|
}
|
||||||
else if ( !strcmp (sw, "-annotate") && (i+1)<argc ) {
|
else if ( !strcmp (sw, "-annotate") && (i+1)<argc ) {
|
||||||
shift;
|
shift;
|
||||||
m_annotateOut = argv[i];
|
m_annotateOut = argv[i];
|
||||||
}
|
}
|
||||||
else if ( !strcmp (sw, "-debug") ) {
|
else if ( !strcmp (sw, "-debug") ) {
|
||||||
V3Error::debugDefault(3);
|
V3Error::debugDefault(3);
|
||||||
}
|
}
|
||||||
else if ( !strcmp (sw, "-debugi") && (i+1)<argc ) {
|
else if ( !strcmp (sw, "-debugi") && (i+1)<argc ) {
|
||||||
shift;
|
shift;
|
||||||
V3Error::debugDefault(atoi(argv[i]));
|
V3Error::debugDefault(atoi(argv[i]));
|
||||||
}
|
}
|
||||||
else if ( !strcmp (sw, "-V") ) {
|
else if ( !strcmp (sw, "-V") ) {
|
||||||
showVersion(true);
|
showVersion(true);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
else if ( !strcmp (sw, "-version") ) {
|
else if ( !strcmp (sw, "-version") ) {
|
||||||
showVersion(false);
|
showVersion(false);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
else if ( !strcmp (sw, "-write") && (i+1)<argc ) {
|
else if ( !strcmp (sw, "-write") && (i+1)<argc ) {
|
||||||
shift;
|
shift;
|
||||||
m_writeFile = argv[i];
|
m_writeFile = argv[i];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
v3fatal("Invalid option: "<<argv[i]);
|
v3fatal("Invalid option: "<<argv[i]);
|
||||||
}
|
}
|
||||||
shift;
|
shift;
|
||||||
} // - options
|
} // - options
|
||||||
else if (1) {
|
else if (1) {
|
||||||
addReadFile(argv[i]);
|
addReadFile(argv[i]);
|
||||||
shift;
|
shift;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
v3fatal("Invalid argument: "<<argv[i]);
|
v3fatal("Invalid argument: "<<argv[i]);
|
||||||
shift;
|
shift;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#undef shift
|
#undef shift
|
||||||
}
|
}
|
||||||
@@ -154,20 +154,20 @@ int main(int argc, char** argv, char** env) {
|
|||||||
top.opt.parseOptsList(argc-1, argv+1);
|
top.opt.parseOptsList(argc-1, argv+1);
|
||||||
|
|
||||||
if (top.opt.readFiles().empty()) {
|
if (top.opt.readFiles().empty()) {
|
||||||
top.opt.addReadFile("vlt_coverage.dat");
|
top.opt.addReadFile("vlt_coverage.dat");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const VlStringSet& readFiles = top.opt.readFiles();
|
const VlStringSet& readFiles = top.opt.readFiles();
|
||||||
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
|
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
|
||||||
string filename = *it;
|
string filename = *it;
|
||||||
top.readCoverage(filename);
|
top.readCoverage(filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug() >= 9) {
|
if (debug() >= 9) {
|
||||||
top.tests().dump(true);
|
top.tests().dump(true);
|
||||||
top.points().dump();
|
top.points().dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
V3Error::abortIfWarnings();
|
V3Error::abortIfWarnings();
|
||||||
@@ -176,19 +176,19 @@ int main(int argc, char** argv, char** env) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (top.opt.rank()) {
|
if (top.opt.rank()) {
|
||||||
top.rank();
|
top.rank();
|
||||||
top.tests().dump(false);
|
top.tests().dump(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!top.opt.writeFile().empty()) {
|
if (!top.opt.writeFile().empty()) {
|
||||||
top.writeCoverage(top.opt.writeFile());
|
top.writeCoverage(top.opt.writeFile());
|
||||||
V3Error::abortIfWarnings();
|
V3Error::abortIfWarnings();
|
||||||
if (top.opt.unlink()) {
|
if (top.opt.unlink()) {
|
||||||
const VlStringSet& readFiles = top.opt.readFiles();
|
const VlStringSet& readFiles = top.opt.readFiles();
|
||||||
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
|
for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
|
||||||
string filename = *it;
|
string filename = *it;
|
||||||
unlink(filename.c_str());
|
unlink(filename.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,4 +201,3 @@ int main(int argc, char** argv, char** env) {
|
|||||||
// Local Variables:
|
// Local Variables:
|
||||||
// compile-command: "v4make bin/verilator_coverage --debugi 9 test_regress/t/t_vlcov_data_*.dat"
|
// compile-command: "v4make bin/verilator_coverage --debugi 9 test_regress/t/t_vlcov_data_*.dat"
|
||||||
// End:
|
// End:
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -38,13 +38,13 @@ typedef std::set<string> VlStringSet;
|
|||||||
|
|
||||||
class VlcOptions {
|
class VlcOptions {
|
||||||
// MEMBERS (general options)
|
// MEMBERS (general options)
|
||||||
string m_annotateOut; // main switch: --annotate I<output_directory>
|
string m_annotateOut; // main switch: --annotate I<output_directory>
|
||||||
bool m_annotateAll; // main switch: --annotate-all
|
bool m_annotateAll; // main switch: --annotate-all
|
||||||
int m_annotateMin; // main switch: --annotate-min I<count>
|
int m_annotateMin; // main switch: --annotate-min I<count>
|
||||||
VlStringSet m_readFiles; // main switch: --read
|
VlStringSet m_readFiles; // main switch: --read
|
||||||
bool m_rank; // main switch: --rank
|
bool m_rank; // main switch: --rank
|
||||||
bool m_unlink; // main switch: --unlink
|
bool m_unlink; // main switch: --unlink
|
||||||
string m_writeFile; // main switch: --write
|
string m_writeFile; // main switch: --write
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// METHODS
|
// METHODS
|
||||||
@@ -54,10 +54,10 @@ private:
|
|||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VlcOptions() {
|
VlcOptions() {
|
||||||
m_annotateAll = false;
|
m_annotateAll = false;
|
||||||
m_annotateMin = 10;
|
m_annotateMin = 10;
|
||||||
m_rank = false;
|
m_rank = false;
|
||||||
m_unlink = false;
|
m_unlink = false;
|
||||||
}
|
}
|
||||||
~VlcOptions() {}
|
~VlcOptions() {}
|
||||||
void setDebugMode(int level);
|
void setDebugMode(int level);
|
||||||
@@ -81,4 +81,4 @@ public:
|
|||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
#endif // guard
|
#endif // guard
|
||||||
|
|||||||
+49
-49
@@ -36,18 +36,18 @@
|
|||||||
class VlcPoint {
|
class VlcPoint {
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
string m_name; //< Name of the point
|
string m_name; //< Name of the point
|
||||||
vluint64_t m_pointNum; //< Point number
|
vluint64_t m_pointNum; //< Point number
|
||||||
vluint64_t m_testsCovering;//< Number tests with non-zero coverage of this point
|
vluint64_t m_testsCovering; //< Number tests with non-zero coverage of this point
|
||||||
vluint64_t m_count; //< Count of hits across all tests
|
vluint64_t m_count; //< Count of hits across all tests
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VlcPoint(const string& name, int pointNum) {
|
VlcPoint(const string& name, int pointNum) {
|
||||||
m_name = name;
|
m_name = name;
|
||||||
m_pointNum = pointNum;
|
m_pointNum = pointNum;
|
||||||
m_testsCovering = 0;
|
m_testsCovering = 0;
|
||||||
m_count = 0;
|
m_count = 0;
|
||||||
}
|
}
|
||||||
~VlcPoint() {}
|
~VlcPoint() {}
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
@@ -66,31 +66,31 @@ public:
|
|||||||
int column() const { return atoi(keyExtract(VL_CIK_COLUMN).c_str()); }
|
int column() const { return atoi(keyExtract(VL_CIK_COLUMN).c_str()); }
|
||||||
// METHODS
|
// METHODS
|
||||||
string keyExtract(const char* shortKey) const {
|
string keyExtract(const char* shortKey) const {
|
||||||
// Hot function
|
// Hot function
|
||||||
size_t shortLen = strlen(shortKey);
|
size_t shortLen = strlen(shortKey);
|
||||||
const string namestr = name();
|
const string namestr = name();
|
||||||
for (const char* cp = namestr.c_str(); *cp; ++cp) {
|
for (const char* cp = namestr.c_str(); *cp; ++cp) {
|
||||||
if (*cp == '\001') {
|
if (*cp == '\001') {
|
||||||
if (0==strncmp(cp+1, shortKey, shortLen)
|
if (0==strncmp(cp+1, shortKey, shortLen)
|
||||||
&& cp[shortLen+1] == '\002') {
|
&& cp[shortLen+1] == '\002') {
|
||||||
cp += shortLen+2; // Skip \001+short+\002
|
cp += shortLen+2; // Skip \001+short+\002
|
||||||
const char* ep = cp;
|
const char* ep = cp;
|
||||||
while (*ep && *ep != '\001') ++ep;
|
while (*ep && *ep != '\001') ++ep;
|
||||||
return string(cp, ep-cp);
|
return string(cp, ep-cp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
static void dumpHeader() {
|
static void dumpHeader() {
|
||||||
cout<<"Points:\n";
|
cout<<"Points:\n";
|
||||||
cout<<" Num, TestsCover, Count, Name"<<endl;
|
cout<<" Num, TestsCover, Count, Name"<<endl;
|
||||||
}
|
}
|
||||||
void dump() const {
|
void dump() const {
|
||||||
cout<<" "<<std::setw(8)<<std::setfill('0')<<pointNum()
|
cout<<" "<<std::setw(8)<<std::setfill('0')<<pointNum()
|
||||||
<<", "<<std::setw(7)<<std::setfill(' ')<<testsCovering()
|
<<", "<<std::setw(7)<<std::setfill(' ')<<testsCovering()
|
||||||
<<", "<<std::setw(7)<<std::setfill(' ')<<count()
|
<<", "<<std::setw(7)<<std::setfill(' ')<<count()
|
||||||
<<", \""<<name()<<"\""<<endl;
|
<<", \""<<name()<<"\""<<endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,40 +115,40 @@ public:
|
|||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VlcPoints() {
|
VlcPoints() {
|
||||||
m_numPoints = 0;
|
m_numPoints = 0;
|
||||||
}
|
}
|
||||||
~VlcPoints() {}
|
~VlcPoints() {}
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
void dump() {
|
void dump() {
|
||||||
UINFO(2,"dumpPoints...\n");
|
UINFO(2,"dumpPoints...\n");
|
||||||
VlcPoint::dumpHeader();
|
VlcPoint::dumpHeader();
|
||||||
for (VlcPoints::ByName::iterator it=begin(); it!=end(); ++it) {
|
for (VlcPoints::ByName::iterator it=begin(); it!=end(); ++it) {
|
||||||
const VlcPoint& point = pointNumber(it->second);
|
const VlcPoint& point = pointNumber(it->second);
|
||||||
point.dump();
|
point.dump();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VlcPoint& pointNumber(vluint64_t num) {
|
VlcPoint& pointNumber(vluint64_t num) {
|
||||||
return m_points[num];
|
return m_points[num];
|
||||||
}
|
}
|
||||||
vluint64_t findAddPoint(const string& name, vluint64_t count) {
|
vluint64_t findAddPoint(const string& name, vluint64_t count) {
|
||||||
vluint64_t pointnum;
|
vluint64_t pointnum;
|
||||||
NameMap::iterator iter = m_nameMap.find(name);
|
NameMap::iterator iter = m_nameMap.find(name);
|
||||||
if (iter != m_nameMap.end()) {
|
if (iter != m_nameMap.end()) {
|
||||||
pointnum = iter->second;
|
pointnum = iter->second;
|
||||||
m_points[pointnum].countInc(count);
|
m_points[pointnum].countInc(count);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pointnum = m_numPoints++;
|
pointnum = m_numPoints++;
|
||||||
VlcPoint point (name, pointnum);
|
VlcPoint point (name, pointnum);
|
||||||
point.countInc(count);
|
point.countInc(count);
|
||||||
m_points.push_back(point);
|
m_points.push_back(point);
|
||||||
m_nameMap.insert(make_pair(point.name(), point.pointNum()));
|
m_nameMap.insert(make_pair(point.name(), point.pointNum()));
|
||||||
}
|
}
|
||||||
return pointnum;
|
return pointnum;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
#endif // guard
|
#endif // guard
|
||||||
|
|||||||
+36
-36
@@ -33,18 +33,18 @@
|
|||||||
class VlcSourceCount {
|
class VlcSourceCount {
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
int m_lineno; ///< Line number
|
int m_lineno; ///< Line number
|
||||||
int m_column; ///< Column number
|
int m_column; ///< Column number
|
||||||
vluint64_t m_count; ///< Count
|
vluint64_t m_count; ///< Count
|
||||||
bool m_ok; ///< Coverage is above threshold
|
bool m_ok; ///< Coverage is above threshold
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VlcSourceCount(int lineno, int column) {
|
VlcSourceCount(int lineno, int column) {
|
||||||
m_lineno = lineno;
|
m_lineno = lineno;
|
||||||
m_column = column;
|
m_column = column;
|
||||||
m_count = 0;
|
m_count = 0;
|
||||||
m_ok = false;
|
m_ok = false;
|
||||||
}
|
}
|
||||||
~VlcSourceCount() {}
|
~VlcSourceCount() {}
|
||||||
|
|
||||||
@@ -56,8 +56,8 @@ public:
|
|||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
void incCount(vluint64_t count, bool ok) {
|
void incCount(vluint64_t count, bool ok) {
|
||||||
m_count += count;
|
m_count += count;
|
||||||
if (ok) m_ok = true;
|
if (ok) m_ok = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,15 +72,15 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
string m_name; //< Name of the source file
|
string m_name; //< Name of the source file
|
||||||
bool m_needed; //< Need to annotate; has low coverage
|
bool m_needed; //< Need to annotate; has low coverage
|
||||||
LinenoMap m_lines; //< Map of each annotated line
|
LinenoMap m_lines; //< Map of each annotated line
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
explicit VlcSource(const string& name) {
|
explicit VlcSource(const string& name) {
|
||||||
m_name = name;
|
m_name = name;
|
||||||
m_needed = false;
|
m_needed = false;
|
||||||
}
|
}
|
||||||
~VlcSource() {}
|
~VlcSource() {}
|
||||||
|
|
||||||
@@ -92,17 +92,17 @@ public:
|
|||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
void incCount(int lineno, int column, vluint64_t count, bool ok) {
|
void incCount(int lineno, int column, vluint64_t count, bool ok) {
|
||||||
LinenoMap::iterator lit = m_lines.find(lineno);
|
LinenoMap::iterator lit = m_lines.find(lineno);
|
||||||
if (lit == m_lines.end()) {
|
if (lit == m_lines.end()) {
|
||||||
lit = m_lines.insert(make_pair(lineno,ColumnMap())).first;
|
lit = m_lines.insert(make_pair(lineno, ColumnMap())).first;
|
||||||
}
|
}
|
||||||
ColumnMap& cmap = lit->second;
|
ColumnMap& cmap = lit->second;
|
||||||
ColumnMap::iterator cit = cmap.find(column);
|
ColumnMap::iterator cit = cmap.find(column);
|
||||||
if (cit == cmap.end()) {
|
if (cit == cmap.end()) {
|
||||||
cit = cmap.insert(make_pair(column,VlcSourceCount(lineno, column))).first;
|
cit = cmap.insert(make_pair(column, VlcSourceCount(lineno, column))).first;
|
||||||
}
|
}
|
||||||
VlcSourceCount& sc = cit->second;
|
VlcSourceCount& sc = cit->second;
|
||||||
sc.incCount(count,ok);
|
sc.incCount(count, ok);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ public:
|
|||||||
typedef std::map<string,VlcSource> NameMap;
|
typedef std::map<string,VlcSource> NameMap;
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
NameMap m_sources; //< List of all sources
|
NameMap m_sources; //< List of all sources
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// ITERATORS
|
// ITERATORS
|
||||||
@@ -130,17 +130,17 @@ public:
|
|||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
VlcSource& findNewSource(const string& name) {
|
VlcSource& findNewSource(const string& name) {
|
||||||
NameMap::iterator iter = m_sources.find(name);
|
NameMap::iterator iter = m_sources.find(name);
|
||||||
if (iter != m_sources.end()) {
|
if (iter != m_sources.end()) {
|
||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
iter = m_sources.insert(make_pair(name, VlcSource(name))).first;
|
iter = m_sources.insert(make_pair(name, VlcSource(name))).first;
|
||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|||||||
+36
-36
@@ -36,23 +36,23 @@
|
|||||||
class VlcTest {
|
class VlcTest {
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
string m_name; //< Name of the test
|
string m_name; //< Name of the test
|
||||||
double m_computrons; //< Runtime for the test
|
double m_computrons; //< Runtime for the test
|
||||||
vluint64_t m_testrun; //< Test run number, for database use
|
vluint64_t m_testrun; //< Test run number, for database use
|
||||||
vluint64_t m_rank; //< Execution rank suggestion
|
vluint64_t m_rank; //< Execution rank suggestion
|
||||||
vluint64_t m_rankPoints; //< Ranked additional points
|
vluint64_t m_rankPoints; //< Ranked additional points
|
||||||
vluint64_t m_user; //< User data for algorithms (not persisted in .dat file)
|
vluint64_t m_user; //< User data for algorithms (not persisted in .dat file)
|
||||||
VlcBuckets m_buckets; //< Coverage data for each coverage point
|
VlcBuckets m_buckets; //< Coverage data for each coverage point
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VlcTest(const string& name, vluint64_t testrun, double comp) {
|
VlcTest(const string& name, vluint64_t testrun, double comp) {
|
||||||
m_name = name;
|
m_name = name;
|
||||||
m_computrons = comp;
|
m_computrons = comp;
|
||||||
m_testrun = testrun;
|
m_testrun = testrun;
|
||||||
m_rank = 0;
|
m_rank = 0;
|
||||||
m_rankPoints = 0;
|
m_rankPoints = 0;
|
||||||
m_user = 0;
|
m_user = 0;
|
||||||
}
|
}
|
||||||
~VlcTest() {}
|
~VlcTest() {}
|
||||||
|
|
||||||
@@ -71,20 +71,20 @@ public:
|
|||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
static void dumpHeader() {
|
static void dumpHeader() {
|
||||||
cout<<"Tests:\n";
|
cout<<"Tests:\n";
|
||||||
//cout<<" Testrun, Computrons,"; // Currently not loaded
|
//cout<<" Testrun, Computrons,"; // Currently not loaded
|
||||||
cout<<" Covered, Rank, RankPts, Filename"<<endl;
|
cout<<" Covered, Rank, RankPts, Filename"<<endl;
|
||||||
}
|
}
|
||||||
void dump(bool bucketsToo) {
|
void dump(bool bucketsToo) {
|
||||||
if (testrun() || computrons()!=0.0) {
|
if (testrun() || computrons()!=0.0) {
|
||||||
cout<<" "<<std::setw(8)<<std::setfill('0')<<testrun()
|
cout<<" "<<std::setw(8)<<std::setfill('0')<<testrun()
|
||||||
<<", "<<std::setw(7)<<std::setfill(' ')<<computrons()<<",";
|
<<", "<<std::setw(7)<<std::setfill(' ')<<computrons()<<",";
|
||||||
}
|
}
|
||||||
cout<<" "<<std::setw(7)<<std::setfill(' ')<<bucketsCovered()
|
cout<<" "<<std::setw(7)<<std::setfill(' ')<<bucketsCovered()
|
||||||
<<", "<<std::setw(7)<<std::setfill(' ')<<rank()
|
<<", "<<std::setw(7)<<std::setfill(' ')<<rank()
|
||||||
<<", "<<std::setw(7)<<std::setfill(' ')<<rankPoints()
|
<<", "<<std::setw(7)<<std::setfill(' ')<<rankPoints()
|
||||||
<<", \""<<name()<<"\""<<endl;
|
<<", \""<<name()<<"\""<<endl;
|
||||||
if (bucketsToo) m_buckets.dump();
|
if (bucketsToo) m_buckets.dump();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ public:
|
|||||||
typedef std::vector<VlcTest*> ByName;
|
typedef std::vector<VlcTest*> ByName;
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
ByName m_tests; //< List of all tests
|
ByName m_tests; //< List of all tests
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// ITERATORS
|
// ITERATORS
|
||||||
@@ -109,31 +109,31 @@ public:
|
|||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VlcTests() {}
|
VlcTests() {}
|
||||||
~VlcTests() {
|
~VlcTests() {
|
||||||
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
|
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
|
||||||
delete *it; *it=NULL;
|
delete *it; *it=NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
void dump(bool bucketsToo) {
|
void dump(bool bucketsToo) {
|
||||||
UINFO(2,"dumpTests...\n");
|
UINFO(2,"dumpTests...\n");
|
||||||
VlcTest::dumpHeader();
|
VlcTest::dumpHeader();
|
||||||
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
|
for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
|
||||||
(*it)->dump(bucketsToo);
|
(*it)->dump(bucketsToo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VlcTest* newTest(const string& name, vluint64_t testrun, double comp) {
|
VlcTest* newTest(const string& name, vluint64_t testrun, double comp) {
|
||||||
VlcTest* testp = new VlcTest(name, testrun, comp);
|
VlcTest* testp = new VlcTest(name, testrun, comp);
|
||||||
m_tests.push_back(testp);
|
m_tests.push_back(testp);
|
||||||
return testp;
|
return testp;
|
||||||
}
|
}
|
||||||
void clearUser() {
|
void clearUser() {
|
||||||
for (ByName::iterator it = m_tests.begin(); it != m_tests.end(); ++it) {
|
for (ByName::iterator it = m_tests.begin(); it != m_tests.end(); ++it) {
|
||||||
(*it)->user(0);
|
(*it)->user(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|||||||
+122
-122
@@ -34,8 +34,8 @@ void VlcTop::readCoverage(const string& filename, bool nonfatal) {
|
|||||||
|
|
||||||
std::ifstream is(filename.c_str());
|
std::ifstream is(filename.c_str());
|
||||||
if (!is) {
|
if (!is) {
|
||||||
if (!nonfatal) v3fatal("Can't read "<<filename);
|
if (!nonfatal) v3fatal("Can't read "<<filename);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Testrun and computrons argument unsupported as yet
|
// Testrun and computrons argument unsupported as yet
|
||||||
@@ -45,23 +45,23 @@ void VlcTop::readCoverage(const string& filename, bool nonfatal) {
|
|||||||
string line = V3Os::getline(is);
|
string line = V3Os::getline(is);
|
||||||
//UINFO(9," got "<<line<<endl);
|
//UINFO(9," got "<<line<<endl);
|
||||||
if (line[0] == 'C') {
|
if (line[0] == 'C') {
|
||||||
string::size_type secspace=3;
|
string::size_type secspace = 3;
|
||||||
for (; secspace<line.length(); secspace++) {
|
for (; secspace<line.length(); secspace++) {
|
||||||
if (line[secspace]=='\'' && line[secspace+1]==' ') break;
|
if (line[secspace]=='\'' && line[secspace+1]==' ') break;
|
||||||
}
|
}
|
||||||
string point = line.substr(3,secspace-3);
|
string point = line.substr(3, secspace-3);
|
||||||
vluint64_t hits = atoll(line.c_str()+secspace+1);
|
vluint64_t hits = atoll(line.c_str()+secspace+1);
|
||||||
//UINFO(9," point '"<<point<<"'"<<" "<<hits<<endl);
|
//UINFO(9," point '"<<point<<"'"<<" "<<hits<<endl);
|
||||||
|
|
||||||
vluint64_t pointnum = points().findAddPoint(point, hits);
|
vluint64_t pointnum = points().findAddPoint(point, hits);
|
||||||
if (pointnum) {} // Prevent unused
|
if (pointnum) {} // Prevent unused
|
||||||
if (opt.rank()) { // Only if ranking - uses a lot of memory
|
if (opt.rank()) { // Only if ranking - uses a lot of memory
|
||||||
if (hits >= VlcBuckets::sufficient()) {
|
if (hits >= VlcBuckets::sufficient()) {
|
||||||
points().pointNumber(pointnum).testsCoveringInc();
|
points().pointNumber(pointnum).testsCoveringInc();
|
||||||
testp->buckets().addData(pointnum, hits);
|
testp->buckets().addData(pointnum, hits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,14 +70,14 @@ void VlcTop::writeCoverage(const string& filename) {
|
|||||||
|
|
||||||
std::ofstream os(filename.c_str());
|
std::ofstream os(filename.c_str());
|
||||||
if (!os) {
|
if (!os) {
|
||||||
v3fatal("Can't write "<<filename);
|
v3fatal("Can't write "<<filename);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
os << "# SystemC::Coverage-3" << endl;
|
os << "# SystemC::Coverage-3" << endl;
|
||||||
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
|
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
|
||||||
const VlcPoint& point = m_points.pointNumber(it->second);
|
const VlcPoint& point = m_points.pointNumber(it->second);
|
||||||
os <<"C '"<<point.name()<<"' " << point.count()<<endl;
|
os <<"C '"<<point.name()<<"' " << point.count()<<endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,32 +85,32 @@ void VlcTop::writeCoverage(const string& filename) {
|
|||||||
|
|
||||||
struct CmpComputrons {
|
struct CmpComputrons {
|
||||||
inline bool operator() (const VlcTest* lhsp, const VlcTest* rhsp) const {
|
inline bool operator() (const VlcTest* lhsp, const VlcTest* rhsp) const {
|
||||||
if (lhsp->computrons() != rhsp->computrons()) {
|
if (lhsp->computrons() != rhsp->computrons()) {
|
||||||
return lhsp->computrons() < rhsp->computrons();
|
return lhsp->computrons() < rhsp->computrons();
|
||||||
}
|
}
|
||||||
return lhsp->bucketsCovered() > rhsp->bucketsCovered();
|
return lhsp->bucketsCovered() > rhsp->bucketsCovered();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void VlcTop::rank() {
|
void VlcTop::rank() {
|
||||||
UINFO(2,"rank...\n");
|
UINFO(2,"rank...\n");
|
||||||
vluint64_t nextrank=1;
|
vluint64_t nextrank = 1;
|
||||||
|
|
||||||
// Sort by computrons, so fast tests get selected first
|
// Sort by computrons, so fast tests get selected first
|
||||||
std::vector<VlcTest*> bytime;
|
std::vector<VlcTest*> bytime;
|
||||||
for (VlcTests::ByName::iterator it=m_tests.begin(); it!=m_tests.end(); ++it) {
|
for (VlcTests::ByName::iterator it=m_tests.begin(); it!=m_tests.end(); ++it) {
|
||||||
VlcTest* testp = *it;
|
VlcTest* testp = *it;
|
||||||
if (testp->bucketsCovered()) { // else no points, so can't help us
|
if (testp->bucketsCovered()) { // else no points, so can't help us
|
||||||
bytime.push_back(*it);
|
bytime.push_back(*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort(bytime.begin(), bytime.end(), CmpComputrons()); // Sort the vector
|
sort(bytime.begin(), bytime.end(), CmpComputrons()); // Sort the vector
|
||||||
|
|
||||||
VlcBuckets remaining;
|
VlcBuckets remaining;
|
||||||
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
|
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
|
||||||
VlcPoint* pointp = &points().pointNumber(it->second);
|
VlcPoint* pointp = &points().pointNumber(it->second);
|
||||||
// If any tests hit this point, then we'll need to cover it.
|
// If any tests hit this point, then we'll need to cover it.
|
||||||
if (pointp->testsCovering()) { remaining.addData(pointp->pointNum(), 1); }
|
if (pointp->testsCovering()) { remaining.addData(pointp->pointNum(), 1); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additional Greedy algorithm
|
// Additional Greedy algorithm
|
||||||
@@ -118,26 +118,26 @@ void VlcTop::rank() {
|
|||||||
// then hierarchically solve a small subset of tests, and take resulting
|
// then hierarchically solve a small subset of tests, and take resulting
|
||||||
// solution and move up to larger subset of tests. (Aka quick sort.)
|
// solution and move up to larger subset of tests. (Aka quick sort.)
|
||||||
while (1) {
|
while (1) {
|
||||||
if (debug()) { UINFO(9,"Left on iter"<<nextrank<<": "); remaining.dump(); }
|
if (debug()) { UINFO(9,"Left on iter"<<nextrank<<": "); remaining.dump(); }
|
||||||
VlcTest* bestTestp = NULL;
|
VlcTest* bestTestp = NULL;
|
||||||
vluint64_t bestRemain = 0;
|
vluint64_t bestRemain = 0;
|
||||||
for (std::vector<VlcTest*>::iterator it=bytime.begin(); it!=bytime.end(); ++it) {
|
for (std::vector<VlcTest*>::iterator it=bytime.begin(); it!=bytime.end(); ++it) {
|
||||||
VlcTest* testp = *it;
|
VlcTest* testp = *it;
|
||||||
if (!testp->rank()) {
|
if (!testp->rank()) {
|
||||||
vluint64_t remain = testp->buckets().dataPopCount(remaining);
|
vluint64_t remain = testp->buckets().dataPopCount(remaining);
|
||||||
if (remain > bestRemain) {
|
if (remain > bestRemain) {
|
||||||
bestTestp = testp;
|
bestTestp = testp;
|
||||||
bestRemain = remain;
|
bestRemain = remain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (VlcTest* testp = bestTestp) {
|
if (VlcTest* testp = bestTestp) {
|
||||||
testp->rank(nextrank++);
|
testp->rank(nextrank++);
|
||||||
testp->rankPoints(bestRemain);
|
testp->rankPoints(bestRemain);
|
||||||
remaining.orData(bestTestp->buckets());
|
remaining.orData(bestTestp->buckets());
|
||||||
} else {
|
} else {
|
||||||
break; // No test covering more stuff found
|
break; // No test covering more stuff found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,18 +146,18 @@ void VlcTop::rank() {
|
|||||||
void VlcTop::annotateCalc() {
|
void VlcTop::annotateCalc() {
|
||||||
// Calculate per-line information into filedata structure
|
// Calculate per-line information into filedata structure
|
||||||
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
|
for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
|
||||||
const VlcPoint& point = m_points.pointNumber(it->second);
|
const VlcPoint& point = m_points.pointNumber(it->second);
|
||||||
string filename = point.filename();
|
string filename = point.filename();
|
||||||
int lineno = point.lineno();
|
int lineno = point.lineno();
|
||||||
if (!filename.empty() && lineno!=0) {
|
if (!filename.empty() && lineno!=0) {
|
||||||
int column = point.column();
|
int column = point.column();
|
||||||
VlcSource& source = sources().findNewSource(filename);
|
VlcSource& source = sources().findNewSource(filename);
|
||||||
string threshStr = point.thresh();
|
string threshStr = point.thresh();
|
||||||
unsigned thresh = (!threshStr.empty()) ? atoi(threshStr.c_str()) : opt.annotateMin();
|
unsigned thresh = (!threshStr.empty()) ? atoi(threshStr.c_str()) : opt.annotateMin();
|
||||||
bool ok = (point.count() >= thresh);
|
bool ok = (point.count() >= thresh);
|
||||||
UINFO(9, "AnnoCalc count "<<filename<<" "<<lineno<<" "<<point.count()<<endl);
|
UINFO(9, "AnnoCalc count "<<filename<<" "<<lineno<<" "<<point.count()<<endl);
|
||||||
source.incCount(lineno, column, point.count(), ok);
|
source.incCount(lineno, column, point.count(), ok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,23 +167,23 @@ void VlcTop::annotateCalcNeeded() {
|
|||||||
int totCases = 0;
|
int totCases = 0;
|
||||||
int totOk = 0;
|
int totOk = 0;
|
||||||
for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
|
for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
|
||||||
VlcSource& source = sit->second;
|
VlcSource& source = sit->second;
|
||||||
//UINFO(1,"Source "<<source.name()<<endl);
|
//UINFO(1,"Source "<<source.name()<<endl);
|
||||||
if (opt.annotateAll()) source.needed(true);
|
if (opt.annotateAll()) source.needed(true);
|
||||||
VlcSource::LinenoMap& lines = source.lines();
|
VlcSource::LinenoMap& lines = source.lines();
|
||||||
for (VlcSource::LinenoMap::iterator lit=lines.begin(); lit!=lines.end(); ++lit) {
|
for (VlcSource::LinenoMap::iterator lit=lines.begin(); lit!=lines.end(); ++lit) {
|
||||||
VlcSource::ColumnMap& cmap = lit->second;
|
VlcSource::ColumnMap& cmap = lit->second;
|
||||||
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
|
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
|
||||||
VlcSourceCount& col = cit->second;
|
VlcSourceCount& col = cit->second;
|
||||||
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
|
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
|
||||||
++totCases;
|
++totCases;
|
||||||
if (col.ok()) {
|
if (col.ok()) {
|
||||||
++totOk;
|
++totOk;
|
||||||
} else {
|
} else {
|
||||||
source.needed(true);
|
source.needed(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
float pct = totCases ? (100*totOk / totCases) : 0;
|
float pct = totCases ? (100*totOk / totCases) : 0;
|
||||||
cout<<"Total coverage ("<<totOk<<"/"<<totCases<<") "
|
cout<<"Total coverage ("<<totOk<<"/"<<totCases<<") "
|
||||||
@@ -195,60 +195,61 @@ void VlcTop::annotateOutputFiles(const string& dirname) {
|
|||||||
// Create if uncreated, ignore errors
|
// Create if uncreated, ignore errors
|
||||||
V3Os::createDir(dirname);
|
V3Os::createDir(dirname);
|
||||||
for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
|
for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
|
||||||
VlcSource& source = sit->second;
|
VlcSource& source = sit->second;
|
||||||
if (!source.needed()) continue;
|
if (!source.needed()) continue;
|
||||||
string filename = source.name();
|
string filename = source.name();
|
||||||
string outfilename = dirname+"/"+V3Os::filenameNonDir(filename);
|
string outfilename = dirname+"/"+V3Os::filenameNonDir(filename);
|
||||||
|
|
||||||
UINFO(1,"annotateOutputFile "<<filename<<" -> "<<outfilename<<endl);
|
UINFO(1,"annotateOutputFile "<<filename<<" -> "<<outfilename<<endl);
|
||||||
|
|
||||||
std::ifstream is(filename.c_str());
|
std::ifstream is(filename.c_str());
|
||||||
if (!is) {
|
if (!is) {
|
||||||
v3error("Can't read "<<filename);
|
v3error("Can't read "<<filename);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ofstream os(outfilename.c_str());
|
std::ofstream os(outfilename.c_str());
|
||||||
if (!os) {
|
if (!os) {
|
||||||
v3fatal("Can't write "<<outfilename);
|
v3fatal("Can't write "<<outfilename);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
os << "\t// verilator_coverage annotation"<<endl;
|
os << "\t// verilator_coverage annotation"<<endl;
|
||||||
|
|
||||||
int lineno = 0;
|
int lineno = 0;
|
||||||
while (!is.eof()) {
|
while (!is.eof()) {
|
||||||
lineno++;
|
lineno++;
|
||||||
string line = V3Os::getline(is);
|
string line = V3Os::getline(is);
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
VlcSource::LinenoMap& lines = source.lines();
|
VlcSource::LinenoMap& lines = source.lines();
|
||||||
VlcSource::LinenoMap::iterator lit=lines.find(lineno);
|
VlcSource::LinenoMap::iterator lit=lines.find(lineno);
|
||||||
if (lit != lines.end()) {
|
if (lit != lines.end()) {
|
||||||
VlcSource::ColumnMap& cmap = lit->second;
|
VlcSource::ColumnMap& cmap = lit->second;
|
||||||
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
|
for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
|
||||||
VlcSourceCount& col = cit->second;
|
VlcSourceCount& col = cit->second;
|
||||||
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
|
//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
|
||||||
os<<(col.ok()?" ":"%")
|
os<<(col.ok()?" ":"%")
|
||||||
<<std::setfill('0')<<std::setw(6)<<col.count()
|
<<std::setfill('0')<<std::setw(6)<<col.count()
|
||||||
<<"\t"<<line<<endl;
|
<<"\t"<<line<<endl;
|
||||||
if (first) {
|
if (first) {
|
||||||
first = false;
|
first = false;
|
||||||
// Multiple columns on same line; print line just once
|
// Multiple columns on same line; print line just once
|
||||||
string indent;
|
string indent;
|
||||||
for (string::const_iterator pos=line.begin(); pos!=line.end() && isspace(*pos); ++pos) {
|
for (string::const_iterator pos=line.begin();
|
||||||
indent += *pos;
|
pos!=line.end() && isspace(*pos); ++pos) {
|
||||||
}
|
indent += *pos;
|
||||||
line = indent + "verilator_coverage: (next point on previous line)\n";
|
}
|
||||||
}
|
line = indent + "verilator_coverage: (next point on previous line)\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
os<<"\t"<<line<<endl;
|
os<<"\t"<<line<<endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,4 +259,3 @@ void VlcTop::annotate(const string& dirname) {
|
|||||||
annotateCalcNeeded();
|
annotateCalcNeeded();
|
||||||
annotateOutputFiles(dirname);
|
annotateOutputFiles(dirname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+291
-291
@@ -7,7 +7,7 @@ use Getopt::Long;
|
|||||||
use IO::File;
|
use IO::File;
|
||||||
use Pod::Usage;
|
use Pod::Usage;
|
||||||
use strict;
|
use strict;
|
||||||
use vars qw ($Debug @Types %Classes %Children %ClassRefs %Stages);
|
use vars qw($Debug @Types %Classes %Children %ClassRefs %Stages);
|
||||||
|
|
||||||
#======================================================================
|
#======================================================================
|
||||||
# main
|
# main
|
||||||
@@ -17,8 +17,8 @@ my $opt_classes;
|
|||||||
my $opt_report;
|
my $opt_report;
|
||||||
my @Opt_Cpt;
|
my @Opt_Cpt;
|
||||||
my @Opt_I;
|
my @Opt_I;
|
||||||
Getopt::Long::config ("pass_through", "no_auto_abbrev");
|
Getopt::Long::config("pass_through", "no_auto_abbrev");
|
||||||
if (! GetOptions (
|
if (! GetOptions(
|
||||||
"help" => \&usage,
|
"help" => \&usage,
|
||||||
"debug" => sub { $Debug = 1; },
|
"debug" => sub { $Debug = 1; },
|
||||||
"classes!" => \$opt_classes,
|
"classes!" => \$opt_classes,
|
||||||
@@ -51,17 +51,17 @@ foreach my $cpt (@Opt_Cpt) {
|
|||||||
|
|
||||||
sub usage {
|
sub usage {
|
||||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub parameter {
|
sub parameter {
|
||||||
my $param = shift;
|
my $param = shift;
|
||||||
if ($param =~ /^-+I(\S+)/) {
|
if ($param =~ /^-+I(\S+)/) {
|
||||||
push @Opt_I, $1;
|
push @Opt_I, $1;
|
||||||
} elsif ($param =~ s/\.cpp$//) {
|
} elsif ($param =~ s/\.cpp$//) {
|
||||||
push @Opt_Cpt, $param;
|
push @Opt_Cpt, $param;
|
||||||
} else {
|
} else {
|
||||||
die "%Error: Unknown parameter: $param,";
|
die "%Error: Unknown parameter: $param,";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,21 +72,21 @@ sub read_types {
|
|||||||
|
|
||||||
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
||||||
while (defined (my $line = $fh->getline())) {
|
while (defined (my $line = $fh->getline())) {
|
||||||
$line =~ s/\/\/.*$//;
|
$line =~ s/\/\/.*$//;
|
||||||
next if $line =~ /^\s*$/;
|
next if $line =~ /^\s*$/;
|
||||||
if ($line =~ /^\s*(class|struct)\s*(\S+)/) {
|
if ($line =~ /^\s*(class|struct)\s*(\S+)/) {
|
||||||
my $class = $2;
|
my $class = $2;
|
||||||
my $inh = "";
|
my $inh = "";
|
||||||
$inh = $1 if ($line =~ /:\s*public\s+(\S+)/);
|
$inh = $1 if ($line =~ /:\s*public\s+(\S+)/);
|
||||||
print "class $class : $inh\n" if $Debug;
|
print "class $class : $inh\n" if $Debug;
|
||||||
$inh = "" if $class eq "AstNode";
|
$inh = "" if $class eq "AstNode";
|
||||||
if ($inh =~ /Ast/ || $class eq "AstNode") {
|
if ($inh =~ /Ast/ || $class eq "AstNode") {
|
||||||
$class =~ s/^Ast//;
|
$class =~ s/^Ast//;
|
||||||
$inh =~ s/^Ast//;
|
$inh =~ s/^Ast//;
|
||||||
$Classes{$class} = $inh;
|
$Classes{$class} = $inh;
|
||||||
$Children{$inh}{$class} = 1;
|
$Children{$inh}{$class} = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,14 +96,14 @@ sub read_stages {
|
|||||||
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
||||||
my $n = 0;
|
my $n = 0;
|
||||||
while (defined (my $line = $fh->getline())) {
|
while (defined (my $line = $fh->getline())) {
|
||||||
$line =~ s/\/\/.*$//;
|
$line =~ s/\/\/.*$//;
|
||||||
next if $line =~ /^\s*$/;
|
next if $line =~ /^\s*$/;
|
||||||
if ($line =~ /^\s*([A-Za-z0-9]+)::/) {
|
if ($line =~ /^\s*([A-Za-z0-9]+)::/) {
|
||||||
my $stage = $1.".cpp";
|
my $stage = $1.".cpp";
|
||||||
if (!defined ($Stages{$stage})) {
|
if (!defined ($Stages{$stage})) {
|
||||||
$Stages{$stage} = $n++;
|
$Stages{$stage} = $n++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,17 +111,17 @@ sub read_refs {
|
|||||||
my @filenames = @_;
|
my @filenames = @_;
|
||||||
|
|
||||||
foreach my $filename (@filenames) {
|
foreach my $filename (@filenames) {
|
||||||
(my $basename = $filename) =~ s!.*/!!;
|
(my $basename = $filename) =~ s!.*/!!;
|
||||||
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
||||||
while (defined (my $line = $fh->getline())) {
|
while (defined (my $line = $fh->getline())) {
|
||||||
$line =~ s/\/\/.*$//;
|
$line =~ s/\/\/.*$//;
|
||||||
while ($line =~ /\bnew\s*(Ast[A-Za-z0-9_]+)/g) {
|
while ($line =~ /\bnew\s*(Ast[A-Za-z0-9_]+)/g) {
|
||||||
$ClassRefs{$1}{newed}{$basename} = 1;
|
$ClassRefs{$1}{newed}{$basename} = 1;
|
||||||
}
|
}
|
||||||
while ($line =~ /\b(Ast[A-Za-z0-9_]+)/g) {
|
while ($line =~ /\b(Ast[A-Za-z0-9_]+)/g) {
|
||||||
$ClassRefs{$1}{used}{$basename} = 1;
|
$ClassRefs{$1}{used}{$basename} = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#use Data::Dumper;print Dumper(\%ClassRefs);
|
#use Data::Dumper;print Dumper(\%ClassRefs);
|
||||||
}
|
}
|
||||||
@@ -142,8 +142,8 @@ sub subclasses_of {
|
|||||||
|
|
||||||
my @cllist;
|
my @cllist;
|
||||||
for (my $subclass = $::Classes{$type}; $subclass; ) {
|
for (my $subclass = $::Classes{$type}; $subclass; ) {
|
||||||
push @cllist, $subclass;
|
push @cllist, $subclass;
|
||||||
$subclass = $::Classes{$subclass};
|
$subclass = $::Classes{$subclass};
|
||||||
}
|
}
|
||||||
|
|
||||||
return (reverse @cllist);
|
return (reverse @cllist);
|
||||||
@@ -156,10 +156,10 @@ sub children_of {
|
|||||||
my @todo;
|
my @todo;
|
||||||
push @todo, $type;
|
push @todo, $type;
|
||||||
while (my $subclass = shift @todo) {
|
while (my $subclass = shift @todo) {
|
||||||
foreach my $child (sort keys %{$::Children{$subclass}}) {
|
foreach my $child (sort keys %{$::Children{$subclass}}) {
|
||||||
push @todo, $child;
|
push @todo, $child;
|
||||||
push @cllist, $child;
|
push @cllist, $child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (@cllist);
|
return (@cllist);
|
||||||
@@ -173,39 +173,39 @@ sub write_report {
|
|||||||
|
|
||||||
$fh->print("Processing stages (approximate, based on order in Verilator.cpp):\n");
|
$fh->print("Processing stages (approximate, based on order in Verilator.cpp):\n");
|
||||||
foreach my $class (sort {$Stages{$a} <=> $Stages{$b}} keys %Stages) {
|
foreach my $class (sort {$Stages{$a} <=> $Stages{$b}} keys %Stages) {
|
||||||
$fh->print("\t$class\n");
|
$fh->print("\t$class\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
$fh->print("\nProcessing stages (approximate, based on order in Verilator.cpp):\n");
|
$fh->print("\nProcessing stages (approximate, based on order in Verilator.cpp):\n");
|
||||||
foreach my $type (sort (keys %Classes)) {
|
foreach my $type (sort (keys %Classes)) {
|
||||||
printf $fh " class %-20s\n", "Ast${type}";
|
printf $fh " class %-20s\n", "Ast${type}";
|
||||||
$fh->print("\tparent:\t");
|
$fh->print("\tparent:\t");
|
||||||
foreach my $subclass (subclasses_of($type)) {
|
foreach my $subclass (subclasses_of($type)) {
|
||||||
next if $subclass eq 'Node';
|
next if $subclass eq 'Node';
|
||||||
printf $fh "Ast%-12s ",$subclass;
|
printf $fh "Ast%-12s ",$subclass;
|
||||||
}
|
}
|
||||||
printf $fh "\n";
|
printf $fh "\n";
|
||||||
$fh->print("\tchilds:\t");
|
$fh->print("\tchilds:\t");
|
||||||
foreach my $subclass (children_of($type)) {
|
foreach my $subclass (children_of($type)) {
|
||||||
next if $subclass eq 'Node';
|
next if $subclass eq 'Node';
|
||||||
printf $fh "Ast%-12s ",$subclass;
|
printf $fh "Ast%-12s ",$subclass;
|
||||||
}
|
}
|
||||||
printf $fh "\n";
|
printf $fh "\n";
|
||||||
if (my $refs = $ClassRefs{"Ast${type}"}) {
|
if (my $refs = $ClassRefs{"Ast${type}"}) {
|
||||||
$fh->print("\tnewed:\t");
|
$fh->print("\tnewed:\t");
|
||||||
foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)}
|
foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)}
|
||||||
keys %{$refs->{newed}}) {
|
keys %{$refs->{newed}}) {
|
||||||
$fh->print($stage." ");
|
$fh->print($stage." ");
|
||||||
}
|
}
|
||||||
$fh->print("\n");
|
$fh->print("\n");
|
||||||
$fh->print("\tused:\t");
|
$fh->print("\tused:\t");
|
||||||
foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)}
|
foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)}
|
||||||
keys %{$refs->{used}}) {
|
keys %{$refs->{used}}) {
|
||||||
$fh->print($stage." ");
|
$fh->print($stage." ");
|
||||||
}
|
}
|
||||||
$fh->print("\n");
|
$fh->print("\n");
|
||||||
}
|
}
|
||||||
$fh->print("\n");
|
$fh->print("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,11 +213,11 @@ sub write_classes {
|
|||||||
my $fh = open_file(@_);
|
my $fh = open_file(@_);
|
||||||
printf $fh "class AstNode;\n";
|
printf $fh "class AstNode;\n";
|
||||||
foreach my $type (sort (keys %Classes)) {
|
foreach my $type (sort (keys %Classes)) {
|
||||||
printf $fh "class %-20s // ", "Ast${type};";
|
printf $fh "class %-20s // ", "Ast${type};";
|
||||||
foreach my $subclass (subclasses_of($type)) {
|
foreach my $subclass (subclasses_of($type)) {
|
||||||
printf $fh "Ast%-12s ",$subclass;
|
printf $fh "Ast%-12s ",$subclass;
|
||||||
}
|
}
|
||||||
printf $fh "\n";
|
printf $fh "\n";
|
||||||
}
|
}
|
||||||
$fh->close();
|
$fh->close();
|
||||||
}
|
}
|
||||||
@@ -225,12 +225,12 @@ sub write_classes {
|
|||||||
sub write_visitor {
|
sub write_visitor {
|
||||||
my $fh = open_file(@_);
|
my $fh = open_file(@_);
|
||||||
foreach my $type (sort (keys %Classes)) {
|
foreach my $type (sort (keys %Classes)) {
|
||||||
my $base = $Classes{$type};
|
my $base = $Classes{$type};
|
||||||
if ($base) {
|
if ($base) {
|
||||||
printf $fh " virtual void visit(Ast${type}* nodep) { visit((Ast${base}*)(nodep)); }\n";
|
printf $fh " virtual void visit(Ast${type}* nodep) { visit((Ast${base}*)(nodep)); }\n";
|
||||||
} else {
|
} else {
|
||||||
printf $fh " virtual void visit(Ast${type}*) = 0;\n";
|
printf $fh " virtual void visit(Ast${type}*) = 0;\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$fh->close();
|
$fh->close();
|
||||||
}
|
}
|
||||||
@@ -262,11 +262,11 @@ sub write_impl {
|
|||||||
print $fh "\n";
|
print $fh "\n";
|
||||||
print $fh " // These for use by VN_IS macro only\n";
|
print $fh " // These for use by VN_IS macro only\n";
|
||||||
foreach my $type (sort (keys %Classes)) {
|
foreach my $type (sort (keys %Classes)) {
|
||||||
if (children_of($type)) {
|
if (children_of($type)) {
|
||||||
print $fh "inline bool AstNode::privateIs",$type,"(const AstNode* nodep) { return (bool)(dynamic_cast<const Ast",$type,"*>(nodep)); }\n";
|
print $fh "inline bool AstNode::privateIs",$type,"(const AstNode* nodep) { return (bool)(dynamic_cast<const Ast",$type,"*>(nodep)); }\n";
|
||||||
} else {
|
} else {
|
||||||
print $fh "inline bool AstNode::privateIs",$type,"(const AstNode* nodep) { return nodep && nodep->type() == AstType::at",$type,"; }\n";
|
print $fh "inline bool AstNode::privateIs",$type,"(const AstNode* nodep) { return nodep && nodep->type() == AstType::at",$type,"; }\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $type (sort (keys %Classes)) {
|
foreach my $type (sort (keys %Classes)) {
|
||||||
@@ -285,16 +285,16 @@ sub write_types {
|
|||||||
printf $fh " enum en {\n";
|
printf $fh " enum en {\n";
|
||||||
# Add "at" prefix to avoid conflicting with FOPEN and other macros in include files
|
# Add "at" prefix to avoid conflicting with FOPEN and other macros in include files
|
||||||
foreach my $type (sort (keys %Classes)) {
|
foreach my $type (sort (keys %Classes)) {
|
||||||
next if $type =~ /^Node/;
|
next if $type =~ /^Node/;
|
||||||
print $fh "\tat",$type,",\n";
|
print $fh "\tat",$type,",\n";
|
||||||
}
|
}
|
||||||
printf $fh "\t_ENUM_END\n";
|
printf $fh "\t_ENUM_END\n";
|
||||||
printf $fh " };\n";
|
printf $fh " };\n";
|
||||||
printf $fh " const char* ascii() const {\n";
|
printf $fh " const char* ascii() const {\n";
|
||||||
printf $fh " const char* const names[] = {\n";
|
printf $fh " const char* const names[] = {\n";
|
||||||
foreach my $type (sort (keys %Classes)) {
|
foreach my $type (sort (keys %Classes)) {
|
||||||
next if $type =~ /^Node/;
|
next if $type =~ /^Node/;
|
||||||
print $fh "\t\"", uc $type, "\",\n";
|
print $fh "\t\"", uc $type, "\",\n";
|
||||||
}
|
}
|
||||||
printf $fh "\t\"_ENUM_END\"\n";
|
printf $fh "\t\"_ENUM_END\"\n";
|
||||||
printf $fh " };\n";
|
printf $fh " };\n";
|
||||||
@@ -332,11 +332,11 @@ sub _output_line {
|
|||||||
|
|
||||||
sub process {
|
sub process {
|
||||||
my $self = {
|
my $self = {
|
||||||
in_filename => undef,
|
in_filename => undef,
|
||||||
out_filename => undef,
|
out_filename => undef,
|
||||||
out_lines => [],
|
out_lines => [],
|
||||||
out_linenum => 1,
|
out_linenum => 1,
|
||||||
@_,
|
@_,
|
||||||
};
|
};
|
||||||
bless $self, __PACKAGE__;
|
bless $self, __PACKAGE__;
|
||||||
|
|
||||||
@@ -346,25 +346,25 @@ sub process {
|
|||||||
# Read the file and parse into list of functions that generate output
|
# Read the file and parse into list of functions that generate output
|
||||||
my $fhi = IO::File->new($self->{in_filename}) or die "%Error: $! $self->{in_filename},";
|
my $fhi = IO::File->new($self->{in_filename}) or die "%Error: $! $self->{in_filename},";
|
||||||
while (defined(my $line = $fhi->getline)) {
|
while (defined(my $line = $fhi->getline)) {
|
||||||
if (!$didln) {
|
if (!$didln) {
|
||||||
$self->print("#line $. \"$self->{in_filename}\"\n");
|
$self->print("#line $. \"$self->{in_filename}\"\n");
|
||||||
$didln = 1;
|
$didln = 1;
|
||||||
}
|
}
|
||||||
if ($line =~ /^\s+(TREE.*)$/) {
|
if ($line =~ /^\s+(TREE.*)$/) {
|
||||||
my $func = $1;
|
my $func = $1;
|
||||||
$self->{in_linenum} = $.;
|
$self->{in_linenum} = $.;
|
||||||
$self->print("//$line");
|
$self->print("//$line");
|
||||||
$self->output_func(sub{my $self=shift; $self->_output_line(); });
|
$self->output_func(sub{my $self=shift; $self->_output_line(); });
|
||||||
$self->tree_line ($func);
|
$self->tree_line($func);
|
||||||
$didln = 0;
|
$didln = 0;
|
||||||
}
|
}
|
||||||
elsif ($line !~ /^\s*\/[\/\*]\s*TREE/
|
elsif ($line !~ /^\s*\/[\/\*]\s*TREE/
|
||||||
&& $line =~ /\s+TREE/) {
|
&& $line =~ /\s+TREE/) {
|
||||||
$self->error("Unknown astgen line: $line");
|
$self->error("Unknown astgen line: $line");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$self->print($line);
|
$self->print($line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$fhi->close;
|
$fhi->close;
|
||||||
|
|
||||||
@@ -373,16 +373,16 @@ sub process {
|
|||||||
my $fho = ::open_file($self->{out_filename});
|
my $fho = ::open_file($self->{out_filename});
|
||||||
my @togen = @{$self->{out_lines}};
|
my @togen = @{$self->{out_lines}};
|
||||||
foreach my $line (@togen) {
|
foreach my $line (@togen) {
|
||||||
if (ref $line) {
|
if (ref $line) {
|
||||||
$self->{out_lines} = [];
|
$self->{out_lines} = [];
|
||||||
&$line($self);
|
&$line($self);
|
||||||
} else {
|
} else {
|
||||||
$self->{out_lines} = [$line];
|
$self->{out_lines} = [$line];
|
||||||
}
|
}
|
||||||
foreach my $out (@{$self->{out_lines}}) {
|
foreach my $out (@{$self->{out_lines}}) {
|
||||||
$self->{out_linenum}++ while ($out =~ /\n/smg);
|
$self->{out_linenum}++ while ($out =~ /\n/smg);
|
||||||
print $fho $out;
|
print $fho $out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$fho->close;
|
$fho->close;
|
||||||
}
|
}
|
||||||
@@ -396,64 +396,64 @@ sub tree_line {
|
|||||||
|
|
||||||
# doflag "S" indicates an op specifying short-circuiting for a type.
|
# doflag "S" indicates an op specifying short-circuiting for a type.
|
||||||
if ($func =~ /TREEOP(1?)([VCS]?)\s*\(\s* \"([^\"]*)\" \s*,\s* \"([^\"]*)\" \s*\)/sx) {
|
if ($func =~ /TREEOP(1?)([VCS]?)\s*\(\s* \"([^\"]*)\" \s*,\s* \"([^\"]*)\" \s*\)/sx) {
|
||||||
my $order = $1; my $doflag = $2; my $from = $3; my $to = $4;
|
my $order = $1; my $doflag = $2; my $from = $3; my $to = $4;
|
||||||
#$self->print("// $from $to\n");
|
#$self->print("// $from $to\n");
|
||||||
if (!$self->{did_out_tree}) {
|
if (!$self->{did_out_tree}) {
|
||||||
$self->{did_out_tree} = 1;
|
$self->{did_out_tree} = 1;
|
||||||
$self->output_func(sub{ my $self=shift;
|
$self->output_func(sub{ my $self=shift;
|
||||||
$self->tree_match();
|
$self->tree_match();
|
||||||
$self->tree_base();
|
$self->tree_base();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$from =~ /Ast([a-zA-Z0-9]+)\s*\{(.*)\}\s*$/
|
$from =~ /Ast([a-zA-Z0-9]+)\s*\{(.*)\}\s*$/
|
||||||
or $self->error("Can't parse from function: $func");
|
or $self->error("Can't parse from function: $func");
|
||||||
my $type = $1;
|
my $type = $1;
|
||||||
my $subnodes = $2;
|
my $subnodes = $2;
|
||||||
(::subclasses_of($type)) or $self->error("Unknown AstNode type: $type: in $func");
|
(::subclasses_of($type)) or $self->error("Unknown AstNode type: $type: in $func");
|
||||||
|
|
||||||
my $mif;
|
my $mif;
|
||||||
if ($doflag eq '') { $mif = "m_doNConst"; }
|
if ($doflag eq '') { $mif = "m_doNConst"; }
|
||||||
elsif ($doflag eq 'V') { $mif = "m_doV"; }
|
elsif ($doflag eq 'V') { $mif = "m_doV"; }
|
||||||
elsif ($doflag eq 'C') { $mif = ""; }
|
elsif ($doflag eq 'C') { $mif = ""; }
|
||||||
elsif ($doflag eq 'S') { $mif = "m_doNConst"; } # Not just for m_doGenerate
|
elsif ($doflag eq 'S') { $mif = "m_doNConst"; } # Not just for m_doGenerate
|
||||||
else { die; }
|
else { die; }
|
||||||
$subnodes =~ s/,,/__ESCAPEDCOMMA__/g;
|
$subnodes =~ s/,,/__ESCAPEDCOMMA__/g;
|
||||||
foreach my $subnode (split /\s*,\s*/, $subnodes) {
|
foreach my $subnode (split /\s*,\s*/, $subnodes) {
|
||||||
$subnode =~ s/__ESCAPEDCOMMA__/,/g;
|
$subnode =~ s/__ESCAPEDCOMMA__/,/g;
|
||||||
next if $subnode =~ /^\$([a-z0-9]+)$/gi; # "$lhs" is just a comment that this op has a lhs
|
next if $subnode =~ /^\$([a-z0-9]+)$/gi; # "$lhs" is just a comment that this op has a lhs
|
||||||
$mif .= " && " if $mif;
|
$mif .= " && " if $mif;
|
||||||
my $subnodeif = $subnode;
|
my $subnodeif = $subnode;
|
||||||
$subnodeif =~ s/\$([a-zA-Z0-9]+)\.cast([A-Z][A-Za-z0-9]+)$/VN_IS(nodep->$1(),$2)/g;
|
$subnodeif =~ s/\$([a-zA-Z0-9]+)\.cast([A-Z][A-Za-z0-9]+)$/VN_IS(nodep->$1(),$2)/g;
|
||||||
$subnodeif =~ s/\$([a-zA-Z0-9]+)\.([a-zA-Z0-9]+)$/nodep->$1()->$2()/g;
|
$subnodeif =~ s/\$([a-zA-Z0-9]+)\.([a-zA-Z0-9]+)$/nodep->$1()->$2()/g;
|
||||||
$subnodeif = add_nodep($subnodeif);
|
$subnodeif = add_nodep($subnodeif);
|
||||||
$mif .= $subnodeif;
|
$mif .= $subnodeif;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $exec_func = treeop_exec_func($self, $to);
|
my $exec_func = treeop_exec_func($self, $to);
|
||||||
while ($exec_func =~ s/([-()a-zA-Z0-9_>]+)->cast([A-Z][A-Za-z0-9]+)\(\)/VN_CAST($1,$2)/) {}
|
while ($exec_func =~ s/([-()a-zA-Z0-9_>]+)->cast([A-Z][A-Za-z0-9]+)\(\)/VN_CAST($1,$2)/) {}
|
||||||
|
|
||||||
$self->{treeop}{$type} ||= [];
|
$self->{treeop}{$type} ||= [];
|
||||||
my $n = $#{$self->{treeop}{$type}} + 1;
|
my $n = $#{$self->{treeop}{$type}} + 1;
|
||||||
my $typefunc = {
|
my $typefunc = {
|
||||||
order => $order,
|
order => $order,
|
||||||
comment => $func,
|
comment => $func,
|
||||||
match_func => "match_${type}_${n}",
|
match_func => "match_${type}_${n}",
|
||||||
match_if => $mif,
|
match_if => $mif,
|
||||||
exec_func => $exec_func,
|
exec_func => $exec_func,
|
||||||
uinfo_level => ($to =~ /^!/ ? 0:7),
|
uinfo_level => ($to =~ /^!/ ? 0:7),
|
||||||
short_circuit => ($doflag eq 'S'),
|
short_circuit => ($doflag eq 'S'),
|
||||||
};
|
};
|
||||||
|
|
||||||
($typefunc->{uinfo} = $func) =~ s/[ \t\"\{\}]+/ /g;
|
($typefunc->{uinfo} = $func) =~ s/[ \t\"\{\}]+/ /g;
|
||||||
push @{$self->{treeop}{$type}}, $typefunc;
|
push @{$self->{treeop}{$type}}, $typefunc;
|
||||||
}
|
}
|
||||||
elsif ($func =~ /TREE_SKIP_VISIT\s*\(\s* \"([^\"]*)\" \s*\)/sx) {
|
elsif ($func =~ /TREE_SKIP_VISIT\s*\(\s* \"([^\"]*)\" \s*\)/sx) {
|
||||||
my $type = $1;
|
my $type = $1;
|
||||||
$self->{tree_skip_visit}{$type} = 1;
|
$self->{tree_skip_visit}{$type} = 1;
|
||||||
$::Classes{$type} or $self->error("Unknown node type: $type");
|
$::Classes{$type} or $self->error("Unknown node type: $type");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$self->error("Unknown astgen op: $func");
|
$self->error("Unknown astgen op: $func");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,12 +468,12 @@ our $_Exec_Nsyms;
|
|||||||
sub _exec_syms_recurse {
|
sub _exec_syms_recurse {
|
||||||
my $aref = shift;
|
my $aref = shift;
|
||||||
foreach my $sym (@{$aref}) {
|
foreach my $sym (@{$aref}) {
|
||||||
if (ref $sym) { _exec_syms_recurse($sym); }
|
if (ref $sym) { _exec_syms_recurse($sym); }
|
||||||
elsif ($sym =~ /^\$.*/) {
|
elsif ($sym =~ /^\$.*/) {
|
||||||
if (!defined $_Exec_Syms{$sym}) {
|
if (!defined $_Exec_Syms{$sym}) {
|
||||||
$_Exec_Syms{$sym} = "arg".(++$_Exec_Nsyms)."p";
|
$_Exec_Syms{$sym} = "arg".(++$_Exec_Nsyms)."p";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,14 +482,14 @@ sub _exec_new_recurse {
|
|||||||
my $out = "new ".$aref->[0]."(nodep->fileline()";
|
my $out = "new ".$aref->[0]."(nodep->fileline()";
|
||||||
my $first = 1;
|
my $first = 1;
|
||||||
foreach my $sym (@{$aref}) {
|
foreach my $sym (@{$aref}) {
|
||||||
if ($first) { $first=0; next; }
|
if ($first) { $first=0; next; }
|
||||||
$out .= ", ";
|
$out .= ", ";
|
||||||
if (ref $sym) { $out.=_exec_new_recurse($sym); }
|
if (ref $sym) { $out.=_exec_new_recurse($sym); }
|
||||||
elsif ($sym =~ /^\$.*/) {
|
elsif ($sym =~ /^\$.*/) {
|
||||||
$out .= $_Exec_Syms{$sym};
|
$out .= $_Exec_Syms{$sym};
|
||||||
} else {
|
} else {
|
||||||
$out .= $sym;
|
$out .= $sym;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $out.")";
|
return $out.")";
|
||||||
}
|
}
|
||||||
@@ -500,142 +500,142 @@ sub treeop_exec_func {
|
|||||||
my $out = "";
|
my $out = "";
|
||||||
$func =~ s/^!//;
|
$func =~ s/^!//;
|
||||||
if ($func =~ /^\s*[a-zA-Z0-9]+\s*\(/) { # Function call
|
if ($func =~ /^\s*[a-zA-Z0-9]+\s*\(/) { # Function call
|
||||||
(my $outl = $func) =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g;
|
(my $outl = $func) =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g;
|
||||||
$out .= $outl.";";
|
$out .= $outl.";";
|
||||||
}
|
}
|
||||||
elsif ($func =~ /^\s*Ast([a-zA-Z0-9]+) \s*\{\s* (.*) \s* \}$/x) {
|
elsif ($func =~ /^\s*Ast([a-zA-Z0-9]+) \s*\{\s* (.*) \s* \}$/x) {
|
||||||
|
|
||||||
my $nargs = 0;
|
my $nargs = 0;
|
||||||
my %argnums; # Number for each argument name
|
my %argnums; # Number for each argument name
|
||||||
|
|
||||||
my $aref = undef; # Recursive array with structure to form
|
my $aref = undef; # Recursive array with structure to form
|
||||||
my @astack;
|
my @astack;
|
||||||
my $forming = "";
|
my $forming = "";
|
||||||
my $argtext = $func . "\000"; # EOF character
|
my $argtext = $func . "\000"; # EOF character
|
||||||
#print "FF $func\n" if $Debug;
|
#print "FF $func\n" if $Debug;
|
||||||
while ($argtext =~ s/^(.)//) {
|
while ($argtext =~ s/^(.)//) {
|
||||||
my $tok = $1;
|
my $tok = $1;
|
||||||
#print "TOK: $tok $forming\n" if $tok !~ /[a-zA-Z0-9]/;
|
#print "TOK: $tok $forming\n" if $tok !~ /[a-zA-Z0-9]/;
|
||||||
|
|
||||||
if ($tok eq "\000") {
|
if ($tok eq "\000") {
|
||||||
} elsif ($tok =~ /\s+/) {
|
} elsif ($tok =~ /\s+/) {
|
||||||
} elsif ($tok eq "{") {
|
} elsif ($tok eq "{") {
|
||||||
my $newref = [$forming];
|
my $newref = [$forming];
|
||||||
push @{$aref}, $newref;
|
push @{$aref}, $newref;
|
||||||
push @astack, $aref if $aref;
|
push @astack, $aref if $aref;
|
||||||
$aref = $newref;
|
$aref = $newref;
|
||||||
$forming = "";
|
$forming = "";
|
||||||
} elsif ($tok eq "}") {
|
} elsif ($tok eq "}") {
|
||||||
push @{$aref}, $forming if $forming;
|
push @{$aref}, $forming if $forming;
|
||||||
$aref = pop @astack;
|
$aref = pop @astack;
|
||||||
$aref or $self->error("Too many } in execution function: $func\n");
|
$aref or $self->error("Too many } in execution function: $func\n");
|
||||||
$forming = "";
|
$forming = "";
|
||||||
} elsif ($tok eq ",") {
|
} elsif ($tok eq ",") {
|
||||||
push @{$aref}, $forming if $forming;
|
push @{$aref}, $forming if $forming;
|
||||||
$forming = "";
|
$forming = "";
|
||||||
} else {
|
} else {
|
||||||
$forming .= $tok;
|
$forming .= $tok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
($aref && ref $aref->[0] && !$aref->[1]) or $self->error("Badly formed execution function: $func\n");
|
($aref && ref $aref->[0] && !$aref->[1]) or $self->error("Badly formed execution function: $func\n");
|
||||||
$aref = $aref->[0];
|
$aref = $aref->[0];
|
||||||
#use Data::Dumper; print Dumper($aref),"\n";
|
#use Data::Dumper; print Dumper($aref),"\n";
|
||||||
|
|
||||||
# Assign numbers to each $ symbol
|
# Assign numbers to each $ symbol
|
||||||
%_Exec_Syms = ();
|
%_Exec_Syms = ();
|
||||||
$_Exec_Nsyms = 0;
|
$_Exec_Nsyms = 0;
|
||||||
_exec_syms_recurse($aref);
|
_exec_syms_recurse($aref);
|
||||||
|
|
||||||
foreach my $sym (sort {$_Exec_Syms{$a} cmp $_Exec_Syms{$b}} (keys %_Exec_Syms)) {
|
foreach my $sym (sort {$_Exec_Syms{$a} cmp $_Exec_Syms{$b}} (keys %_Exec_Syms)) {
|
||||||
my $argnp = $_Exec_Syms{$sym};
|
my $argnp = $_Exec_Syms{$sym};
|
||||||
my $arg = add_nodep($sym);
|
my $arg = add_nodep($sym);
|
||||||
$out .= "AstNode* ${argnp} = ${arg}->unlinkFrBack();\n";
|
$out .= "AstNode* ${argnp} = ${arg}->unlinkFrBack();\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
$out .= "AstNode* newp = " . _exec_new_recurse($aref).";\n";
|
$out .= "AstNode* newp = " . _exec_new_recurse($aref).";\n";
|
||||||
$out .= "nodep->replaceWith(newp);";
|
$out .= "nodep->replaceWith(newp);";
|
||||||
$out .= "nodep->deleteTree(); VL_DANGLING(nodep);";
|
$out .= "nodep->deleteTree(); VL_DANGLING(nodep);";
|
||||||
#print "FF $out\n" if $Debug;
|
#print "FF $out\n" if $Debug;
|
||||||
} elsif ($func eq "NEVER") {
|
} elsif ($func eq "NEVER") {
|
||||||
$out .= "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");";
|
$out .= "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");";
|
||||||
} elsif ($func eq "DONE") {
|
} elsif ($func eq "DONE") {
|
||||||
} else {
|
} else {
|
||||||
$self->error("Unknown execution function format: $func\n");
|
$self->error("Unknown execution function format: $func\n");
|
||||||
}
|
}
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub tree_match {
|
sub tree_match {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->print (" // TREEOP functions, each return true if they matched & transformed\n");
|
$self->print(" // TREEOP functions, each return true if they matched & transformed\n");
|
||||||
#use Data::Dumper; print Dumper($self);
|
#use Data::Dumper; print Dumper($self);
|
||||||
foreach my $base (sort (keys %{$self->{treeop}})) {
|
foreach my $base (sort (keys %{$self->{treeop}})) {
|
||||||
foreach my $typefunc (@{$self->{treeop}{$base}}) {
|
foreach my $typefunc (@{$self->{treeop}{$base}}) {
|
||||||
$self->print(" // Generated by astgen\n");
|
$self->print(" // Generated by astgen\n");
|
||||||
$self->print(" bool $typefunc->{match_func}(Ast${base}* nodep) {\n",
|
$self->print(" bool $typefunc->{match_func}(Ast${base}* nodep) {\n",
|
||||||
"\t// $typefunc->{comment}\n",);
|
"\t// $typefunc->{comment}\n",);
|
||||||
$self->print( "\tif ($typefunc->{match_if}) {\n");
|
$self->print( "\tif ($typefunc->{match_if}) {\n");
|
||||||
$self->print( "\t UINFO($typefunc->{uinfo_level},cvtToHex(nodep)"
|
$self->print( "\t UINFO($typefunc->{uinfo_level},cvtToHex(nodep)"
|
||||||
."<<\" $typefunc->{uinfo}\\n\");\n");
|
."<<\" $typefunc->{uinfo}\\n\");\n");
|
||||||
$self->print( "\t $typefunc->{exec_func}\n");
|
$self->print( "\t $typefunc->{exec_func}\n");
|
||||||
$self->print( "\t return true;\n");
|
$self->print( "\t return true;\n");
|
||||||
$self->print( "\t}\n");
|
$self->print( "\t}\n");
|
||||||
$self->print( "\treturn false;\n");
|
$self->print( "\treturn false;\n");
|
||||||
$self->print(" }\n",);
|
$self->print(" }\n",);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub tree_base {
|
sub tree_base {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->print (" // TREEOP visitors, call each base type's match\n");
|
$self->print(" // TREEOP visitors, call each base type's match\n");
|
||||||
$self->print (" // Bottom class up, as more simple transforms are generally better\n");
|
$self->print(" // Bottom class up, as more simple transforms are generally better\n");
|
||||||
foreach my $type (sort (keys %::Classes)) {
|
foreach my $type (sort (keys %::Classes)) {
|
||||||
my $base = $::Classes{$type};
|
my $base = $::Classes{$type};
|
||||||
my @out_for_type_sc;
|
my @out_for_type_sc;
|
||||||
my @out_for_type;
|
my @out_for_type;
|
||||||
foreach my $base (::subclasses_of($type), $type) {
|
foreach my $base (::subclasses_of($type), $type) {
|
||||||
foreach my $typefunc (@{$self->{treeop}{$base}}) {
|
foreach my $typefunc (@{$self->{treeop}{$base}}) {
|
||||||
my @lines = (" if ($typefunc->{match_func}(nodep)) return;\n",);
|
my @lines = (" if ($typefunc->{match_func}(nodep)) return;\n",);
|
||||||
if ($typefunc->{short_circuit}) { # short-circuit match fn
|
if ($typefunc->{short_circuit}) { # short-circuit match fn
|
||||||
push @out_for_type_sc, @lines;
|
push @out_for_type_sc, @lines;
|
||||||
} else { # Standard match fn
|
} else { # Standard match fn
|
||||||
if ($typefunc->{order}) {
|
if ($typefunc->{order}) {
|
||||||
unshift @out_for_type, @lines; # TREEOP1's go in front of others
|
unshift @out_for_type, @lines; # TREEOP1's go in front of others
|
||||||
} else {
|
} else {
|
||||||
push @out_for_type, @lines;
|
push @out_for_type, @lines;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# We need to deal with two cases. For short circuited functions we
|
# We need to deal with two cases. For short circuited functions we
|
||||||
# evaluate the LHS, then apply the short-circuit matches, then
|
# evaluate the LHS, then apply the short-circuit matches, then
|
||||||
# evaluate the RHS and possibly THS (ternary operators may
|
# evaluate the RHS and possibly THS (ternary operators may
|
||||||
# short-circuit) and apply all the other matches.
|
# short-circuit) and apply all the other matches.
|
||||||
|
|
||||||
# For types without short-circuits, we just use iterateChildren, which
|
# For types without short-circuits, we just use iterateChildren, which
|
||||||
# saves one comparison.
|
# saves one comparison.
|
||||||
if ($out_for_type_sc[0]) { # Short-circuited types
|
if ($out_for_type_sc[0]) { # Short-circuited types
|
||||||
$self->print(" // Generated by astgen with short-circuiting\n",
|
$self->print(" // Generated by astgen with short-circuiting\n",
|
||||||
" virtual void visit(Ast${type}* nodep) {\n",
|
" virtual void visit(Ast${type}* nodep) {\n",
|
||||||
" iterateAndNextNull(nodep->lhsp());\n",
|
" iterateAndNextNull(nodep->lhsp());\n",
|
||||||
@out_for_type_sc);
|
@out_for_type_sc);
|
||||||
$self->print(" iterateAndNextNull(nodep->rhsp());\n",
|
$self->print(" iterateAndNextNull(nodep->rhsp());\n",
|
||||||
" AstNodeTriop *tnp = VN_CAST(nodep, NodeTriop);\n",
|
" AstNodeTriop *tnp = VN_CAST(nodep, NodeTriop);\n",
|
||||||
" if (tnp && tnp->thsp()) iterateAndNextNull(tnp->thsp());\n",
|
" if (tnp && tnp->thsp()) iterateAndNextNull(tnp->thsp());\n",
|
||||||
@out_for_type,
|
@out_for_type,
|
||||||
" }\n") if ($out_for_type[0]);
|
" }\n") if ($out_for_type[0]);
|
||||||
} elsif ($out_for_type[0]) { # Other types with something to print
|
} elsif ($out_for_type[0]) { # Other types with something to print
|
||||||
my $skip = $self->{tree_skip_visit}{$type};
|
my $skip = $self->{tree_skip_visit}{$type};
|
||||||
my $gen = $skip ? "Gen" : "";
|
my $gen = $skip ? "Gen" : "";
|
||||||
$self->print(" // Generated by astgen\n",
|
$self->print(" // Generated by astgen\n",
|
||||||
" virtual void visit$gen(Ast${type}* nodep) {\n",
|
" virtual void visit$gen(Ast${type}* nodep) {\n",
|
||||||
($skip?"":
|
($skip?"":
|
||||||
" iterateChildren(nodep);\n"),
|
" iterateChildren(nodep);\n"),
|
||||||
@out_for_type,
|
@out_for_type,
|
||||||
" }\n");
|
" }\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+237
-237
@@ -7,7 +7,7 @@ use Getopt::Long;
|
|||||||
use IO::File;
|
use IO::File;
|
||||||
use Pod::Usage;
|
use Pod::Usage;
|
||||||
use strict;
|
use strict;
|
||||||
use vars qw ($Debug $VERSION);
|
use vars qw($Debug $VERSION);
|
||||||
|
|
||||||
$VERSION = '3.404';
|
$VERSION = '3.404';
|
||||||
|
|
||||||
@@ -28,21 +28,21 @@ our $Opt_Input;
|
|||||||
|
|
||||||
autoflush STDOUT 1;
|
autoflush STDOUT 1;
|
||||||
autoflush STDERR 1;
|
autoflush STDERR 1;
|
||||||
Getopt::Long::config ("no_auto_abbrev");
|
Getopt::Long::config("no_auto_abbrev");
|
||||||
if (! GetOptions (
|
if (! GetOptions(
|
||||||
# Local options
|
# Local options
|
||||||
"help" => \&usage,
|
"help" => \&usage,
|
||||||
"version" => sub { print "Version $VERSION\n"; exit(0); },
|
"version" => sub { print "Version $VERSION\n"; exit(0); },
|
||||||
"yacc=s" => \$Opt_Yacc,
|
"yacc=s" => \$Opt_Yacc,
|
||||||
# Passed to Bison
|
# Passed to Bison
|
||||||
"t|debug" => sub { $Opt_Debug = 1; },
|
"t|debug" => sub { $Opt_Debug = 1; },
|
||||||
"b|file-prefix=s" => \$Opt_File_Prefix,
|
"b|file-prefix=s" => \$Opt_File_Prefix,
|
||||||
"d" => \$Opt_Definitions,
|
"d" => \$Opt_Definitions,
|
||||||
"k|token-table" => \$Opt_Token_Table,
|
"k|token-table" => \$Opt_Token_Table,
|
||||||
"o=s" => \$Opt_Output,
|
"o=s" => \$Opt_Output,
|
||||||
"p|name-prefix=s" => \$Opt_Name_Prefix,
|
"p|name-prefix=s" => \$Opt_Name_Prefix,
|
||||||
"v|verbose" => \$Opt_Verbose,
|
"v|verbose" => \$Opt_Verbose,
|
||||||
"<>" => \¶meter,
|
"<>" => \¶meter,
|
||||||
)) {
|
)) {
|
||||||
die "%Error: Bad usage, try 'bisonpre --help'\n";
|
die "%Error: Bad usage, try 'bisonpre --help'\n";
|
||||||
}
|
}
|
||||||
@@ -57,15 +57,15 @@ process();
|
|||||||
sub usage {
|
sub usage {
|
||||||
print "Version $VERSION\n";
|
print "Version $VERSION\n";
|
||||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT, -noperldoc=>1);
|
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT, -noperldoc=>1);
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub parameter {
|
sub parameter {
|
||||||
my $param = shift;
|
my $param = shift;
|
||||||
if (!defined $Opt_Input) {
|
if (!defined $Opt_Input) {
|
||||||
$Opt_Input = $param;
|
$Opt_Input = $param;
|
||||||
} else {
|
} else {
|
||||||
die "bisonpre: %Error: Unknown parameter: $param\n";
|
die "bisonpre: %Error: Unknown parameter: $param\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,31 +81,31 @@ sub process {
|
|||||||
|
|
||||||
# Run bison
|
# Run bison
|
||||||
my $command = ($Opt_Yacc
|
my $command = ($Opt_Yacc
|
||||||
.($Opt_Debug?" -t":"")
|
.($Opt_Debug?" -t":"")
|
||||||
.($Opt_Definitions?" -d":"")
|
.($Opt_Definitions?" -d":"")
|
||||||
.($Opt_Token_Table?" -k":"")
|
.($Opt_Token_Table?" -k":"")
|
||||||
.($Opt_Verbose?" -v":"")
|
.($Opt_Verbose?" -v":"")
|
||||||
.(($Opt_Verbose && $supports_report)?" --report=itemset --report=lookahead":"")
|
.(($Opt_Verbose && $supports_report)?" --report=itemset --report=lookahead":"")
|
||||||
# -p required for GLR parsers; they write to -p basename, not -o
|
# -p required for GLR parsers; they write to -p basename, not -o
|
||||||
.($Opt_Name_Prefix?" -p $Opt_Name_Prefix":"")
|
.($Opt_Name_Prefix?" -p $Opt_Name_Prefix":"")
|
||||||
." -b ".tmp_prefix()
|
." -b ".tmp_prefix()
|
||||||
." -o ".tmp_prefix().".c"
|
." -o ".tmp_prefix().".c"
|
||||||
." ".tmp_prefix().".y" );
|
." ".tmp_prefix().".y" );
|
||||||
|
|
||||||
print " $command\n";
|
print " $command\n";
|
||||||
system $command;
|
system $command;
|
||||||
my $status = $?;
|
my $status = $?;
|
||||||
if ($status != 0) {
|
if ($status != 0) {
|
||||||
remove_outputs();
|
remove_outputs();
|
||||||
my $v = bison_version_check();
|
my $v = bison_version_check();
|
||||||
die "bisonpre: %Error: $Opt_Yacc version $v run failed due to errors\n";
|
die "bisonpre: %Error: $Opt_Yacc version $v run failed due to errors\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
clean_output(tmp_prefix().".output",output_prefix().".output", 1,0);
|
clean_output(tmp_prefix().".output",output_prefix().".output", 1,0);
|
||||||
warning_check(output_prefix().".output");
|
warning_check(output_prefix().".output");
|
||||||
|
|
||||||
clean_output(tmp_prefix().".c", output_prefix().".c", 0,1);
|
clean_output(tmp_prefix().".c", output_prefix().".c", 0,1);
|
||||||
clean_output(tmp_prefix().".h", output_prefix().".h", 0,1);
|
clean_output(tmp_prefix().".h", output_prefix().".h", 0,1);
|
||||||
remove_tmp();
|
remove_tmp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,10 +116,10 @@ sub tmp_prefix {
|
|||||||
sub output_prefix {
|
sub output_prefix {
|
||||||
my $o;
|
my $o;
|
||||||
if ($Opt_Output) {
|
if ($Opt_Output) {
|
||||||
(my $o = $Opt_Output) =~ s!\.[^.]*$!!;
|
(my $o = $Opt_Output) =~ s!\.[^.]*$!!;
|
||||||
return $o;
|
return $o;
|
||||||
} else {
|
} else {
|
||||||
return $Opt_File_Prefix.".tab";
|
return $Opt_File_Prefix.".tab";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,11 +139,11 @@ sub remove_outputs {
|
|||||||
sub bison_version_check {
|
sub bison_version_check {
|
||||||
my $v = `$Opt_Yacc --version`;
|
my $v = `$Opt_Yacc --version`;
|
||||||
if ($v && $v =~ /([0-9]+\.[0-9]+)/) {
|
if ($v && $v =~ /([0-9]+\.[0-9]+)/) {
|
||||||
my $v = $1;
|
my $v = $1;
|
||||||
($v >= 1.875) or die "bisonpre: %Error: '$Opt_Yacc' is version $v; version 1.875 or newer is required\n";
|
($v >= 1.875) or die "bisonpre: %Error: '$Opt_Yacc' is version $v; version 1.875 or newer is required\n";
|
||||||
return $v;
|
return $v;
|
||||||
} else {
|
} else {
|
||||||
die "bisonpre: %Error: '$Opt_Yacc' is not installed, or not working\n";
|
die "bisonpre: %Error: '$Opt_Yacc' is not installed, or not working\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,55 +164,55 @@ sub clean_output {
|
|||||||
$newbase =~ s/\.y/./;
|
$newbase =~ s/\.y/./;
|
||||||
|
|
||||||
if ($is_output) {
|
if ($is_output) {
|
||||||
my %state_line; my $l=0;
|
my %state_line; my $l=0;
|
||||||
foreach my $line (@lines) {
|
foreach my $line (@lines) {
|
||||||
$l++;
|
$l++;
|
||||||
# We add a colon so it's easy to search for the definition
|
# We add a colon so it's easy to search for the definition
|
||||||
$state_line{$1} = $l if $line =~ s/^state (\d+)\s*$/state $1:/;
|
$state_line{$1} = $l if $line =~ s/^state (\d+)\s*$/state $1:/;
|
||||||
}
|
}
|
||||||
my @out;
|
my @out;
|
||||||
foreach my $line (@lines) {
|
foreach my $line (@lines) {
|
||||||
if ($line =~ /^State (\d+) (conflicts)/) {
|
if ($line =~ /^State (\d+) (conflicts)/) {
|
||||||
chomp $line;
|
chomp $line;
|
||||||
$line .= " // line $state_line{$1}" if $state_line{$1};
|
$line .= " // line $state_line{$1}" if $state_line{$1};
|
||||||
$line .= "\n";
|
$line .= "\n";
|
||||||
}
|
}
|
||||||
push @out, $line;
|
push @out, $line;
|
||||||
}
|
}
|
||||||
@lines = @out; @out = ();
|
@lines = @out; @out = ();
|
||||||
}
|
}
|
||||||
if ($is_c) {
|
if ($is_c) {
|
||||||
my %token_values;
|
my %token_values;
|
||||||
my $in_en=0;
|
my $in_en=0;
|
||||||
foreach my $line (@lines) {
|
foreach my $line (@lines) {
|
||||||
$in_en=1 if $line =~ /enum\s+yytokentype/;
|
$in_en=1 if $line =~ /enum\s+yytokentype/;
|
||||||
$in_en=0 if $line =~ /;/;
|
$in_en=0 if $line =~ /;/;
|
||||||
$token_values{$2} = $1 if $in_en && $line =~ /\b(\S+) = (\d+)/;
|
$token_values{$2} = $1 if $in_en && $line =~ /\b(\S+) = (\d+)/;
|
||||||
}
|
}
|
||||||
my @out;
|
my @out;
|
||||||
foreach my $line (@lines) {
|
foreach my $line (@lines) {
|
||||||
if ($line =~ /BISONPRE_TOKEN_NAMES/) {
|
if ($line =~ /BISONPRE_TOKEN_NAMES/) {
|
||||||
push @out, $line;
|
push @out, $line;
|
||||||
foreach my $tv (sort keys %token_values) {
|
foreach my $tv (sort keys %token_values) {
|
||||||
push @out, sprintf("\tcase %d: return \"%s\";\n",
|
push @out, sprintf("\tcase %d: return \"%s\";\n",
|
||||||
$tv, $token_values{$tv});
|
$tv, $token_values{$tv});
|
||||||
}
|
}
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
push @out, $line;
|
push @out, $line;
|
||||||
}
|
}
|
||||||
@lines = @out; @out = ();
|
@lines = @out; @out = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
$fh = IO::File->new(">$outname") or die "%Error: $! writing $outname\n";
|
$fh = IO::File->new(">$outname") or die "%Error: $! writing $outname\n";
|
||||||
foreach my $line (@lines) {
|
foreach my $line (@lines) {
|
||||||
# Fix filename refs
|
# Fix filename refs
|
||||||
$line =~ s!$basename!$newbase!g;
|
$line =~ s!$basename!$newbase!g;
|
||||||
# Fix bison 2.3 and GCC 4.2.1
|
# Fix bison 2.3 and GCC 4.2.1
|
||||||
$line =~ s!\(YY_\("!(YY_((char*)"!g;
|
$line =~ s!\(YY_\("!(YY_((char*)"!g;
|
||||||
# Fix bison 2.3 glr-parser warning about yyerrorloc.YYTYPE::yydummy uninit
|
# Fix bison 2.3 glr-parser warning about yyerrorloc.YYTYPE::yydummy uninit
|
||||||
$line =~ s!(YYLTYPE yyerrloc;)!$1 yyerrloc.yydummy=0;/*bisonpre*/!g;
|
$line =~ s!(YYLTYPE yyerrloc;)!$1 yyerrloc.yydummy=0;/*bisonpre*/!g;
|
||||||
$fh->write($line);
|
$fh->write($line);
|
||||||
}
|
}
|
||||||
$fh->close;
|
$fh->close;
|
||||||
}
|
}
|
||||||
@@ -222,9 +222,9 @@ sub warning_check {
|
|||||||
|
|
||||||
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
|
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
|
||||||
while (defined(my $line = $fh->getline)) {
|
while (defined(my $line = $fh->getline)) {
|
||||||
if ($line =~ /(conflicts|warning:|^useless)/i) {
|
if ($line =~ /(conflicts|warning:|^useless)/i) {
|
||||||
die "%Error: $filename:$.: $line\n";
|
die "%Error: $filename:$.: $line\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$fh->close;
|
$fh->close;
|
||||||
}
|
}
|
||||||
@@ -249,160 +249,160 @@ sub clean_input {
|
|||||||
my $last_rule;
|
my $last_rule;
|
||||||
my $section = 1;
|
my $section = 1;
|
||||||
{
|
{
|
||||||
my @linesin = @lines; @lines=(); my $l=0;
|
my @linesin = @lines; @lines=(); my $l=0;
|
||||||
foreach my $line (@linesin) {
|
foreach my $line (@linesin) {
|
||||||
$l++;
|
$l++;
|
||||||
# ^/ to prevent comments from matching
|
# ^/ to prevent comments from matching
|
||||||
$line =~ m!^[a-zA-Z0-9_<>]+:[^/]*[a-zA-Z]! and die "%Error: $filename:$l: Move text on rule line to next line: $line\n";
|
$line =~ m!^[a-zA-Z0-9_<>]+:[^/]*[a-zA-Z]! and die "%Error: $filename:$l: Move text on rule line to next line: $line\n";
|
||||||
if ($line =~ /^%%/) {
|
if ($line =~ /^%%/) {
|
||||||
$section++;
|
$section++;
|
||||||
if ($section==2) { $last_rule = undef; }
|
if ($section==2) { $last_rule = undef; }
|
||||||
}
|
}
|
||||||
elsif ($line =~ s/^([a-zA-Z0-9_]+)<(\S*)>:/$1:/) {
|
elsif ($line =~ s/^([a-zA-Z0-9_]+)<(\S*)>:/$1:/) {
|
||||||
!$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n";
|
!$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n";
|
||||||
$types{$2}{$1} = 1;
|
$types{$2}{$1} = 1;
|
||||||
$rules{$1}{name} = $1;
|
$rules{$1}{name} = $1;
|
||||||
$rules{$1}{type} = $2;
|
$rules{$1}{type} = $2;
|
||||||
!$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n";
|
!$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n";
|
||||||
$last_rule = $1;
|
$last_rule = $1;
|
||||||
} elsif ($line =~ /^([a-zA-Z0-9_]+):/) {
|
} elsif ($line =~ /^([a-zA-Z0-9_]+):/) {
|
||||||
!$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n";
|
!$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n";
|
||||||
$rules{$1}{name} = $1;
|
$rules{$1}{name} = $1;
|
||||||
$rules{$1}{type} = "";
|
$rules{$1}{type} = "";
|
||||||
!$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n";
|
!$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n";
|
||||||
$last_rule = $1;
|
$last_rule = $1;
|
||||||
}
|
}
|
||||||
push @lines, $line;
|
push @lines, $line;
|
||||||
# Now clean the line and extract some more info
|
# Now clean the line and extract some more info
|
||||||
(my $cline = $line) =~ s/\/\/.*$/\n/;
|
(my $cline = $line) =~ s/\/\/.*$/\n/;
|
||||||
(my $rline = $line) =~ s/\/\/.*$/\n/;
|
(my $rline = $line) =~ s/\/\/.*$/\n/;
|
||||||
if ($cline =~ /^\s*;/) {
|
if ($cline =~ /^\s*;/) {
|
||||||
$last_rule or die "%Error: $filename:$l: Stray semicolon\n";
|
$last_rule or die "%Error: $filename:$l: Stray semicolon\n";
|
||||||
$last_rule = undef;
|
$last_rule = undef;
|
||||||
} elsif ($last_rule) {
|
} elsif ($last_rule) {
|
||||||
$rules{$last_rule}{rules_and_productions} .= $cline;
|
$rules{$last_rule}{rules_and_productions} .= $cline;
|
||||||
}
|
}
|
||||||
if ($cline =~ /^%token\s*<(\S+)>\s*(\S+)/) {
|
if ($cline =~ /^%token\s*<(\S+)>\s*(\S+)/) {
|
||||||
!$tokens{$2} or die "%Error: $filename:$l: Redeclaring '$2': $line\n";
|
!$tokens{$2} or die "%Error: $filename:$l: Redeclaring '$2': $line\n";
|
||||||
$tokens{$2} = $1;
|
$tokens{$2} = $1;
|
||||||
}
|
}
|
||||||
foreach my $tok (split /[^a-zA-Z0-9_]+/, $cline) {
|
foreach my $tok (split /[^a-zA-Z0-9_]+/, $cline) {
|
||||||
if ($last_rule && $tok=~/^[a-zA-Z]/) {
|
if ($last_rule && $tok=~/^[a-zA-Z]/) {
|
||||||
#print "TT $last_rule $tok\n";
|
#print "TT $last_rule $tok\n";
|
||||||
$rules{$last_rule}{subrules}{$tok} = 1;
|
$rules{$last_rule}{subrules}{$tok} = 1;
|
||||||
$rules{$tok}{parentrules}{$last_rule} = 1;
|
$rules{$tok}{parentrules}{$last_rule} = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#use Data::Dumper; print Dumper(\%rules);
|
#use Data::Dumper; print Dumper(\%rules);
|
||||||
|
|
||||||
# Replace BISONPRE_VERSION(ver,,...) with expanded list
|
# Replace BISONPRE_VERSION(ver,,...) with expanded list
|
||||||
{
|
{
|
||||||
my @linesin = @lines; @lines=(); my $l=0;
|
my @linesin = @lines; @lines=(); my $l=0;
|
||||||
foreach my $line (@linesin) {
|
foreach my $line (@linesin) {
|
||||||
$l++;
|
$l++;
|
||||||
if ($line =~ /BISONPRE_VERSION/) {
|
if ($line =~ /BISONPRE_VERSION/) {
|
||||||
# 1 3 4
|
# 1 3 4
|
||||||
($line =~ /BISONPRE_VERSION\((\S+)\s*,\s*((\S+)\s*,)?\s*([^\),]+)\)\s*$/)
|
($line =~ /BISONPRE_VERSION\((\S+)\s*,\s*((\S+)\s*,)?\s*([^\),]+)\)\s*$/)
|
||||||
or die "%Error: $filename:$l: Bad form of BISONPRE_VERSION: $line\n";
|
or die "%Error: $filename:$l: Bad form of BISONPRE_VERSION: $line\n";
|
||||||
my $ver=$1; my $ver_max=$3; my $cmd=$4;
|
my $ver=$1; my $ver_max=$3; my $cmd=$4;
|
||||||
if ($Self->{bison_version} >= $1
|
if ($Self->{bison_version} >= $1
|
||||||
&& (!$ver_max || $Self->{bison_version} <= $ver_max)) {
|
&& (!$ver_max || $Self->{bison_version} <= $ver_max)) {
|
||||||
$line = $cmd."\n";
|
$line = $cmd."\n";
|
||||||
} else {
|
} else {
|
||||||
$line = "//NOP: $line";
|
$line = "//NOP: $line";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
push @lines, $line;
|
push @lines, $line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Replace BISONPRE_NOT(type,...) with expanded list
|
# Replace BISONPRE_NOT(type,...) with expanded list
|
||||||
{
|
{
|
||||||
my @linesin = @lines; @lines=(); my $l=0;
|
my @linesin = @lines; @lines=(); my $l=0;
|
||||||
foreach my $line (@linesin) {
|
foreach my $line (@linesin) {
|
||||||
$l++;
|
$l++;
|
||||||
if ($line =~ /BISONPRE_NOT/) {
|
if ($line =~ /BISONPRE_NOT/) {
|
||||||
($line =~ s/BISONPRE_NOT\((\S+)\)\s*({[^}]+})\s*$//)
|
($line =~ s/BISONPRE_NOT\((\S+)\)\s*(\{[^}]+})\s*$//)
|
||||||
or die "%Error: $filename:$l: Bad form of BISONPRE_NOT: $line\n";
|
or die "%Error: $filename:$l: Bad form of BISONPRE_NOT: $line\n";
|
||||||
my $endtok = $1; my $action = $2;
|
my $endtok = $1; my $action = $2;
|
||||||
my @endtoks = split (/,/, $endtok);
|
my @endtoks = split(/,/, $endtok);
|
||||||
map { $tokens{$_} or die "%Error: $filename:$l: Can't find definition for token: $_\n"
|
map { $tokens{$_} or die "%Error: $filename:$l: Can't find definition for token: $_\n"
|
||||||
} @endtoks;
|
} @endtoks;
|
||||||
# Push it all onto one line to avoid error messages changing
|
# Push it all onto one line to avoid error messages changing
|
||||||
my $bar = "";
|
my $bar = "";
|
||||||
tok:
|
tok:
|
||||||
foreach my $tok (sort keys %tokens) {
|
foreach my $tok (sort keys %tokens) {
|
||||||
foreach (@endtoks) {
|
foreach (@endtoks) {
|
||||||
next tok if $tok eq $_;
|
next tok if $tok eq $_;
|
||||||
}
|
}
|
||||||
if ($endtok ne $tok) {
|
if ($endtok ne $tok) {
|
||||||
$line .= "\t$bar $tok $action";
|
$line .= "\t$bar $tok $action";
|
||||||
$bar = "|";
|
$bar = "|";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$line .= "\n";
|
$line .= "\n";
|
||||||
}
|
}
|
||||||
push @lines, $line;
|
push @lines, $line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Replace BISONPRE_COPY(type,{code})
|
# Replace BISONPRE_COPY(type,{code})
|
||||||
{
|
{
|
||||||
my @linesin = @lines; @lines=(); my $l=0;
|
my @linesin = @lines; @lines=(); my $l=0;
|
||||||
foreach my $line (@linesin) {
|
foreach my $line (@linesin) {
|
||||||
$l++;
|
$l++;
|
||||||
if ($line =~ /BISONPRE_COPY/) {
|
if ($line =~ /BISONPRE_COPY/) {
|
||||||
$line = _bisonpre_copy($line,$l,0);
|
$line = _bisonpre_copy($line,$l,0);
|
||||||
}
|
}
|
||||||
push @lines, $line;
|
push @lines, $line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Replace ~[x]~ - must be after BISONPRE_COPY expansion
|
# Replace ~[x]~ - must be after BISONPRE_COPY expansion
|
||||||
{
|
{
|
||||||
my @linesin = @lines; @lines=(); my $l=0;
|
my @linesin = @lines; @lines=(); my $l=0;
|
||||||
foreach my $line (@linesin) {
|
foreach my $line (@linesin) {
|
||||||
$l++;
|
$l++;
|
||||||
$line =~ s/~[a-zA-Z0-9_]+~//g;
|
$line =~ s/~[a-zA-Z0-9_]+~//g;
|
||||||
push @lines, $line;
|
push @lines, $line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Find "BISONPRE_TYPES"
|
# Find "BISONPRE_TYPES"
|
||||||
{
|
{
|
||||||
my @linesin = @lines; @lines=(); my $l=0;
|
my @linesin = @lines; @lines=(); my $l=0;
|
||||||
my $needmore = 0;
|
my $needmore = 0;
|
||||||
foreach my $line (@linesin) {
|
foreach my $line (@linesin) {
|
||||||
$l++;
|
$l++;
|
||||||
if ($line =~ m!//BISONPRE_TYPES!) {
|
if ($line =~ m!//BISONPRE_TYPES!) {
|
||||||
push @lines, $line;
|
push @lines, $line;
|
||||||
foreach my $type (sort keys %types) {
|
foreach my $type (sort keys %types) {
|
||||||
next if !$type;
|
next if !$type;
|
||||||
my $line = "%type<$type>\t";
|
my $line = "%type<$type>\t";
|
||||||
foreach my $rule (sort keys %{$types{$type}}) {
|
foreach my $rule (sort keys %{$types{$type}}) {
|
||||||
$line.=" ".$rule;
|
$line.=" ".$rule;
|
||||||
}
|
}
|
||||||
$line .= "\n";
|
$line .= "\n";
|
||||||
push @lines, $line;
|
push @lines, $line;
|
||||||
$needmore++
|
$needmore++
|
||||||
}
|
}
|
||||||
} elsif ($needmore) {
|
} elsif ($needmore) {
|
||||||
# Bison doesn't have a #line directive, so we need somewhere to insert into
|
# Bison doesn't have a #line directive, so we need somewhere to insert into
|
||||||
$line =~ s!^\s*//.*$!!;
|
$line =~ s!^\s*//.*$!!;
|
||||||
($line =~ m/^\s*$/) or die "%Error: $filename:$l: Need $needmore more blank lines to insure line numbers are constant\n";
|
($line =~ m/^\s*$/) or die "%Error: $filename:$l: Need $needmore more blank lines to insure line numbers are constant\n";
|
||||||
$needmore--;
|
$needmore--;
|
||||||
} else {
|
} else {
|
||||||
push @lines, $line;
|
push @lines, $line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$fh = IO::File->new(">$outname") or die "%Error: $! writing $outname\n";
|
$fh = IO::File->new(">$outname") or die "%Error: $! writing $outname\n";
|
||||||
foreach my $line (@lines) {
|
foreach my $line (@lines) {
|
||||||
$fh->write($line);
|
$fh->write($line);
|
||||||
}
|
}
|
||||||
$fh->close;
|
$fh->close;
|
||||||
}
|
}
|
||||||
@@ -412,28 +412,28 @@ sub _bisonpre_copy {
|
|||||||
my $l = shift;
|
my $l = shift;
|
||||||
my $depth = shift;
|
my $depth = shift;
|
||||||
while ($text =~ /BISONPRE_COPY/) {
|
while ($text =~ /BISONPRE_COPY/) {
|
||||||
($text =~ s/BISONPRE_COPY(_ONCE)?\((\S+)\s*,\s*{([^}]*)}\s*\)/{HERE}/)
|
($text =~ s/BISONPRE_COPY(_ONCE)?\((\S+)\s*,\s*\{([^}]*)}\s*\)/{HERE}/)
|
||||||
or die "%Error: $Self->{filename}:$l: Bad form of BISONPRE_NOT: $text\n";
|
or die "%Error: $Self->{filename}:$l: Bad form of BISONPRE_NOT: $text\n";
|
||||||
my $once = $1; my $rule = $2; my $code = $3;
|
my $once = $1; my $rule = $2; my $code = $3;
|
||||||
$Self->{rules}{$rule} or die "%Error: $Self->{filename}:$l: Can't find definition for rule: $rule\n";
|
$Self->{rules}{$rule} or die "%Error: $Self->{filename}:$l: Can't find definition for rule: $rule\n";
|
||||||
if ($depth > 0 && $once) {
|
if ($depth > 0 && $once) {
|
||||||
# _ONCE means don't inherit
|
# _ONCE means don't inherit
|
||||||
$text =~ s/\|[ \t]+{HERE}//; # Don't OR in nothing
|
$text =~ s/\|[ \t]+{HERE}//; # Don't OR in nothing
|
||||||
$text =~ s/{HERE}//;
|
$text =~ s/{HERE}//;
|
||||||
} else {
|
} else {
|
||||||
# Push it all onto one line to avoid error messages changing
|
# Push it all onto one line to avoid error messages changing
|
||||||
my $insert = $Self->{rules}{$rule}{rules_and_productions};
|
my $insert = $Self->{rules}{$rule}{rules_and_productions};
|
||||||
$insert =~ s/^\S+://g; # Strip rule name
|
$insert =~ s/^\S+://g; # Strip rule name
|
||||||
# Recurse so BISONPRE under B
|
# Recurse so BISONPRE under B
|
||||||
#print "COPY $l code $code\n";
|
#print "COPY $l code $code\n";
|
||||||
#print "COPY $l in $insert\n";
|
#print "COPY $l in $insert\n";
|
||||||
$_=$insert; eval("$code; \$_;"); $insert = $_;
|
$_=$insert; eval("$code; \$_;"); $insert = $_;
|
||||||
#print "COPY $l out $insert\n";
|
#print "COPY $l out $insert\n";
|
||||||
while ($insert =~ s/[ \t\n]+\n/\n/go) {}
|
while ($insert =~ s/[ \t\n]+\n/\n/go) {}
|
||||||
while ($insert =~ s/\n/ /go) {} # Optional - preserve line numbering
|
while ($insert =~ s/\n/ /go) {} # Optional - preserve line numbering
|
||||||
$text =~ s/{HERE}/$insert/;
|
$text =~ s/{HERE}/$insert/;
|
||||||
}
|
}
|
||||||
$depth++;
|
$depth++;
|
||||||
}
|
}
|
||||||
return $text;
|
return $text;
|
||||||
}
|
}
|
||||||
|
|||||||
+90
-90
@@ -7,7 +7,7 @@ use Getopt::Long;
|
|||||||
use IO::File;
|
use IO::File;
|
||||||
use Pod::Usage;
|
use Pod::Usage;
|
||||||
use strict;
|
use strict;
|
||||||
use vars qw ($Debug $VERSION);
|
use vars qw($Debug $VERSION);
|
||||||
|
|
||||||
$VERSION = '3.881';
|
$VERSION = '3.881';
|
||||||
|
|
||||||
@@ -23,12 +23,12 @@ our $Opt_Debug;
|
|||||||
|
|
||||||
autoflush STDOUT 1;
|
autoflush STDOUT 1;
|
||||||
autoflush STDERR 1;
|
autoflush STDERR 1;
|
||||||
Getopt::Long::config ("no_auto_abbrev","pass_through");
|
Getopt::Long::config("no_auto_abbrev","pass_through");
|
||||||
our @Opt_Args = ("cppcheck", @ARGV);
|
our @Opt_Args = ("cppcheck", @ARGV);
|
||||||
if (! GetOptions (
|
if (! GetOptions(
|
||||||
# Local options
|
# Local options
|
||||||
"help" => \&usage,
|
"help" => \&usage,
|
||||||
"version" => sub { print "Version $VERSION\n"; system("cppcheck","--version"); exit(0); },
|
"version" => sub { print "Version $VERSION\n"; system("cppcheck","--version"); exit(0); },
|
||||||
)) {
|
)) {
|
||||||
die "%Error: Bad usage, try 'cppcheck_filtered --help'\n";
|
die "%Error: Bad usage, try 'cppcheck_filtered --help'\n";
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ process();
|
|||||||
sub usage {
|
sub usage {
|
||||||
print "Version $VERSION\n";
|
print "Version $VERSION\n";
|
||||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT, -noperldoc=>1);
|
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT, -noperldoc=>1);
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
@@ -54,72 +54,72 @@ sub process {
|
|||||||
my %errs;
|
my %errs;
|
||||||
my $last_error = "";
|
my $last_error = "";
|
||||||
while (defined(my $line = $fh->getline())) {
|
while (defined(my $line = $fh->getline())) {
|
||||||
$line =~ s/^\s+//;
|
$line =~ s/^\s+//;
|
||||||
$line =~ s/Checking usage of global functions\.+//; # Sometimes tacked at end-of-line
|
$line =~ s/Checking usage of global functions\.+//; # Sometimes tacked at end-of-line
|
||||||
# General gunk
|
# General gunk
|
||||||
next if $uniq{$line}++;
|
next if $uniq{$line}++;
|
||||||
next if $line =~ m!^<\?xml version!;
|
next if $line =~ m!^<\?xml version!;
|
||||||
next if $line =~ m!^<cppcheck!;
|
next if $line =~ m!^<cppcheck!;
|
||||||
next if $line =~ m!^<results!;
|
next if $line =~ m!^<results!;
|
||||||
next if $line =~ m!^</results>!;
|
next if $line =~ m!^</results>!;
|
||||||
next if $line =~ m!^<errors!;
|
next if $line =~ m!^<errors!;
|
||||||
next if $line =~ m!^</error>!;
|
next if $line =~ m!^</error>!;
|
||||||
next if $line =~ m!^</errors>!;
|
next if $line =~ m!^</errors>!;
|
||||||
next if $line =~ m!^<error.*id="unmatchedSuppression"!; # --suppress=unmatchedSuppression doesn't work
|
next if $line =~ m!^<error.*id="unmatchedSuppression"!; # --suppress=unmatchedSuppression doesn't work
|
||||||
next if $line =~ m!Cppcheck cannot find all the include files!; # An earlier id line is more specific
|
next if $line =~ m!Cppcheck cannot find all the include files!; # An earlier id line is more specific
|
||||||
next if $line =~ m!^Checking !;
|
next if $line =~ m!^Checking !;
|
||||||
next if $line =~ m!^make.*Entering directory !;
|
next if $line =~ m!^make.*Entering directory !;
|
||||||
next if $line =~ m!^make.*Leaving directory !;
|
next if $line =~ m!^make.*Leaving directory !;
|
||||||
next if $line =~ m!^\s+$!g;
|
next if $line =~ m!^\s+$!g;
|
||||||
|
|
||||||
# Specific suppressions (see _suppress also)
|
# Specific suppressions (see _suppress also)
|
||||||
next if $line =~ m!id="unusedPrivateFunction" .*::debug!; # Doesn't know UINFO will use it
|
next if $line =~ m!id="unusedPrivateFunction" .*::debug!; # Doesn't know UINFO will use it
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
if ($line =~ /^cppcheck --/) {
|
if ($line =~ /^cppcheck --/) {
|
||||||
print $line if $Debug;
|
print $line if $Debug;
|
||||||
} elsif ($line =~ m!^\d+/\d+ files checked!) {
|
} elsif ($line =~ m!^\d+/\d+ files checked!) {
|
||||||
print $line;
|
print $line;
|
||||||
} else {
|
} else {
|
||||||
my $suppress;
|
my $suppress;
|
||||||
# --xml-format=1
|
# --xml-format=1
|
||||||
if ($line =~ /file="([^"]+)"\s+line="(\d+)"\s+id="([^"]+)"/) {
|
if ($line =~ /file="([^"]+)"\s+line="(\d+)"\s+id="([^"]+)"/) {
|
||||||
my $file = $1; my $linenum = $2; my $id = $3;
|
my $file = $1; my $linenum = $2; my $id = $3;
|
||||||
$suppress = 1 if _suppress($file,$linenum,$id);
|
$suppress = 1 if _suppress($file,$linenum,$id);
|
||||||
}
|
}
|
||||||
# --xml-format=2
|
# --xml-format=2
|
||||||
if ($line =~ /<error id.*/) {
|
if ($line =~ /<error id.*/) {
|
||||||
$last_error = $line;
|
$last_error = $line;
|
||||||
chomp $last_error;
|
chomp $last_error;
|
||||||
$suppress = 1;
|
$suppress = 1;
|
||||||
}
|
}
|
||||||
elsif ($line =~ /<location.* file="([^"]+)"\s+line="(\d+)"/) {
|
elsif ($line =~ /<location.* file="([^"]+)"\s+line="(\d+)"/) {
|
||||||
my $file = $1; my $linenum = $2; my $id;
|
my $file = $1; my $linenum = $2; my $id;
|
||||||
if ($last_error =~ / id="([^"]+)"/) {
|
if ($last_error =~ / id="([^"]+)"/) {
|
||||||
$id = $1;
|
$id = $1;
|
||||||
} else {
|
} else {
|
||||||
$id = "?";
|
$id = "?";
|
||||||
}
|
}
|
||||||
$suppress = 1 if _suppress($file,$linenum,$id);
|
$suppress = 1 if _suppress($file,$linenum,$id);
|
||||||
$suppress = 1 if $file eq "*";
|
$suppress = 1 if $file eq "*";
|
||||||
if (!$suppress) {
|
if (!$suppress) {
|
||||||
chomp $line;
|
chomp $line;
|
||||||
print "$file:$linenum: ".$last_error."\n";
|
print "$file:$linenum: ".$last_error."\n";
|
||||||
$suppress = 1;
|
$suppress = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$suppress) {
|
if (!$suppress) {
|
||||||
my $eline = "%Error: cppcheck: $line";
|
my $eline = "%Error: cppcheck: $line";
|
||||||
print $eline;
|
print $eline;
|
||||||
$errs{$eline}++;
|
$errs{$eline}++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (scalar(keys %errs)) {
|
if (scalar(keys %errs)) {
|
||||||
#my $all = join('',sort(keys %errs));
|
#my $all = join('',sort(keys %errs));
|
||||||
#$Self->error("Cppcheck errors:\n$all");
|
#$Self->error("Cppcheck errors:\n$all");
|
||||||
#die "%Error: cppcheck_filtered found errors\n";
|
#die "%Error: cppcheck_filtered found errors\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,32 +143,32 @@ sub _suppress {
|
|||||||
|
|
||||||
my $fh = IO::File->new("<$filename");
|
my $fh = IO::File->new("<$filename");
|
||||||
if (!$fh) {
|
if (!$fh) {
|
||||||
warn "%Warning: $! $filename,";
|
warn "%Warning: $! $filename,";
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
my $l = 0;
|
my $l = 0;
|
||||||
while (defined(my $line = $fh->getline())) {
|
while (defined(my $line = $fh->getline())) {
|
||||||
++$l;
|
++$l;
|
||||||
if ($l+1 == $linenum) {
|
if ($l+1 == $linenum) {
|
||||||
if ($line =~ /cppcheck-suppress((\s+\S+)+)/) {
|
if ($line =~ /cppcheck-suppress((\s+\S+)+)/) {
|
||||||
my $supids = $1;
|
my $supids = $1;
|
||||||
foreach my $supid (split /\s+/, $supids) {
|
foreach my $supid (split /\s+/, $supids) {
|
||||||
if ($supid eq $id
|
if ($supid eq $id
|
||||||
|| $supid eq ($SuppressMap{$id}||'')) {
|
|| $supid eq ($SuppressMap{$id}||'')) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
warn "%Warning: $filename: $l: Found suppress for ids='$supids', not expected id='$id'\n";
|
warn "%Warning: $filename: $l: Found suppress for ids='$supids', not expected id='$id'\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($l == $linenum) {
|
if ($l == $linenum) {
|
||||||
if (0 && # We now use VL_DANGLING instead of this rule
|
if (0 && # We now use VL_DANGLING instead of this rule
|
||||||
$id eq "uselessAssignmentPtrArg"
|
$id eq "uselessAssignmentPtrArg"
|
||||||
&& $line =~ /(delete|Delete|Edit).*p *= *(NULL|nullptr);/) {
|
&& $line =~ /(delete|Delete|Edit).*p *= *(NULL|nullptr);/) {
|
||||||
# delete(nodep); nodep=NULL; # This is ok, it's how we prevent later using nodep
|
# delete(nodep); nodep=NULL; # This is ok, it's how we prevent later using nodep
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -227,6 +227,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||||||
"$finish" { FL; return yD_FINISH; }
|
"$finish" { FL; return yD_FINISH; }
|
||||||
"$floor" { FL; return yD_FLOOR; }
|
"$floor" { FL; return yD_FLOOR; }
|
||||||
"$fopen" { FL; return yD_FOPEN; }
|
"$fopen" { FL; return yD_FOPEN; }
|
||||||
|
"$fread" { FL; return yD_FREAD; }
|
||||||
"$fscanf" { FL; return yD_FSCANF; }
|
"$fscanf" { FL; return yD_FSCANF; }
|
||||||
"$fullskew" { FL; return yaTIMINGSPEC; }
|
"$fullskew" { FL; return yaTIMINGSPEC; }
|
||||||
"$fwrite" { FL; return yD_FWRITE; }
|
"$fwrite" { FL; return yD_FWRITE; }
|
||||||
|
|||||||
+31
-11
@@ -475,6 +475,7 @@ class AstSenTree;
|
|||||||
%token<fl> yD_FINISH "$finish"
|
%token<fl> yD_FINISH "$finish"
|
||||||
%token<fl> yD_FLOOR "$floor"
|
%token<fl> yD_FLOOR "$floor"
|
||||||
%token<fl> yD_FOPEN "$fopen"
|
%token<fl> yD_FOPEN "$fopen"
|
||||||
|
%token<fl> yD_FREAD "$fread"
|
||||||
%token<fl> yD_FSCANF "$fscanf"
|
%token<fl> yD_FSCANF "$fscanf"
|
||||||
%token<fl> yD_FWRITE "$fwrite"
|
%token<fl> yD_FWRITE "$fwrite"
|
||||||
%token<fl> yD_HIGH "$high"
|
%token<fl> yD_HIGH "$high"
|
||||||
@@ -2084,7 +2085,9 @@ param_assignment<varp>: // ==IEEE: param_assignment
|
|||||||
id/*new-parameter*/ variable_dimensionListE sigAttrListE '=' exprOrDataType
|
id/*new-parameter*/ variable_dimensionListE sigAttrListE '=' exprOrDataType
|
||||||
/**/ { $$ = VARDONEA($<fl>1,*$1, $2, $3); $$->valuep($5); }
|
/**/ { $$ = VARDONEA($<fl>1,*$1, $2, $3); $$->valuep($5); }
|
||||||
| id/*new-parameter*/ variable_dimensionListE sigAttrListE
|
| id/*new-parameter*/ variable_dimensionListE sigAttrListE
|
||||||
/**/ { $$ = VARDONEA($<fl>1,*$1, $2, $3); }
|
/**/ { $$ = VARDONEA($<fl>1,*$1, $2, $3);
|
||||||
|
if ($<fl>1->language() < V3LangCode::L1800_2009) {
|
||||||
|
$<fl>1->v3error("Parameter requires default value, or use IEEE 1800-2009 or later."); } }
|
||||||
;
|
;
|
||||||
|
|
||||||
list_of_param_assignments<varp>: // ==IEEE: list_of_param_assignments
|
list_of_param_assignments<varp>: // ==IEEE: list_of_param_assignments
|
||||||
@@ -2390,8 +2393,21 @@ statement_item<nodep>: // IEEE: statement_item
|
|||||||
// // Below under expr
|
// // Below under expr
|
||||||
//
|
//
|
||||||
// // IEEE: subroutine_call_statement
|
// // IEEE: subroutine_call_statement
|
||||||
//UNSUP yVOID yP_TICK '(' function_subroutine_callNoMethod ')' ';' { }
|
// // IEEE says we then expect a function call
|
||||||
//UNSUP yVOID yP_TICK '(' expr '.' function_subroutine_callNoMethod ')' ';' { }
|
// // (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 included here to resolve our not knowing what is a method call
|
||||||
// // Expr here must result in a subroutine_call
|
// // Expr here must result in a subroutine_call
|
||||||
| task_subroutine_callNoMethod ';' { $$ = $1; }
|
| 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_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); }
|
||||||
| yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); }
|
| yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); }
|
||||||
| yD_FGETS '(' idClassSel ',' expr ')' { $$ = new AstFGetS($1,$3,$5); }
|
| 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_FLOOR '(' expr ')' { $$ = new AstFloorD($1,$3); }
|
||||||
| yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); }
|
| yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); }
|
||||||
| yD_HIGH '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_HIGH,$3,NULL); }
|
| 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
|
// // IEEE: concatenation/constant_concatenation
|
||||||
// // Replicate(1) required as otherwise "{a}" would not be self-determined
|
// // Replicate(1) required as otherwise "{a}" would not be self-determined
|
||||||
| '{' cateList '}' { $$ = new AstReplicate($1,$2,1); }
|
| '{' 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
|
||||||
// // IEEE: [ assignment_pattern_expression_type ] == [ ps_type_id /ps_paremeter_id/data_type]
|
// // IEEE: [ assignment_pattern_expression_type ] == [ ps_type_id /ps_paremeter_id/data_type]
|
||||||
// // We allow more here than the spec requires
|
// // 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) {
|
AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, string name, int value) {
|
||||||
FileLine* newfl = new FileLine (fileline);
|
return new AstAssignW(fileline, new AstVarRef(fileline, name, true),
|
||||||
newfl->warnOff(V3ErrorCode::WIDTH, true);
|
new AstConst(fileline, V3Number(fileline, (value ? "'1" : "'0"))));
|
||||||
AstNode* nodep = new AstConst(newfl, V3Number(newfl));
|
|
||||||
// Adding a NOT is less work than figuring out how wide to make it
|
|
||||||
if (value) nodep = new AstNot(newfl, nodep);
|
|
||||||
nodep = new AstAssignW(newfl, new AstVarRef(fileline, name, true),
|
|
||||||
nodep);
|
|
||||||
return nodep;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) {
|
AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) {
|
||||||
|
|||||||
+52
-52
@@ -7,7 +7,7 @@ use Getopt::Long;
|
|||||||
use IO::File;
|
use IO::File;
|
||||||
use Pod::Usage;
|
use Pod::Usage;
|
||||||
use strict;
|
use strict;
|
||||||
use vars qw ($Debug);
|
use vars qw($Debug);
|
||||||
|
|
||||||
our @Items;
|
our @Items;
|
||||||
|
|
||||||
@@ -16,12 +16,12 @@ our @Items;
|
|||||||
|
|
||||||
$Debug = 0;
|
$Debug = 0;
|
||||||
my $Opt_Srcdir = ".";
|
my $Opt_Srcdir = ".";
|
||||||
Getopt::Long::config ("pass_through", "no_auto_abbrev");
|
Getopt::Long::config("pass_through", "no_auto_abbrev");
|
||||||
if (! GetOptions (
|
if (! GetOptions(
|
||||||
"help" => \&usage,
|
"help" => \&usage,
|
||||||
"debug" => sub { $Debug = 1; },
|
"debug" => sub { $Debug = 1; },
|
||||||
"srcdir=s" => \$Opt_Srcdir,
|
"srcdir=s" => \$Opt_Srcdir,
|
||||||
"<>" => sub { die "%Error: Unknown parameter: $_[0],"; },
|
"<>" => sub { die "%Error: Unknown parameter: $_[0],"; },
|
||||||
)) {
|
)) {
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ write_keys("$Opt_Srcdir/../include/verilated_cov_key.h");
|
|||||||
|
|
||||||
sub usage {
|
sub usage {
|
||||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
@@ -44,17 +44,17 @@ sub read_keys {
|
|||||||
|
|
||||||
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
|
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
|
||||||
while (defined (my $line = $fh->getline())) {
|
while (defined (my $line = $fh->getline())) {
|
||||||
$line =~ s/\/\/.*$//;
|
$line =~ s/\/\/.*$//;
|
||||||
next if $line =~ /^\s*$/;
|
next if $line =~ /^\s*$/;
|
||||||
if ($line =~ /^\s*VLCOVGEN_ITEM/) {
|
if ($line =~ /^\s*VLCOVGEN_ITEM/) {
|
||||||
$line =~ /^\s*VLCOVGEN_ITEM *\( *"([^"]+)" *\)/
|
$line =~ /^\s*VLCOVGEN_ITEM *\( *"([^"]+)" *\)/
|
||||||
or die "%Error: $filename:$.: Misformed VLCOVGEN_ITEM line,";
|
or die "%Error: $filename:$.: Misformed VLCOVGEN_ITEM line,";
|
||||||
my @data;
|
my @data;
|
||||||
my $code = "\@data = ($1);";
|
my $code = "\@data = ($1);";
|
||||||
eval $code;
|
eval $code;
|
||||||
die "%Error: $filename:$.: Parsing '$code': $@," if $@;
|
die "%Error: $filename:$.: Parsing '$code': $@," if $@;
|
||||||
push @Items, {@data};
|
push @Items, {@data};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,11 +64,11 @@ sub lint {
|
|||||||
my %shorts;
|
my %shorts;
|
||||||
my $ok = 1;
|
my $ok = 1;
|
||||||
foreach my $itemref (@Items) {
|
foreach my $itemref (@Items) {
|
||||||
if ($shorts{$itemref->{short}}) {
|
if ($shorts{$itemref->{short}}) {
|
||||||
warn "%Error: Duplicate short code: $itemref->{short},";
|
warn "%Error: Duplicate short code: $itemref->{short},";
|
||||||
$ok = 0;
|
$ok = 0;
|
||||||
}
|
}
|
||||||
$shorts{$itemref->{short}} = 1;
|
$shorts{$itemref->{short}} = 1;
|
||||||
}
|
}
|
||||||
return $ok;
|
return $ok;
|
||||||
}
|
}
|
||||||
@@ -82,40 +82,40 @@ sub write_keys {
|
|||||||
my @out;
|
my @out;
|
||||||
my $deleting;
|
my $deleting;
|
||||||
while (defined(my $line = $fh->getline)) {
|
while (defined(my $line = $fh->getline)) {
|
||||||
push @in, $line;
|
push @in, $line;
|
||||||
if ($line =~ /VLCOVGEN_CIK_AUTO_EDIT_BEGIN/) {
|
if ($line =~ /VLCOVGEN_CIK_AUTO_EDIT_BEGIN/) {
|
||||||
$deleting = 1;
|
$deleting = 1;
|
||||||
push @out, $line;
|
push @out, $line;
|
||||||
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
|
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
|
||||||
push @out, sprintf("#define VL_CIK_%s \"%s\"\n",
|
push @out, sprintf("#define VL_CIK_%s \"%s\"\n",
|
||||||
uc $keyref->{name}, $keyref->{short});
|
uc $keyref->{name}, $keyref->{short});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elsif ($line =~ /VLCOVGEN_SHORT_AUTO_EDIT_BEGIN/) {
|
elsif ($line =~ /VLCOVGEN_SHORT_AUTO_EDIT_BEGIN/) {
|
||||||
$deleting = 1;
|
$deleting = 1;
|
||||||
push @out, $line;
|
push @out, $line;
|
||||||
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
|
foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
|
||||||
push @out, sprintf(" if (key == \"%s\") return VL_CIK_%s;\n",
|
push @out, sprintf(" if (key == \"%s\") return VL_CIK_%s;\n",
|
||||||
$keyref->{name}, uc $keyref->{name});
|
$keyref->{name}, uc $keyref->{name});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elsif ($line =~ /VLCOVGEN_.*AUTO_EDIT_END/) {
|
elsif ($line =~ /VLCOVGEN_.*AUTO_EDIT_END/) {
|
||||||
$deleting = 0;
|
$deleting = 0;
|
||||||
push @out, $line;
|
push @out, $line;
|
||||||
}
|
}
|
||||||
elsif ($deleting) {
|
elsif ($deleting) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
push @out, $line;
|
push @out, $line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$fh->close;
|
$fh->close;
|
||||||
|
|
||||||
my $ok = join("", @out) eq join("", @in);
|
my $ok = join("", @out) eq join("", @in);
|
||||||
if (!$ok) {
|
if (!$ok) {
|
||||||
my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename\n";
|
my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename\n";
|
||||||
$fh->print(join "", @out);
|
$fh->print(join "", @out);
|
||||||
$fh->close;
|
$fh->close;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+652
-637
File diff suppressed because it is too large
Load Diff
@@ -19,34 +19,35 @@
|
|||||||
class TestSimulator {
|
class TestSimulator {
|
||||||
private:
|
private:
|
||||||
struct SimTypes {
|
struct SimTypes {
|
||||||
int verilator;
|
int verilator;
|
||||||
int icarus;
|
int icarus;
|
||||||
int mti;
|
int mti;
|
||||||
int ncsim;
|
int ncsim;
|
||||||
int vcs;
|
int vcs;
|
||||||
};
|
};
|
||||||
s_vpi_vlog_info m_info;
|
s_vpi_vlog_info m_info;
|
||||||
SimTypes m_simulators;
|
SimTypes m_simulators;
|
||||||
public:
|
public:
|
||||||
TestSimulator() {
|
TestSimulator() {
|
||||||
vpi_get_vlog_info(&m_info);
|
vpi_get_vlog_info(&m_info);
|
||||||
if (0 == strcmp(m_info.product, "Verilator")) {
|
if (0 == strcmp(m_info.product, "Verilator")) {
|
||||||
m_simulators.verilator = true;
|
m_simulators.verilator = true;
|
||||||
} else if (0 == strcmp(m_info.product, "Verilator")) {
|
} else if (0 == strcmp(m_info.product, "Verilator")) {
|
||||||
m_simulators.icarus = true;
|
m_simulators.icarus = true;
|
||||||
} else if (0 == strncmp(m_info.product, "Chronologic Simulation VCS", strlen("Chronologic Simulation VCS"))) {
|
} else if (0 == strncmp(m_info.product, "Chronologic Simulation VCS",
|
||||||
m_simulators.vcs = true;
|
strlen("Chronologic Simulation VCS"))) {
|
||||||
} else {
|
m_simulators.vcs = true;
|
||||||
printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n",
|
} else {
|
||||||
__FILE__, __LINE__, m_info.product);
|
printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n",
|
||||||
}
|
__FILE__, __LINE__, m_info.product);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
~TestSimulator() { }
|
~TestSimulator() { }
|
||||||
// METHORS
|
// METHORS
|
||||||
private:
|
private:
|
||||||
static TestSimulator& singleton() {
|
static TestSimulator& singleton() {
|
||||||
static TestSimulator s_singleton;
|
static TestSimulator s_singleton;
|
||||||
return s_singleton;
|
return s_singleton;
|
||||||
}
|
}
|
||||||
static const SimTypes& simulators() { return singleton().m_simulators; }
|
static const SimTypes& simulators() { return singleton().m_simulators; }
|
||||||
public:
|
public:
|
||||||
@@ -62,19 +63,19 @@ public:
|
|||||||
static bool has_get_scalar() { return !simulators().icarus; }
|
static bool has_get_scalar() { return !simulators().icarus; }
|
||||||
// return test level scope
|
// return test level scope
|
||||||
static const char* top() {
|
static const char* top() {
|
||||||
if (simulators().verilator) {
|
if (simulators().verilator) {
|
||||||
return "t";
|
return "t";
|
||||||
} else {
|
} else {
|
||||||
return "top.t";
|
return "top.t";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// return absolute scope of obj
|
// return absolute scope of obj
|
||||||
static const char* rooted(const char *obj) {
|
static const char* rooted(const char *obj) {
|
||||||
static string buf;
|
static string buf;
|
||||||
ostringstream os;
|
ostringstream os;
|
||||||
os<<top()<<"."<<obj;
|
os<<top()<<"."<<obj;
|
||||||
buf = os.str();
|
buf = os.str();
|
||||||
return buf.c_str();
|
return buf.c_str();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class TestVpiHandle {
|
|||||||
public:
|
public:
|
||||||
TestVpiHandle() : m_handle(NULL), m_free(true) { }
|
TestVpiHandle() : m_handle(NULL), m_free(true) { }
|
||||||
TestVpiHandle(vpiHandle h) : m_handle(h), m_free(true) { }
|
TestVpiHandle(vpiHandle h) : m_handle(h), m_free(true) { }
|
||||||
~TestVpiHandle() { if (m_handle && m_free) { vpi_free_object(m_handle); m_handle=NULL; } } // icarus has yet to catch up with 1800-2009
|
~TestVpiHandle() { if (m_handle && m_free) { vpi_free_object(m_handle); m_handle=NULL; } }
|
||||||
operator vpiHandle() const { return m_handle; }
|
operator vpiHandle() const { return m_handle; }
|
||||||
inline TestVpiHandle& operator= (vpiHandle h) { m_handle = h; return *this; }
|
inline TestVpiHandle& operator= (vpiHandle h) { m_handle = h; return *this; }
|
||||||
TestVpiHandle& nofree() {
|
TestVpiHandle& nofree() {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ compile(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ($Self->{vlt_all}) {
|
if ($Self->{vlt_all}) {
|
||||||
file_grep ($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
|
file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ compile(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ($Self->{vlt_all}) {
|
if ($Self->{vlt_all}) {
|
||||||
file_grep ($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
|
file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|||||||
@@ -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(
|
compile(
|
||||||
fails => 1,
|
fails => 1,
|
||||||
expect =>
|
expect_filename => $Self->{golden_filename},
|
||||||
q{%Error: t/t_array_pattern_bad.v:23: Assignment pattern key 'valids' not found as member
|
|
||||||
.*%Error: Exiting due to.*},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ execute(
|
|||||||
fails => $Self->{vlt_all},
|
fails => $Self->{vlt_all},
|
||||||
);
|
);
|
||||||
|
|
||||||
file_grep ("$Self->{obj_dir}/vlt_compile.log",
|
file_grep("$Self->{obj_dir}/vlt_compile.log",
|
||||||
qr/%Warning-USERFATAL: Parameter 5 is invalid...string and constant both work/);
|
qr/%Warning-USERFATAL: Parameter 5 is invalid...string and constant both work/);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ execute(
|
|||||||
fails => 1
|
fails => 1
|
||||||
);
|
);
|
||||||
|
|
||||||
file_grep ($Self->{run_log_filename}, qr/'assert property' failed/);
|
file_grep($Self->{run_log_filename}, qr/'assert property' failed/);
|
||||||
# We expect to get a message when this assert fires:
|
# We expect to get a message when this assert fires:
|
||||||
file_grep ($Self->{run_log_filename}, qr/cyc != 3/);
|
file_grep($Self->{run_log_filename}, qr/cyc != 3/);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ execute(
|
|||||||
fails => 1
|
fails => 1
|
||||||
);
|
);
|
||||||
|
|
||||||
file_grep ($Self->{run_log_filename}, qr/'assert property' failed/);
|
file_grep($Self->{run_log_filename}, qr/'assert property' failed/);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -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(
|
compile(
|
||||||
v_flags2 => ["--lint-only"],
|
v_flags2 => ["--lint-only"],
|
||||||
fails => 1,
|
fails => 1,
|
||||||
expect =>
|
expect_filename => $Self->{golden_filename},
|
||||||
'%Error: t/t_bitsel_const_bad.v:\d+: Illegal bit or array select; type does not have a bit range, or bad dimension: type is logic
|
|
||||||
.*%Error: Exiting due to.*',
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
|
|||||||
@@ -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(
|
compile(
|
||||||
v_flags2 => ["--lint-only"],
|
v_flags2 => ["--lint-only"],
|
||||||
fails => 1,
|
fails => 1,
|
||||||
expect =>
|
expect_filename => $Self->{golden_filename},
|
||||||
'%Error: t/t_case_genx_bad.v:\d+: Use of x/\? constant in generate case statement, \(no such thing as \'generate casez\'\)
|
|
||||||
%Error: Exiting due to.*',
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ compile(
|
|||||||
verilator_flags2 => ["--stats --prof-cfuncs -CFLAGS '-pg' -LDFLAGS '-pg'"],
|
verilator_flags2 => ["--stats --prof-cfuncs -CFLAGS '-pg' -LDFLAGS '-pg'"],
|
||||||
);
|
);
|
||||||
|
|
||||||
file_grep ($Self->{stats}, qr/Optimizations, Tables created\s+(\d+)/i, 10);
|
file_grep($Self->{stats}, qr/Optimizations, Tables created\s+(\d+)/i, 10);
|
||||||
file_grep ($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 10);
|
file_grep($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 10);
|
||||||
|
|
||||||
unlink $_ foreach (glob "$Self->{obj_dir}/gmon.out.*");
|
unlink $_ foreach (glob "$Self->{obj_dir}/gmon.out.*");
|
||||||
$ENV{GMON_OUT_PREFIX} = "$Self->{obj_dir}/gmon.out";
|
$ENV{GMON_OUT_PREFIX} = "$Self->{obj_dir}/gmon.out";
|
||||||
@@ -36,7 +36,7 @@ run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{VM_PREFIX} $gmon_base > gprof.
|
|||||||
run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc gprof.out > cfuncs.out"],
|
run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc gprof.out > cfuncs.out"],
|
||||||
check_finished => 0);
|
check_finished => 0);
|
||||||
|
|
||||||
file_grep ("$Self->{obj_dir}/cfuncs.out", qr/Overall summary by/);
|
file_grep("$Self->{obj_dir}/cfuncs.out", qr/Overall summary by/);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ module t (/*AUTOARG*/
|
|||||||
input clk;
|
input clk;
|
||||||
|
|
||||||
reg [63:0] crc;
|
reg [63:0] crc;
|
||||||
`verilator_file_descriptor fd;
|
integer fd;
|
||||||
`verilator_file_descriptor fdtmp;
|
integer fdtmp;
|
||||||
|
|
||||||
t_case_write1_tasks tasks ();
|
t_case_write1_tasks tasks ();
|
||||||
|
|
||||||
@@ -33,14 +33,14 @@ module t (/*AUTOARG*/
|
|||||||
cyc <= cyc + 1;
|
cyc <= cyc + 1;
|
||||||
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||||
if (cyc==1) begin
|
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"});
|
$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");
|
fdtmp = $fopen({`STRINGIFY(`TEST_OBJ_DIR), "/t_case_write1_logger.log"}, "w");
|
||||||
fd <= fdtmp;
|
fd <= fdtmp;
|
||||||
end
|
end
|
||||||
if (cyc==90) begin
|
if (cyc==90) begin
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ module t (/*AUTOARG*/
|
|||||||
input clk;
|
input clk;
|
||||||
|
|
||||||
reg [63:0] crc;
|
reg [63:0] crc;
|
||||||
`verilator_file_descriptor fd;
|
integer fd;
|
||||||
`verilator_file_descriptor fdtmp;
|
integer fdtmp;
|
||||||
|
|
||||||
t_case_write2_tasks tasks ();
|
t_case_write2_tasks tasks ();
|
||||||
|
|
||||||
@@ -33,14 +33,14 @@ module t (/*AUTOARG*/
|
|||||||
cyc <= cyc + 1;
|
cyc <= cyc + 1;
|
||||||
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||||
if (cyc==1) begin
|
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"});
|
$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");
|
fdtmp = $fopen({`STRINGIFY(`TEST_OBJ_DIR), "/t_case_write2_logger.log"}, "w");
|
||||||
fd <= fdtmp;
|
fd <= fdtmp;
|
||||||
end
|
end
|
||||||
if (cyc==90) begin
|
if (cyc==90) begin
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ compile(
|
|||||||
expect_filename => $Self->{golden_filename},
|
expect_filename => $Self->{golden_filename},
|
||||||
);
|
);
|
||||||
|
|
||||||
file_grep ("$Self->{obj_dir}/V$Self->{name}__cdc.txt", qr/CDC Report/);
|
file_grep("$Self->{obj_dir}/V$Self->{name}__cdc.txt", qr/CDC Report/);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ execute(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ($Self->{vlt_all}) {
|
if ($Self->{vlt_all}) {
|
||||||
file_grep ($Self->{stats}, qr/Optimizations, Gate assign merged\s+(\d+)/i, 28);
|
file_grep($Self->{stats}, qr/Optimizations, Gate assign merged\s+(\d+)/i, 28);
|
||||||
};
|
};
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
|
|||||||
@@ -38,16 +38,16 @@ int main(int argc, char *argv[]) {
|
|||||||
Verilated::debug(0);
|
Verilated::debug(0);
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
clockit(0, 0);
|
clockit(0, 0);
|
||||||
clockit(0, 1);
|
clockit(0, 1);
|
||||||
clockit(1, 1);
|
clockit(1, 1);
|
||||||
clockit(0, 0);
|
clockit(0, 0);
|
||||||
clockit(1, 1);
|
clockit(1, 1);
|
||||||
clockit(1, 0);
|
clockit(1, 0);
|
||||||
clockit(0, 0);
|
clockit(0, 0);
|
||||||
clockit(0, 1);
|
clockit(0, 1);
|
||||||
clockit(1, 0);
|
clockit(1, 0);
|
||||||
clockit(0, 0);
|
clockit(0, 0);
|
||||||
}
|
}
|
||||||
topp->check = 1;
|
topp->check = 1;
|
||||||
clockit(0,0);
|
clockit(0,0);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ execute(
|
|||||||
check_finished => 1,
|
check_finished => 1,
|
||||||
);
|
);
|
||||||
|
|
||||||
vcd_identical("$Self->{obj_dir}/simx.vcd", "t/$Self->{name}.out");
|
vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename});
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -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(
|
compile(
|
||||||
v_flags2 => ["--lint-only"],
|
v_flags2 => ["--lint-only"],
|
||||||
fails => 1,
|
fails => 1,
|
||||||
expect =>
|
expect_filename => $Self->{golden_filename},
|
||||||
'%Warning-WIDTHCONCAT: t/t_concat_large_bad.v:\d+: More than a 8k bit replication is probably wrong: 32768
|
|
||||||
%Warning-WIDTHCONCAT: Use .*
|
|
||||||
%Error: Exiting due to.*',
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
|
|||||||
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
|
# Read the input .v file and do any CHECK_COVER requests
|
||||||
inline_checks();
|
inline_checks();
|
||||||
|
|
||||||
file_grep ($Self->{stats}, qr/Coverage, Toggle points joined\s+(\d+)/i, 25)
|
file_grep($Self->{stats}, qr/Coverage, Toggle points joined\s+(\d+)/i, 25)
|
||||||
if $Self->{vlt_all};
|
if $Self->{vlt_all};
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ compile(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ($Self->{vlt_all}) {
|
if ($Self->{vlt_all}) {
|
||||||
file_grep ($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 4);
|
file_grep($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ compile(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ($Self->{vlt_all}) {
|
if ($Self->{vlt_all}) {
|
||||||
file_grep ($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 6);
|
file_grep($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ execute(
|
|||||||
expect_filename => $Self->{golden_filename},
|
expect_filename => $Self->{golden_filename},
|
||||||
);
|
);
|
||||||
|
|
||||||
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}__stats.txt",
|
file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}__stats.txt",
|
||||||
qr/Node count, DISPLAY \s+ 32 \s+ 25 \s+ 25 \s+ 25/);
|
qr/Node count, DISPLAY \s+ 32 \s+ 25 \s+ 25 \s+ 25/);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ if (!-r "$root/.git") {
|
|||||||
my $lineno = 0;
|
my $lineno = 0;
|
||||||
foreach my $line ((split /\n/, $diff), "+++ b/_the_end") {
|
foreach my $line ((split /\n/, $diff), "+++ b/_the_end") {
|
||||||
if ($line =~ m!^\+\+\+ b/(.*)!) {
|
if ($line =~ m!^\+\+\+ b/(.*)!) {
|
||||||
if ($file && !$atab && $btab) {
|
if ($file && !$atab && $btab
|
||||||
|
&& $file !~ /\.out$/) {
|
||||||
$summary = "File modifications adds new tabs (please untabify the patch):";
|
$summary = "File modifications adds new tabs (please untabify the patch):";
|
||||||
$warns{$file} = "File modification adds new tabs (please untabify the patch): $file";
|
$warns{$file} = "File modification adds new tabs (please untabify the patch): $file";
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user