mirror of
https://github.com/verilator/verilator.git
synced 2026-10-04 17:13:40 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77e7e2bf1c | ||
|
|
1c5c9e2435 | ||
|
|
f0ed4346b2 | ||
|
|
94c8064798 | ||
|
|
cf0464c263 | ||
|
|
6268db643c | ||
|
|
fd98d231e4 | ||
|
|
92649ba494 | ||
|
|
0efe343494 | ||
|
|
84335b9580 | ||
|
|
e8b2c57610 | ||
|
|
5e22ca77ec | ||
|
|
b6e8133a4d | ||
|
|
02a22c12ea | ||
|
|
fe917ba7f4 | ||
|
|
2c568603f6 | ||
|
|
51422e3ee8 | ||
|
|
0ef3c10931 | ||
|
|
35be80f789 | ||
|
|
c29e7619eb | ||
|
|
a265417727 | ||
|
|
b69af164f7 | ||
|
|
ff61bb509c | ||
|
|
c8ba51581f | ||
|
|
29f1a9208e | ||
|
|
8b954dc381 | ||
|
|
767ac2547d | ||
|
|
a46aa2d62b | ||
|
|
9219ddaece | ||
|
|
c7c99d8553 | ||
|
|
e3354a0191 | ||
|
|
df3d1a4da9 | ||
|
|
3963fe4384 | ||
|
|
38261ac649 | ||
|
|
e49539fb4c | ||
|
|
3cd96cf558 | ||
|
|
1bcaaa0f0d | ||
|
|
7922a1de28 | ||
|
|
e897c862f2 | ||
|
|
f55040a38b | ||
|
|
2d580e6939 | ||
|
|
fc48008c1c | ||
|
|
4cf2e4024f | ||
|
|
57c7d77af3 | ||
|
|
c8cf2afb15 | ||
|
|
770045676f | ||
|
|
68cca0e114 | ||
|
|
0a1b775ed6 | ||
|
|
54a101acbe | ||
|
|
db1af07d72 | ||
|
|
ff82f75023 | ||
|
|
9ae54786e4 | ||
|
|
22ff760f0b | ||
|
|
86fe6ac3a8 | ||
|
|
9f52e23158 | ||
|
|
e1410775fb | ||
|
|
a7a790416e | ||
|
|
fe5c4df079 | ||
|
|
1376e5de92 | ||
|
|
7f5b1a402c | ||
|
|
22573d238b | ||
|
|
32859d9fc2 | ||
|
|
1b12800b8f |
@@ -23,6 +23,7 @@ dddrun*
|
||||
doxygen-doc
|
||||
gdbrun*
|
||||
gmon.out
|
||||
ncverilog.history
|
||||
internals.txt
|
||||
verilator.txt
|
||||
verilator_bin*
|
||||
|
||||
@@ -2,6 +2,48 @@ Revision history for Verilator
|
||||
|
||||
The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
* Verilator 3.924 2018-06-12
|
||||
|
||||
*** Renamed --profile-cfuncs to --prof-cfuncs.
|
||||
|
||||
**** Report interface ports connected to wrong interface, bug1294. [Todd Strader]
|
||||
|
||||
**** When tracing, use scalars on single bit arrays to appease vcddiff.
|
||||
|
||||
**** Fix parsing "output signed" in V2K port list, msg2540. [James Jung]
|
||||
|
||||
**** Fix parsing error on bad missing #, bug1308. [Dan Kirkham]
|
||||
|
||||
**** Fix $clog2 to be in verilog 2005, bug1319. [James Hutchinson]
|
||||
|
||||
|
||||
* Verilator 3.922 2018-03-17
|
||||
|
||||
** Support IEEE 1800-2017 as default language.
|
||||
|
||||
*** Support trig functions ($sin() etc), bug1281. [Patrick Stewart]
|
||||
|
||||
*** Support calling system functions as tasks, bug1285. [Joel Holdsworth]
|
||||
|
||||
*** Support assert properties, bug785, bug1290. [John Coiner, et al]
|
||||
|
||||
*** Support $writememh. [John Coiner]
|
||||
|
||||
*** Add --no-debug-leak to reduce memory use under debug. [John Coiner]
|
||||
|
||||
**** Fix severe runtime performance bug in certain foreach loops. [John Coiner]
|
||||
|
||||
**** On convergence errors, show activity. [John Coiner]
|
||||
|
||||
**** Fix GCC 8.0 issues, bug1273.
|
||||
|
||||
**** Fix pullup/pulldowns on bit selects, bug1274. [Rob Stoddard]
|
||||
|
||||
**** Fix verilator_coverage --annotate-min, bug1284. [Tymoteusz Blazejczyk]
|
||||
|
||||
**** Fix quoting of quoted arguments. [John Coiner]
|
||||
|
||||
|
||||
* Verilator 3.920 2018-02-01
|
||||
|
||||
** Moving forward, use the git "stable" branch to track the latest release,
|
||||
@@ -2156,7 +2198,7 @@ Bug fixes:
|
||||
|
||||
* Verilator 3.501 2005/11/16 Stable
|
||||
|
||||
*** Add --profile-cfuncs for correlating profiles back to Verilog.
|
||||
*** Add --prof-cfuncs for correlating profiles back to Verilog.
|
||||
|
||||
**** Fixed functions where regs are declared before inputs. [Danny Ding]
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
/obj_dir/
|
||||
/obj_dbg/
|
||||
/obj_opt/
|
||||
/obj_vlt/
|
||||
/obj_vltmt/
|
||||
/obj_dist/
|
||||
/INCA_libs/
|
||||
/cov_work/
|
||||
/logs/
|
||||
@@ -34,6 +37,7 @@ verilator.pc$
|
||||
verilator_bin.*
|
||||
verilator_coverage_bin.*
|
||||
.vcsmx_rebuild$
|
||||
ncverilog.history
|
||||
autom4te\.cache/
|
||||
nodist/
|
||||
/simv$
|
||||
|
||||
+89
-47
@@ -54,18 +54,6 @@ push @ARGV, (split ' ',$ENV{VERILATOR_TEST_FLAGS}||"");
|
||||
# We sneak a look at the flags so we can do some pre-environment checks
|
||||
# All flags will hit verilator...
|
||||
foreach my $sw (@ARGV) {
|
||||
# Some special treatment for parameters to allow verilog literals for numbers
|
||||
if ((substr($sw, 0, 2) eq "-G") || (substr($sw, 0, 8) eq "-pvalue+")) {
|
||||
# If there is a single quote in the parameter put it double quotes ,
|
||||
# else just put it in double quotes
|
||||
if ($sw =~ m![\']!) {
|
||||
$sw = "\"$sw\"";
|
||||
} else {
|
||||
$sw = "'$sw'";
|
||||
}
|
||||
} else {
|
||||
$sw = "'$sw'" if $sw =~ m![^---a-zA-Z0-9_/\\:.+]!;
|
||||
}
|
||||
push @Opt_Verilator_Sw, $sw;
|
||||
}
|
||||
|
||||
@@ -84,16 +72,30 @@ if (! GetOptions (
|
||||
pod2usage(-exitstatus=>2, -verbose=>0);
|
||||
}
|
||||
|
||||
# Determine runtime flags and run
|
||||
if ($opt_gdbbt && !gdb_works()) {
|
||||
warn "-Info: --gdbbt ignored: gdb doesn't seem to be working\n" if $Debug;
|
||||
$opt_gdbbt = 0;
|
||||
}
|
||||
|
||||
# Determine runtime flags and run
|
||||
# Opt_Verilator_Sw is what we want verilator to see on its argc/argv.
|
||||
# Starting with that, escape all special chars for the shell;
|
||||
# The shell will undo the escapes and the verilator binary should
|
||||
# then see exactly the contents of @Opt_Verilator_Sw.
|
||||
my @quoted_sw = map {sh_escape($_)} @Opt_Verilator_Sw;
|
||||
if ($opt_gdb) {
|
||||
# Generic GDB interactive
|
||||
run (("gdb"||$ENV{VERILATOR_GDB})
|
||||
." ".verilator_bin()
|
||||
." -ex 'run ".join(' ',@Opt_Verilator_Sw)."'"
|
||||
# Note, uncomment to set breakpoints before running:
|
||||
# ." -ex 'break main'"
|
||||
|
||||
# Note, we must use double-quotes ("run <switches>")
|
||||
# and not single ('run <switches>') below. Bash swallows
|
||||
# escapes as you would expect in a double-quoted string.
|
||||
# That's not true for a single-quoted string, where \'
|
||||
# actually terminates the string -- not what we want!
|
||||
." -ex \"run ".join(' ', @quoted_sw)."\""
|
||||
." -ex 'set width 0'"
|
||||
." -ex 'bt'");
|
||||
} elsif ($opt_gdbbt && $Debug) {
|
||||
@@ -101,13 +103,12 @@ if ($opt_gdb) {
|
||||
run ("gdb"
|
||||
." ".verilator_bin()
|
||||
." --batch --quiet --return-child-result"
|
||||
." -ex 'run ".join(' ',@Opt_Verilator_Sw)."'"
|
||||
." -ex \"run ".join(' ', @quoted_sw)."\""
|
||||
." -ex 'set width 0'"
|
||||
." -ex 'bt'");
|
||||
} else {
|
||||
# Normal, non gdb
|
||||
run (verilator_bin()
|
||||
." ".join(' ',@Opt_Verilator_Sw));
|
||||
run (verilator_bin()." ".join(' ',@quoted_sw));
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
@@ -196,6 +197,16 @@ sub run {
|
||||
}
|
||||
}
|
||||
|
||||
sub sh_escape {
|
||||
my ($arg) = @_;
|
||||
|
||||
# This is similar to quotemeta() but less aggressive.
|
||||
# There's no need to escape hyphens, periods, or forward slashes
|
||||
# for the shell as these have no special meaning to the shell.
|
||||
$arg =~ s/([^0-9a-zA-Z_\-\.\/])/\\$1/g;
|
||||
return $arg;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
package main;
|
||||
@@ -217,8 +228,8 @@ Verilator - Convert Verilog code to C++/SystemC
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Verilator converts synthesizable (not behavioral) Verilog code, plus some
|
||||
Synthesis, SystemVerilog and a small subset of Verilog AMS assertions, into
|
||||
Verilator converts synthesizable (generally not behavioral) Verilog code,
|
||||
plus some Synthesis, SystemVerilog and a small subset of Verilog AMS into
|
||||
C++ or SystemC code. It is not a complete simulator, but a compiler.
|
||||
|
||||
Verilator is invoked with parameters similar to GCC, Cadence
|
||||
@@ -238,8 +249,8 @@ To get started, jump down to "EXAMPLE C++ EXECUTION".
|
||||
|
||||
=head1 ARGUMENT SUMMARY
|
||||
|
||||
This is a short summary of the arguments to Verilator. See the detailed
|
||||
descriptions in the next sections for more information.
|
||||
This is a short summary of the arguments to Verilator itself. See the
|
||||
detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
|
||||
|
||||
{file.v} Verilog package, module and top module filenames
|
||||
{file.c/cc/cpp} Optional C++ files to compile in
|
||||
@@ -251,6 +262,7 @@ descriptions in the next sections for more information.
|
||||
+1800-2005ext+<ext> Use SystemVerilog 2005 with file extension <ext>
|
||||
+1800-2009ext+<ext> Use SystemVerilog 2009 with file extension <ext>
|
||||
+1800-2012ext+<ext> Use SystemVerilog 2012 with file extension <ext>
|
||||
+1800-2017ext+<ext> Use SystemVerilog 2017 with file extension <ext>
|
||||
--assert Enable all assertions
|
||||
--autoflush Flush streams after all $displays
|
||||
--bbox-sys Blackbox unknown $system calls
|
||||
@@ -270,6 +282,7 @@ descriptions in the next sections for more information.
|
||||
-D<var>[=<value>] Set preprocessor define
|
||||
--debug Enable debugging
|
||||
--debug-check Enable debugging assertions
|
||||
--no-debug-leak Disable leaking memory in --debug mode
|
||||
--debugi <level> Enable debugging at a specified level
|
||||
--debugi-<srcfile> <level> Enable debugging a source file at a level
|
||||
--default-language <lang> Default language to parse
|
||||
@@ -324,7 +337,7 @@ descriptions in the next sections for more information.
|
||||
--pins-uint8 Specify types for top level ports
|
||||
--pipe-filter <command> Filter all input through a script
|
||||
--prefix <topname> Name of top level class
|
||||
--profile-cfuncs Name functions for profiling
|
||||
--prof-cfuncs Name functions for profiling
|
||||
--private Debugging; see docs
|
||||
--public Debugging; see docs
|
||||
-pvalue+<name>=<value> Overwrite toplevel parameter
|
||||
@@ -336,7 +349,7 @@ descriptions in the next sections for more information.
|
||||
--stats Create statistics file
|
||||
--stats-vars Provide statistics on variables
|
||||
-sv Enable SystemVerilog parsing
|
||||
+systemverilogext+<ext> Synonym for +1800-2012ext+<ext>
|
||||
+systemverilogext+<ext> Synonym for +1800-2017ext+<ext>
|
||||
--top-module <topname> Name of top level input module
|
||||
--trace Enable waveform creation
|
||||
--trace-depth <levels> Depth of tracing
|
||||
@@ -353,6 +366,7 @@ descriptions in the next sections for more information.
|
||||
-v <filename> Verilog library
|
||||
+verilog1995ext+<ext> Synonym for +1364-1995ext+<ext>
|
||||
+verilog2001ext+<ext> Synonym for +1364-2001ext+<ext>
|
||||
--version Displays program version and exits
|
||||
--vpi Enable VPI compiles
|
||||
-Wall Enable all style warnings
|
||||
-Werror-<message> Convert warnings to errors
|
||||
@@ -367,7 +381,9 @@ descriptions in the next sections for more information.
|
||||
-y <dir> Directory to search for modules
|
||||
|
||||
|
||||
=head1 ARGUMENTS
|
||||
=head1 VERILATION ARGUMENTS
|
||||
|
||||
The following are the arguments that may be passed to Verilator itself.
|
||||
|
||||
=over 4
|
||||
|
||||
@@ -403,6 +419,8 @@ with the --exe option.
|
||||
|
||||
=item +1800-2012ext+I<ext>
|
||||
|
||||
=item +1800-2017ext+I<ext>
|
||||
|
||||
Specifies the language standard to be used with a specific filename
|
||||
extension, I<ext>.
|
||||
|
||||
@@ -530,7 +548,7 @@ functions to avoid error C1061.
|
||||
|
||||
=back
|
||||
|
||||
=item --converge-limit <loops>
|
||||
=item --converge-limit I<loops>
|
||||
|
||||
Rarely needed. Specifies the maximum number of runtime iterations before
|
||||
creating a model failed to converge error. Defaults to 100.
|
||||
@@ -627,9 +645,21 @@ to C<--dump-treei 3>).
|
||||
Rarely needed. Enable internal debugging assertion checks, without
|
||||
changing debug verbosity. Enabled automatically when --debug specified.
|
||||
|
||||
=item --debugi <level>
|
||||
=item --no-debug-leak
|
||||
|
||||
=item --debugi-<srcfile> <level>
|
||||
In --debug mode, by default Verilator intentionally leaks AstNode's
|
||||
instead of freeing them, so that each node pointer is unique in the
|
||||
resulting tree files and dot files.
|
||||
|
||||
This option disables the leak. This may avoid out-of-memory errors
|
||||
when Verilating large models in --debug mode.
|
||||
|
||||
Outside of --debug mode, AstNode's should never be leaked and this option
|
||||
has no effect.
|
||||
|
||||
=item --debugi I<level>
|
||||
|
||||
=item --debugi-I<srcfile> I<level>
|
||||
|
||||
Rarely needed - for developer use. Set internal debugging level globally
|
||||
to the specified debug level (1-10) or set the specified Verilator source
|
||||
@@ -640,7 +670,7 @@ produce more detailed messages.
|
||||
|
||||
Select the language to be used by default when first processing each
|
||||
Verilog file. The language value must be "1364-1995", "1364-2001",
|
||||
"1364-2005", "1800-2005", "1800-2009" or "1800-2012".
|
||||
"1364-2005", "1800-2005", "1800-2009", "1800-2012" or "1800-2017".
|
||||
|
||||
Any language associated with a particular file extension (see the various
|
||||
+I<lang>ext+ options) will be used in preference to the language specified
|
||||
@@ -653,7 +683,7 @@ legacy mixed language designs, the various +I<lang>ext+ options should be
|
||||
used.
|
||||
|
||||
If no language is specified, either by this flag or +I<lang>ext+ options,
|
||||
then the latest SystemVerilog language (IEEE 1800-2012) is used.
|
||||
then the latest SystemVerilog language (IEEE 1800-2017) is used.
|
||||
|
||||
=item +define+I<var>=I<value>
|
||||
|
||||
@@ -671,9 +701,9 @@ the Verilator Internals manual. --dump-tree is enabled automatically with
|
||||
--debug, so "--debug --no-dump-tree" may be useful if the dump files are
|
||||
large and not desired.
|
||||
|
||||
=item --dump-treei <level>
|
||||
=item --dump-treei I<level>
|
||||
|
||||
=item --dump-treei-<srcfile> <level>
|
||||
=item --dump-treei-I<srcfile> I<level>
|
||||
|
||||
Rarely needed - for developer use. Set internal tree dumping level
|
||||
globally to a specific dumping level or set the specified Verilator source
|
||||
@@ -687,7 +717,7 @@ Preprocess the source code, but do not compile, as with 'gcc -E'. Output
|
||||
is written to standard out. Beware of enabling debugging messages, as they
|
||||
will also go to standard out.
|
||||
|
||||
=item --error-limit <value>
|
||||
=item --error-limit I<value>
|
||||
|
||||
After this number of errors or warnings are encountered, exit. Defaults to
|
||||
50.
|
||||
@@ -714,7 +744,7 @@ The file may contain // comments which are ignored to the end of the line.
|
||||
Any $VAR, $(VAR), or ${VAR} will be replaced with the specified environment
|
||||
variable.
|
||||
|
||||
=item -FI <file>
|
||||
=item -FI I<file>
|
||||
|
||||
Force include of the specified C++ header file. All generated C++ files
|
||||
will insert a #include of the specified file before any other includes. The
|
||||
@@ -746,7 +776,7 @@ Double literals must contain a dot (.) and/or an exponent (e).
|
||||
|
||||
=item Strings
|
||||
|
||||
String must in double quotes ("). On the command line it is required to escape
|
||||
String must in double quotes (""). On the command line it is required to escape
|
||||
them properly, e.g. as -GSTR="\"My String\"" or -GSTR='"My String"'.
|
||||
|
||||
=back
|
||||
@@ -872,7 +902,7 @@ otherwise manually create the Mdir before calling Verilator.
|
||||
Specifies the name to prepend to all lower level classes. Defaults to
|
||||
the same as --prefix.
|
||||
|
||||
=item --no-clk <signal-name>
|
||||
=item --no-clk I<signal-name>
|
||||
|
||||
Prevent the specified signal from being marked as clock. See C<--clk>.
|
||||
|
||||
@@ -931,7 +961,7 @@ disables an optimization, an upper case letter enables it. This is
|
||||
intended for debugging use only; see the source code for version-dependent
|
||||
mappings of optimizations to -O letters.
|
||||
|
||||
=item -o <executable>
|
||||
=item -o I<executable>
|
||||
|
||||
Specify the name for the final executable built if using --exe. Defaults
|
||||
to the --prefix if not specified.
|
||||
@@ -1030,7 +1060,7 @@ Specifies the name of the top level class and makefile. Defaults to V
|
||||
prepended to the name of the --top-module switch, or V prepended to the
|
||||
first Verilog filename passed on the command line.
|
||||
|
||||
=item --profile-cfuncs
|
||||
=item --prof-cfuncs
|
||||
|
||||
Modify the created C++ functions to support profiling. The functions will
|
||||
be minimized to contain one "basic" statement, generally a single always
|
||||
@@ -1038,7 +1068,7 @@ block or wire statement. (Note this will slow down the executable by ~5%.)
|
||||
Furthermore, the function name will be suffixed with the basename of the
|
||||
Verilog module and line number the statement came from. This allows gprof
|
||||
or oprofile reports to be correlated with the original Verilog source
|
||||
statements.
|
||||
statements. See also L<verilator_profcfunc>.
|
||||
|
||||
=item --private
|
||||
|
||||
@@ -1131,7 +1161,7 @@ compatibility with other simulators.
|
||||
|
||||
=item +systemverilogext+I<ext>
|
||||
|
||||
A synonym for C<+1800-2012ext+>I<ext>.
|
||||
A synonym for C<+1800-2017ext+>I<ext>.
|
||||
|
||||
=item --top-module I<topname>
|
||||
|
||||
@@ -1225,6 +1255,10 @@ Note -v is fairly standard across Verilog tools.
|
||||
|
||||
Synonyms for C<+1364-1995ext+>I<ext> and C<+1364-2001ext+>I<ext> respectively
|
||||
|
||||
=item --version
|
||||
|
||||
Displays program version and exits.
|
||||
|
||||
=item --vpi
|
||||
|
||||
Enable use of VPI and linking against the verilated_vpi.cpp files.
|
||||
@@ -1251,8 +1285,9 @@ supports which the older version does not support.
|
||||
|
||||
=item -Wno-I<message>
|
||||
|
||||
Disable the specified warning message. This will override any lint_on
|
||||
directives in the source, i.e. the warning will still not be printed.
|
||||
Disable the specified warning message, or in some cases where noted here
|
||||
disable an error. This will override any lint_on directives in the source,
|
||||
i.e. the warning will still not be printed.
|
||||
|
||||
=item -Wno-lint
|
||||
|
||||
@@ -1343,7 +1378,7 @@ not otherwise initialized.
|
||||
|
||||
--x-initial=unique, the default, initializes variables using a function,
|
||||
which determines the value to use each initialization. This gives greatest
|
||||
flexibility and allows finding reset bugs. See L</"Unknown states">
|
||||
flexibility and allows finding reset bugs. See L</"Unknown states">.
|
||||
|
||||
--x-initial=fast, is best for performance, and initializes all variables to
|
||||
a state Verilator determines is optimal. This may allow further code
|
||||
@@ -1604,7 +1639,7 @@ code with -DVL_INLINE_OPT=inline. This will inline functions, however this
|
||||
requires that all cpp files be compiled in a single compiler run.
|
||||
|
||||
You may uncover further tuning possibilities by profiling the Verilog code.
|
||||
Use Verilator's --profile-cfuncs, then GCC's -g -pg. You can then run
|
||||
Use Verilator's --prof-cfuncs, then GCC's -g -pg. You can then run
|
||||
either oprofile or gprof to see where in the C++ code the time is spent.
|
||||
Run the gprof output through verilator_profcfunc and it will tell you what
|
||||
Verilog line numbers on which most of the time is being spent.
|
||||
@@ -2194,6 +2229,11 @@ Verilator currently has some support for SystemVerilog synthesis
|
||||
constructs. As SystemVerilog features enter common usage they are added;
|
||||
please file a bug if a feature you need is missing.
|
||||
|
||||
=head2 SystemVerilog 2017 (IEEE 1800-2017) Support
|
||||
|
||||
Verilator supports the 2017 "for" loop constructs, and several minor
|
||||
cleanups made in 1800-2017.
|
||||
|
||||
=head2 Verilog AMS Support
|
||||
|
||||
Verilator implements a very small subset of Verilog AMS (Verilog Analog and
|
||||
@@ -3047,13 +3087,15 @@ Simply use a different register for the flop:
|
||||
always @* foo[0] = foo_flopped[0];
|
||||
always @* foo[1] = ...
|
||||
|
||||
It is also possible to disable this error when one of the assignments is
|
||||
inside a public task.
|
||||
|
||||
This is not illegal in SystemVerilog, but a violation of good coding
|
||||
practice. Verilator reports this as an error, because ignoring this warning
|
||||
may make Verilator simulations differ from other simulators.
|
||||
|
||||
It is generally safe to disable this error (with a "// verilator lint_off
|
||||
BLKANDNBLK" metacomment or the -Wno-BLKANDNBLK option) when one of the
|
||||
assignments is inside a public task, or when the blocked and non-blocking
|
||||
assignments have non-overlapping bits and structure members.
|
||||
|
||||
=item BLKSEQ
|
||||
|
||||
This indicates that a blocking assignment (=) is used in a sequential
|
||||
@@ -3669,7 +3711,7 @@ For example:
|
||||
will toggle forever and thus the executable will give the didn't converge
|
||||
error to prevent an infinite loop.
|
||||
|
||||
To debug this, run Verilator with --profile-cfuncs. Run make on the
|
||||
To debug this, run Verilator with --prof-cfuncs. Run make on the
|
||||
generated files with "OPT=-DVL_DEBUG". Then call Verilated::debug(1) in
|
||||
your main.cpp.
|
||||
|
||||
|
||||
@@ -85,7 +85,8 @@ sub diff_dir {
|
||||
diff_file($a,$b);
|
||||
$any = 1;
|
||||
}
|
||||
$any or warn "%Warning: No .tree files found\n";
|
||||
$any or warn ("%Warning: No .tree files found that have similar base names:\n "
|
||||
.join("\n ", sort keys %files),"\n");
|
||||
}
|
||||
|
||||
sub diff_file {
|
||||
|
||||
+11
-3
@@ -73,6 +73,14 @@ sub profcfunc {
|
||||
$funcs{$func}{sec} += $sec;
|
||||
$funcs{$func}{calls} += $calls;
|
||||
}
|
||||
# Older gprofs have no call column for single-call functions
|
||||
# %time cumesec selfsec {stuff} name
|
||||
elsif ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
|
||||
my $pct=$1; my $sec=$2; my $calls=1; my $func=$3;
|
||||
$funcs{$func}{pct} += $pct;
|
||||
$funcs{$func}{sec} += $sec;
|
||||
$funcs{$func}{calls} += $calls;
|
||||
}
|
||||
}
|
||||
$fh->close;
|
||||
|
||||
@@ -191,11 +199,11 @@ __END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
verilator_profcfunc - Read gprof report created with --profile-cfuncs
|
||||
verilator_profcfunc - Read gprof report created with --prof-cfuncs
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
verilator --profile-cfuncs ....
|
||||
verilator --prof-cfuncs ....
|
||||
gcc --ggdb -pg ....
|
||||
{run executable}
|
||||
gprof
|
||||
@@ -205,7 +213,7 @@ verilator_profcfunc - Read gprof report created with --profile-cfuncs
|
||||
|
||||
Verilator_profcfunc reads a profile report created by gprof. The names of
|
||||
the functions are then transformed, assuming the user used verilator's
|
||||
--profile-cfuncs, and a report printed showing the percentage of time, etc,
|
||||
--prof-cfuncs, and a report printed showing the percentage of time, etc,
|
||||
in each Verilog block.
|
||||
|
||||
=head1 ARGUMENTS
|
||||
|
||||
+3
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[3.920 2018-02-01])
|
||||
AC_INIT([Verilator],[3.924 2018-06-12])
|
||||
# When releasing, also update header of Changes file
|
||||
# and commit using "devel release" or "Version bump" message
|
||||
|
||||
@@ -77,6 +77,8 @@ AC_PROG_CXX
|
||||
AC_PROG_INSTALL
|
||||
|
||||
AC_LANG_PUSH(C++)
|
||||
cxx_version=$($CXX --version | head -1)
|
||||
AC_MSG_RESULT([compiler is $CXX --version = $cxx_version])
|
||||
AC_MSG_CHECKING([that C++ compiler can compile simple program])
|
||||
AC_RUN_IFELSE(
|
||||
[AC_LANG_SOURCE([int main() { return 0; }])],
|
||||
|
||||
+222
-40
@@ -40,9 +40,9 @@ VerilatedVoidCb Verilated::s_flushCb = NULL;
|
||||
Verilated::Serialized Verilated::s_s;
|
||||
VL_THREAD_LOCAL Verilated::ThreadLocal Verilated::t_s;
|
||||
|
||||
struct Verilated::CommandArgValues Verilated::s_args = {0, NULL};
|
||||
Verilated::CommandArgValues Verilated::s_args;
|
||||
|
||||
VerilatedImp VerilatedImp::s_s;
|
||||
VerilatedImp VerilatedImp::s_s;
|
||||
|
||||
//===========================================================================
|
||||
// User definable functions
|
||||
@@ -122,10 +122,16 @@ std::string _vl_string_vprintf(const char* formatp, va_list ap) VL_MT_SAFE {
|
||||
va_list aq;
|
||||
va_copy(aq, ap);
|
||||
int len = VL_VSNPRINTF(NULL, 0, formatp, aq);
|
||||
if (VL_UNLIKELY(len < 1)) return "";
|
||||
va_end(aq);
|
||||
if (VL_UNLIKELY(len < 1)) {
|
||||
va_end(ap);
|
||||
return "";
|
||||
}
|
||||
|
||||
char* bufp = new char[len+1];
|
||||
VL_VSNPRINTF(bufp, len+1, formatp, ap);
|
||||
va_end(ap);
|
||||
|
||||
std::string out = std::string(bufp, len);
|
||||
delete[] bufp;
|
||||
return out;
|
||||
@@ -159,7 +165,11 @@ void VL_DBG_MSGF(const char* formatp, ...) VL_MT_SAFE {
|
||||
std::string out = _vl_string_vprintf(formatp, ap);
|
||||
va_end(ap);
|
||||
// printf("-imm-V{t%d,%" VL_PRI64 "d}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str());
|
||||
VL_PRINTF_MT("-V{t%d,%" VL_PRI64 "d}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str());
|
||||
|
||||
// Using VL_PRINTF not VL_PRINTF_MT so that we can call VL_DBG_MSGF
|
||||
// from within the guts of the thread execution machinery (and it goes
|
||||
// to the screen and not into the queues we're debugging)
|
||||
VL_PRINTF("-V{t%d,%" VL_PRI64 "u}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str());
|
||||
}
|
||||
|
||||
#ifdef VL_THREADED
|
||||
@@ -198,7 +208,7 @@ IData VL_RAND32() VL_MT_SAFE {
|
||||
t_seeded = true;
|
||||
long seedval;
|
||||
{
|
||||
VerilatedLockGuard guard(s_mutex);
|
||||
VerilatedLockGuard lock(s_mutex);
|
||||
seedval = lrand48()<<16 ^ lrand48();
|
||||
if (!seedval) seedval++;
|
||||
}
|
||||
@@ -430,7 +440,8 @@ QData VL_POW_QQW(int, int, int rbits, QData lhs, WDataInP rwp) VL_MT_SAFE {
|
||||
return out;
|
||||
}
|
||||
|
||||
WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool lsign, bool rsign) VL_MT_SAFE {
|
||||
WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp,
|
||||
bool lsign, bool rsign) VL_MT_SAFE {
|
||||
// obits==lbits, rbits can be different
|
||||
if (rsign && VL_SIGN_W(rbits, rwp)) {
|
||||
int words = VL_WORDS_I(obits);
|
||||
@@ -450,7 +461,9 @@ WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, W
|
||||
}
|
||||
return VL_POW_WWW(obits, rbits, rbits, owp, lwp, rwp);
|
||||
}
|
||||
WDataOutP VL_POWSS_WWQ(int obits, int lbits, int rbits, WDataOutP owp, WDataInP lwp, QData rhs, bool lsign, bool rsign) VL_MT_SAFE {
|
||||
WDataOutP VL_POWSS_WWQ(int obits, int lbits, int rbits,
|
||||
WDataOutP owp, WDataInP lwp, QData rhs,
|
||||
bool lsign, bool rsign) VL_MT_SAFE {
|
||||
WData rhsw[2]; VL_SET_WQ(rhsw, rhs);
|
||||
return VL_POWSS_WWW(obits,lbits,rbits,owp,lwp,rhsw,lsign,rsign);
|
||||
}
|
||||
@@ -982,7 +995,8 @@ void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) VL_MT_SAFE
|
||||
}
|
||||
}
|
||||
*destp = '\0'; // Terminate
|
||||
if (!start) while (isspace(*(destp-1)) && destp>destoutp) *--destp = '\0'; // Drop trailing spaces
|
||||
// Drop trailing spaces
|
||||
if (!start) while (isspace(*(destp-1)) && destp>destoutp) *--destp = '\0';
|
||||
}
|
||||
|
||||
void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp) VL_MT_SAFE {
|
||||
@@ -1201,10 +1215,134 @@ IData VL_SSCANF_INX(int, const std::string& ld, const char* formatp, ...) VL_MT_
|
||||
return got;
|
||||
}
|
||||
|
||||
void VL_WRITEMEM_Q(bool hex, int width, int depth, int array_lsb, int,
|
||||
QData ofilename, const void* memp, IData start,
|
||||
IData end) VL_MT_SAFE {
|
||||
WData fnw[2]; VL_SET_WQ(fnw, ofilename);
|
||||
return VL_WRITEMEM_W(hex, width,depth,array_lsb,2,fnw,memp,start,end);
|
||||
}
|
||||
|
||||
void VL_WRITEMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
WDataInP ofilenamep, const void* memp, IData start,
|
||||
IData end) VL_MT_SAFE {
|
||||
char ofilenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
||||
_VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, ofilenamez, ofilenamep);
|
||||
std::string ofilenames(ofilenamez);
|
||||
return VL_WRITEMEM_N(hex, width,depth,array_lsb,ofilenames,memp,start,end);
|
||||
}
|
||||
|
||||
const char* memhFormat(int nBits) {
|
||||
assert((nBits >= 1) && (nBits <= 32));
|
||||
|
||||
static char buf[32];
|
||||
switch ((nBits - 1) / 4) {
|
||||
case 0: VL_SNPRINTF(buf, 32, "%%01x"); break;
|
||||
case 1: VL_SNPRINTF(buf, 32, "%%02x"); break;
|
||||
case 2: VL_SNPRINTF(buf, 32, "%%03x"); break;
|
||||
case 3: VL_SNPRINTF(buf, 32, "%%04x"); break;
|
||||
case 4: VL_SNPRINTF(buf, 32, "%%05x"); break;
|
||||
case 5: VL_SNPRINTF(buf, 32, "%%06x"); break;
|
||||
case 6: VL_SNPRINTF(buf, 32, "%%07x"); break;
|
||||
case 7: VL_SNPRINTF(buf, 32, "%%08x"); break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void VL_WRITEMEM_N(
|
||||
bool hex, // Hex format, else binary
|
||||
int width, // Width of each array row
|
||||
int depth, // Number of rows
|
||||
int array_lsb, // Index of first row. Valid row addresses
|
||||
// // range from array_lsb up to (array_lsb + depth - 1)
|
||||
const std::string& ofilenamep, // Output file name
|
||||
const void* memp, // Array state
|
||||
IData start, // First array row address to write
|
||||
IData end // Last address to write
|
||||
) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(!hex)) {
|
||||
VL_FATAL_MT(ofilenamep.c_str(), 0, "",
|
||||
"VL_WRITEMEM_N only supports hex format for now, sorry!");
|
||||
return;
|
||||
}
|
||||
FILE* fp = fopen(ofilenamep.c_str(), "w");
|
||||
if (VL_UNLIKELY(!fp)) {
|
||||
VL_FATAL_MT(ofilenamep.c_str(), 0, "", "$writemem file not found");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int row_addr = start; row_addr <= end; ++row_addr) {
|
||||
if ((row_addr < array_lsb)
|
||||
|| (row_addr > array_lsb + depth - 1)) {
|
||||
vluint32_t endmax = ~0;
|
||||
if (end != endmax) {
|
||||
VL_FATAL_MT(ofilenamep.c_str(), 0, "",
|
||||
"$writemem specified address out-of-bounds");
|
||||
}
|
||||
// else, it's not an error to overflow due to end == endmax,
|
||||
// just return cleanly.
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Compute the offset into the memp array.
|
||||
int row_offset = row_addr - array_lsb;
|
||||
|
||||
if (width <= 8) {
|
||||
const CData* datap
|
||||
= &(reinterpret_cast<const CData*>(memp))[row_offset];
|
||||
fprintf(fp, memhFormat(width), VL_MASK_I(width) & *datap);
|
||||
fprintf(fp, "\n");
|
||||
} else if (width <= 16) {
|
||||
const SData* datap
|
||||
= &(reinterpret_cast<const SData*>(memp))[row_offset];
|
||||
fprintf(fp, memhFormat(width), VL_MASK_I(width) & *datap);
|
||||
fprintf(fp, "\n");
|
||||
} else if (width <= 32) {
|
||||
const IData* datap
|
||||
= &(reinterpret_cast<const IData*>(memp))[row_offset];
|
||||
fprintf(fp, memhFormat(width), VL_MASK_I(width) & *datap);
|
||||
fprintf(fp, "\n");
|
||||
} else if (width <= 64) {
|
||||
const QData* datap
|
||||
= &(reinterpret_cast<const QData*>(memp))[row_offset];
|
||||
vluint64_t value = VL_MASK_Q(width) & *datap;
|
||||
vluint32_t lo = value & 0xffffffff;
|
||||
vluint32_t hi = value >> 32;
|
||||
fprintf(fp, memhFormat(width - 32), hi);
|
||||
fprintf(fp, "%08x\n", lo);
|
||||
} else {
|
||||
WDataInP memDatap = reinterpret_cast<WDataInP>(memp);
|
||||
WDataInP datap = &memDatap[row_offset * VL_WORDS_I(width)];
|
||||
// output as a sequence of VL_WORDSIZE'd words
|
||||
// from MSB to LSB. Mask off the MSB word which could
|
||||
// contain junk above the top of valid data.
|
||||
int word_idx = ((width - 1) / VL_WORDSIZE);
|
||||
bool first = true;
|
||||
while (word_idx >= 0) {
|
||||
IData data = datap[word_idx];
|
||||
if (first) {
|
||||
data &= VL_MASK_I(width);
|
||||
int top_word_nbits = ((width - 1) & 0x1f) + 1;
|
||||
fprintf(fp, memhFormat(top_word_nbits), data);
|
||||
} else {
|
||||
fprintf(fp, "%08x", data);
|
||||
}
|
||||
|
||||
word_idx--;
|
||||
first = false;
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int,
|
||||
QData ofilename, void* memp, IData start, IData end) VL_MT_SAFE {
|
||||
WData fnw[2]; VL_SET_WQ(fnw, ofilename);
|
||||
return VL_READMEM_W(hex,width,depth,array_lsb,2, fnw,memp,start,end);
|
||||
return VL_READMEM_W(hex,width,depth,array_lsb,2,fnw,memp,start,end);
|
||||
}
|
||||
|
||||
void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
@@ -1212,12 +1350,20 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
char ofilenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
||||
_VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, ofilenamez, ofilenamep);
|
||||
std::string ofilenames(ofilenamez);
|
||||
return VL_READMEM_N(hex,width,depth,array_lsb,fnwords,ofilenames,memp,start,end);
|
||||
return VL_READMEM_N(hex,width,depth,array_lsb,ofilenames,memp,start,end);
|
||||
}
|
||||
|
||||
void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
const std::string& ofilenamep, void* memp, IData start, IData end) VL_MT_SAFE {
|
||||
if (fnwords) {}
|
||||
void VL_READMEM_N(
|
||||
bool hex, // Hex format, else binary
|
||||
int width, // Width of each array row
|
||||
int depth, // Number of rows
|
||||
int array_lsb, // Index of first row. Valid row addresses
|
||||
// // range from array_lsb up to (array_lsb + depth - 1)
|
||||
const std::string& ofilenamep, // Input file name
|
||||
void* memp, // Array state
|
||||
IData start, // First array row address to read
|
||||
IData end // Last row address to read
|
||||
) VL_MT_SAFE {
|
||||
FILE* fp = fopen(ofilenamep.c_str(), "r");
|
||||
if (VL_UNLIKELY(!fp)) {
|
||||
// We don't report the Verilog source filename as it slow to have to pass it down
|
||||
@@ -1239,7 +1385,8 @@ void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
while (1) {
|
||||
int c = fgetc(fp);
|
||||
if (VL_UNLIKELY(c==EOF)) break;
|
||||
//printf("%d: Got '%c' Addr%x IN%d IgE%d IgC%d ninc%d\n", linenum, c, addr, innum, ignore_to_eol, ignore_to_cmt, needinc);
|
||||
//printf("%d: Got '%c' Addr%x IN%d IgE%d IgC%d ninc%d\n",
|
||||
// linenum, c, addr, innum, ignore_to_eol, ignore_to_cmt, needinc);
|
||||
if (c=='\n') { linenum++; ignore_to_eol=false; if (innum) reading_addr=false; innum=false; }
|
||||
else if (c=='\t' || c==' ' || c=='\r' || c=='\f') { if (innum) reading_addr=false; innum=false; }
|
||||
// Skip // comments and detect /* comments
|
||||
@@ -1267,7 +1414,8 @@ void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
//printf(" Value width=%d @%x = %c\n", width, addr, c);
|
||||
if (VL_UNLIKELY(addr >= static_cast<IData>(depth+array_lsb)
|
||||
|| addr < static_cast<IData>(array_lsb))) {
|
||||
VL_FATAL_MT (ofilenamep.c_str(), linenum, "", "$readmem file address beyond bounds of array");
|
||||
VL_FATAL_MT (ofilenamep.c_str(), linenum, "",
|
||||
"$readmem file address beyond bounds of array");
|
||||
} else {
|
||||
int entry = addr - array_lsb;
|
||||
QData shift = hex ? VL_ULL(4) : VL_ULL(1);
|
||||
@@ -1296,7 +1444,8 @@ void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
datap[0] |= value;
|
||||
}
|
||||
if (VL_UNLIKELY(value>=(1<<shift))) {
|
||||
VL_FATAL_MT (ofilenamep.c_str(), linenum, "", "$readmemb (binary) file contains hex characters");
|
||||
VL_FATAL_MT (ofilenamep.c_str(), linenum, "",
|
||||
"$readmemb (binary) file contains hex characters");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1460,7 +1609,8 @@ std::string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp) VL_MT_SAFE {
|
||||
Verilated::ThreadLocal::ThreadLocal()
|
||||
:
|
||||
#ifdef VL_THREADED
|
||||
t_trainId(0),
|
||||
t_mtaskId(0),
|
||||
t_endOfEvalReqd(0),
|
||||
#endif
|
||||
t_dpiScopep(NULL), t_dpiFilename(0), t_dpiLineno(0) {
|
||||
}
|
||||
@@ -1468,7 +1618,7 @@ Verilated::ThreadLocal::~ThreadLocal() {
|
||||
}
|
||||
|
||||
void Verilated::debug(int val) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
s_s.s_debug = val;
|
||||
if (val) {
|
||||
#ifdef VL_DEBUG
|
||||
@@ -1479,23 +1629,23 @@ void Verilated::debug(int val) VL_MT_SAFE {
|
||||
}
|
||||
}
|
||||
void Verilated::randReset(int val) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
s_s.s_randReset = val;
|
||||
}
|
||||
void Verilated::calcUnusedSigs(bool flag) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
s_s.s_calcUnusedSigs = flag;
|
||||
}
|
||||
void Verilated::gotFinish(bool flag) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
s_s.s_gotFinish = flag;
|
||||
}
|
||||
void Verilated::assertOn(bool flag) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
s_s.s_assertOn = flag;
|
||||
}
|
||||
void Verilated::fatalOnVpiError(bool flag) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
s_s.s_fatalOnVpiError = flag;
|
||||
}
|
||||
|
||||
@@ -1517,7 +1667,7 @@ const char* Verilated::catName(const char* n1, const char* n2) VL_MT_SAFE {
|
||||
}
|
||||
|
||||
void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
if (s_flushCb == cb) {} // Ok - don't duplicate
|
||||
else if (!s_flushCb) { s_flushCb=cb; }
|
||||
else {
|
||||
@@ -1527,12 +1677,14 @@ void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
|
||||
}
|
||||
|
||||
void Verilated::flushCall() VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
if (s_flushCb) (*s_flushCb)();
|
||||
fflush(stderr);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void Verilated::commandArgs(int argc, const char** argv) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
s_args.argc = argc;
|
||||
s_args.argv = argv;
|
||||
VerilatedImp::commandArgs(argc,argv);
|
||||
@@ -1570,16 +1722,6 @@ void Verilated::scopesDump() VL_MT_SAFE {
|
||||
VerilatedImp::scopesDump();
|
||||
}
|
||||
|
||||
void Verilated::numThreads(unsigned threads) VL_MT_SAFE {
|
||||
VerilatedImp::numThreads(threads);
|
||||
}
|
||||
unsigned Verilated::numThreads() VL_MT_SAFE {
|
||||
return VerilatedImp::numThreads();
|
||||
}
|
||||
void Verilated::spawnThreads() VL_MT_SAFE {
|
||||
VerilatedImp::spawnThreads();
|
||||
}
|
||||
|
||||
const VerilatedScope* Verilated::scopeFind(const char* namep) VL_MT_SAFE {
|
||||
return VerilatedImp::scopeFind(namep);
|
||||
}
|
||||
@@ -1593,8 +1735,8 @@ const VerilatedScopeNameMap* Verilated::scopeNameMap() VL_MT_SAFE {
|
||||
}
|
||||
|
||||
#ifdef VL_THREADED
|
||||
void Verilated::endOfThreadTrainGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("End of thread train\n"););
|
||||
void Verilated::endOfThreadMTaskGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("End of thread mtask\n"););
|
||||
VerilatedThreadMsgQueue::flush(evalMsgQp);
|
||||
}
|
||||
|
||||
@@ -1604,6 +1746,44 @@ void Verilated::endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
}
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
// VerilatedImp:: Methods
|
||||
|
||||
void VerilatedImp::internalsDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_argMutex);
|
||||
VL_PRINTF_MT("internalsDump:\n");
|
||||
versionDump();
|
||||
VL_PRINTF_MT(" Argv:");
|
||||
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
||||
VL_PRINTF_MT(" %s",it->c_str());
|
||||
}
|
||||
VL_PRINTF_MT("\n");
|
||||
scopesDump();
|
||||
exportsDump();
|
||||
userDump();
|
||||
}
|
||||
void VerilatedImp::versionDump() VL_MT_SAFE {
|
||||
VL_PRINTF_MT(" Version: %s %s\n",
|
||||
Verilated::productName(), Verilated::productVersion());
|
||||
}
|
||||
|
||||
void VerilatedImp::commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
|
||||
VerilatedLockGuard lock(s_s.m_argMutex);
|
||||
s_s.m_argVec.clear(); // Always clear
|
||||
commandArgsAddGuts(argc, argv);
|
||||
}
|
||||
void VerilatedImp::commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
|
||||
VerilatedLockGuard lock(s_s.m_argMutex);
|
||||
commandArgsAddGuts(argc, argv);
|
||||
}
|
||||
void VerilatedImp::commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex) {
|
||||
if (!s_s.m_argVecLoaded) s_s.m_argVec.clear();
|
||||
for (int i=0; i<argc; ++i) {
|
||||
s_s.m_argVec.push_back(argv[i]);
|
||||
}
|
||||
s_s.m_argVecLoaded = true; // Can't just test later for empty vector, no arguments is ok
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// VerilatedSyms:: Methods
|
||||
|
||||
@@ -1743,7 +1923,9 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
|
||||
} else {
|
||||
// We could have a linked list of ranges, but really this whole thing needs
|
||||
// to be generalized to support structs and unions, etc.
|
||||
VL_FATAL_MT(__FILE__,__LINE__,"",(std::string("Unsupported multi-dimensional public varInsert: ")+namep).c_str());
|
||||
VL_FATAL_MT(__FILE__,__LINE__,"",
|
||||
(std::string("Unsupported multi-dimensional public varInsert: ")
|
||||
+ namep).c_str());
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
@@ -1800,7 +1982,7 @@ void VerilatedScope::scopeDump() const {
|
||||
//===========================================================================
|
||||
// VerilatedOneThreaded:: Methods
|
||||
|
||||
#ifdef VL_THREADED
|
||||
#if defined(VL_THREADED) && defined(VL_DEBUG)
|
||||
void VerilatedAssertOneThread::fatal_different() VL_MT_SAFE {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", "Routine called that is single threaded, but called from"
|
||||
" a different thread then the expected constructing thread");
|
||||
|
||||
+189
-97
@@ -111,6 +111,8 @@ extern vluint32_t VL_THREAD_ID() VL_MT_SAFE;
|
||||
|
||||
#if VL_THREADED
|
||||
|
||||
#define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before relaxing
|
||||
|
||||
/// Mutex, wrapped to allow -fthread_safety checks
|
||||
class VL_CAPABILITY("mutex") VerilatedMutex {
|
||||
private:
|
||||
@@ -119,9 +121,19 @@ class VL_CAPABILITY("mutex") VerilatedMutex {
|
||||
VerilatedMutex() {}
|
||||
~VerilatedMutex() {}
|
||||
/// Acquire/lock mutex
|
||||
void lock() VL_ACQUIRE() { m_mutex.lock(); }
|
||||
void lock() VL_ACQUIRE() {
|
||||
// Try to acquire the lock by spinning. If the wait is short,
|
||||
// avoids a trap to the OS plus OS scheduler overhead.
|
||||
if (VL_LIKELY(try_lock())) return; // Short circuit loop
|
||||
for (int i = 0; i < VL_LOCK_SPINS; ++i) {
|
||||
if (VL_LIKELY(try_lock())) return;
|
||||
VL_CPU_RELAX();
|
||||
}
|
||||
// Spinning hasn't worked, pay the cost of blocking.
|
||||
m_mutex.lock();
|
||||
}
|
||||
/// Release/unlock mutex
|
||||
void unlock() VL_RELEASE() { m_mutex.unlock(); }
|
||||
void unlock() VL_RELEASE() { m_mutex.unlock(); }
|
||||
/// Try to acquire mutex. Returns true on success, and false on failure.
|
||||
bool try_lock() VL_TRY_ACQUIRE(true) { return m_mutex.try_lock(); }
|
||||
};
|
||||
@@ -143,14 +155,21 @@ class VL_SCOPED_CAPABILITY VerilatedLockGuard {
|
||||
|
||||
#else // !VL_THREADED
|
||||
|
||||
// Empty classes to avoid #ifdefs everywhere
|
||||
class VerilatedMutex {};
|
||||
/// Empty non-threaded mutex to avoid #ifdefs in consuming code
|
||||
class VerilatedMutex {
|
||||
public:
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
};
|
||||
|
||||
/// Empty non-threaded lock guard to avoid #ifdefs in consuming code
|
||||
class VerilatedLockGuard {
|
||||
VL_UNCOPYABLE(VerilatedLockGuard);
|
||||
public:
|
||||
explicit VerilatedLockGuard(VerilatedMutex&) {}
|
||||
~VerilatedLockGuard() {}
|
||||
};
|
||||
|
||||
#endif // VL_THREADED
|
||||
|
||||
/// Remember the calling thread at construction time, and make sure later calls use same thread
|
||||
@@ -167,9 +186,7 @@ public:
|
||||
// METHODS
|
||||
/// Check that the current thread ID is the same as the construction thread ID
|
||||
void check() VL_MT_UNSAFE_ONE {
|
||||
// Memoize results in local thread, to prevent slow get_id() call
|
||||
VL_THREAD_LOCAL bool t_okThread = (m_threadid == VL_THREAD_ID());
|
||||
if (!VL_LIKELY(t_okThread)) {
|
||||
if (!VL_LIKELY(m_threadid == VL_THREAD_ID())) {
|
||||
fatal_different();
|
||||
}
|
||||
}
|
||||
@@ -315,15 +332,16 @@ class Verilated {
|
||||
static VerilatedVoidCb s_flushCb; ///< Flush callback function
|
||||
|
||||
static struct Serialized { // All these members serialized/deserialized
|
||||
// Slow path
|
||||
int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
|
||||
// Fast path
|
||||
int s_debug; ///< See accessors... only when VL_DEBUG set
|
||||
bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
|
||||
bool s_gotFinish; ///< A $finish statement executed
|
||||
bool s_assertOn; ///< Assertions are enabled
|
||||
bool s_fatalOnVpiError; ///< Stop on vpi error/unsupported
|
||||
Serialized();
|
||||
// Slow path
|
||||
int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
|
||||
Serialized();
|
||||
~Serialized() {}
|
||||
} s_s;
|
||||
|
||||
// no need to be save-restored (serialized) the
|
||||
@@ -331,12 +349,14 @@ class Verilated {
|
||||
static struct CommandArgValues {
|
||||
int argc;
|
||||
const char** argv;
|
||||
CommandArgValues() : argc(0), argv(NULL) {}
|
||||
~CommandArgValues() {}
|
||||
} s_args;
|
||||
|
||||
// Not covered by mutex, as per-thread
|
||||
static VL_THREAD_LOCAL struct ThreadLocal {
|
||||
#ifdef VL_THREADED
|
||||
vluint32_t t_trainId; ///< Current train# executing on this thread
|
||||
vluint32_t t_mtaskId; ///< Current mtask# executing on this thread
|
||||
vluint32_t t_endOfEvalReqd; ///< Messages may be pending, thread needs endOf-eval calls
|
||||
#endif
|
||||
const VerilatedScope* t_dpiScopep; ///< DPI context scope
|
||||
@@ -373,7 +393,8 @@ public:
|
||||
#endif
|
||||
/// Enable calculation of unused signals
|
||||
static void calcUnusedSigs(bool flag) VL_MT_SAFE;
|
||||
static bool calcUnusedSigs() VL_MT_SAFE { return s_s.s_calcUnusedSigs; } ///< Return calcUnusedSigs value
|
||||
static bool calcUnusedSigs() VL_MT_SAFE { ///< Return calcUnusedSigs value
|
||||
return s_s.s_calcUnusedSigs; }
|
||||
/// Did the simulation $finish?
|
||||
static void gotFinish(bool flag) VL_MT_SAFE;
|
||||
static bool gotFinish() VL_MT_SAFE { return s_s.s_gotFinish; } ///< Return if got a $finish
|
||||
@@ -393,7 +414,8 @@ public:
|
||||
|
||||
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs
|
||||
static void commandArgs(int argc, const char** argv) VL_MT_SAFE;
|
||||
static void commandArgs(int argc, char** argv) VL_MT_SAFE { commandArgs(argc, const_cast<const char**>(argv)); }
|
||||
static void commandArgs(int argc, char** argv) VL_MT_SAFE {
|
||||
commandArgs(argc, const_cast<const char**>(argv)); }
|
||||
static void commandArgsAdd(int argc, const char** argv);
|
||||
static CommandArgValues* getCommandArgs() VL_MT_SAFE { return &s_args; }
|
||||
/// Match plusargs with a given prefix. Returns static char* valid only for a single call
|
||||
@@ -417,17 +439,6 @@ public:
|
||||
/// releases - contact the authors before production use.
|
||||
static void scopesDump() VL_MT_SAFE;
|
||||
|
||||
/// Set the number of threads to execute on.
|
||||
/// 0x0 = use all available CPU threads, or 1 if no support compiled in
|
||||
/// Ignored after spawnThreads() has been called
|
||||
static void numThreads(unsigned threads) VL_MT_SAFE;
|
||||
static unsigned numThreads() VL_MT_SAFE;
|
||||
/// Spawn child threads, using numThreads() as # of threads
|
||||
/// Verilator calls this automatically on the first eval() call
|
||||
/// User code may call it earlier if desired
|
||||
/// Once called the first time, later calls are ignored
|
||||
static void spawnThreads() VL_MT_SAFE;
|
||||
|
||||
public:
|
||||
// METHODS - INTERNAL USE ONLY (but public due to what uses it)
|
||||
// Internal: Create a new module name by concatenating two strings
|
||||
@@ -454,22 +465,29 @@ public:
|
||||
static size_t serializedSize() VL_PURE { return sizeof(s_s); }
|
||||
static void* serializedPtr() VL_MT_UNSAFE { return &s_s; } // Unsafe, for Serialize only
|
||||
#ifdef VL_THREADED
|
||||
/// Set the trainId, called when a train starts
|
||||
static void trainId(vluint32_t id) VL_MT_SAFE { t_s.t_trainId = id; }
|
||||
static vluint32_t trainId() VL_MT_SAFE { return t_s.t_trainId; }
|
||||
/// Set the mtaskId, called when an mtask starts
|
||||
static void mtaskId(vluint32_t id) VL_MT_SAFE { t_s.t_mtaskId = id; }
|
||||
static vluint32_t mtaskId() VL_MT_SAFE { return t_s.t_mtaskId; }
|
||||
static void endOfEvalReqdInc() VL_MT_SAFE { ++t_s.t_endOfEvalReqd; }
|
||||
static void endOfEvalReqdDec() VL_MT_SAFE { --t_s.t_endOfEvalReqd; }
|
||||
/// Called at end of each thread train, before finishing eval
|
||||
static void endOfThreadTrain(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(t_s.t_endOfEvalReqd)) { endOfThreadTrainGuts(evalMsgQp); } }
|
||||
|
||||
/// Called at end of each thread mtask, before finishing eval
|
||||
static void endOfThreadMTask(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(t_s.t_endOfEvalReqd)) { endOfThreadMTaskGuts(evalMsgQp); }
|
||||
}
|
||||
/// Called at end of eval loop
|
||||
static void endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(t_s.t_endOfEvalReqd)) { endOfEvalGuts(evalMsgQp); } }
|
||||
// It doesn't work to set endOfEvalReqd on the threadpool thread
|
||||
// and then check it on the eval thread since it's thread local.
|
||||
// It should be ok to call into endOfEvalGuts, it returns immediately
|
||||
// if there are no transactions.
|
||||
endOfEvalGuts(evalMsgQp);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef VL_THREADED
|
||||
static void endOfThreadTrainGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE;
|
||||
static void endOfThreadMTaskGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE;
|
||||
static void endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE;
|
||||
#endif
|
||||
};
|
||||
@@ -526,6 +544,11 @@ extern QData VL_RAND_RESET_Q(int obits); ///< Random reset a signal
|
||||
extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp); ///< Random reset a signal
|
||||
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp); ///< Zero reset a signal (slow - else use VL_ZERO_W)
|
||||
|
||||
#if VL_THREADED
|
||||
/// Return high-precision counter for profiling, or 0x0 if not available
|
||||
inline QData VL_RDTSC_Q() { vluint64_t val; VL_RDTSC(val); return val; }
|
||||
#endif
|
||||
|
||||
/// Math
|
||||
extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus);
|
||||
|
||||
@@ -535,8 +558,8 @@ extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi);
|
||||
extern IData VL_FOPEN_S(const char* filenamep, const char* mode);
|
||||
extern IData VL_FOPEN_WI(int fnwords, WDataInP ofilename, IData mode);
|
||||
extern IData VL_FOPEN_QI(QData ofilename, IData mode);
|
||||
inline IData VL_FOPEN_II(IData ofilename, IData mode) VL_MT_SAFE { return VL_FOPEN_QI(ofilename,mode); }
|
||||
|
||||
inline IData VL_FOPEN_II(IData ofilename, IData mode) VL_MT_SAFE {
|
||||
return VL_FOPEN_QI(ofilename,mode); }
|
||||
|
||||
extern void VL_FCLOSE_I(IData fdi);
|
||||
|
||||
@@ -548,6 +571,14 @@ inline void VL_READMEM_I(bool hex, int width, int depth, int array_lsb, int fnwo
|
||||
IData ofilename, void* memp, IData start, IData end) VL_MT_SAFE {
|
||||
VL_READMEM_Q(hex, width,depth,array_lsb,fnwords, ofilename,memp,start,end); }
|
||||
|
||||
extern void VL_WRITEMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
WDataInP ofilename, const void* memp, IData start, IData end);
|
||||
extern void VL_WRITEMEM_Q(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
QData ofilename, const void* memp, IData start, IData end);
|
||||
inline void VL_WRITEMEM_I(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
IData ofilename, const void* memp, IData start, IData end) VL_MT_SAFE {
|
||||
VL_WRITEMEM_Q(hex, width,depth,array_lsb,fnwords, ofilename,memp,start,end); }
|
||||
|
||||
extern void VL_WRITEF(const char* formatp, ...);
|
||||
extern void VL_FWRITEF(IData fpi, const char* formatp, ...);
|
||||
|
||||
@@ -576,16 +607,20 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
|
||||
#define VL_BITISSET_I(data,bit) (data & (VL_UL(1)<<VL_BITBIT_I(bit)))
|
||||
#define VL_BITISSET_Q(data,bit) (data & (VL_ULL(1)<<VL_BITBIT_Q(bit)))
|
||||
#define VL_BITISSET_W(data,bit) (data[VL_BITWORD_I(bit)] & (VL_UL(1)<<VL_BITBIT_I(bit)))
|
||||
#define VL_BITISSETLIMIT_W(data,width,bit) (((bit)<(width)) && data[VL_BITWORD_I(bit)] & (VL_UL(1)<<VL_BITBIT_I(bit)))
|
||||
#define VL_BITISSETLIMIT_W(data,width,bit) \
|
||||
(((bit)<(width)) && data[VL_BITWORD_I(bit)] & (VL_UL(1)<<VL_BITBIT_I(bit)))
|
||||
|
||||
/// Shift appropriate word by bit. Does not account for wrapping between two words
|
||||
#define VL_BITRSHIFT_W(data,bit) (data[VL_BITWORD_I(bit)] >> VL_BITBIT_I(bit))
|
||||
|
||||
/// Create two 32-bit words from quadword
|
||||
/// WData is always at least 2 words; does not clean upper bits
|
||||
#define VL_SET_WQ(owp,data) { owp[0]=static_cast<IData>(data); owp[1]=static_cast<IData>((data)>>VL_WORDSIZE); }
|
||||
#define VL_SET_WQ(owp,data) { owp[0]=static_cast<IData>(data); \
|
||||
owp[1]=static_cast<IData>((data)>>VL_WORDSIZE); }
|
||||
#define VL_SET_WI(owp,data) { owp[0]=static_cast<IData>(data); owp[1]=0; }
|
||||
#define VL_SET_QW(lwp) ( (static_cast<QData>(lwp[0])) | (static_cast<QData>(lwp[1])<<(static_cast<QData>(VL_WORDSIZE)) ))
|
||||
#define VL_SET_QW(lwp) \
|
||||
( (static_cast<QData>(lwp[0])) \
|
||||
| (static_cast<QData>(lwp[1])<<(static_cast<QData>(VL_WORDSIZE)) ))
|
||||
#define _VL_SET_QII(ld,rd) ( (static_cast<QData>(ld)<<VL_ULL(32)) | static_cast<QData>(rd) )
|
||||
|
||||
/// Return FILE* from IData
|
||||
@@ -593,19 +628,26 @@ extern FILE* VL_CVT_I_FP(IData lhs);
|
||||
|
||||
// Use a union to avoid cast-to-different-size warnings
|
||||
/// Return void* from QData
|
||||
static inline void* VL_CVT_Q_VP(QData lhs) VL_PURE { union { void* fp; QData q; } u; u.q=lhs; return u.fp; }
|
||||
static inline void* VL_CVT_Q_VP(QData lhs) VL_PURE {
|
||||
union { void* fp; QData q; } u; u.q=lhs; return u.fp; }
|
||||
/// Return QData from void*
|
||||
static inline QData VL_CVT_VP_Q(void* fp) VL_PURE { union { void* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; }
|
||||
static inline QData VL_CVT_VP_Q(void* fp) VL_PURE {
|
||||
union { void* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; }
|
||||
/// Return double from QData (bits, not numerically)
|
||||
static inline double VL_CVT_D_Q(QData lhs) VL_PURE { union { double d; QData q; } u; u.q=lhs; return u.d; }
|
||||
static inline double VL_CVT_D_Q(QData lhs) VL_PURE {
|
||||
union { double d; QData q; } u; u.q=lhs; return u.d; }
|
||||
/// Return QData from double (bits, not numerically)
|
||||
static inline QData VL_CVT_Q_D(double lhs) VL_PURE { union { double d; QData q; } u; u.d=lhs; return u.q; }
|
||||
static inline QData VL_CVT_Q_D(double lhs) VL_PURE {
|
||||
union { double d; QData q; } u; u.d=lhs; return u.q; }
|
||||
/// Return double from QData (numeric)
|
||||
static inline double VL_ITOR_D_I(IData lhs) VL_PURE { return static_cast<double>(static_cast<vlsint32_t>(lhs)); }
|
||||
static inline double VL_ITOR_D_I(IData lhs) VL_PURE {
|
||||
return static_cast<double>(static_cast<vlsint32_t>(lhs)); }
|
||||
/// Return QData from double (numeric)
|
||||
static inline IData VL_RTOI_I_D(double lhs) VL_PURE { return static_cast<vlsint32_t>(VL_TRUNC(lhs)); }
|
||||
static inline IData VL_RTOI_I_D(double lhs) VL_PURE {
|
||||
return static_cast<vlsint32_t>(VL_TRUNC(lhs)); }
|
||||
/// Return QData from double (numeric)
|
||||
static inline IData VL_RTOIROUND_I_D(double lhs) VL_PURE { return static_cast<vlsint32_t>(VL_ROUND(lhs)); }
|
||||
static inline IData VL_RTOIROUND_I_D(double lhs) VL_PURE {
|
||||
return static_cast<vlsint32_t>(VL_ROUND(lhs)); }
|
||||
|
||||
// Sign extend such that if MSB set, we get ffff_ffff, else 0s
|
||||
// (Requires clean input)
|
||||
@@ -616,8 +658,10 @@ static inline IData VL_RTOIROUND_I_D(double lhs) VL_PURE { return static_cast<v
|
||||
|
||||
// Sign bit extended up to MSB, doesn't include unsigned portion
|
||||
// Optimization bug in GCC 3.3 returns different bitmasks to later states for
|
||||
static inline IData VL_EXTENDSIGN_I(int lbits, IData lhs) VL_PURE { return (-((lhs)&(VL_UL(1)<<(lbits-1)))); }
|
||||
static inline QData VL_EXTENDSIGN_Q(int lbits, QData lhs) VL_PURE { return (-((lhs)&(VL_ULL(1)<<(lbits-1)))); }
|
||||
static inline IData VL_EXTENDSIGN_I(int lbits, IData lhs) VL_PURE {
|
||||
return (-((lhs)&(VL_UL(1)<<(lbits-1)))); }
|
||||
static inline QData VL_EXTENDSIGN_Q(int lbits, QData lhs) VL_PURE {
|
||||
return (-((lhs)&(VL_ULL(1)<<(lbits-1)))); }
|
||||
|
||||
// Debugging prints
|
||||
extern void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp);
|
||||
@@ -1400,13 +1444,19 @@ WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDa
|
||||
WDataOutP VL_POW_WWQ(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, QData rhs);
|
||||
QData VL_POW_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp);
|
||||
|
||||
#define VL_POWSS_IIQ(obits,lbits,rbits,lhs,rhs,lsign,rsign) VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign)
|
||||
#define VL_POWSS_IIQ(obits,lbits,rbits,lhs,rhs,lsign,rsign) VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign)
|
||||
#define VL_POWSS_IIW(obits,lbits,rbits,lhs,rwp,lsign,rsign) VL_POWSS_QQW(obits,lbits,rbits,lhs,rwp,lsign,rsign)
|
||||
#define VL_POWSS_QQI(obits,lbits,rbits,lhs,rhs,lsign,rsign) VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign)
|
||||
#define VL_POWSS_WWI(obits,lbits,rbits,owp,lwp,rhs,lsign,rsign) VL_POWSS_WWQ(obits,lbits,rbits,owp,lwp,rhs,lsign,rsign)
|
||||
#define VL_POWSS_IIQ(obits,lbits,rbits,lhs,rhs,lsign,rsign) \
|
||||
VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign)
|
||||
#define VL_POWSS_IIQ(obits,lbits,rbits,lhs,rhs,lsign,rsign) \
|
||||
VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign)
|
||||
#define VL_POWSS_IIW(obits,lbits,rbits,lhs,rwp,lsign,rsign) \
|
||||
VL_POWSS_QQW(obits,lbits,rbits,lhs,rwp,lsign,rsign)
|
||||
#define VL_POWSS_QQI(obits,lbits,rbits,lhs,rhs,lsign,rsign) \
|
||||
VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign)
|
||||
#define VL_POWSS_WWI(obits,lbits,rbits,owp,lwp,rhs,lsign,rsign) \
|
||||
VL_POWSS_WWQ(obits,lbits,rbits,owp,lwp,rhs,lsign,rsign)
|
||||
|
||||
static inline IData VL_POWSS_III(int obits, int, int rbits, IData lhs, IData rhs, bool lsign, bool rsign) VL_MT_SAFE {
|
||||
static inline IData VL_POWSS_III(int obits, int, int rbits,
|
||||
IData lhs, IData rhs, bool lsign, bool rsign) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(rhs==0)) return 1;
|
||||
if (rsign && VL_SIGN_I(rbits, rhs)) {
|
||||
if (lhs==0) return 0; // "X"
|
||||
@@ -1419,7 +1469,8 @@ static inline IData VL_POWSS_III(int obits, int, int rbits, IData lhs, IData rhs
|
||||
}
|
||||
return VL_POW_III(obits, rbits, rbits, lhs, rhs);
|
||||
}
|
||||
static inline QData VL_POWSS_QQQ(int obits, int, int rbits, QData lhs, QData rhs, bool lsign, bool rsign) VL_MT_SAFE {
|
||||
static inline QData VL_POWSS_QQQ(int obits, int, int rbits,
|
||||
QData lhs, QData rhs, bool lsign, bool rsign) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(rhs==0)) return 1;
|
||||
if (rsign && VL_SIGN_I(rbits, rhs)) {
|
||||
if (lhs==0) return 0; // "X"
|
||||
@@ -1432,9 +1483,12 @@ static inline QData VL_POWSS_QQQ(int obits, int, int rbits, QData lhs, QData rhs
|
||||
}
|
||||
return VL_POW_QQQ(obits, rbits, rbits, lhs, rhs);
|
||||
}
|
||||
WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool lsign, bool rsign);
|
||||
WDataOutP VL_POWSS_WWQ(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, QData rhs, bool lsign, bool rsign);
|
||||
QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp, bool lsign, bool rsign);
|
||||
WDataOutP VL_POWSS_WWW(int obits, int, int rbits,
|
||||
WDataOutP owp, WDataInP lwp, WDataInP rwp, bool lsign, bool rsign);
|
||||
WDataOutP VL_POWSS_WWQ(int obits, int, int rbits,
|
||||
WDataOutP owp, WDataInP lwp, QData rhs, bool lsign, bool rsign);
|
||||
QData VL_POWSS_QQW(int obits, int, int rbits,
|
||||
QData lhs, WDataInP rwp, bool lsign, bool rsign);
|
||||
|
||||
//===================================================================
|
||||
// Concat/replication
|
||||
@@ -1554,21 +1608,24 @@ static inline QData VL_REPLICATE_QII(int, int lbits, int, IData ld, IData rep) V
|
||||
}
|
||||
return (returndata);
|
||||
}
|
||||
static inline WDataOutP VL_REPLICATE_WII(int obits, int lbits, int, WDataOutP owp, IData ld, IData rep) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_REPLICATE_WII(int obits, int lbits, int,
|
||||
WDataOutP owp, IData ld, IData rep) VL_MT_SAFE {
|
||||
owp[0] = ld;
|
||||
for (unsigned i=1; i < rep; ++i){
|
||||
_VL_INSERT_WI(obits,owp,ld,i*lbits+lbits-1,i*lbits);
|
||||
}
|
||||
return(owp);
|
||||
}
|
||||
static inline WDataOutP VL_REPLICATE_WQI(int obits, int lbits, int, WDataOutP owp, QData ld, IData rep) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_REPLICATE_WQI(int obits, int lbits, int,
|
||||
WDataOutP owp, QData ld, IData rep) VL_MT_SAFE {
|
||||
VL_SET_WQ(owp,ld);
|
||||
for (unsigned i=1; i < rep; ++i){
|
||||
_VL_INSERT_WQ(obits,owp,ld,i*lbits+lbits-1,i*lbits);
|
||||
}
|
||||
return(owp);
|
||||
}
|
||||
static inline WDataOutP VL_REPLICATE_WWI(int obits, int lbits, int, WDataOutP owp, WDataInP lwp, IData rep) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_REPLICATE_WWI(int obits, int lbits, int,
|
||||
WDataOutP owp, WDataInP lwp, IData rep) VL_MT_SAFE {
|
||||
for (int i=0; i < VL_WORDS_I(lbits); ++i) owp[i] = lwp[i];
|
||||
for (unsigned i=1; i < rep; ++i){
|
||||
_VL_INSERT_WW(obits,owp,lwp,i*lbits+lbits-1,i*lbits);
|
||||
@@ -1633,15 +1690,20 @@ static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_
|
||||
}
|
||||
switch (rd_log2) {
|
||||
case 0:
|
||||
ret = ((ret >> 1) & VL_ULL(0x5555555555555555)) | ((ret & VL_ULL(0x5555555555555555)) << 1); // FALLTHRU
|
||||
ret = (((ret >> 1) & VL_ULL(0x5555555555555555))
|
||||
| ((ret & VL_ULL(0x5555555555555555)) << 1)); // FALLTHRU
|
||||
case 1:
|
||||
ret = ((ret >> 2) & VL_ULL(0x3333333333333333)) | ((ret & VL_ULL(0x3333333333333333)) << 2); // FALLTHRU
|
||||
ret = (((ret >> 2) & VL_ULL(0x3333333333333333))
|
||||
| ((ret & VL_ULL(0x3333333333333333)) << 2)); // FALLTHRU
|
||||
case 2:
|
||||
ret = ((ret >> 4) & VL_ULL(0x0f0f0f0f0f0f0f0f)) | ((ret & VL_ULL(0x0f0f0f0f0f0f0f0f)) << 4); // FALLTHRU
|
||||
ret = (((ret >> 4) & VL_ULL(0x0f0f0f0f0f0f0f0f))
|
||||
| ((ret & VL_ULL(0x0f0f0f0f0f0f0f0f)) << 4)); // FALLTHRU
|
||||
case 3:
|
||||
ret = ((ret >> 8) & VL_ULL(0x00ff00ff00ff00ff)) | ((ret & VL_ULL(0x00ff00ff00ff00ff)) << 8); // FALLTHRU
|
||||
ret = (((ret >> 8) & VL_ULL(0x00ff00ff00ff00ff))
|
||||
| ((ret & VL_ULL(0x00ff00ff00ff00ff)) << 8)); // FALLTHRU
|
||||
case 4:
|
||||
ret = ((ret >> 16) & VL_ULL(0x0000ffff0000ffff)) | ((ret & VL_ULL(0x0000ffff0000ffff)) << 16); // FALLTHRU
|
||||
ret = (((ret >> 16) & VL_ULL(0x0000ffff0000ffff))
|
||||
| ((ret & VL_ULL(0x0000ffff0000ffff)) << 16)); // FALLTHRU
|
||||
case 5:
|
||||
ret = ((ret >> 32) | (ret << 32));
|
||||
}
|
||||
@@ -1694,61 +1756,75 @@ static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WData
|
||||
// Thus we specify inputs must be clean, so we don't need to clean the output.
|
||||
// Note the bit shifts are always constants, so the adds in these constify out.
|
||||
// Casts required, as args may be 8 bit entities, and need to shift to appropriate output size
|
||||
#define VL_CONCAT_III(obits,lbits,rbits,ld,rd) (static_cast<IData>(ld)<<(rbits) | static_cast<IData>(rd))
|
||||
#define VL_CONCAT_QII(obits,lbits,rbits,ld,rd) (static_cast<QData>(ld)<<(rbits) | static_cast<QData>(rd))
|
||||
#define VL_CONCAT_QIQ(obits,lbits,rbits,ld,rd) (static_cast<QData>(ld)<<(rbits) | static_cast<QData>(rd))
|
||||
#define VL_CONCAT_QQI(obits,lbits,rbits,ld,rd) (static_cast<QData>(ld)<<(rbits) | static_cast<QData>(rd))
|
||||
#define VL_CONCAT_QQQ(obits,lbits,rbits,ld,rd) (static_cast<QData>(ld)<<(rbits) | static_cast<QData>(rd))
|
||||
#define VL_CONCAT_III(obits,lbits,rbits,ld,rd) \
|
||||
(static_cast<IData>(ld)<<(rbits) | static_cast<IData>(rd))
|
||||
#define VL_CONCAT_QII(obits,lbits,rbits,ld,rd) \
|
||||
(static_cast<QData>(ld)<<(rbits) | static_cast<QData>(rd))
|
||||
#define VL_CONCAT_QIQ(obits,lbits,rbits,ld,rd) \
|
||||
(static_cast<QData>(ld)<<(rbits) | static_cast<QData>(rd))
|
||||
#define VL_CONCAT_QQI(obits,lbits,rbits,ld,rd) \
|
||||
(static_cast<QData>(ld)<<(rbits) | static_cast<QData>(rd))
|
||||
#define VL_CONCAT_QQQ(obits,lbits,rbits,ld,rd) \
|
||||
(static_cast<QData>(ld)<<(rbits) | static_cast<QData>(rd))
|
||||
|
||||
static inline WDataOutP VL_CONCAT_WII(int obits,int lbits,int rbits,WDataOutP owp,IData ld,IData rd) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_CONCAT_WII(int obits, int lbits, int rbits,
|
||||
WDataOutP owp, IData ld,IData rd) VL_MT_SAFE {
|
||||
owp[0] = rd;
|
||||
for (int i=1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_VL_INSERT_WI(obits,owp,ld,rbits+lbits-1,rbits);
|
||||
return(owp);
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WWI(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, IData rd) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_CONCAT_WWI(int obits, int lbits, int rbits,
|
||||
WDataOutP owp, WDataInP lwp, IData rd) VL_MT_SAFE {
|
||||
owp[0] = rd;
|
||||
for (int i=1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_VL_INSERT_WW(obits,owp,lwp,rbits+lbits-1,rbits);
|
||||
return(owp);
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WIW(int obits,int lbits,int rbits,WDataOutP owp,IData ld, WDataInP rwp) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_CONCAT_WIW(int obits, int lbits, int rbits,
|
||||
WDataOutP owp, IData ld, WDataInP rwp) VL_MT_SAFE {
|
||||
for (int i=0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
|
||||
for (int i=VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_VL_INSERT_WI(obits,owp,ld,rbits+lbits-1,rbits);
|
||||
return(owp);
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WIQ(int obits,int lbits,int rbits,WDataOutP owp,IData ld,QData rd) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_CONCAT_WIQ(int obits, int lbits, int rbits,
|
||||
WDataOutP owp, IData ld, QData rd) VL_MT_SAFE {
|
||||
VL_SET_WQ(owp,rd);
|
||||
for (int i=2; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_VL_INSERT_WI(obits,owp,ld,rbits+lbits-1,rbits);
|
||||
return(owp);
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WQI(int obits,int lbits,int rbits,WDataOutP owp,QData ld,IData rd) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_CONCAT_WQI(int obits, int lbits, int rbits,
|
||||
WDataOutP owp, QData ld, IData rd) VL_MT_SAFE {
|
||||
owp[0] = rd;
|
||||
for (int i=1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_VL_INSERT_WQ(obits,owp,ld,rbits+lbits-1,rbits);
|
||||
return(owp);
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WQQ(int obits,int lbits,int rbits,WDataOutP owp,QData ld,QData rd) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_CONCAT_WQQ(int obits, int lbits, int rbits,
|
||||
WDataOutP owp, QData ld, QData rd) VL_MT_SAFE {
|
||||
VL_SET_WQ(owp,rd);
|
||||
for (int i=2; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_VL_INSERT_WQ(obits,owp,ld,rbits+lbits-1,rbits);
|
||||
return(owp);
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WWQ(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, QData rd) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_CONCAT_WWQ(int obits, int lbits, int rbits,
|
||||
WDataOutP owp, WDataInP lwp, QData rd) VL_MT_SAFE {
|
||||
VL_SET_WQ(owp,rd);
|
||||
for (int i=2; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_VL_INSERT_WW(obits,owp,lwp,rbits+lbits-1,rbits);
|
||||
return(owp);
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WQW(int obits,int lbits,int rbits,WDataOutP owp,QData ld, WDataInP rwp) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_CONCAT_WQW(int obits, int lbits, int rbits,
|
||||
WDataOutP owp, QData ld, WDataInP rwp) VL_MT_SAFE {
|
||||
for (int i=0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
|
||||
for (int i=VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_VL_INSERT_WQ(obits,owp,ld,rbits+lbits-1,rbits);
|
||||
return(owp);
|
||||
}
|
||||
static inline WDataOutP VL_CONCAT_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_CONCAT_WWW(int obits, int lbits, int rbits,
|
||||
WDataOutP owp, WDataInP lwp, WDataInP rwp) VL_MT_SAFE {
|
||||
for (int i=0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
|
||||
for (int i=VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
|
||||
_VL_INSERT_WW(obits,owp,lwp,rbits+lbits-1,rbits);
|
||||
@@ -1787,7 +1863,8 @@ static inline WDataOutP VL_SHIFTL_WWI(int obits,int,int,WDataOutP owp,WDataInP l
|
||||
}
|
||||
return(owp);
|
||||
}
|
||||
static inline WDataOutP VL_SHIFTL_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_SHIFTL_WWW(int obits, int lbits, int rbits,
|
||||
WDataOutP owp, WDataInP lwp, WDataInP rwp) VL_MT_SAFE {
|
||||
for (int i=1; i < VL_WORDS_I(rbits); ++i) {
|
||||
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
|
||||
return VL_ZERO_W(obits, owp);
|
||||
@@ -1807,7 +1884,8 @@ static inline IData VL_SHIFTL_IIW(int obits,int,int rbits,IData lhs, WDataInP rw
|
||||
// EMIT_RULE: VL_SHIFTR: oclean=lclean; rclean==clean;
|
||||
// Important: Unlike most other funcs, the shift might well be a computed
|
||||
// expression. Thus consider this when optimizing. (And perhaps have 2 funcs?)
|
||||
static inline WDataOutP VL_SHIFTR_WWI(int obits,int,int,WDataOutP owp,WDataInP lwp, IData rd) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_SHIFTR_WWI(int obits, int, int,
|
||||
WDataOutP owp,WDataInP lwp, IData rd) VL_MT_SAFE {
|
||||
int word_shift = VL_BITWORD_I(rd); // Maybe 0
|
||||
int bit_shift = VL_BITBIT_I(rd);
|
||||
if (rd >= static_cast<IData>(obits)) { // rd may be huge with MSB set
|
||||
@@ -1832,7 +1910,8 @@ static inline WDataOutP VL_SHIFTR_WWI(int obits,int,int,WDataOutP owp,WDataInP l
|
||||
}
|
||||
return(owp);
|
||||
}
|
||||
static inline WDataOutP VL_SHIFTR_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_SHIFTR_WWW(int obits, int lbits, int rbits,
|
||||
WDataOutP owp, WDataInP lwp, WDataInP rwp) VL_MT_SAFE {
|
||||
for (int i=1; i < VL_WORDS_I(rbits); ++i) {
|
||||
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
|
||||
return VL_ZERO_W(obits, owp);
|
||||
@@ -1864,10 +1943,12 @@ static inline QData VL_SHIFTRS_QQI(int obits, int lbits, int, QData lhs, IData r
|
||||
QData signext = ~(VL_MASK_Q(lbits) >> rhs);
|
||||
return (lhs >> rhs) | (sign & VL_CLEAN_QQ(obits,obits,signext));
|
||||
}
|
||||
static inline IData VL_SHIFTRS_IQI(int obits, int lbits, int rbits, QData lhs, IData rhs) VL_PURE {
|
||||
static inline IData VL_SHIFTRS_IQI(int obits, int lbits, int rbits,
|
||||
QData lhs, IData rhs) VL_PURE {
|
||||
return static_cast<IData>(VL_SHIFTRS_QQI(obits, lbits, rbits, lhs, rhs));
|
||||
}
|
||||
static inline WDataOutP VL_SHIFTRS_WWI(int obits,int lbits,int,WDataOutP owp,WDataInP lwp, IData rd) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_SHIFTRS_WWI(int obits, int lbits, int,
|
||||
WDataOutP owp, WDataInP lwp, IData rd) VL_MT_SAFE {
|
||||
int word_shift = VL_BITWORD_I(rd);
|
||||
int bit_shift = VL_BITBIT_I(rd);
|
||||
int lmsw = VL_WORDS_I(obits)-1;
|
||||
@@ -1899,7 +1980,8 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits,int lbits,int,WDataOutP owp,WDa
|
||||
}
|
||||
return(owp);
|
||||
}
|
||||
static inline WDataOutP VL_SHIFTRS_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_SHIFTRS_WWW(int obits, int lbits, int rbits,
|
||||
WDataOutP owp, WDataInP lwp, WDataInP rwp) VL_MT_SAFE {
|
||||
for (int i=1; i < VL_WORDS_I(rbits); ++i) {
|
||||
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
|
||||
int lmsw = VL_WORDS_I(obits)-1;
|
||||
@@ -1911,7 +1993,8 @@ static inline WDataOutP VL_SHIFTRS_WWW(int obits,int lbits,int rbits,WDataOutP o
|
||||
}
|
||||
return VL_SHIFTRS_WWI(obits,lbits,32,owp,lwp,rwp[0]);
|
||||
}
|
||||
static inline IData VL_SHIFTRS_IIW(int obits,int lbits,int rbits,IData lhs, WDataInP rwp) VL_MT_SAFE {
|
||||
static inline IData VL_SHIFTRS_IIW(int obits, int lbits, int rbits,
|
||||
IData lhs, WDataInP rwp) VL_MT_SAFE {
|
||||
for (int i=1; i < VL_WORDS_I(rbits); ++i) {
|
||||
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
|
||||
IData sign = -(lhs >> (lbits-1)); // ffff_ffff if negative
|
||||
@@ -1920,7 +2003,8 @@ static inline IData VL_SHIFTRS_IIW(int obits,int lbits,int rbits,IData lhs, WDat
|
||||
}
|
||||
return VL_SHIFTRS_III(obits,lbits,32,lhs,rwp[0]);
|
||||
}
|
||||
static inline QData VL_SHIFTRS_QQW(int obits,int lbits,int rbits,QData lhs, WDataInP rwp) VL_MT_SAFE {
|
||||
static inline QData VL_SHIFTRS_QQW(int obits, int lbits, int rbits,
|
||||
QData lhs, WDataInP rwp) VL_MT_SAFE {
|
||||
for (int i=1; i < VL_WORDS_I(rbits); ++i) {
|
||||
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
|
||||
QData sign = -(lhs >> (lbits-1)); // ffff_ffff if negative
|
||||
@@ -1963,7 +2047,8 @@ static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP lwp, IData
|
||||
#define VL_SEL_QQII(obits,lbits,rbits,tbits,lhs,lsb,width) ((lhs)>>(lsb))
|
||||
#define VL_SEL_IQII(obits,lbits,rbits,tbits,lhs,lsb,width) (static_cast<IData>((lhs)>>(lsb)))
|
||||
|
||||
static inline IData VL_SEL_IWII(int, int lbits, int, int, WDataInP lwp, IData lsb, IData width) VL_MT_SAFE {
|
||||
static inline IData VL_SEL_IWII(int, int lbits, int, int,
|
||||
WDataInP lwp, IData lsb, IData width) VL_MT_SAFE {
|
||||
int msb = lsb+width-1;
|
||||
if (VL_UNLIKELY(msb>lbits)) {
|
||||
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
|
||||
@@ -1977,7 +2062,8 @@ static inline IData VL_SEL_IWII(int, int lbits, int, int, WDataInP lwp, IData ls
|
||||
}
|
||||
}
|
||||
|
||||
static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP lwp, IData lsb, IData width) VL_MT_SAFE {
|
||||
static inline QData VL_SEL_QWII(int, int lbits, int, int,
|
||||
WDataInP lwp, IData lsb, IData width) VL_MT_SAFE {
|
||||
int msb = lsb+width-1;
|
||||
if (VL_UNLIKELY(msb>lbits)) {
|
||||
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
|
||||
@@ -1998,7 +2084,8 @@ static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP lwp, IData ls
|
||||
}
|
||||
}
|
||||
|
||||
static inline WDataOutP VL_SEL_WWII(int obits,int lbits,int,int,WDataOutP owp,WDataInP lwp, IData lsb, IData width) VL_MT_SAFE {
|
||||
static inline WDataOutP VL_SEL_WWII(int obits, int lbits, int, int,
|
||||
WDataOutP owp, WDataInP lwp, IData lsb, IData width) VL_MT_SAFE {
|
||||
int msb = lsb+width-1;
|
||||
int word_shift = VL_BITWORD_I(lsb);
|
||||
if (VL_UNLIKELY(msb>lbits)) { // Outside bounds,
|
||||
@@ -2121,37 +2208,41 @@ static inline WDataOutP VL_CONSTHI_W_1X(int obits, int lsb, WDataOutP obase,
|
||||
o[0]=d0;
|
||||
_END(obits,1); }
|
||||
static inline WDataOutP VL_CONSTHI_W_2X(int obits, int lsb, WDataOutP obase,
|
||||
IData d1,IData d0) VL_MT_SAFE {
|
||||
IData d1, IData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0]=d0; o[1]=d1;
|
||||
_END(obits,2); }
|
||||
static inline WDataOutP VL_CONSTHI_W_3X(int obits, int lsb, WDataOutP obase,
|
||||
IData d2,IData d1,IData d0) VL_MT_SAFE {
|
||||
IData d2, IData d1, IData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0]=d0; o[1]=d1; o[2]=d2;
|
||||
_END(obits,3); }
|
||||
static inline WDataOutP VL_CONSTHI_W_4X(int obits, int lsb, WDataOutP obase,
|
||||
IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE {
|
||||
IData d3, IData d2, IData d1, IData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3;
|
||||
_END(obits,4); }
|
||||
static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP obase,
|
||||
IData d4,IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE {
|
||||
IData d4,
|
||||
IData d3, IData d2, IData d1, IData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4;
|
||||
_END(obits,5); }
|
||||
static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP obase,
|
||||
IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE {
|
||||
IData d5, IData d4,
|
||||
IData d3, IData d2, IData d1, IData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5;
|
||||
_END(obits,6); }
|
||||
static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP obase,
|
||||
IData d6,IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE {
|
||||
IData d6, IData d5, IData d4,
|
||||
IData d3, IData d2, IData d1, IData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6;
|
||||
_END(obits,7); }
|
||||
static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP obase,
|
||||
IData d7,IData d6,IData d5,IData d4,IData d3,IData d2,IData d1,IData d0) VL_MT_SAFE {
|
||||
IData d7, IData d6, IData d5, IData d4,
|
||||
IData d3, IData d2, IData d1, IData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
|
||||
_END(obits,8); }
|
||||
@@ -2160,7 +2251,8 @@ static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP obase,
|
||||
|
||||
// Partial constant, lower words of vector wider than 8*32, starting at bit number lsb
|
||||
static inline void VL_CONSTLO_W_8X(int lsb, WDataOutP obase,
|
||||
IData d7, IData d6, IData d5, IData d4, IData d3, IData d2, IData d1, IData d0) VL_MT_SAFE {
|
||||
IData d7, IData d6, IData d5, IData d4,
|
||||
IData d3, IData d2, IData d1, IData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7; }
|
||||
|
||||
|
||||
@@ -186,14 +186,16 @@ endif
|
||||
|
||||
debug-make::
|
||||
@echo
|
||||
@echo CPPFLAGS: $(CPPFLAGS)
|
||||
@echo VM_PREFIX: $(VM_PREFIX)
|
||||
@echo VM_PARALLEL_BUILDS: $(VM_PARALLEL_BUILDS)
|
||||
@echo VM_CLASSES_FAST: $(VM_CLASSES_FAST)
|
||||
@echo VM_CLASSES_SLOW: $(VM_CLASSES_SLOW)
|
||||
@echo VM_SUPPORT_FAST: $(VM_SUPPORT_FAST)
|
||||
@echo VM_SUPPORT_SLOW: $(VM_SUPPORT_SLOW)
|
||||
@echo VM_GLOBAL_FAST: $(VM_GLOBAL_FAST)
|
||||
@echo VM_GLOBAL_SLOW: $(VM_GLOBAL_SLOW)
|
||||
@echo CPPFLAGS: $(CPPFLAGS)
|
||||
@echo VK_OBJS: $(VK_OBJS)
|
||||
@echo
|
||||
|
||||
######################################################################
|
||||
|
||||
@@ -233,12 +233,12 @@ public:
|
||||
// PUBLIC METHODS
|
||||
void clear() VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
clearGuts();
|
||||
}
|
||||
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
if (matchp && matchp[0]) {
|
||||
ItemList newlist;
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
@@ -254,7 +254,7 @@ public:
|
||||
}
|
||||
void zero() VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
(*it)->zero();
|
||||
}
|
||||
@@ -262,18 +262,18 @@ public:
|
||||
|
||||
// We assume there's always call to i/f/p in that order
|
||||
void inserti (VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
assert(!m_insertp);
|
||||
m_insertp = itemp;
|
||||
}
|
||||
void insertf (const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
m_insertFilenamep = filenamep;
|
||||
m_insertLineno = lineno;
|
||||
}
|
||||
void insertp (const char* ckeyps[MAX_KEYS],
|
||||
const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
assert(m_insertp);
|
||||
// First two key/vals are filename
|
||||
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
|
||||
@@ -328,7 +328,7 @@ public:
|
||||
|
||||
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
#ifndef VM_COVERAGE
|
||||
VL_FATAL_MT("",0,"","%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
||||
#endif
|
||||
|
||||
@@ -192,11 +192,13 @@ void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int w
|
||||
|
||||
static inline const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) {
|
||||
if (VL_UNLIKELY(!h)) {
|
||||
VL_FATAL_MT(__FILE__,__LINE__,"","%%Error: DPI svOpenArrayHandle function called with NULL handle");
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||
"%%Error: DPI svOpenArrayHandle function called with NULL handle");
|
||||
}
|
||||
const VerilatedDpiOpenVar* varp = reinterpret_cast<const VerilatedDpiOpenVar*>(h);
|
||||
if (VL_UNLIKELY(!varp->magicOk())) {
|
||||
VL_FATAL_MT(__FILE__,__LINE__,"","%%Error: DPI svOpenArrayHandle function called with non-Verilator handle");
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||
"%%Error: DPI svOpenArrayHandle function called with non-Verilator handle");
|
||||
}
|
||||
return varp;
|
||||
}
|
||||
@@ -246,7 +248,8 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp,
|
||||
int nargs, int indx1, int indx2, int indx3) {
|
||||
void* datap = varp->datap();
|
||||
if (VL_UNLIKELY(nargs != varp->udims())) {
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function called on %d dimensional array using %d dimensional function.\n",
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function called on"
|
||||
" %d dimensional array using %d dimensional function.\n",
|
||||
varp->udims(), nargs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -56,17 +56,22 @@ inline std::string VL_REPLICATEN_NNQ(int,int,int, const std::string& lhs, IData
|
||||
for (unsigned times=0; times<rep; ++times) out += lhs;
|
||||
return out;
|
||||
}
|
||||
inline std::string VL_REPLICATEN_NNI(int obits,int lbits,int rbits, const std::string& lhs, IData rep) VL_PURE {
|
||||
inline std::string VL_REPLICATEN_NNI(int obits,int lbits,int rbits,
|
||||
const std::string& lhs, IData rep) VL_PURE {
|
||||
return VL_REPLICATEN_NNQ(obits,lbits,rbits,lhs,rep);
|
||||
}
|
||||
|
||||
inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); }
|
||||
|
||||
extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE;
|
||||
extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
const std::string& ofilename, void* memp, IData start, IData end) VL_MT_SAFE;
|
||||
extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb,
|
||||
const std::string& ofilename,
|
||||
void* memp, IData start, IData end) VL_MT_SAFE;
|
||||
extern void VL_WRITEMEM_N(bool hex, int width, int depth, int array_lsb,
|
||||
const std::string& ofilename,
|
||||
const void* memp, IData start, IData end) VL_MT_SAFE;
|
||||
extern IData VL_SSCANF_INX(int lbits, const std::string& ld, const char* formatp, ...) VL_MT_SAFE;
|
||||
extern void VL_SFORMAT_X(int obits_ignored, std::string &output, const char* formatp, ...) VL_MT_SAFE;
|
||||
extern void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp, ...) VL_MT_SAFE;
|
||||
extern std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE;
|
||||
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rdp) VL_MT_SAFE;
|
||||
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, IData& rdr) VL_MT_SAFE {
|
||||
|
||||
+44
-94
@@ -49,25 +49,25 @@ class VerilatedScope;
|
||||
// Threaded message passing
|
||||
|
||||
#ifdef VL_THREADED
|
||||
/// Message, enqueued on a train, and consumed on the main eval thread
|
||||
/// Message, enqueued on an mtask, and consumed on the main eval thread
|
||||
class VerilatedMsg {
|
||||
public:
|
||||
// TYPES
|
||||
struct Cmp {
|
||||
bool operator() (const VerilatedMsg& a, const VerilatedMsg& b) {
|
||||
return a.trainId() < b.trainId(); }
|
||||
bool operator() (const VerilatedMsg& a, const VerilatedMsg& b) const {
|
||||
return a.mtaskId() < b.mtaskId(); }
|
||||
};
|
||||
private:
|
||||
// MEMBERS
|
||||
vluint32_t m_trainId; ///< Train that did enqueue
|
||||
vluint32_t m_mtaskId; ///< MTask that did enqueue
|
||||
std::function<void()> m_cb; ///< Lambda to execute when message received
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedMsg(const std::function<void()>& cb)
|
||||
: m_trainId(Verilated::trainId()), m_cb(cb) {}
|
||||
: m_mtaskId(Verilated::mtaskId()), m_cb(cb) {}
|
||||
~VerilatedMsg() {}
|
||||
// METHODS
|
||||
vluint32_t trainId() const { return m_trainId; }
|
||||
vluint32_t mtaskId() const { return m_mtaskId; }
|
||||
/// Execute the lambda function
|
||||
void run() const { m_cb(); }
|
||||
};
|
||||
@@ -84,7 +84,9 @@ class VerilatedEvalMsgQueue {
|
||||
VerilatedThreadQueue m_queue VL_GUARDED_BY(m_mutex); ///< Message queue
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedEvalMsgQueue() : m_depth(0) { }
|
||||
VerilatedEvalMsgQueue() : m_depth(0) {
|
||||
assert(atomic_is_lock_free(&m_depth));
|
||||
}
|
||||
~VerilatedEvalMsgQueue() { }
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedEvalMsgQueue);
|
||||
@@ -92,8 +94,7 @@ public:
|
||||
// METHODS
|
||||
//// Add message to queue (called by producer)
|
||||
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
|
||||
Verilated::endOfEvalReqdInc(); // No mutex, threadsafe
|
||||
VerilatedLockGuard guard(m_mutex);
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
m_queue.insert(msg); // Pass by value to copy the message into queue
|
||||
++m_depth;
|
||||
}
|
||||
@@ -114,10 +115,9 @@ public:
|
||||
m_queue.erase(it);
|
||||
m_mutex.unlock();
|
||||
m_depth--; // Ok if outside critical section as only this code checks the value
|
||||
Verilated::endOfEvalReqdDec(); // No mutex, threadsafe
|
||||
{
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("Executing callback from trainId=%d\n", msg.trainId()););
|
||||
msg.run();
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("Executing callback from mtaskId=%d\n", msg.mtaskId()););
|
||||
msg.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,8 +143,15 @@ private:
|
||||
public:
|
||||
/// Add message to queue, called by producer
|
||||
static void post(const VerilatedMsg& msg) VL_MT_SAFE {
|
||||
Verilated::endOfEvalReqdInc();
|
||||
threadton().m_queue.push(msg); // Pass by value to copy the message into queue
|
||||
// Handle calls to threaded routines outside
|
||||
// of any mtask -- if an initial block calls $finish, say.
|
||||
if (Verilated::mtaskId() == 0) {
|
||||
// No queueing, just do the action immediately
|
||||
msg.run();
|
||||
} else {
|
||||
Verilated::endOfEvalReqdInc();
|
||||
threadton().m_queue.push(msg); // Pass by value to copy the message into queue
|
||||
}
|
||||
}
|
||||
/// Push all messages to the eval's queue
|
||||
static void flush(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
@@ -192,15 +199,10 @@ class VerilatedImp {
|
||||
std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors
|
||||
std::deque<IData> m_fdFree VL_GUARDED_BY(m_fdMutex); ///< List of free descriptors (SLOW - FOPEN/CLOSE only)
|
||||
|
||||
// Threads
|
||||
VerilatedMutex m_threadMutex; ///< Protect m_numThreads, etc
|
||||
bool m_spawned VL_GUARDED_BY(m_threadMutex); ///< Already called spawnThreads()
|
||||
unsigned m_numThreads VL_GUARDED_BY(m_threadMutex); ///< Number of threads user requested, 0x0=all cpus
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// CONSTRUCTORS
|
||||
VerilatedImp()
|
||||
: m_argVecLoaded(false), m_exportNext(0), m_spawned(false), m_numThreads(0) {
|
||||
: m_argVecLoaded(false), m_exportNext(0) {
|
||||
m_fdps.resize(3);
|
||||
m_fdps[0] = stdin;
|
||||
m_fdps[1] = stdout;
|
||||
@@ -210,33 +212,16 @@ public: // But only for verilated*.cpp
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedImp);
|
||||
public:
|
||||
static void internalsDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_argMutex);
|
||||
VL_PRINTF_MT("internalsDump:\n");
|
||||
VL_PRINTF_MT(" Argv:");
|
||||
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
||||
VL_PRINTF_MT(" %s",it->c_str());
|
||||
}
|
||||
VL_PRINTF_MT("\n");
|
||||
VL_PRINTF_MT(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion());
|
||||
scopesDump();
|
||||
exportsDump();
|
||||
userDump();
|
||||
}
|
||||
// METHODS - debug
|
||||
static void internalsDump() VL_MT_SAFE;
|
||||
static void versionDump() VL_MT_SAFE;
|
||||
|
||||
// METHODS - arguments
|
||||
public:
|
||||
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
|
||||
VerilatedLockGuard guard(s_s.m_argMutex);
|
||||
s_s.m_argVec.clear(); // Always clear
|
||||
commandArgsAddGuts(argc, argv);
|
||||
}
|
||||
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
|
||||
VerilatedLockGuard guard(s_s.m_argMutex);
|
||||
commandArgsAddGuts(argc, argv);
|
||||
}
|
||||
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
|
||||
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
|
||||
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
|
||||
VerilatedLockGuard guard(s_s.m_argMutex);
|
||||
VerilatedLockGuard lock(s_s.m_argMutex);
|
||||
// Note prefixp does not include the leading "+"
|
||||
size_t len = strlen(prefixp);
|
||||
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
|
||||
@@ -253,11 +238,7 @@ public:
|
||||
return "";
|
||||
}
|
||||
private:
|
||||
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex) {
|
||||
if (!s_s.m_argVecLoaded) s_s.m_argVec.clear();
|
||||
for (int i=0; i<argc; ++i) s_s.m_argVec.push_back(argv[i]);
|
||||
s_s.m_argVecLoaded = true; // Can't just test later for empty vector, no arguments is ok
|
||||
}
|
||||
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex);
|
||||
|
||||
public:
|
||||
// METHODS - user scope tracking
|
||||
@@ -265,14 +246,14 @@ public:
|
||||
// There's often many more scopes than userdata's and thus having a ~48byte
|
||||
// per map overhead * N scopes would take much more space and cache thrashing.
|
||||
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_userMapMutex);
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
|
||||
if (it != s_s.m_userMap.end()) it->second = userData;
|
||||
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
|
||||
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep,userKey),userData));
|
||||
}
|
||||
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_userMapMutex);
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
|
||||
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
|
||||
else return NULL;
|
||||
@@ -281,7 +262,7 @@ private:
|
||||
/// Symbol table destruction cleans up the entries for each scope.
|
||||
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope on destruction, so we simply iterate.
|
||||
VerilatedLockGuard guard(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(); ) {
|
||||
if (it->first.first == scopep) {
|
||||
s_s.m_userMap.erase(it++);
|
||||
@@ -291,7 +272,7 @@ private:
|
||||
}
|
||||
}
|
||||
static void userDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(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;
|
||||
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; }
|
||||
@@ -304,27 +285,27 @@ public: // But only for verilated*.cpp
|
||||
// METHODS - scope name
|
||||
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope at construction
|
||||
VerilatedLockGuard guard(s_s.m_nameMutex);
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||
if (it == s_s.m_nameMap.end()) {
|
||||
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(),scopep));
|
||||
}
|
||||
}
|
||||
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_nameMutex); // If too slow, can assume this is only VL_MT_SAFE_POSINIT
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex); // If too slow, can assume this is only VL_MT_SAFE_POSINIT
|
||||
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
|
||||
else return NULL;
|
||||
}
|
||||
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope at destruction
|
||||
VerilatedLockGuard guard(s_s.m_nameMutex);
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
userEraseScope(scopep);
|
||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
||||
}
|
||||
static void scopesDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_nameMutex);
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
VL_PRINTF_MT(" scopesDump:\n");
|
||||
for (VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) {
|
||||
const VerilatedScope* scopep = it->second;
|
||||
@@ -348,7 +329,7 @@ public: // But only for verilated*.cpp
|
||||
// miss at the cost of a multiply, and all lookups move to slowpath.
|
||||
static int exportInsert(const char* namep) VL_MT_SAFE {
|
||||
// Slow ok - called once/function at creation
|
||||
VerilatedLockGuard guard(s_s.m_exportMutex);
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
|
||||
if (it == s_s.m_exportMap.end()) {
|
||||
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
|
||||
@@ -358,7 +339,7 @@ public: // But only for verilated*.cpp
|
||||
}
|
||||
}
|
||||
static int exportFind(const char* namep) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_exportMutex);
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
ExportNameMap::const_iterator it=s_s.m_exportMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
|
||||
std::string msg = (std::string("%Error: Testbench C called ")+namep
|
||||
@@ -368,14 +349,14 @@ public: // But only for verilated*.cpp
|
||||
}
|
||||
static const char* exportName(int funcnum) VL_MT_SAFE {
|
||||
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
||||
VerilatedLockGuard guard(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) {
|
||||
if (it->second == funcnum) return it->first;
|
||||
}
|
||||
return "*UNKNOWN*";
|
||||
}
|
||||
static void exportsDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_exportMutex);
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
bool first = true;
|
||||
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
||||
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
|
||||
@@ -390,7 +371,7 @@ public: // But only for verilated*.cpp
|
||||
static IData fdNew(FILE* fp) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
// Bit 31 indicates it's a descriptor not a MCD
|
||||
VerilatedLockGuard guard(s_s.m_fdMutex);
|
||||
VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
if (s_s.m_fdFree.empty()) {
|
||||
// Need to create more space in m_fdps and m_fdFree
|
||||
size_t start = s_s.m_fdps.size();
|
||||
@@ -403,7 +384,7 @@ public: // But only for verilated*.cpp
|
||||
}
|
||||
static void fdDelete(IData fdi) VL_MT_SAFE {
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
VerilatedLockGuard guard(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(!s_s.m_fdps[idx])) return; // Already free
|
||||
s_s.m_fdps[idx] = NULL;
|
||||
@@ -411,41 +392,10 @@ public: // But only for verilated*.cpp
|
||||
}
|
||||
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
VerilatedLockGuard guard(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;
|
||||
return s_s.m_fdps[idx];
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - Threading
|
||||
static void numThreads(unsigned threads) VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_threadMutex);
|
||||
if (!s_s.m_spawned) s_s.m_numThreads = threads;
|
||||
}
|
||||
static unsigned numThreads() VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_threadMutex);
|
||||
#ifdef VL_THREADED
|
||||
unsigned threads = s_s.m_numThreads;
|
||||
if (threads == 0x0) {
|
||||
threads = std::thread::hardware_concurrency(); // Or 0=unknown, C++11
|
||||
}
|
||||
if (threads<1) threads = 1;
|
||||
return threads;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
static void spawnThreads() VL_MT_SAFE {
|
||||
VerilatedLockGuard guard(s_s.m_threadMutex);
|
||||
if (!s_s.m_spawned) {
|
||||
// Convert numThreads from 0 to the spawned number
|
||||
numThreads(numThreads());
|
||||
s_s.m_spawned = true;
|
||||
#ifdef VL_THREADED
|
||||
// THREADED-TODO startup threads
|
||||
#endif
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
|
||||
@@ -138,7 +138,8 @@ public:
|
||||
}
|
||||
// Read a datum and compare with expected value
|
||||
VerilatedDeserialize& readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
||||
VerilatedDeserialize& readAssert(vluint64_t data) VL_MT_UNSAFE_ONE { return readAssert(&data, sizeof(data)); }
|
||||
VerilatedDeserialize& readAssert(vluint64_t data) VL_MT_UNSAFE_ONE {
|
||||
return readAssert(&data, sizeof(data)); }
|
||||
private:
|
||||
bool readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
||||
VerilatedDeserialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
||||
|
||||
@@ -52,7 +52,8 @@ public:
|
||||
int right() const { return m_right; }
|
||||
int low() const { return (m_left < m_right) ? m_left : m_right; }
|
||||
int high() const { return (m_left > m_right) ? m_left : m_right; }
|
||||
int elements() const { return (VL_LIKELY(m_left>=m_right) ? (m_left-m_right+1) : (m_right-m_left+1)); }
|
||||
int elements() const {
|
||||
return (VL_LIKELY(m_left>=m_right) ? (m_left-m_right+1) : (m_right-m_left+1)); }
|
||||
int increment() const { return (m_left >= m_right) ? 1 : -1; }
|
||||
};
|
||||
|
||||
@@ -81,45 +82,54 @@ public:
|
||||
class Unpacked {};
|
||||
// Without packed
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags)
|
||||
: m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(0) { }
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(0) { }
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Unpacked, int u0l, int u0r)
|
||||
: m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(1) {
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(1) {
|
||||
m_unpacked[0].init(u0l, u0r); }
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Unpacked, int u0l, int u0r, int u1l, int u1r)
|
||||
: m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(2) {
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(2) {
|
||||
m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); }
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Unpacked, int u0l, int u0r, int u1l, int u1r, int u2l, int u2r)
|
||||
: m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(3) {
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(3) {
|
||||
m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); m_unpacked[2].init(u2l, u2r); }
|
||||
// With packed
|
||||
class Packed {};
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Packed, int pl, int pr)
|
||||
: m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(0), m_packed(pl,pr) { }
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(0), m_packed(pl,pr) { }
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Packed, int pl, int pr,
|
||||
Unpacked, int u0l, int u0r)
|
||||
: m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(1), m_packed(pl,pr) {
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(1), m_packed(pl,pr) {
|
||||
m_unpacked[0].init(u0l, u0r); }
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Packed, int pl, int pr,
|
||||
Unpacked, int u0l, int u0r, int u1l, int u1r)
|
||||
: m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(2), m_packed(pl,pr) {
|
||||
: m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)),
|
||||
m_pdims(1), m_udims(2), m_packed(pl,pr) {
|
||||
m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); }
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Packed, int pl, int pr,
|
||||
Unpacked, int u0l, int u0r, int u1l, int u1r, int u2l, int u2r)
|
||||
: m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(3), m_packed(pl,pr) {
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(3), m_packed(pl,pr) {
|
||||
m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); m_unpacked[2].init(u2l, u2r); }
|
||||
public:
|
||||
~VerilatedVarProps() {}
|
||||
// METHODS
|
||||
bool magicOk() const { return m_magic==MAGIC; }
|
||||
VerilatedVarType vltype() const { return m_vltype; }
|
||||
VerilatedVarFlags vldir() const { return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR); }
|
||||
VerilatedVarFlags vldir() const {
|
||||
return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR); }
|
||||
vluint32_t entSize() const;
|
||||
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
||||
/// DPI compatible C standard layout
|
||||
|
||||
@@ -61,18 +61,18 @@ private:
|
||||
static Singleton& singleton() { static Singleton s; return s; }
|
||||
public:
|
||||
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
||||
VerilatedLockGuard guard(singleton().s_vcdMutex);
|
||||
VerilatedLockGuard lock(singleton().s_vcdMutex);
|
||||
singleton().s_vcdVecp.push_back(vcdp);
|
||||
}
|
||||
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
||||
VerilatedLockGuard guard(singleton().s_vcdMutex);
|
||||
VerilatedLockGuard lock(singleton().s_vcdMutex);
|
||||
VcdVec::iterator pos = find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
|
||||
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
|
||||
}
|
||||
static void flush_all() VL_EXCLUDES(singleton().s_vcdMutex) VL_MT_UNSAFE_ONE {
|
||||
// Thread safety: Although this function is protected by a mutex so perhaps
|
||||
// in the future we can allow tracing in separate threads, vcdp->flush() assumes call from single thread
|
||||
VerilatedLockGuard guard(singleton().s_vcdMutex);
|
||||
VerilatedLockGuard lock(singleton().s_vcdMutex);
|
||||
for (VcdVec::const_iterator it=singleton().s_vcdVecp.begin(); it!=singleton().s_vcdVecp.end(); ++it) {
|
||||
VerilatedVcd* vcdp = *it;
|
||||
vcdp->flush();
|
||||
@@ -343,7 +343,7 @@ void VerilatedVcd::bufferResize(vluint64_t minsize) {
|
||||
memcpy(m_wrBufp, oldbufp, m_writep - oldbufp);
|
||||
m_writep = m_wrBufp + (m_writep - oldbufp);
|
||||
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
|
||||
delete oldbufp; oldbufp=NULL;
|
||||
delete [] oldbufp; oldbufp=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,12 +382,14 @@ void VerilatedVcd::bufferFlush () VL_MT_UNSAFE_ONE {
|
||||
// Simple methods
|
||||
|
||||
void VerilatedVcd::set_time_unit (const char* unitp) {
|
||||
//cout<<" set_time_unit ("<<unitp<<") == "<<timescaleToDouble(unitp)<<" == "<<doubleToTimescale(timescaleToDouble(unitp))<<endl;
|
||||
//cout<<" set_time_unit ("<<unitp<<") == "<<timescaleToDouble(unitp)
|
||||
// <<" == "<<doubleToTimescale(timescaleToDouble(unitp))<<endl;
|
||||
m_timeUnit = timescaleToDouble(unitp);
|
||||
}
|
||||
|
||||
void VerilatedVcd::set_time_resolution (const char* unitp) {
|
||||
//cout<<"set_time_resolution ("<<unitp<<") == "<<timescaleToDouble(unitp)<<" == "<<doubleToTimescale(timescaleToDouble(unitp))<<endl;
|
||||
//cout<<"set_time_resolution ("<<unitp<<") == "<<timescaleToDouble(unitp)
|
||||
// <<" == "<<doubleToTimescale(timescaleToDouble(unitp))<<endl;
|
||||
m_timeRes = timescaleToDouble(unitp);
|
||||
}
|
||||
|
||||
|
||||
+63
-29
@@ -91,7 +91,8 @@ public:
|
||||
t_freeHead = oldp;
|
||||
}
|
||||
// MEMBERS
|
||||
static inline VerilatedVpio* castp(vpiHandle h) { return dynamic_cast<VerilatedVpio*>((VerilatedVpio*)h); }
|
||||
static inline VerilatedVpio* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpio*>((VerilatedVpio*)h); }
|
||||
inline vpiHandle castVpiHandle() { return reinterpret_cast<vpiHandle>(this); }
|
||||
// ACCESSORS
|
||||
virtual const char* name() const { return "<null>"; }
|
||||
@@ -117,7 +118,8 @@ public:
|
||||
m_cbData.value = &m_value;
|
||||
}
|
||||
virtual ~VerilatedVpioCb() {}
|
||||
static inline VerilatedVpioCb* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioCb*>((VerilatedVpio*)h); }
|
||||
static inline VerilatedVpioCb* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioCb*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() const { return vpiCallback; }
|
||||
vluint32_t reason() const { return m_cbData.reason; }
|
||||
VerilatedPliCb cb_rtnp() const { return m_cbData.cb_rtn; }
|
||||
@@ -130,7 +132,8 @@ class VerilatedVpioConst : public VerilatedVpio {
|
||||
public:
|
||||
explicit VerilatedVpioConst(vlsint32_t num) : m_num(num) {}
|
||||
virtual ~VerilatedVpioConst() {}
|
||||
static inline VerilatedVpioConst* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioConst*>((VerilatedVpio*)h); }
|
||||
static inline VerilatedVpioConst* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioConst*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() const { return vpiUndefined; }
|
||||
vlsint32_t num() const { return m_num; }
|
||||
};
|
||||
@@ -141,7 +144,8 @@ class VerilatedVpioRange : public VerilatedVpio {
|
||||
public:
|
||||
explicit VerilatedVpioRange(const VerilatedRange* range) : m_range(range), m_iteration(0) {}
|
||||
virtual ~VerilatedVpioRange() {}
|
||||
static inline VerilatedVpioRange* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioRange*>((VerilatedVpio*)h); }
|
||||
static inline VerilatedVpioRange* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioRange*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() const { return vpiRange; }
|
||||
virtual vluint32_t size() const { return m_range->elements(); }
|
||||
virtual const VerilatedRange* rangep() const { return m_range; }
|
||||
@@ -164,7 +168,8 @@ public:
|
||||
explicit VerilatedVpioScope(const VerilatedScope* scopep)
|
||||
: m_scopep(scopep) {}
|
||||
virtual ~VerilatedVpioScope() {}
|
||||
static inline VerilatedVpioScope* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioScope*>((VerilatedVpio*)h); }
|
||||
static inline VerilatedVpioScope* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioScope*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() const { return vpiScope; }
|
||||
const VerilatedScope* scopep() const { return m_scopep; }
|
||||
virtual const char* name() const { return m_scopep->name(); }
|
||||
@@ -198,7 +203,8 @@ public:
|
||||
virtual ~VerilatedVpioVar() {
|
||||
if (m_prevDatap) { delete [] m_prevDatap; m_prevDatap = NULL; }
|
||||
}
|
||||
static inline VerilatedVpioVar* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioVar*>((VerilatedVpio*)h); }
|
||||
static inline VerilatedVpioVar* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioVar*>((VerilatedVpio*)h); }
|
||||
const VerilatedVar* varp() const { return m_varp; }
|
||||
const VerilatedScope* scopep() const { return m_scopep; }
|
||||
vluint32_t mask() const { return m_mask.u32; }
|
||||
@@ -236,7 +242,8 @@ public:
|
||||
m_varDatap = ((vluint8_t*)varp->datap()) + entSize()*offset;
|
||||
}
|
||||
virtual ~VerilatedVpioMemoryWord() {}
|
||||
static inline VerilatedVpioMemoryWord* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioMemoryWord*>((VerilatedVpio*)h); }
|
||||
static inline VerilatedVpioMemoryWord* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioMemoryWord*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() const { return vpiMemoryWord; }
|
||||
virtual vluint32_t size() const { return varp()->packed().elements(); }
|
||||
virtual const VerilatedRange* rangep() const { return &(varp()->packed()); }
|
||||
@@ -256,7 +263,8 @@ public:
|
||||
explicit VerilatedVpioVarIter(const VerilatedScope* scopep)
|
||||
: m_scopep(scopep), m_started(false) { }
|
||||
virtual ~VerilatedVpioVarIter() {}
|
||||
static inline VerilatedVpioVarIter* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioVarIter*>((VerilatedVpio*)h); }
|
||||
static inline VerilatedVpioVarIter* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioVarIter*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() const { return vpiIterator; }
|
||||
virtual vpiHandle dovpi_scan() {
|
||||
if (VL_LIKELY(m_scopep->varsp())) {
|
||||
@@ -281,9 +289,13 @@ class VerilatedVpioMemoryWordIter : public VerilatedVpio {
|
||||
bool m_done;
|
||||
public:
|
||||
VerilatedVpioMemoryWordIter(const vpiHandle handle, const VerilatedVar* varp)
|
||||
: m_handle(handle), m_varp(varp), m_iteration(varp->unpacked().right()), m_direction(VL_LIKELY(varp->unpacked().left()>varp->unpacked().right())?1:-1), m_done(false) { }
|
||||
: m_handle(handle), m_varp(varp), m_iteration(varp->unpacked().right()),
|
||||
m_direction(VL_LIKELY(varp->unpacked().left() > varp->unpacked().right())
|
||||
? 1 : -1),
|
||||
m_done(false) { }
|
||||
virtual ~VerilatedVpioMemoryWordIter() {}
|
||||
static inline VerilatedVpioMemoryWordIter* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioMemoryWordIter*>((VerilatedVpio*)h); }
|
||||
static inline VerilatedVpioMemoryWordIter* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioMemoryWordIter*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() const { return vpiIterator; }
|
||||
void iterationInc() {
|
||||
if (!(m_done = (m_iteration == m_varp->unpacked().left()))) m_iteration+=m_direction;
|
||||
@@ -337,7 +349,9 @@ public:
|
||||
varop->createPrevDatap();
|
||||
}
|
||||
}
|
||||
if (VL_UNLIKELY(vop->reason() >= CB_ENUM_MAX_VALUE)) VL_FATAL_MT(__FILE__,__LINE__,"", "vpi bb reason too large");
|
||||
if (VL_UNLIKELY(vop->reason() >= CB_ENUM_MAX_VALUE)) {
|
||||
VL_FATAL_MT(__FILE__,__LINE__,"", "vpi bb reason too large");
|
||||
}
|
||||
s_s.m_cbObjLists[vop->reason()].push_back(vop);
|
||||
}
|
||||
static void cbTimedAdd(VerilatedVpioCb* vop) {
|
||||
@@ -459,11 +473,12 @@ public:
|
||||
m_errorInfo.level = level;
|
||||
return this;
|
||||
}
|
||||
void setMessage(std::string file, PLI_INT32 line, std::string message, ...) {
|
||||
void setMessage(std::string file, PLI_INT32 line, const char* message, ...) {
|
||||
// message cannot be a const string& as va_start cannot use a reference
|
||||
static VL_THREAD_LOCAL std::string filehold;
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
VL_VSNPRINTF(m_buff, sizeof(m_buff), message.c_str(), args);
|
||||
VL_VSNPRINTF(m_buff, sizeof(m_buff), message, args);
|
||||
va_end(args);
|
||||
m_errorInfo.state = vpiPLI;
|
||||
filehold = file;
|
||||
@@ -921,7 +936,8 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
|
||||
QData time = 0;
|
||||
if (cb_data_p->time) time = _VL_SET_QII(cb_data_p->time->high, cb_data_p->time->low);
|
||||
VerilatedVpioCb* vop = new VerilatedVpioCb(cb_data_p, VL_TIME_Q()+time);
|
||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_register_cb %d %p delay=%" VL_PRI64 "u\n",cb_data_p->reason,vop,time););
|
||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_register_cb %d %p delay=%" VL_PRI64 "u\n",
|
||||
cb_data_p->reason, vop, time););
|
||||
VerilatedVpiImp::cbTimedAdd(vop);
|
||||
return vop->castVpiHandle();
|
||||
}
|
||||
@@ -1016,12 +1032,14 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
|
||||
if (VL_LIKELY(varop)) {
|
||||
if (varop->varp()->dims()<2) return 0;
|
||||
if (VL_LIKELY(varop->varp()->unpacked().left() >= varop->varp()->unpacked().right())) {
|
||||
if (VL_UNLIKELY(indx > varop->varp()->unpacked().left() || indx < varop->varp()->unpacked().right())) return 0;
|
||||
if (VL_UNLIKELY(indx > varop->varp()->unpacked().left()
|
||||
|| indx < varop->varp()->unpacked().right())) return 0;
|
||||
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
|
||||
indx - varop->varp()->unpacked().right()))
|
||||
->castVpiHandle();
|
||||
} else {
|
||||
if (VL_UNLIKELY(indx < varop->varp()->unpacked().left() || indx > varop->varp()->unpacked().right())) return 0;
|
||||
if (VL_UNLIKELY(indx < varop->varp()->unpacked().left()
|
||||
|| indx > varop->varp()->unpacked().right())) return 0;
|
||||
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
|
||||
indx - varop->varp()->unpacked().left()))
|
||||
->castVpiHandle();
|
||||
@@ -1206,7 +1224,8 @@ void vpi_put_delays(vpiHandle object, p_vpi_delay delay_p) {
|
||||
// value processing
|
||||
|
||||
void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
|
||||
static VL_THREAD_LOCAL char outStr[1+VL_MULS_MAX_WORDS*32]; // Maximum required size is for binary string, one byte per bit plus null termination
|
||||
// Maximum required size is for binary string, one byte per bit plus null termination
|
||||
static VL_THREAD_LOCAL char outStr[1+VL_MULS_MAX_WORDS*32];
|
||||
// cppcheck-suppress variableScope
|
||||
static VL_THREAD_LOCAL int outStrSz = sizeof(outStr)-1;
|
||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_get_value %p\n",object););
|
||||
@@ -1274,8 +1293,10 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
|
||||
if (bits > outStrSz) {
|
||||
// limit maximum size of output to size of buffer to prevent overrun.
|
||||
bits = outStrSz;
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bits);
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s"
|
||||
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format),
|
||||
vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bits);
|
||||
}
|
||||
for (i=0; i<bits; ++i) {
|
||||
char val = (datap[i>>3]>>(i&7))&1;
|
||||
@@ -1286,7 +1307,8 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
|
||||
}
|
||||
default:
|
||||
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format),
|
||||
vop->fullname());
|
||||
return;
|
||||
}
|
||||
} else if (value_p->format == vpiOctStrVal) {
|
||||
@@ -1303,8 +1325,10 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
|
||||
int i;
|
||||
if (chars > outStrSz) {
|
||||
// limit maximum size of output to size of buffer to prevent overrun.
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars);
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s"
|
||||
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format),
|
||||
vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars);
|
||||
chars = outStrSz;
|
||||
}
|
||||
for (i=0; i<chars; ++i) {
|
||||
@@ -1368,8 +1392,10 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
|
||||
int i;
|
||||
if (chars > outStrSz) {
|
||||
// limit maximum size of output to size of buffer to prevent overrun.
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars);
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s"
|
||||
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format),
|
||||
vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars);
|
||||
chars = outStrSz;
|
||||
}
|
||||
for (i=0; i<chars; ++i) {
|
||||
@@ -1406,7 +1432,8 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
|
||||
int i;
|
||||
if (bytes > outStrSz) {
|
||||
// limit maximum size of output to size of buffer to prevent overrun.
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s"
|
||||
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
||||
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format),
|
||||
vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bytes);
|
||||
bytes = outStrSz;
|
||||
@@ -1478,7 +1505,9 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
|
||||
VL_DBG_MSGF("- vpi: varp=%p putatp=%p\n",
|
||||
vop->varp()->datap(), vop->varDatap()););
|
||||
if (VL_UNLIKELY(!vop->varp()->isPublicRW())) {
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value to signal marked read-only, use public_flat_rw instead: ", vop->fullname());
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value to signal marked read-only,"
|
||||
" use public_flat_rw instead: ",
|
||||
vop->fullname());
|
||||
return 0;
|
||||
}
|
||||
if (value_p->format == vpiVectorVal) {
|
||||
@@ -1615,7 +1644,9 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
|
||||
}
|
||||
if (success > 1) {
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Trailing garbage '%s' in '%s' as value %s for %s",
|
||||
VL_FUNC, remainder, value_p->value.str, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
||||
VL_FUNC, remainder, value_p->value.str,
|
||||
VerilatedVpiError::strFromVpiVal(value_p->format),
|
||||
vop->fullname());
|
||||
}
|
||||
switch (vop->varp()->vltype()) {
|
||||
case VLVT_UINT8 : *(reinterpret_cast<CData*>(vop->varDatap())) = val & vop->mask(); break;
|
||||
@@ -1655,7 +1686,9 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
|
||||
else if (digit >= 'A' && digit <= 'F') hex = digit - 'A' + 10;
|
||||
else {
|
||||
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Non hex character '%c' in '%s' as value %s for %s",
|
||||
VL_FUNC, digit, value_p->value.str, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
|
||||
VL_FUNC, digit, value_p->value.str,
|
||||
VerilatedVpiError::strFromVpiVal(value_p->format),
|
||||
vop->fullname());
|
||||
hex = 0;
|
||||
}
|
||||
} else {
|
||||
@@ -1688,7 +1721,8 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
|
||||
int len = strlen(value_p->value.str);
|
||||
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
for (int i=0; i<bytes; ++i) {
|
||||
datap[i] = (i < len)?value_p->value.str[len-i-1]:0; // prepend with 0 values before placing string the least signifcant bytes
|
||||
// prepend with 0 values before placing string the least signifcant bytes
|
||||
datap[i] = (i < len)?value_p->value.str[len-i-1]:0;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
@@ -353,6 +353,45 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
# define VL_ROUND(n) round(n)
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Performance counters
|
||||
|
||||
#if VL_THREADED
|
||||
/// The vluint64_t argument is loaded with a high-performance counter for profiling
|
||||
/// or 0x0 if not implemeted on this platform
|
||||
# if defined(__i386__) || defined(__x86_64__)
|
||||
# define VL_RDTSC(val) { \
|
||||
vluint32_t hi, lo; \
|
||||
asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); \
|
||||
(val) = ((vluint64_t)lo) | (((vluint64_t)hi)<<32); \
|
||||
}
|
||||
# elif defined(__aarch64__)
|
||||
# define VL_RDTSC(val) asm volatile("mrs %[rt],PMCCNTR_EL0" : [rt] "=r" (val));
|
||||
# else
|
||||
// We just silently ignore unknown OSes, as only leads to missing statistics
|
||||
# define VL_RDTSC(val) (val) = 0;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Threading related OS-specific functions
|
||||
|
||||
#if VL_THREADED
|
||||
# if defined(__i386__) || defined(__x86_64__)
|
||||
/// For more efficient busy waiting on SMT CPUs, let the processor know
|
||||
/// we're just waiting so it can let another thread run
|
||||
# define VL_CPU_RELAX() asm volatile("rep; nop" ::: "memory")
|
||||
# elif defined(__ia64__)
|
||||
# define VL_CPU_RELAX() asm volatile("hint @pause" ::: "memory")
|
||||
# elif defined(__aarch64__)
|
||||
# define VL_CPU_RELAX() asm volatile("yield" ::: "memory")
|
||||
# elif defined(__powerpc64__)
|
||||
# define VL_CPU_RELAX() asm volatile("or 1, 1, 1; or 2, 2, 2;" ::: "memory")
|
||||
# else
|
||||
# error "Missing VL_CPU_RELAX() definition. Or, don't use VL_THREADED"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
|
||||
#endif /*guard*/
|
||||
|
||||
+21
-21
@@ -7,7 +7,7 @@
|
||||
* This file contains the constant definitions, structure definitions,
|
||||
* and routine declarations used by SystemVerilog DPI.
|
||||
*
|
||||
* This file is from the SystemVerilog IEEE 1800-2012 Annex I.
|
||||
* This file is from the SystemVerilog IEEE 1800-2017 Annex I.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SVDPI
|
||||
@@ -117,7 +117,7 @@ typedef uint32_t svBitVecVal;
|
||||
/*
|
||||
* Return implementation version information string ("1800-2005" or "SV3.1a").
|
||||
*/
|
||||
XXTERN const char* svDpiVersion();
|
||||
XXTERN const char* svDpiVersion( void );
|
||||
|
||||
/* a handle to a scope (an instance of a module or interface) */
|
||||
XXTERN typedef void* svScope;
|
||||
@@ -241,28 +241,28 @@ XXTERN void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s
|
||||
XXTERN void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3);
|
||||
|
||||
XXTERN svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...);
|
||||
XXTERN svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1);
|
||||
XXTERN svBit svGetBitArrElem2(const svOpenArrayHandle s, int indx1, int indx2);
|
||||
XXTERN svBit svGetBitArrElem3(const svOpenArrayHandle s, int indx1, int indx2,
|
||||
XXTERN svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...);
|
||||
XXTERN svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1);
|
||||
XXTERN svBit svGetBitArrElem2(const svOpenArrayHandle s, int indx1, int indx2);
|
||||
XXTERN svBit svGetBitArrElem3(const svOpenArrayHandle s, int indx1, int indx2,
|
||||
int indx3);
|
||||
XXTERN svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...);
|
||||
XXTERN svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1);
|
||||
XXTERN svLogic svGetLogicArrElem2(const svOpenArrayHandle s, int indx1, int indx2);
|
||||
XXTERN svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2,
|
||||
XXTERN svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...);
|
||||
XXTERN svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1);
|
||||
XXTERN svLogic svGetLogicArrElem2(const svOpenArrayHandle s, int indx1, int indx2);
|
||||
XXTERN svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2,
|
||||
int indx3);
|
||||
XXTERN void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
XXTERN void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
...);
|
||||
XXTERN void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1);
|
||||
XXTERN void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
XXTERN void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1);
|
||||
XXTERN void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
int indx2);
|
||||
XXTERN void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
XXTERN void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
int indx2, int indx3);
|
||||
XXTERN void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...);
|
||||
XXTERN void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1);
|
||||
XXTERN void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1,
|
||||
XXTERN void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...);
|
||||
XXTERN void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1);
|
||||
XXTERN void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1,
|
||||
int indx2);
|
||||
XXTERN void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1,
|
||||
XXTERN void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1,
|
||||
int indx2, int indx3);
|
||||
|
||||
/* Functions for working with DPI context */
|
||||
@@ -273,7 +273,7 @@ XXTERN void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1
|
||||
* is the scope of the function's declaration site, not call site.
|
||||
* Returns NULL if called from C code that is *not* an imported function.
|
||||
*/
|
||||
XXTERN svScope svGetScope();
|
||||
XXTERN svScope svGetScope( void );
|
||||
|
||||
/*
|
||||
* Set context for subsequent export function execution.
|
||||
@@ -337,7 +337,7 @@ XXTERN int svGetCallerInfo(const char** fileName, int *lineNumber);
|
||||
* Returns 1 if the current execution thread is in the disabled state.
|
||||
* Disable protocol must be adhered to if in the disabled state.
|
||||
*/
|
||||
XXTERN int svIsDisabledState();
|
||||
XXTERN int svIsDisabledState( void );
|
||||
|
||||
/*
|
||||
* Imported functions call this API function during disable processing to
|
||||
@@ -345,7 +345,7 @@ XXTERN int svIsDisabledState();
|
||||
* This function must be called before returning from an imported function that is
|
||||
* in the disabled state.
|
||||
*/
|
||||
XXTERN void svAckDisabledState();
|
||||
XXTERN void svAckDisabledState( void );
|
||||
|
||||
/*
|
||||
**********************************************************
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*******************************************************************************
|
||||
* vpi_user.h
|
||||
*
|
||||
* IEEE Std 1800-2012 Programming Language Interface (PLI)
|
||||
* IEEE Std 1800-2017 Programming Language Interface (PLI)
|
||||
*
|
||||
* This file contains the constant definitions, structure definitions, and
|
||||
* routine declarations used by the SystemVerilog Verification Procedural
|
||||
@@ -251,7 +251,7 @@ typedef PLI_UINT32 *vpiHandle;
|
||||
#define vpiModPathOut 96 /* output terminal of a module path */
|
||||
#define vpiOperand 97 /* operand of expression */
|
||||
#define vpiPortInst 98 /* connected port instance */
|
||||
#define vpiProcess 99 /* process in module */
|
||||
#define vpiProcess 99 /* process in module, program or interface */
|
||||
#define vpiVariables 100 /* variables in module */
|
||||
#define vpiUse 101 /* usage */
|
||||
|
||||
@@ -978,7 +978,7 @@ XXTERN vpiHandle vpi_handle_by_multi_index PROTO_PARAMS((vpiHandle obj,
|
||||
|
||||
/****************************** GLOBAL VARIABLES ******************************/
|
||||
|
||||
PLI_VEXTERN PLI_DLLESPEC void (*vlog_startup_routines[])();
|
||||
PLI_VEXTERN PLI_DLLESPEC void (*vlog_startup_routines[])( void );
|
||||
|
||||
/* array of function pointers, last pointer should be null */
|
||||
|
||||
|
||||
+1
-1
@@ -749,7 +749,7 @@ File a bug (if there isn't already) so others know what you're working on.
|
||||
|
||||
=item 2.
|
||||
|
||||
Make a testcase in the test_regress/t/t_EXAMPLE format, see L<TESTING>.
|
||||
Make a testcase in the test_regress/t/t_EXAMPLE format, see L</TESTING>.
|
||||
|
||||
=item 3.
|
||||
|
||||
|
||||
+7
-3
@@ -174,11 +174,13 @@ private:
|
||||
// Convert to a non-delayed assignment
|
||||
UINFO(5," ASSIGNDLY "<<nodep<<endl);
|
||||
if (m_check == CT_INITIAL) {
|
||||
nodep->v3warn(INITIALDLY,"Delayed assignments (<=) in initial or final block; suggest blocking assignments (=).");
|
||||
nodep->v3warn(INITIALDLY, "Delayed assignments (<=) in initial"
|
||||
" or final block; suggest blocking assignments (=).");
|
||||
} else if (m_check == CT_LATCH) {
|
||||
// Suppress. Shouldn't matter that the interior of the latch races
|
||||
} else {
|
||||
nodep->v3warn(COMBDLY,"Delayed assignments (<=) in non-clocked (non flop or latch) block; suggest blocking assignments (=).");
|
||||
nodep->v3warn(COMBDLY, "Delayed assignments (<=) in non-clocked"
|
||||
" (non flop or latch) block; suggest blocking assignments (=).");
|
||||
}
|
||||
AstNode* newp = new AstAssign (nodep->fileline(),
|
||||
nodep->lhsp()->unlinkFrBack(),
|
||||
@@ -437,6 +439,8 @@ public:
|
||||
|
||||
void V3Active::activeAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ActiveVisitor visitor (nodep);
|
||||
{
|
||||
ActiveVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("active", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+3
-1
@@ -159,6 +159,8 @@ public:
|
||||
|
||||
void V3ActiveTop::activeTopAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ActiveTopVisitor visitor (nodep);
|
||||
{
|
||||
ActiveTopVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("activetop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+34
-9
@@ -88,11 +88,17 @@ private:
|
||||
return newp;
|
||||
}
|
||||
|
||||
AstNode* newFireAssert(AstNode* nodep, const string& message) {
|
||||
AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message) {
|
||||
// Like newFireAssert() but omits the asserts-on check
|
||||
AstDisplay* dispp = new AstDisplay (nodep->fileline(), AstDisplayType::DT_ERROR, message, NULL, NULL);
|
||||
AstNode* bodysp = dispp;
|
||||
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
|
||||
bodysp->addNext(new AstStop (nodep->fileline()));
|
||||
return bodysp;
|
||||
}
|
||||
|
||||
AstNode* newFireAssert(AstNode* nodep, const string& message) {
|
||||
AstNode* bodysp = newFireAssertUnchecked(nodep, message);
|
||||
bodysp = newIfAssertOn(bodysp);
|
||||
return bodysp;
|
||||
}
|
||||
@@ -105,7 +111,9 @@ private:
|
||||
//
|
||||
AstNode* bodysp = NULL;
|
||||
bool selfDestruct = false;
|
||||
AstIf* ifp = NULL;
|
||||
if (AstPslCover* snodep = nodep->castPslCover()) {
|
||||
++m_statAsCover;
|
||||
if (!v3Global.opt.coverageUser()) {
|
||||
selfDestruct = true;
|
||||
} else {
|
||||
@@ -116,14 +124,30 @@ private:
|
||||
if (message!="") covincp->declp()->comment(message);
|
||||
bodysp = covincp;
|
||||
}
|
||||
|
||||
if (bodysp && stmtsp) bodysp = bodysp->addNext(stmtsp);
|
||||
ifp = new AstIf (nodep->fileline(), propp, bodysp, NULL);
|
||||
bodysp = ifp;
|
||||
|
||||
} else if (nodep->castPslAssert()) {
|
||||
++m_statAsPsl;
|
||||
// Insert an automatic error message and $stop after
|
||||
// any user-supplied statements.
|
||||
AstNode* autoMsgp = newFireAssertUnchecked(nodep, "'assert property' failed.");
|
||||
if (stmtsp) {
|
||||
stmtsp->addNext(autoMsgp);
|
||||
} else {
|
||||
stmtsp = autoMsgp;
|
||||
}
|
||||
ifp = new AstIf(nodep->fileline(), propp, NULL, stmtsp);
|
||||
// It's more LIKELY that we'll take the NULL if clause
|
||||
// than the sim-killing else clause:
|
||||
ifp->branchPred(AstBranchPred::BP_LIKELY);
|
||||
bodysp = newIfAssertOn(ifp);
|
||||
} else {
|
||||
nodep->v3fatalSrc("Unknown node type");
|
||||
}
|
||||
if (bodysp && stmtsp) bodysp = bodysp->addNext(stmtsp);
|
||||
AstIf* ifp = new AstIf (nodep->fileline(), propp, bodysp, NULL);
|
||||
bodysp = ifp;
|
||||
if (nodep->castVAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||
//
|
||||
|
||||
AstNode* newp = new AstAlways (nodep->fileline(),
|
||||
VAlwaysKwd::ALWAYS,
|
||||
sentreep,
|
||||
@@ -294,12 +318,11 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstPslCover* nodep) {
|
||||
virtual void visit(AstNodePslCoverOrAssert* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_beginp && nodep->name() == "") nodep->name(m_beginp->name());
|
||||
newPslAssertion(nodep, nodep->propp(), nodep->sentreep(),
|
||||
nodep->stmtsp(), nodep->name()); VL_DANGLING(nodep);
|
||||
++m_statAsCover;
|
||||
}
|
||||
virtual void visit(AstVAssert* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
@@ -349,6 +372,8 @@ public:
|
||||
|
||||
void V3Assert::assertAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
AssertVisitor visitor (nodep);
|
||||
{
|
||||
AssertVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("assert", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+4
-2
@@ -86,7 +86,7 @@ private:
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstPslCover* nodep) {
|
||||
virtual void visit(AstNodePslCoverOrAssert* nodep) {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
clearAssertInfo();
|
||||
nodep->iterateChildren(*this);
|
||||
@@ -136,6 +136,8 @@ public:
|
||||
|
||||
void V3AssertPre::assertPreAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
AssertPreVisitor visitor (nodep);
|
||||
{
|
||||
AssertPreVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("assertpre", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+14
-3
@@ -229,7 +229,8 @@ inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next)
|
||||
// Called on all major tree changers.
|
||||
// Only for use for those really nasty bugs relating to internals
|
||||
// Note this may be null.
|
||||
//if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<": "<<(void*)this<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
|
||||
//if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "
|
||||
// <<prefix<<": "<<(void*)this<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
|
||||
//if (debug()) {
|
||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||
// // Commenting out the section below may crash, as the tree state
|
||||
@@ -677,9 +678,17 @@ void AstNode::deleteNode() {
|
||||
this->m_op2p = (AstNode*)1;
|
||||
this->m_op3p = (AstNode*)1;
|
||||
this->m_op4p = (AstNode*)1;
|
||||
if (
|
||||
#if !defined(VL_DEBUG) || defined(VL_LEAK_CHECKS)
|
||||
delete this; // Leak massively, so each pointer is unique and we can debug easier
|
||||
1
|
||||
#else
|
||||
!v3Global.opt.debugLeak()
|
||||
#endif
|
||||
) {
|
||||
delete this;
|
||||
}
|
||||
// Else leak massively, so each pointer is unique
|
||||
// and we can debug easier.
|
||||
}
|
||||
|
||||
AstNode::~AstNode() {
|
||||
@@ -779,7 +788,9 @@ void AstNode::iterateAndNext(AstNVisitor& v) {
|
||||
niterp->m_iterpp = &niterp;
|
||||
niterp->accept(v);
|
||||
// accept may do a replaceNode and change niterp on us...
|
||||
//if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<(void*)nodep<<" now into "<<(void*)niterp<<endl); // niterp maybe NULL, so need cast
|
||||
// niterp maybe NULL, so need cast if printing
|
||||
//if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<(void*)nodep
|
||||
// <<" now into "<<(void*)niterp<<endl);
|
||||
if (!niterp) return; // Perhaps node deleted inside accept
|
||||
niterp->m_iterpp = NULL;
|
||||
if (VL_UNLIKELY(niterp!=nodep)) { // Edited node inside accept
|
||||
|
||||
+28
-15
@@ -1101,7 +1101,8 @@ public:
|
||||
AstNode* op4p() const { return m_op4p; }
|
||||
AstNodeDType* dtypep() const { return m_dtypep; }
|
||||
AstNode* clonep() const { return ((m_cloneCnt==s_cloneCntGbl)?m_clonep:NULL); }
|
||||
AstNode* firstAbovep() const { return ((backp() && backp()->nextp()!=this) ? backp() : NULL); } // Returns NULL when second or later in list
|
||||
AstNode* firstAbovep() const { // Returns NULL when second or later in list
|
||||
return ((backp() && backp()->nextp()!=this) ? backp() : NULL); }
|
||||
bool brokeExists() const;
|
||||
bool brokeExistsAbove() const;
|
||||
|
||||
@@ -1287,12 +1288,13 @@ public:
|
||||
static AstNode* addNextNull(AstNode* nodep, AstNode* newp); // Returns nodep, adds newp (maybe NULL) to end of nodep's list
|
||||
inline AstNode* addNext(AstNode* newp) { return addNext(this, newp); }
|
||||
inline AstNode* addNextNull(AstNode* newp) { return addNextNull(this, newp); }
|
||||
void addNextHere(AstNode* newp); // Adds after speced node
|
||||
void addNextHere(AstNode* newp); // Insert newp at this->nextp
|
||||
void addPrev(AstNode* newp) { replaceWith(newp); newp->addNext(this); }
|
||||
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
|
||||
void replaceWith(AstNode* newp); // Replace current node in tree with new node
|
||||
AstNode* unlinkFrBack(AstNRelinker* linkerp=NULL); // Unlink this from whoever points to it.
|
||||
AstNode* unlinkFrBackWithNext(AstNRelinker* linkerp=NULL); // Unlink this from whoever points to it, keep entire next list with unlinked node
|
||||
// Unlink this from whoever points to it, keep entire next list with unlinked node
|
||||
AstNode* unlinkFrBackWithNext(AstNRelinker* linkerp=NULL);
|
||||
void swapWith(AstNode* bp);
|
||||
void relink(AstNRelinker* linkerp); // Generally use linker->relink() instead
|
||||
void cloneRelinkNode() { cloneRelink(); }
|
||||
@@ -1321,17 +1323,20 @@ public:
|
||||
virtual bool isPure() const { return true; } // Else a $display, etc, that must be ordered with other displays
|
||||
virtual bool isBrancher() const { return false; } // Changes control flow, disable some optimizations
|
||||
virtual bool isGateOptimizable() const { return true; } // Else a AstTime etc that can't be pushed out
|
||||
virtual bool isGateDedupable() const { return isGateOptimizable(); } // GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
|
||||
// GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
|
||||
virtual bool isGateDedupable() const { return isGateOptimizable(); }
|
||||
virtual bool isSubstOptimizable() const { return true; } // Else a AstTime etc that can't be substituted out
|
||||
virtual bool isPredictOptimizable() const { return true; } // Else a AstTime etc which output can't be predicted from input
|
||||
virtual bool isOutputter() const { return false; } // Else creates output or exits, etc, not unconsumed
|
||||
virtual bool isUnlikely() const { return false; } // Else $stop or similar statement which means an above IF statement is unlikely to be taken
|
||||
// isUnlikely handles $stop or similar statement which means an above IF statement is unlikely to be taken
|
||||
virtual bool isUnlikely() const { return false; }
|
||||
virtual int instrCount() const { return 0; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(V3Hash::Illegal()); } // Not a node that supports it
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
virtual bool hasDType() const { return false; } // Iff has a data type; dtype() must be non null
|
||||
virtual AstNodeDType* getChildDTypep() const { return NULL; } // Iff has a non-null childDTypep(), as generic node function
|
||||
virtual bool maybePointedTo() const { return false; } // Another AstNode* may have a pointer into this node, other then normal front/back/etc.
|
||||
// Another AstNode* may have a pointer into this node, other then normal front/back/etc.
|
||||
virtual bool maybePointedTo() const { return false; }
|
||||
virtual const char* broken() const { return NULL; }
|
||||
|
||||
// INVOKERS
|
||||
@@ -1454,7 +1459,9 @@ public:
|
||||
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
|
||||
void thsp(AstNode* nodep) { return setOp3p(nodep); }
|
||||
// METHODS
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) = 0; // Set out to evaluation of a AstConst'ed
|
||||
// Set out to evaluation of a AstConst'ed
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs,
|
||||
const V3Number& rhs, const V3Number& ths) = 0;
|
||||
virtual bool cleanLhs() = 0; // True if LHS must have extra upper bits zero
|
||||
virtual bool cleanRhs() = 0; // True if RHS must have extra upper bits zero
|
||||
virtual bool cleanThs() = 0; // True if THS must have extra upper bits zero
|
||||
@@ -1740,7 +1747,8 @@ public:
|
||||
bool isNosign() const { return m_numeric.isNosign(); }
|
||||
AstNumeric numeric() const { return m_numeric; }
|
||||
int widthWords() const { return VL_WORDS_I(width()); }
|
||||
int widthMin() const { return m_widthMin?m_widthMin:m_width; } // If sized, the size, if unsized the min digits to represent it
|
||||
int widthMin() const { // If sized, the size, if unsized the min digits to represent it
|
||||
return m_widthMin?m_widthMin:m_width; }
|
||||
int widthPow2() const;
|
||||
void widthMinFromWidth() { m_widthMin = m_width; }
|
||||
bool widthSized() const { return !m_widthMin || m_widthMin==m_width; }
|
||||
@@ -1958,7 +1966,7 @@ class AstNodeFTaskRef : public AstNode {
|
||||
private:
|
||||
AstNodeFTask* m_taskp; // [AfterLink] Pointer to task referenced
|
||||
string m_name; // Name of variable
|
||||
string m_dotted; // Dotted part of scope to task or ""
|
||||
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
|
||||
string m_inlinedDots; // Dotted hierarchy flattened out
|
||||
AstPackage* m_packagep; // Package hierarchy
|
||||
public:
|
||||
@@ -2061,7 +2069,7 @@ public:
|
||||
class AstNodeRange : public AstNode {
|
||||
// A range, sized or unsized
|
||||
public:
|
||||
AstNodeRange(FileLine* fl) : AstNode (fl) { }
|
||||
explicit AstNodeRange(FileLine* fl) : AstNode (fl) { }
|
||||
ASTNODE_BASE_FUNCS(NodeRange)
|
||||
};
|
||||
|
||||
@@ -2078,11 +2086,16 @@ public:
|
||||
|
||||
inline int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; }
|
||||
inline int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; }
|
||||
inline bool AstNode::width1() const { return dtypep() && dtypep()->width()==1; } // V3Const uses to know it can optimize
|
||||
inline int AstNode::widthInstrs() const { return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1)); }
|
||||
inline bool AstNode::isDouble() const { return dtypep() && dtypep()->castBasicDType() && dtypep()->castBasicDType()->isDouble(); }
|
||||
inline bool AstNode::isString() const { return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString(); }
|
||||
inline bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); }
|
||||
inline bool AstNode::width1() const { // V3Const uses to know it can optimize
|
||||
return dtypep() && dtypep()->width()==1; }
|
||||
inline int AstNode::widthInstrs() const {
|
||||
return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1)); }
|
||||
inline bool AstNode::isDouble() const {
|
||||
return dtypep() && dtypep()->castBasicDType() && dtypep()->castBasicDType()->isDouble(); }
|
||||
inline bool AstNode::isString() const {
|
||||
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString(); }
|
||||
inline bool AstNode::isSigned() const {
|
||||
return dtypep() && dtypep()->isSigned(); }
|
||||
|
||||
inline bool AstNode::isZero() { return (this->castConst() && this->castConst()->num().isEqZero()); }
|
||||
inline bool AstNode::isNeqZero() { return (this->castConst() && this->castConst()->num().isNeqZero()); }
|
||||
|
||||
+4
-3
@@ -64,7 +64,8 @@ int AstNodeSel::bitConst() const {
|
||||
void AstNodeClassDType::repairMemberCache() {
|
||||
clearCache();
|
||||
for (AstMemberDType* itemp = membersp(); itemp; itemp=itemp->nextp()->castMemberDType()) {
|
||||
if (m_members.find(itemp->name())!=m_members.end()) { itemp->v3error("Duplicate declaration of member name: "<<itemp->prettyName()); }
|
||||
if (m_members.find(itemp->name())!=m_members.end()) {
|
||||
itemp->v3error("Duplicate declaration of member name: "<<itemp->prettyName()); }
|
||||
else m_members.insert(make_pair(itemp->name(), itemp));
|
||||
}
|
||||
}
|
||||
@@ -1023,7 +1024,7 @@ void AstVarXRef::dump(ostream& str) {
|
||||
if (packagep()) { str<<" pkg="<<(void*)packagep(); }
|
||||
if (lvalue()) str<<" [LV] => ";
|
||||
else str<<" [RV] <- ";
|
||||
str<<dotted()<<". - ";
|
||||
str<<".="<<dotted()<<" ";
|
||||
if (inlinedDots()!="") str<<" inline.="<<inlinedDots()<<" - ";
|
||||
if (varScopep()) { varScopep()->dump(str); }
|
||||
else if (varp()) { varp()->dump(str); }
|
||||
@@ -1094,7 +1095,7 @@ void AstNodeFTaskRef::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (packagep()) { str<<" pkg="<<(void*)packagep(); }
|
||||
str<<" -> ";
|
||||
if (dotted()!="") { str<<dotted()<<". - "; }
|
||||
if (dotted()!="") { str<<".="<<dotted()<<" "; }
|
||||
if (taskp()) { taskp()->dump(str); }
|
||||
else { str<<"UNLINKED"; }
|
||||
}
|
||||
|
||||
+290
-102
@@ -149,7 +149,7 @@ public:
|
||||
class AstUnsizedRange : public AstNodeRange {
|
||||
// Unsized range specification, for open arrays
|
||||
public:
|
||||
AstUnsizedRange(FileLine* fl) : AstNodeRange(fl) { }
|
||||
explicit AstUnsizedRange(FileLine* fl) : AstNodeRange(fl) { }
|
||||
ASTNODE_NODE_FUNCS(UnsizedRange)
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual string emitVerilog() { return "[]"; }
|
||||
@@ -706,13 +706,17 @@ public:
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
|
||||
virtual bool similarDType(AstNodeDType* samep) const { return this==samep; }
|
||||
//
|
||||
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
// (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); }
|
||||
// op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
|
||||
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
|
||||
virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); }
|
||||
virtual AstNodeDType* skipRefToEnump() const { return subDTypep()->skipRefToEnump(); }
|
||||
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
|
||||
// (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
|
||||
// METHODS
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
virtual void tag(const string& text) { m_tag = text;}
|
||||
@@ -1183,7 +1187,8 @@ public:
|
||||
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
|
||||
string cPubArgType(bool named, bool forReturn) const; // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
|
||||
string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument
|
||||
string vlArgType(bool named, bool forReturn, bool forFunc) const; // Return Verilator internal type for argument: CData, SData, IData, WData
|
||||
// Return Verilator internal type for argument: CData, SData, IData, WData
|
||||
string vlArgType(bool named, bool forReturn, bool forFunc) const;
|
||||
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
|
||||
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc
|
||||
string vlPropInit() const; // Return VerilatorVarProps initializer
|
||||
@@ -1191,7 +1196,8 @@ public:
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
|
||||
AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
// (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
AstBasicDType* basicp() const { return subDTypep()->basicp(); }
|
||||
AstNode* valuep() const { return op3p(); } // op3 = Initial value that never changes (static const)
|
||||
void valuep(AstNode* nodep) { setOp3p(nodep); } // It's valuep, not constp, as may be more complicated than an AstConst
|
||||
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
|
||||
@@ -1443,11 +1449,14 @@ class AstVarRef : public AstNodeVarRef {
|
||||
// A reference to a variable (lvalue or rvalue)
|
||||
public:
|
||||
AstVarRef(FileLine* fl, const string& name, bool lvalue)
|
||||
:AstNodeVarRef(fl, name, NULL, lvalue) {}
|
||||
AstVarRef(FileLine* fl, AstVar* varp, bool lvalue) // This form only allowed post-link
|
||||
:AstNodeVarRef(fl, varp->name(), varp, lvalue) {} // because output/wire compression may lead to deletion of AstVar's
|
||||
AstVarRef(FileLine* fl, AstVarScope* varscp, bool lvalue) // This form only allowed post-link
|
||||
:AstNodeVarRef(fl, varscp->varp()->name(), varscp->varp(), lvalue) { // because output/wire compression may lead to deletion of AstVar's
|
||||
: AstNodeVarRef(fl, name, NULL, lvalue) {}
|
||||
// This form only allowed post-link because output/wire compression may
|
||||
// lead to deletion of AstVar's
|
||||
AstVarRef(FileLine* fl, AstVar* varp, bool lvalue)
|
||||
: AstNodeVarRef(fl, varp->name(), varp, lvalue) {}
|
||||
// This form only allowed post-link (see above)
|
||||
AstVarRef(FileLine* fl, AstVarScope* varscp, bool lvalue)
|
||||
: AstNodeVarRef(fl, varscp->varp()->name(), varscp->varp(), lvalue) {
|
||||
varScopep(varscp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(VarRef)
|
||||
@@ -1475,7 +1484,7 @@ class AstVarXRef : public AstNodeVarRef {
|
||||
// A VarRef to something in another module before AstScope.
|
||||
// Includes pin on a cell, as part of a ASSIGN statement to connect I/Os until AstScope
|
||||
private:
|
||||
string m_dotted; // Scope name to connected to
|
||||
string m_dotted; // Dotted part of scope the name()'ed reference is under or ""
|
||||
string m_inlinedDots; // Dotted hierarchy flattened out
|
||||
public:
|
||||
AstVarXRef(FileLine* fl, const string& name, const string& dotted, bool lvalue)
|
||||
@@ -2331,7 +2340,9 @@ public:
|
||||
ASTNODE_NODE_FUNCS(CoverDecl)
|
||||
virtual const char* broken() const {
|
||||
BROKEN_RTN(m_dataDeclp && !m_dataDeclp->brokeExists());
|
||||
if (m_dataDeclp && m_dataDeclp->m_dataDeclp) v3fatalSrc("dataDeclp should point to real data, not be a list"); // Avoid O(n^2) accessing
|
||||
if (m_dataDeclp && m_dataDeclp->m_dataDeclp) { // Avoid O(n^2) accessing
|
||||
v3fatalSrc("dataDeclp should point to real data, not be a list");
|
||||
}
|
||||
return NULL; }
|
||||
virtual void cloneRelink() { if (m_dataDeclp && m_dataDeclp->clonep()) m_dataDeclp = m_dataDeclp->clonep(); }
|
||||
virtual void dump(ostream& str);
|
||||
@@ -2594,6 +2605,26 @@ public:
|
||||
void lhsp(AstNode* nodep) { setOp3p(nodep); }
|
||||
};
|
||||
|
||||
class AstSysFuncAsTask : public AstNodeStmt {
|
||||
// Call what is normally a system function (with a return) in a non-return context
|
||||
// Parents: stmtlist
|
||||
// Children: a system function
|
||||
public:
|
||||
AstSysFuncAsTask(FileLine* fileline, AstNode* exprsp)
|
||||
: AstNodeStmt (fileline) { addNOp1p(exprsp); }
|
||||
ASTNODE_NODE_FUNCS(SysFuncAsTask)
|
||||
virtual string verilogKwd() const { return ""; }
|
||||
virtual bool isGateOptimizable() const { return true; }
|
||||
virtual bool isPredictOptimizable() const { return true; }
|
||||
virtual bool isPure() const { return true; }
|
||||
virtual bool isOutputter() const { return false; }
|
||||
virtual int instrCount() const { return 0; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
AstNode* lhsp() const { return op1p(); } // op1 = Expressions to eval
|
||||
void lhsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to eval
|
||||
};
|
||||
|
||||
class AstSysIgnore : public AstNodeStmt {
|
||||
// Parents: stmtlist
|
||||
// Children: varrefs or exprs
|
||||
@@ -2742,17 +2773,16 @@ public:
|
||||
void fromp(AstNode* nodep) { setOp2p(nodep); }
|
||||
};
|
||||
|
||||
class AstReadMem : public AstNodeStmt {
|
||||
class AstNodeReadWriteMem : public AstNodeStmt {
|
||||
private:
|
||||
bool m_isHex; // readmemh, not readmemb
|
||||
public:
|
||||
AstReadMem(FileLine* fileline, bool hex,
|
||||
AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp)
|
||||
AstNodeReadWriteMem(FileLine* fileline, bool hex,
|
||||
AstNode* filenamep, AstNode* memp,
|
||||
AstNode* lsbp, AstNode* msbp)
|
||||
: AstNodeStmt (fileline), m_isHex(hex) {
|
||||
setOp1p(filenamep); setOp2p(memp); setNOp3p(lsbp); setNOp4p(msbp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ReadMem)
|
||||
virtual string verilogKwd() const { return (isHex()?"$readmemh":"$readmemb"); }
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual bool isPure() const { return false; }
|
||||
@@ -2760,12 +2790,35 @@ public:
|
||||
virtual bool isUnlikely() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(const AstNode* samep) const {
|
||||
return isHex()==static_cast<const AstReadMem*>(samep)->isHex(); }
|
||||
return isHex()==static_cast<const AstNodeReadWriteMem*>(samep)->isHex();
|
||||
}
|
||||
bool isHex() const { return m_isHex; }
|
||||
AstNode* filenamep() const { return op1p(); }
|
||||
AstNode* memp() const { return op2p(); }
|
||||
AstNode* lsbp() const { return op3p(); }
|
||||
AstNode* msbp() const { return op4p(); }
|
||||
virtual const char* cFuncPrefixp() const = 0;
|
||||
};
|
||||
|
||||
class AstReadMem : public AstNodeReadWriteMem {
|
||||
public:
|
||||
AstReadMem(FileLine* fileline, bool hex,
|
||||
AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp)
|
||||
: AstNodeReadWriteMem(fileline, hex, filenamep, memp, lsbp, msbp)
|
||||
{ }
|
||||
ASTNODE_NODE_FUNCS(ReadMem);
|
||||
virtual string verilogKwd() const { return (isHex()?"$readmemh":"$readmemb"); }
|
||||
virtual const char* cFuncPrefixp() const { return "VL_READMEM_"; }
|
||||
};
|
||||
|
||||
class AstWriteMem : public AstNodeReadWriteMem {
|
||||
public:
|
||||
AstWriteMem(FileLine* fileline,
|
||||
AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp)
|
||||
: AstNodeReadWriteMem(fileline, true, filenamep, memp, lsbp, msbp) { }
|
||||
ASTNODE_NODE_FUNCS(WriteMem)
|
||||
virtual string verilogKwd() const { return (isHex()?"$writememh":"$writememb"); }
|
||||
virtual const char* cFuncPrefixp() const { return "VL_WRITEMEM_"; }
|
||||
};
|
||||
|
||||
class AstSystemT : public AstNodeStmt {
|
||||
@@ -3420,10 +3473,14 @@ public:
|
||||
void scopeAttrp(AstNode* nodep) { addOp1p(nodep); }
|
||||
AstText* scopeEntrp() const { return op2p()->castText(); }
|
||||
void scopeEntrp(AstNode* nodep) { addOp2p(nodep); }
|
||||
string scopeSymName() const { return scopeNameFormatter(scopeAttrp()); } // Name for __Vscope variable including children
|
||||
string scopeDpiName() const { return scopeNameFormatter(scopeEntrp()); } // Name for DPI import scope
|
||||
string scopePrettySymName() const { return scopePrettyNameFormatter(scopeAttrp()); } // Name for __Vscope variable including children
|
||||
string scopePrettyDpiName() const { return scopePrettyNameFormatter(scopeEntrp()); } // Name for __Vscope variable including children
|
||||
string scopeSymName() const { // Name for __Vscope variable including children
|
||||
return scopeNameFormatter(scopeAttrp()); }
|
||||
string scopeDpiName() const { // Name for DPI import scope
|
||||
return scopeNameFormatter(scopeEntrp()); }
|
||||
string scopePrettySymName() const { // Name for __Vscope variable including children
|
||||
return scopePrettyNameFormatter(scopeAttrp()); }
|
||||
string scopePrettyDpiName() const { // Name for __Vscope variable including children
|
||||
return scopePrettyNameFormatter(scopeEntrp()); }
|
||||
bool dpiExport() const { return m_dpiExport; }
|
||||
void dpiExport(bool flag) { m_dpiExport=flag; }
|
||||
};
|
||||
@@ -3947,94 +4004,176 @@ public:
|
||||
AstNode* filep() const { return lhsp(); }
|
||||
};
|
||||
|
||||
class AstCeilD : public AstNodeUniop {
|
||||
class AstNodeSystemUniop : public AstNodeUniop {
|
||||
public:
|
||||
AstCeilD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
dtypeSetDouble(); }
|
||||
ASTNODE_NODE_FUNCS(CeilD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(ceil(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$ceil(%l)"; }
|
||||
virtual string emitC() { return "ceil(%li)"; }
|
||||
AstNodeSystemUniop(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
dtypeSetDouble(); }
|
||||
ASTNODE_BASE_FUNCS(NodeSystemUniop)
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
class AstExpD : public AstNodeUniop {
|
||||
class AstLogD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstExpD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
dtypeSetDouble(); }
|
||||
ASTNODE_NODE_FUNCS(ExpD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(exp(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$exp(%l)"; }
|
||||
virtual string emitC() { return "exp(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
class AstFloorD : public AstNodeUniop {
|
||||
public:
|
||||
AstFloorD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
dtypeSetDouble(); }
|
||||
ASTNODE_NODE_FUNCS(FloorD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(floor(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$floor(%l)"; }
|
||||
virtual string emitC() { return "floor(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
class AstLogD : public AstNodeUniop {
|
||||
public:
|
||||
AstLogD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
dtypeSetDouble(); }
|
||||
AstLogD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(LogD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(log(lhs.toDouble())); }
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(log(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$ln(%l)"; }
|
||||
virtual string emitC() { return "log(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
class AstLog10D : public AstNodeUniop {
|
||||
class AstLog10D : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstLog10D(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
dtypeSetDouble(); }
|
||||
AstLog10D(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(Log10D)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(log10(lhs.toDouble())); }
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(log10(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$log10(%l)"; }
|
||||
virtual string emitC() { return "log10(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
class AstSqrtD : public AstNodeUniop {
|
||||
class AstExpD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstSqrtD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
dtypeSetDouble(); }
|
||||
AstExpD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(ExpD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(exp(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$exp(%l)"; }
|
||||
virtual string emitC() { return "exp(%li)"; }
|
||||
};
|
||||
|
||||
class AstSqrtD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstSqrtD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(SqrtD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(sqrt(lhs.toDouble())); }
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(sqrt(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$sqrt(%l)"; }
|
||||
virtual string emitC() { return "sqrt(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
class AstFloorD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstFloorD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(FloorD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(floor(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$floor(%l)"; }
|
||||
virtual string emitC() { return "floor(%li)"; }
|
||||
};
|
||||
|
||||
class AstCeilD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstCeilD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(CeilD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(ceil(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$ceil(%l)"; }
|
||||
virtual string emitC() { return "ceil(%li)"; }
|
||||
};
|
||||
|
||||
class AstSinD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstSinD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(SinD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(sin(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$sin(%l)"; }
|
||||
virtual string emitC() { return "sin(%li)"; }
|
||||
};
|
||||
|
||||
class AstCosD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstCosD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(CosD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(cos(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$cos(%l)"; }
|
||||
virtual string emitC() { return "cos(%li)"; }
|
||||
};
|
||||
|
||||
class AstTanD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstTanD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(TanD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(tan(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$tan(%l)"; }
|
||||
virtual string emitC() { return "tan(%li)"; }
|
||||
};
|
||||
|
||||
class AstAsinD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstAsinD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(AsinD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(asin(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$asin(%l)"; }
|
||||
virtual string emitC() { return "asin(%li)"; }
|
||||
};
|
||||
|
||||
class AstAcosD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstAcosD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(AcosD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(acos(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$acos(%l)"; }
|
||||
virtual string emitC() { return "acos(%li)"; }
|
||||
};
|
||||
|
||||
class AstAtanD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstAtanD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(AtanD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(atan(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$atan(%l)"; }
|
||||
virtual string emitC() { return "atan(%li)"; }
|
||||
};
|
||||
|
||||
class AstSinhD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstSinhD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(SinhD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(sinh(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$sinh(%l)"; }
|
||||
virtual string emitC() { return "sinh(%li)"; }
|
||||
};
|
||||
|
||||
class AstCoshD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstCoshD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(CoshD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(cosh(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$cosh(%l)"; }
|
||||
virtual string emitC() { return "cosh(%li)"; }
|
||||
};
|
||||
|
||||
class AstTanhD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstTanhD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(TanhD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(tanh(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$tanh(%l)"; }
|
||||
virtual string emitC() { return "tanh(%li)"; }
|
||||
};
|
||||
|
||||
class AstAsinhD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstAsinhD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(AsinhD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(asinh(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$asinh(%l)"; }
|
||||
virtual string emitC() { return "asinh(%li)"; }
|
||||
};
|
||||
|
||||
class AstAcoshD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstAcoshD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(AcoshD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(acosh(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$acosh(%l)"; }
|
||||
virtual string emitC() { return "acosh(%li)"; }
|
||||
};
|
||||
|
||||
class AstAtanhD : public AstNodeSystemUniop {
|
||||
public:
|
||||
AstAtanhD(FileLine* fl, AstNode* lhsp) : AstNodeSystemUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(AtanhD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.setDouble(atanh(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$atanh(%l)"; }
|
||||
virtual string emitC() { return "atanh(%li)"; }
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
@@ -4525,7 +4664,9 @@ public:
|
||||
virtual string emitSimpleOperator() { return ">>"; }
|
||||
virtual bool cleanOut() {return false;}
|
||||
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} // LHS size might be > output size, so don't want to force size
|
||||
// LHS size might be > output size, so don't want to force size
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual bool sizeMattersRhs() {return false;}
|
||||
};
|
||||
class AstShiftRS : public AstNodeBiop {
|
||||
// Shift right with sign extension, >>> operator
|
||||
@@ -5004,6 +5145,39 @@ public:
|
||||
AstNode* filep() const { return rhsp(); }
|
||||
};
|
||||
|
||||
class AstNodeSystemBiop : public AstNodeBiop {
|
||||
public:
|
||||
AstNodeSystemBiop(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
dtypeSetDouble(); }
|
||||
virtual bool cleanOut() {return false;}
|
||||
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
class AstAtan2D : public AstNodeSystemBiop {
|
||||
public:
|
||||
AstAtan2D(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeSystemBiop(fl, lhsp, rhsp) {}
|
||||
ASTNODE_NODE_FUNCS(Atan2D)
|
||||
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAtan2D(this->fileline(), lhsp, rhsp); }
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) {
|
||||
out.setDouble(atan2(lhs.toDouble(), rhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$atan2(%l,%r)"; }
|
||||
virtual string emitC() { return "atan2(%li,%ri)"; }
|
||||
};
|
||||
|
||||
class AstHypotD : public AstNodeSystemBiop {
|
||||
public:
|
||||
AstHypotD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeSystemBiop(fl, lhsp, rhsp) {}
|
||||
ASTNODE_NODE_FUNCS(HypotD)
|
||||
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstHypotD(this->fileline(), lhsp, rhsp); }
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) {
|
||||
out.setDouble(hypot(lhs.toDouble(), rhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$hypot(%l,%r)"; }
|
||||
virtual string emitC() { return "hypot(%li,%ri)"; }
|
||||
};
|
||||
|
||||
class AstPattern : public AstNodeMath {
|
||||
// Verilog '{a,b,c,d...}
|
||||
// Parents: AstNodeAssign, AstPattern, ...
|
||||
@@ -5109,30 +5283,44 @@ public:
|
||||
AstNode* propp() const { return op3p(); } // op3 = property
|
||||
};
|
||||
|
||||
class AstPslCover : public AstNodeStmt {
|
||||
class AstNodePslCoverOrAssert : public AstNodeStmt {
|
||||
// Psl Cover
|
||||
// Parents: {statement list}
|
||||
// Children: expression, report string
|
||||
private:
|
||||
string m_name; // Name to report
|
||||
public:
|
||||
AstPslCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, const string& name="")
|
||||
AstNodePslCoverOrAssert(FileLine* fl, AstNode* propp, AstNode* stmtsp, const string& name="")
|
||||
: AstNodeStmt(fl)
|
||||
, m_name(name) {
|
||||
addOp1p(propp);
|
||||
addNOp4p(stmtsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(PslCover)
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
ASTNODE_BASE_FUNCS(NodePslCoverOrAssert)
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
virtual V3Hash sameHash() const { return V3Hash(name()); }
|
||||
virtual bool same(const AstNode* samep) const { return samep->name() == name(); }
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
AstNode* propp() const { return op1p(); } // op1 = property
|
||||
AstSenTree* sentreep() const { return op2p()->castSenTree(); } // op2 = clock domain
|
||||
void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain
|
||||
AstNode* coverincp() const { return op3p(); } // op3 = coverage node
|
||||
void coverincp(AstCoverInc* nodep) { addOp3p(nodep); } // op3 = coverage node
|
||||
AstNode* stmtsp() const { return op4p(); } // op4 = statements
|
||||
AstNode* propp() const { return op1p(); } // op1 = property
|
||||
AstSenTree* sentreep() const { return op2p()->castSenTree(); } // op2 = clock domain
|
||||
void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain
|
||||
AstNode* stmtsp() const { return op4p(); } // op4 = statements
|
||||
};
|
||||
|
||||
class AstPslCover : public AstNodePslCoverOrAssert {
|
||||
public:
|
||||
ASTNODE_NODE_FUNCS(PslCover)
|
||||
AstPslCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, const string& name="")
|
||||
: AstNodePslCoverOrAssert(fl, propp, stmtsp, name) {}
|
||||
AstNode* coverincp() const { return op3p(); } // op3 = coverage node
|
||||
void coverincp(AstCoverInc* nodep) { addOp3p(nodep); } // op3 = coverage node
|
||||
};
|
||||
|
||||
class AstPslAssert : public AstNodePslCoverOrAssert {
|
||||
public:
|
||||
ASTNODE_NODE_FUNCS(PslAssert)
|
||||
AstPslAssert(FileLine* fl, AstNode* propp, AstNode* stmtsp, const string& name="")
|
||||
: AstNodePslCoverOrAssert(fl, propp, stmtsp, name) {}
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
|
||||
+7
-5
@@ -291,10 +291,12 @@ public:
|
||||
|
||||
void V3Begin::debeginAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
BeginState state;
|
||||
{ BeginVisitor bvisitor (nodep,&state); }
|
||||
if (state.anyFuncInBegin()) {
|
||||
BeginRelinkVisitor brvisitor (nodep,&state);
|
||||
}
|
||||
{
|
||||
BeginState state;
|
||||
{ BeginVisitor bvisitor (nodep,&state); }
|
||||
if (state.anyFuncInBegin()) {
|
||||
BeginRelinkVisitor brvisitor (nodep,&state);
|
||||
}
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("begin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+5
-2
@@ -224,8 +224,11 @@ private:
|
||||
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo): "<<whyp);
|
||||
}
|
||||
if (nodep->dtypep()) {
|
||||
if (!nodep->dtypep()->brokeExists()) { nodep->v3fatalSrc("Broken link in node->dtypep() to "<<(void*)nodep->dtypep()); }
|
||||
else if (!nodep->dtypep()->castNodeDType()) { nodep->v3fatalSrc("Non-dtype link in node->dtypep() to "<<(void*)nodep->dtypep()); }
|
||||
if (!nodep->dtypep()->brokeExists()) {
|
||||
nodep->v3fatalSrc("Broken link in node->dtypep() to "<<(void*)nodep->dtypep());
|
||||
} else if (!nodep->dtypep()->castNodeDType()) {
|
||||
nodep->v3fatalSrc("Non-dtype link in node->dtypep() to "<<(void*)nodep->dtypep());
|
||||
}
|
||||
}
|
||||
if (v3Global.assertDTypesResolved()) {
|
||||
if (nodep->hasDType()) {
|
||||
|
||||
+4
-2
@@ -77,7 +77,8 @@ public:
|
||||
m_numStmts += 1;
|
||||
}
|
||||
|
||||
V3CCtorsVisitor(AstNodeModule* nodep, string basename, string argsp="", string callargsp="",
|
||||
V3CCtorsVisitor(AstNodeModule* nodep, const string& basename,
|
||||
const string& argsp="", const string& callargsp="",
|
||||
const string& stmt="") {
|
||||
m_basename = basename;
|
||||
m_argsp = argsp;
|
||||
@@ -129,7 +130,8 @@ void V3CCtors::evalAsserts() {
|
||||
newp = new AstAnd(varp->fileline(), newp,
|
||||
new AstConst(varp->fileline(), num));
|
||||
AstNodeIf* ifp = new AstIf(varp->fileline(), newp,
|
||||
new AstCStmt(varp->fileline(), "Verilated::overWidthError(\""+varp->prettyName()+"\");"));
|
||||
new AstCStmt(varp->fileline(),
|
||||
"Verilated::overWidthError(\""+varp->prettyName()+"\");"));
|
||||
ifp->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||
newp = ifp;
|
||||
funcp->addStmtsp(newp);
|
||||
|
||||
+3
-1
@@ -488,7 +488,9 @@ public:
|
||||
|
||||
void V3Case::caseAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
CaseVisitor visitor (nodep);
|
||||
{
|
||||
CaseVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("case", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
void V3Case::caseLint(AstNodeCase* nodep) {
|
||||
|
||||
+3
-1
@@ -187,6 +187,8 @@ public:
|
||||
|
||||
void V3Cast::castAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
CastVisitor visitor (nodep);
|
||||
{
|
||||
CastVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("cast", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+10
-4
@@ -175,13 +175,17 @@ private:
|
||||
newChangeDet();
|
||||
} else {
|
||||
if (debug()) nodep->dumpTree(cout,"-DETECTARRAY-class-");
|
||||
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable (probably with UNOPTFLAT warning suppressed): "<<m_vscp->varp()->prettyName());
|
||||
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable"
|
||||
" (probably with UNOPTFLAT warning suppressed): "
|
||||
<<m_vscp->varp()->prettyName());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (debug()) nodep->dumpTree(cout,"-DETECTARRAY-general-");
|
||||
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable (probably with UNOPTFLAT warning suppressed): "<<m_vscp->varp()->prettyName());
|
||||
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable"
|
||||
" (probably with UNOPTFLAT warning suppressed): "
|
||||
<<m_vscp->varp()->prettyName());
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
@@ -300,7 +304,9 @@ public:
|
||||
|
||||
void V3Changed::changedAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ChangedState state;
|
||||
ChangedVisitor visitor (nodep, &state);
|
||||
{
|
||||
ChangedState state;
|
||||
ChangedVisitor visitor (nodep, &state);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("changed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+3
-1
@@ -297,6 +297,8 @@ public:
|
||||
|
||||
void V3Clean::cleanAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
CleanVisitor visitor (nodep);
|
||||
{
|
||||
CleanVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("clean", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+4
-2
@@ -912,8 +912,10 @@ public:
|
||||
|
||||
void V3ClkGater::clkGaterAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
// While the gater does well at some modules, it seems to slow down many others
|
||||
UINFO(5,"ClkGater is disabled due to performance issues\n");
|
||||
{
|
||||
// While the gater does well at some modules, it seems to slow down many others
|
||||
UINFO(5,"ClkGater is disabled due to performance issues\n");
|
||||
} // Destruct before checking
|
||||
//GaterVisitor visitor (nodep);
|
||||
V3Global::dumpCheckGlobalTree("clkgater", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+3
-1
@@ -406,6 +406,8 @@ public:
|
||||
|
||||
void V3Clock::clockAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ClockVisitor visitor (nodep);
|
||||
{
|
||||
ClockVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("clock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+3
-1
@@ -473,6 +473,8 @@ public:
|
||||
|
||||
void V3Combine::combineAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
CombineVisitor visitor (nodep);
|
||||
{
|
||||
CombineVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("combine", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ V3ConfigIgnores V3ConfigIgnores::s_singleton;
|
||||
//######################################################################
|
||||
// V3Config
|
||||
|
||||
void V3Config::addIgnore(V3ErrorCode code, bool on, string filename, int min, int max) {
|
||||
void V3Config::addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max) {
|
||||
if (filename=="*") {
|
||||
FileLine::globalWarnOff(code,!on);
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@
|
||||
|
||||
class V3Config {
|
||||
public:
|
||||
static void addIgnore(V3ErrorCode code, bool on, string filename, int min, int max);
|
||||
static void addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max);
|
||||
static void applyIgnores(FileLine* filelinep);
|
||||
};
|
||||
|
||||
|
||||
+18
-9
@@ -1202,7 +1202,8 @@ private:
|
||||
AstAnd* newp = new AstAnd(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), val),
|
||||
fromp);
|
||||
newp->dtypeSetLogicSized(nodep->width(), nodep->width(), AstNumeric::UNSIGNED); // widthMin no longer applicable if different C-expanded width
|
||||
// widthMin no longer applicable if different C-expanded width
|
||||
newp->dtypeSetLogicSized(nodep->width(), nodep->width(), AstNumeric::UNSIGNED);
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
if (debug()>=9) newp->dumpTree(cout," _new: ");
|
||||
@@ -2559,15 +2560,19 @@ AstNode* V3Const::constifyGenerateParamsEdit(AstNode* nodep) {
|
||||
void V3Const::constifyAllLint(AstNetlist* nodep) {
|
||||
// Only call from Verilator.cpp, as it uses user#'s
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ConstVisitor visitor (ConstVisitor::PROC_V_WARN);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
{
|
||||
ConstVisitor visitor (ConstVisitor::PROC_V_WARN);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Const::constifyCpp(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ConstVisitor visitor (ConstVisitor::PROC_CPP);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
{
|
||||
ConstVisitor visitor (ConstVisitor::PROC_CPP);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("const_cpp", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
@@ -2582,16 +2587,20 @@ void V3Const::constifyAllLive(AstNetlist* nodep) {
|
||||
// This only pushes constants up, doesn't make any other edits
|
||||
// IE doesn't prune dead statements, as we need to do some usability checks after this
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ConstVisitor visitor (ConstVisitor::PROC_LIVE);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
{
|
||||
ConstVisitor visitor (ConstVisitor::PROC_LIVE);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Const::constifyAll(AstNetlist* nodep) {
|
||||
// Only call from Verilator.cpp, as it uses user#'s
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ConstVisitor visitor (ConstVisitor::PROC_V_EXPENSIVE);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
{
|
||||
ConstVisitor visitor (ConstVisitor::PROC_V_EXPENSIVE);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -395,6 +395,8 @@ public:
|
||||
|
||||
void V3Coverage::coverage(AstNetlist* rootp) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
CoverageVisitor visitor (rootp);
|
||||
{
|
||||
CoverageVisitor visitor (rootp);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("coverage", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
@@ -134,6 +134,8 @@ public:
|
||||
|
||||
void V3CoverageJoin::coverageJoin(AstNetlist* rootp) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
CoverageJoinVisitor visitor (rootp);
|
||||
{
|
||||
CoverageJoinVisitor visitor (rootp);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("coveragejoin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+15
-5
@@ -425,30 +425,40 @@ public:
|
||||
|
||||
void V3Dead::deadifyModules(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
DeadVisitor visitor (nodep, false, false, false, false);
|
||||
{
|
||||
DeadVisitor visitor (nodep, false, false, false, false);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadModules", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
||||
void V3Dead::deadifyDTypes(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
DeadVisitor visitor (nodep, false, true, false, false);
|
||||
{
|
||||
DeadVisitor visitor (nodep, false, true, false, false);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadDtypes", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
DeadVisitor visitor (nodep, false, true, true, false);
|
||||
{
|
||||
DeadVisitor visitor (nodep, false, true, true, false);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Dead::deadifyAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
DeadVisitor visitor (nodep, true, true, false, true);
|
||||
{
|
||||
DeadVisitor visitor (nodep, true, true, false, true);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadAll", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Dead::deadifyAllScoped(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
DeadVisitor visitor (nodep, true, true, true, true);
|
||||
{
|
||||
DeadVisitor visitor (nodep, true, true, true, true);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadAllScoped", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+15
-7
@@ -115,7 +115,8 @@ private:
|
||||
//UINFO(4," MVU "<<flags<<" "<<nodep<<endl);
|
||||
nodep->user5( nodep->user5() | flags );
|
||||
if ((nodep->user5() & VU_DLY) && (nodep->user5() & VU_NONDLY)) {
|
||||
nodep->v3warn(BLKANDNBLK,"Unsupported: Blocked and non-blocking assignments to same variable: "<<nodep->varp()->prettyName());
|
||||
nodep->v3warn(BLKANDNBLK,"Unsupported: Blocked and non-blocking assignments to same variable: "
|
||||
<<nodep->varp()->prettyName());
|
||||
}
|
||||
}
|
||||
AstVarScope* createVarSc(AstVarScope* oldvarscp, string name, int width/*0==fromoldvar*/, AstNodeDType* newdtypep) {
|
||||
@@ -149,7 +150,8 @@ private:
|
||||
AstActive* createActivePost(AstVarRef* varrefp) {
|
||||
AstActive* newactp = new AstActive (varrefp->fileline(), "sequentdly",
|
||||
m_activep->sensesp());
|
||||
m_activep->addNext(newactp);
|
||||
// Was addNext(), but addNextHere() avoids a linear search.
|
||||
m_activep->addNextHere(newactp);
|
||||
return newactp;
|
||||
}
|
||||
void checkActivePost(AstVarRef* varrefp, AstActive* oldactivep) {
|
||||
@@ -158,7 +160,8 @@ private:
|
||||
if (oldactivep->sensesp() != m_activep->sensesp()) {
|
||||
if (!varrefp->varp()->fileline()->warnIsOff(V3ErrorCode::MULTIDRIVEN)
|
||||
&& !varrefp->varp()->user2()) {
|
||||
varrefp->varp()->v3warn(MULTIDRIVEN,"Signal has multiple driving blocks with different clocking: "<<varrefp->varp()->prettyName()<<endl
|
||||
varrefp->varp()->v3warn(MULTIDRIVEN,"Signal has multiple driving blocks with different clocking: "
|
||||
<<varrefp->varp()->prettyName()<<endl
|
||||
<<varrefp->warnMore()<<"... Location of first driving block"<<endl
|
||||
<<oldactivep->warnMore()<<"... Location of other driving block");
|
||||
varrefp->varp()->user2(true);
|
||||
@@ -195,8 +198,9 @@ private:
|
||||
arrayselp = lhsp->castArraySel();
|
||||
}
|
||||
if (!arrayselp) nodep->v3fatalSrc("No arraysel under bitsel?");
|
||||
if (arrayselp->dtypep()->skipRefp()->castUnpackArrayDType()) nodep->v3fatalSrc("ArraySel with unpacked arrays should have been removed in V3Slice");
|
||||
|
||||
if (arrayselp->dtypep()->skipRefp()->castUnpackArrayDType()) {
|
||||
nodep->v3fatalSrc("ArraySel with unpacked arrays should have been removed in V3Slice");
|
||||
}
|
||||
UINFO(4,"AssignDlyArray: "<<nodep<<endl);
|
||||
//
|
||||
//=== Dimensions: __Vdlyvdim__
|
||||
@@ -391,7 +395,9 @@ private:
|
||||
UINFO(4,"AssignDlyVar: "<<nodep<<endl);
|
||||
markVarUsage(nodep->varScopep(), VU_DLY);
|
||||
if (!m_activep) nodep->v3fatalSrc("<= not under sensitivity block");
|
||||
if (!m_activep->hasClocked()) nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should have converted in V3Active");
|
||||
if (!m_activep->hasClocked()) {
|
||||
nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should have converted in V3Active");
|
||||
}
|
||||
AstVarScope* oldvscp = nodep->varScopep();
|
||||
if (!oldvscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
|
||||
AstVarScope* dlyvscp = oldvscp->user1p()->castVarScope();
|
||||
@@ -470,6 +476,8 @@ public:
|
||||
|
||||
void V3Delayed::delayedAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
DelayedVisitor visitor (nodep);
|
||||
{
|
||||
DelayedVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("delayed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+3
-1
@@ -174,6 +174,8 @@ public:
|
||||
|
||||
void V3Depth::depthAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
DepthVisitor visitor (nodep);
|
||||
{
|
||||
DepthVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("depth", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
||||
@@ -139,6 +139,8 @@ public:
|
||||
|
||||
void V3DepthBlock::depthBlockAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
DepthBlockVisitor visitor (nodep);
|
||||
{
|
||||
DepthBlockVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deepblock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+3
-1
@@ -311,6 +311,8 @@ public:
|
||||
|
||||
void V3Descope::descopeAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
DescopeVisitor visitor (nodep);
|
||||
{
|
||||
DescopeVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("descope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+122
-91
@@ -78,7 +78,8 @@ public:
|
||||
typedef enum {EVL_CLASS_IO, EVL_CLASS_SIG, EVL_CLASS_TEMP, EVL_CLASS_PAR, EVL_CLASS_ALL,
|
||||
EVL_FUNC_ALL} EisWhich;
|
||||
void emitVarList(AstNode* firstp, EisWhich which, const string& prefixIfImp);
|
||||
void emitVarCtors();
|
||||
void emitVarCtors(bool* firstp);
|
||||
void emitCtorSep(bool* firstp);
|
||||
bool emitSimpleOk(AstNodeMath* nodep);
|
||||
void emitIQW(AstNode* nodep) {
|
||||
// Other abbrevs: "C"har, "S"hort, "F"loat, "D"ouble, stri"N"g
|
||||
@@ -322,8 +323,8 @@ public:
|
||||
nodep->modep()->iterateAndNext(*this);
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstReadMem* nodep) {
|
||||
puts("VL_READMEM_");
|
||||
virtual void visit(AstNodeReadWriteMem* nodep) {
|
||||
puts(nodep->cFuncPrefixp());
|
||||
emitIQW(nodep->filenamep());
|
||||
puts(" ("); // We take a void* rather than emitIQW(nodep->memp());
|
||||
puts(nodep->isHex()?"true":"false");
|
||||
@@ -333,21 +334,26 @@ public:
|
||||
uint32_t array_lsb = 0;
|
||||
{
|
||||
AstVarRef* varrefp = nodep->memp()->castVarRef();
|
||||
if (!varrefp) { nodep->v3error("Readmem loading non-variable"); }
|
||||
if (!varrefp) {
|
||||
nodep->v3error(nodep->verilogKwd() << " loading non-variable");
|
||||
}
|
||||
else if (AstUnpackArrayDType* adtypep = varrefp->varp()->dtypeSkipRefp()->castUnpackArrayDType()) {
|
||||
puts(cvtToStr(varrefp->varp()->dtypep()->arrayUnpackedElements()));
|
||||
array_lsb = adtypep->lsb();
|
||||
}
|
||||
else {
|
||||
nodep->v3error("Readmem loading other than unpacked-array variable");
|
||||
nodep->v3error(nodep->verilogKwd()
|
||||
<< " loading other than unpacked-array variable");
|
||||
}
|
||||
}
|
||||
putbs(", ");
|
||||
puts(cvtToStr(array_lsb));
|
||||
putbs(",");
|
||||
puts(cvtToStr(nodep->filenamep()->widthWords()));
|
||||
checkMaxWords(nodep->filenamep());
|
||||
putbs(", ");
|
||||
if (!nodep->filenamep()->dtypep()->isString()) {
|
||||
puts(cvtToStr(nodep->filenamep()->widthWords()));
|
||||
checkMaxWords(nodep->filenamep());
|
||||
putbs(", ");
|
||||
}
|
||||
nodep->filenamep()->iterateAndNext(*this);
|
||||
putbs(", ");
|
||||
nodep->memp()->iterateAndNext(*this);
|
||||
@@ -374,6 +380,11 @@ public:
|
||||
puts(")); }\n");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSysFuncAsTask* nodep) {
|
||||
if (!nodep->lhsp()->isWide()) puts("(void)");
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
if (!nodep->lhsp()->isWide()) puts(";");
|
||||
}
|
||||
virtual void visit(AstSystemT* nodep) {
|
||||
puts("(void)VL_SYSTEM_I");
|
||||
emitIQW(nodep->lhsp());
|
||||
@@ -507,31 +518,36 @@ public:
|
||||
}
|
||||
virtual void visit(AstMulS* nodep) {
|
||||
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
|
||||
nodep->v3error("Unsupported: Signed multiply of "<<nodep->width()<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
|
||||
nodep->v3error("Unsupported: Signed multiply of "<<nodep->width()
|
||||
<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
|
||||
}
|
||||
visit(nodep->castNodeBiop());
|
||||
}
|
||||
virtual void visit(AstPow* nodep) {
|
||||
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
|
||||
nodep->v3error("Unsupported: Power of "<<nodep->width()<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
|
||||
nodep->v3error("Unsupported: Power of "<<nodep->width()
|
||||
<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
|
||||
}
|
||||
visit(nodep->castNodeBiop());
|
||||
}
|
||||
virtual void visit(AstPowSS* nodep) {
|
||||
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
|
||||
nodep->v3error("Unsupported: Power of "<<nodep->width()<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
|
||||
nodep->v3error("Unsupported: Power of "<<nodep->width()
|
||||
<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
|
||||
}
|
||||
visit(nodep->castNodeBiop());
|
||||
}
|
||||
virtual void visit(AstPowSU* nodep) {
|
||||
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
|
||||
nodep->v3error("Unsupported: Power of "<<nodep->width()<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
|
||||
nodep->v3error("Unsupported: Power of "<<nodep->width()
|
||||
<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
|
||||
}
|
||||
visit(nodep->castNodeBiop());
|
||||
}
|
||||
virtual void visit(AstPowUS* nodep) {
|
||||
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
|
||||
nodep->v3error("Unsupported: Power of "<<nodep->width()<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
|
||||
nodep->v3error("Unsupported: Power of "<<nodep->width()
|
||||
<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
|
||||
}
|
||||
visit(nodep->castNodeBiop());
|
||||
}
|
||||
@@ -883,6 +899,7 @@ class EmitCImp : EmitCStmts {
|
||||
puts(modClassName(m_modp)+"::"+nodep->name()
|
||||
+"\\n\"); );\n");
|
||||
|
||||
// Declare and set vlTOPp
|
||||
if (nodep->symProlog()) puts(EmitCBaseVisitor::symTopAssign()+"\n");
|
||||
|
||||
if (nodep->initsp()) putsDecoration("// Variables\n");
|
||||
@@ -976,9 +993,10 @@ class EmitCImp : EmitCStmts {
|
||||
// High level
|
||||
void emitImp(AstNodeModule* modp);
|
||||
void emitStaticDecl(AstNodeModule* modp);
|
||||
void emitSettleLoop(std::string eval_call, bool initial);
|
||||
void emitWrapEval(AstNodeModule* modp);
|
||||
void emitInt(AstNodeModule* modp);
|
||||
void writeMakefile(string filename);
|
||||
void maybeSplit(AstNodeModule* modp);
|
||||
|
||||
public:
|
||||
EmitCImp() {
|
||||
@@ -1071,12 +1089,20 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
|
||||
}
|
||||
}
|
||||
|
||||
void EmitCStmts::emitVarCtors() {
|
||||
void EmitCStmts::emitCtorSep(bool* firstp) {
|
||||
if (*firstp) {
|
||||
puts(" : "); *firstp = false;
|
||||
} else {
|
||||
puts(", ");
|
||||
}
|
||||
if (ofp()->exceededWidth()) puts("\n ");
|
||||
}
|
||||
|
||||
void EmitCStmts::emitVarCtors(bool* firstp) {
|
||||
if (!m_ctorVarsVec.empty()) {
|
||||
ofp()->indentInc();
|
||||
puts("\n");
|
||||
puts("#if (SYSTEMC_VERSION>20011000)\n"); // SystemC 2.0.1 and newer
|
||||
bool first = true;
|
||||
for (vector<AstVar*>::iterator it = m_ctorVarsVec.begin(); it != m_ctorVarsVec.end(); ++it) {
|
||||
AstVar* varp = *it;
|
||||
bool isArray = !varp->dtypeSkipRefp()->castBasicDType();
|
||||
@@ -1085,9 +1111,7 @@ void EmitCStmts::emitVarCtors() {
|
||||
puts(varp->name());
|
||||
puts("\n");
|
||||
} else {
|
||||
if (first) { puts(" : "); first=false; }
|
||||
else puts(", ");
|
||||
if (ofp()->exceededWidth()) puts("\n ");
|
||||
emitCtorSep(firstp);
|
||||
puts(varp->name());
|
||||
puts("("); putsQuoted(varp->name()); puts(")");
|
||||
}
|
||||
@@ -1511,12 +1535,14 @@ void EmitCImp::emitCoverageDecl(AstNodeModule* modp) {
|
||||
|
||||
void EmitCImp::emitCtorImp(AstNodeModule* modp) {
|
||||
puts("\n");
|
||||
bool first = true;
|
||||
if (optSystemC() && modp->isTop()) {
|
||||
puts("VL_SC_CTOR_IMP("+modClassName(modp)+")");
|
||||
} else {
|
||||
puts("VL_CTOR_IMP("+modClassName(modp)+")");
|
||||
puts("VL_CTOR_IMP("+modClassName(modp)+")");
|
||||
first = false; // VL_CTOR_IMP includes the first ':'
|
||||
}
|
||||
emitVarCtors();
|
||||
emitVarCtors(&first);
|
||||
puts(" {\n");
|
||||
emitCellCtors(modp);
|
||||
emitSensitives();
|
||||
@@ -1548,7 +1574,8 @@ void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
|
||||
puts("\n// Coverage\n");
|
||||
// Rather than putting out VL_COVER_INSERT calls directly, we do it via this function
|
||||
// This gets around gcc slowness constructing all of the template arguments.
|
||||
puts("void "+modClassName(m_modp)+"::__vlCoverInsert(uint32_t* countp, bool enable, const char* filenamep, int lineno, int column,\n");
|
||||
puts("void "+modClassName(m_modp)+"::__vlCoverInsert(uint32_t* countp, bool enable,"
|
||||
" const char* filenamep, int lineno, int column,\n");
|
||||
puts( "const char* hierp, const char* pagep, const char* commentp) {\n");
|
||||
puts( "static uint32_t fake_zero_count = 0;\n"); // static doesn't need save-restore as constant
|
||||
puts( "if (!enable) countp = &fake_zero_count;\n"); // Used for second++ instantiation of identical bin
|
||||
@@ -1725,6 +1752,29 @@ void EmitCImp::emitSensitives() {
|
||||
}
|
||||
}
|
||||
|
||||
void EmitCImp::emitSettleLoop(std::string eval_call, bool initial) {
|
||||
putsDecoration("// Evaluate till stable\n");
|
||||
puts("int __VclockLoop = 0;\n");
|
||||
puts("QData __Vchange = 1;\n");
|
||||
puts("do {\n");
|
||||
puts( eval_call + "\n");
|
||||
puts( "if (VL_UNLIKELY(++__VclockLoop > "+cvtToStr(v3Global.opt.convergeLimit())
|
||||
+")) {\n");
|
||||
puts( "// About to fail, so enable debug to see what's not settling.\n");
|
||||
puts( "// Note you must run make with OPT=-DVL_DEBUG for debug prints.\n");
|
||||
puts( "int __Vsaved_debug = Verilated::debug();\n");
|
||||
puts( "Verilated::debug(1);\n");
|
||||
puts( "__Vchange = _change_request(vlSymsp);\n");
|
||||
puts( "Verilated::debug(__Vsaved_debug);\n");
|
||||
puts( "VL_FATAL_MT(__FILE__,__LINE__,__FILE__,\"Verilated model didn't ");
|
||||
if (initial) puts ("DC ");
|
||||
puts( "converge\");\n");
|
||||
puts( "} else {\n");
|
||||
puts( "__Vchange = _change_request(vlSymsp);\n");
|
||||
puts( "}\n");
|
||||
puts("} while (VL_UNLIKELY(__Vchange));\n");
|
||||
}
|
||||
|
||||
void EmitCImp::emitWrapEval(AstNodeModule* modp) {
|
||||
puts("\nvoid "+modClassName(modp)+"::eval() {\n");
|
||||
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+++++TOP Evaluate "+modClassName(modp)+"::eval\\n\"); );\n");
|
||||
@@ -1740,28 +1790,18 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) {
|
||||
puts("if (VL_UNLIKELY(__Vm_inhibitSim)) return;\n");
|
||||
}
|
||||
|
||||
if (v3Global.opt.threads()) { // THREADED-TODO move to per-train
|
||||
uint32_t trainId = 0;
|
||||
putsDecoration("// Train "+cvtToStr(trainId)+" start\n");
|
||||
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"Train starting, trainId="+cvtToStr(trainId)+"\\n\"););\n");
|
||||
puts("Verilated::trainId("+cvtToStr(trainId)+");\n");
|
||||
if (v3Global.opt.threads() == 1) {
|
||||
uint32_t mtaskId = 0;
|
||||
putsDecoration("// MTask "+cvtToStr(mtaskId)+" start\n");
|
||||
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"MTask starting, mtaskId="+cvtToStr(mtaskId)+"\\n\"););\n");
|
||||
puts("Verilated::mtaskId("+cvtToStr(mtaskId)+");\n");
|
||||
}
|
||||
|
||||
putsDecoration("// Evaluate till stable\n");
|
||||
puts("int __VclockLoop = 0;\n");
|
||||
puts("QData __Vchange = 1;\n");
|
||||
puts("while (VL_LIKELY(__Vchange)) {\n");
|
||||
puts( "VL_DEBUG_IF(VL_DBG_MSGF(\"+ Clock loop\\n\"););\n");
|
||||
if (v3Global.opt.trace()) {
|
||||
puts("vlSymsp->__Vm_activity = true;\n");
|
||||
}
|
||||
puts( "_eval(vlSymsp);\n");
|
||||
puts( "__Vchange = _change_request(vlSymsp);\n");
|
||||
puts( "if (VL_UNLIKELY(++__VclockLoop > "+cvtToStr(v3Global.opt.convergeLimit())
|
||||
+")) VL_FATAL_MT(__FILE__,__LINE__,__FILE__,\"Verilated model didn't converge\");\n");
|
||||
puts("}\n");
|
||||
if (v3Global.opt.threads()) { // THREADED-TODO move to end of all trains on thread
|
||||
puts("Verilated::endOfThreadTrain(vlSymsp->__Vm_evalMsgQp);\n");
|
||||
emitSettleLoop(
|
||||
(string("VL_DEBUG_IF(VL_DBG_MSGF(\"+ Clock loop\\n\"););\n")
|
||||
+ (v3Global.opt.trace() ? "vlSymsp->__Vm_activity = true;\n" : "")
|
||||
+ "_eval(vlSymsp);"), false);
|
||||
if (v3Global.opt.threads() == 1) {
|
||||
puts("Verilated::endOfThreadMTask(vlSymsp->__Vm_evalMsgQp);\n");
|
||||
}
|
||||
if (v3Global.opt.threads()) {
|
||||
puts("Verilated::endOfEval(vlSymsp->__Vm_evalMsgQp);\n");
|
||||
@@ -1776,15 +1816,8 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) {
|
||||
if (v3Global.opt.trace()) {
|
||||
puts("vlSymsp->__Vm_activity = true;\n");
|
||||
}
|
||||
puts( "int __VclockLoop = 0;\n");
|
||||
puts( "QData __Vchange = 1;\n");
|
||||
puts( "while (VL_LIKELY(__Vchange)) {\n");
|
||||
puts( "_eval_settle(vlSymsp);\n");
|
||||
puts( "_eval(vlSymsp);\n");
|
||||
puts( "__Vchange = _change_request(vlSymsp);\n");
|
||||
puts( "if (VL_UNLIKELY(++__VclockLoop > "+cvtToStr(v3Global.opt.convergeLimit())
|
||||
+")) VL_FATAL_MT(__FILE__,__LINE__,__FILE__,\"Verilated model didn't DC converge\");\n");
|
||||
puts( "}\n");
|
||||
emitSettleLoop((string("_eval_settle(vlSymsp);\n")
|
||||
+"_eval(vlSymsp);"), true);
|
||||
puts("}\n");
|
||||
splitSizeInc(10);
|
||||
}
|
||||
@@ -2194,6 +2227,17 @@ void EmitCImp::emitImp(AstNodeModule* modp) {
|
||||
|
||||
//######################################################################
|
||||
|
||||
void EmitCImp::maybeSplit(AstNodeModule* modp) {
|
||||
if (splitNeeded()) {
|
||||
// Close old file
|
||||
delete m_ofp; m_ofp=NULL;
|
||||
// Open a new file
|
||||
m_ofp = newOutCFile(modp, !m_fast, true/*source*/, splitFilenumInc());
|
||||
emitImp(modp);
|
||||
}
|
||||
splitSizeInc(10); // Even blank functions get a file with a low csplit
|
||||
}
|
||||
|
||||
void EmitCImp::main(AstNodeModule* modp, bool slow, bool fast) {
|
||||
// Output a module
|
||||
m_modp = modp;
|
||||
@@ -2204,37 +2248,18 @@ void EmitCImp::main(AstNodeModule* modp, bool slow, bool fast) {
|
||||
UINFO(0," Emitting "<<modClassName(modp)<<endl);
|
||||
}
|
||||
|
||||
if (optSystemC()) {
|
||||
if (m_fast) {
|
||||
m_ofp = newOutCFile (modp, !m_fast, false/*source*/);
|
||||
emitInt (modp);
|
||||
delete m_ofp; m_ofp=NULL;
|
||||
}
|
||||
|
||||
m_ofp = newOutCFile (modp, !m_fast, true/*source*/);
|
||||
}
|
||||
else {
|
||||
if (m_fast) {
|
||||
m_ofp = newOutCFile (modp, !m_fast, false/*source*/);
|
||||
emitInt (modp);
|
||||
delete m_ofp; m_ofp=NULL;
|
||||
}
|
||||
|
||||
m_ofp = newOutCFile (modp, !m_fast, true/*source*/);
|
||||
if (m_fast) {
|
||||
m_ofp = newOutCFile(modp, !m_fast, false/*source*/);
|
||||
emitInt(modp);
|
||||
delete m_ofp; m_ofp=NULL;
|
||||
}
|
||||
|
||||
emitImp (modp);
|
||||
m_ofp = newOutCFile(modp, !m_fast, true/*source*/);
|
||||
emitImp(modp);
|
||||
|
||||
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (AstCFunc* funcp = nodep->castCFunc()) {
|
||||
if (splitNeeded()) {
|
||||
// Close old file
|
||||
delete m_ofp; m_ofp=NULL;
|
||||
// Open a new file
|
||||
m_ofp = newOutCFile (modp, !m_fast, true/*source*/, splitFilenumInc());
|
||||
emitImp (modp);
|
||||
}
|
||||
splitSizeInc(10); // Even blank functions get a file with a low csplit
|
||||
maybeSplit(modp);
|
||||
mainDoFunc(funcp);
|
||||
}
|
||||
}
|
||||
@@ -2291,8 +2316,9 @@ class EmitCTrace : EmitCStmts {
|
||||
putsDecoration("// Callback from vcd->open()\n");
|
||||
puts(topClassName()+"* t=("+topClassName()+"*)userthis;\n");
|
||||
puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n");
|
||||
puts("if (!Verilated::calcUnusedSigs()) VL_FATAL_MT(__FILE__,__LINE__,__FILE__,\"Turning on wave traces requires Verilated::traceEverOn(true) call before time 0.\");\n");
|
||||
|
||||
puts("if (!Verilated::calcUnusedSigs()) {\n");
|
||||
puts( "VL_FATAL_MT(__FILE__,__LINE__,__FILE__,\"Turning on wave traces requires Verilated::traceEverOn(true) call before time 0.\");\n");
|
||||
puts("}\n");
|
||||
puts("vcdp->scopeEscape(' ');\n");
|
||||
puts("t->traceInitThis(vlSymsp, vcdp, code);\n");
|
||||
puts("vcdp->scopeEscape('.');\n"); // Restore so later traced files won't break
|
||||
@@ -2382,14 +2408,20 @@ class EmitCTrace : EmitCStmts {
|
||||
string full = ((m_funcp->funcType() == AstCFuncType::TRACE_FULL
|
||||
|| m_funcp->funcType() == AstCFuncType::TRACE_FULL_SUB)
|
||||
? "full":"chg");
|
||||
bool emitWidth = false;
|
||||
if (nodep->dtypep()->basicp()->isDouble()) {
|
||||
puts("vcdp->"+full+"Double");
|
||||
} else if (nodep->isWide() || emitTraceIsScBv(nodep) || emitTraceIsScBigUint(nodep)) {
|
||||
puts("vcdp->"+full+"Array");
|
||||
emitWidth = true;
|
||||
} else if (nodep->isQuad()) {
|
||||
puts("vcdp->"+full+"Quad ");
|
||||
} else if (nodep->declp()->bitRange().ranged()) {
|
||||
emitWidth = true;
|
||||
} else if (nodep->declp()->bitRange().ranged()
|
||||
// 1 element smaller to use Bit dump
|
||||
&& nodep->declp()->bitRange().elements() != 1) {
|
||||
puts("vcdp->"+full+"Bus ");
|
||||
emitWidth = true;
|
||||
} else {
|
||||
puts("vcdp->"+full+"Bit ");
|
||||
}
|
||||
@@ -2397,8 +2429,7 @@ class EmitCTrace : EmitCStmts {
|
||||
+ ((arrayindex<0) ? 0 : (arrayindex*nodep->declp()->widthWords()))));
|
||||
puts(",");
|
||||
emitTraceValue(nodep, arrayindex);
|
||||
if (!nodep->dtypep()->basicp()->isDouble() // When float/double no longer have widths this can go
|
||||
&& (nodep->declp()->bitRange().ranged() || emitTraceIsScBv(nodep) || emitTraceIsScBigUint(nodep))) {
|
||||
if (emitWidth) {
|
||||
puts(","+cvtToStr(nodep->declp()->widthMin()));
|
||||
}
|
||||
puts(");\n");
|
||||
@@ -2535,19 +2566,19 @@ void V3EmitC::emitc() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
// Process each module in turn
|
||||
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nodep->nextp()->castNodeModule()) {
|
||||
if (v3Global.opt.outputSplit()) {
|
||||
{ EmitCImp imp; imp.main(nodep, false, true); }
|
||||
{ EmitCImp imp; imp.main(nodep, true, false); }
|
||||
} else {
|
||||
{ EmitCImp imp; imp.main(nodep, true, true); }
|
||||
}
|
||||
if (v3Global.opt.outputSplit()) {
|
||||
{ EmitCImp fast; fast.main(nodep, false, true); }
|
||||
{ EmitCImp slow; slow.main(nodep, true, false); }
|
||||
} else {
|
||||
{ EmitCImp both; both.main(nodep, true, true); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void V3EmitC::emitcTrace() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
if (v3Global.opt.trace()) {
|
||||
{ EmitCTrace imp (true); imp.main(); }
|
||||
{ EmitCTrace imp (false); imp.main(); }
|
||||
{ EmitCTrace slow(true); slow.main(); }
|
||||
{ EmitCTrace fast(false); fast.main(); }
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -103,7 +103,8 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
if (rsvd != "") {
|
||||
// Generally V3Name should find all of these and throw SYMRSVDWORD.
|
||||
// We'll still check here because the compiler errors resulting if we miss this warning are SO nasty
|
||||
nodep->v3error("Symbol matching "+rsvd+" reserved word reached emitter, should have hit SYMRSVDWORD: '"<<nodep->prettyName()<<"'");
|
||||
nodep->v3error("Symbol matching "+rsvd+" reserved word reached emitter,"
|
||||
" should have hit SYMRSVDWORD: '"<<nodep->prettyName()<<"'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -268,7 +268,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
if (nodep->stmtsp()) nodep->stmtsp()->iterateAndNext(*this);
|
||||
puts("end\n");
|
||||
}
|
||||
virtual void visit(AstReadMem* nodep) {
|
||||
virtual void visit(AstNodeReadWriteMem* nodep) {
|
||||
putfs(nodep,nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
if (nodep->filenamep()) nodep->filenamep()->iterateAndNext(*this);
|
||||
@@ -278,6 +278,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
if (nodep->msbp()) { putbs(","); nodep->msbp()->iterateAndNext(*this); }
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstSysFuncAsTask* nodep) {
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
puts(";\n");
|
||||
}
|
||||
virtual void visit(AstSysIgnore* nodep) {
|
||||
putfs(nodep,nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
|
||||
+7
-3
@@ -266,8 +266,11 @@ inline void v3errorEndFatal(ostringstream& sstr) { V3Error::v3errorEnd(sstr); as
|
||||
// Careful, you can't put () around msg, as you would in most macro definitions
|
||||
// Note the commas are the comma operator, not separating arguments. These are needed to insure
|
||||
// evaluation order as otherwise we couldn't insure v3errorPrep is called first.
|
||||
#define v3warnCode(code,msg) v3errorEnd((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<<msg), V3Error::v3errorStr()));
|
||||
#define v3warnCodeFatal(code,msg) v3errorEndFatal((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<<msg), V3Error::v3errorStr()));
|
||||
#define v3warnCode(code,msg) \
|
||||
v3errorEnd((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<<msg), V3Error::v3errorStr()));
|
||||
#define v3warnCodeFatal(code,msg) \
|
||||
v3errorEndFatal((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<<msg), \
|
||||
V3Error::v3errorStr()));
|
||||
#define v3warn(code,msg) v3warnCode(V3ErrorCode::code, msg)
|
||||
#define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg)
|
||||
#define v3error(msg) v3warnCode(V3ErrorCode::EC_ERROR, msg)
|
||||
@@ -286,7 +289,8 @@ inline void v3errorEndFatal(ostringstream& sstr) { V3Error::v3errorEnd(sstr); as
|
||||
|
||||
#define UASSERT(condition,stmsg) { if (VL_UNLIKELY(!(condition))) { v3fatalSrc(stmsg); }}
|
||||
// For use in V3Ast static functions only
|
||||
#define UASSERT_STATIC(condition,stmsg) { if (VL_UNLIKELY(!(condition))) { cerr<<"Internal Error: "<<__FILE__<<":"<<dec<<__LINE__<<":"<<(stmsg)<<endl; abort(); } }
|
||||
#define UASSERT_STATIC(condition,stmsg) { if (VL_UNLIKELY(!(condition))) { \
|
||||
cerr<<"Internal Error: "<<__FILE__<<":"<<dec<<__LINE__<<":"<<(stmsg)<<endl; abort(); } }
|
||||
|
||||
#define V3ERROR_NA { v3error("Internal: Unexpected Call"); v3fatalSrc("Unexpected Call"); }
|
||||
|
||||
|
||||
+6
-2
@@ -243,7 +243,9 @@ private:
|
||||
}
|
||||
bool expandWide (AstNodeAssign* nodep, AstArraySel* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(ARRAYSEL) "<<nodep<<endl);
|
||||
if (nodep->dtypep()->skipRefp()->castUnpackArrayDType()) nodep->v3fatalSrc("ArraySel with unpacked arrays should have been removed in V3Slice");
|
||||
if (nodep->dtypep()->skipRefp()->castUnpackArrayDType()) {
|
||||
nodep->v3fatalSrc("ArraySel with unpacked arrays should have been removed in V3Slice");
|
||||
}
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, newAstWordSelClone (rhsp, w));
|
||||
}
|
||||
@@ -936,6 +938,8 @@ public:
|
||||
|
||||
void V3Expand::expandAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ExpandVisitor visitor (nodep);
|
||||
{
|
||||
ExpandVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("expand", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-1
@@ -238,7 +238,8 @@ inline bool V3FileDependImp::checkTimes(const string& filename, const string& cm
|
||||
UINFO(2," --check-times failed: missing "<<chkFilename<<endl);
|
||||
return false;
|
||||
}
|
||||
//UINFO(9," got d="<<chkDir<<" s="<<chkSize<<" ct="<<chkCstime<<"."<<chkCnstime<<" mt="<<chkMstime<<"."<<chkMnstime<<" fn = "<<chkFilename<<endl);
|
||||
//UINFO(9," got d="<<chkDir<<" s="<<chkSize<<" ct="<<chkCstime<<"."
|
||||
// <<chkCnstime<<" mt="<<chkMstime<<"."<<chkMnstime<<" fn = "<<chkFilename<<endl);
|
||||
//UINFO(9," nowSt s="<<chkStat.st_size<<" mt="<<chkStat.st_mtime<<" ct="<<chkStat.st_ctime<<" fn = "<<chkFilename<<endl);
|
||||
if (filename != chkFilename) { // Other then the .dat file itself, as we were writing it at the time...
|
||||
// We'd like this rule:
|
||||
|
||||
+4
-2
@@ -1496,7 +1496,9 @@ public:
|
||||
|
||||
void V3Gate::gateAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
GateVisitor visitor (nodep);
|
||||
GateDeassignVisitor deassign (nodep);
|
||||
{
|
||||
GateVisitor visitor (nodep);
|
||||
GateDeassignVisitor deassign (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("gate", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+3
-1
@@ -242,6 +242,8 @@ public:
|
||||
|
||||
void V3GenClk::genClkAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
GenClkReadVisitor visitor (nodep);
|
||||
{
|
||||
GenClkReadVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("genclk", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
@@ -69,7 +69,12 @@ private:
|
||||
// MEMBERS
|
||||
uint32_t m_step; // Processing step, so we can avoid clearUser all the time
|
||||
HashMap m_hashMap; // Dfa Vertex for each set of NFA vertexes
|
||||
|
||||
#ifdef VL_CPPCHECK
|
||||
static int debug() { return 9; }
|
||||
#else
|
||||
static int debug() { return 0; }
|
||||
#endif
|
||||
|
||||
// METHODS
|
||||
DfaGraph* graphp() { return static_cast<DfaGraph*>(m_graphp); }
|
||||
|
||||
+9
-12
@@ -42,6 +42,7 @@
|
||||
#include "V3Inst.h"
|
||||
#include "V3Stats.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3String.h"
|
||||
|
||||
// CONFIG
|
||||
static const int INLINE_MODS_SMALLER = 100; // If a mod is < this # nodes, can always inline it
|
||||
@@ -270,14 +271,14 @@ public:
|
||||
|
||||
class InlineRelinkVisitor : public AstNVisitor {
|
||||
private:
|
||||
typedef vl_unordered_set<string> RenamedInterfacesSet;
|
||||
typedef vl_unordered_set<string> StringSet;
|
||||
|
||||
// NODE STATE
|
||||
// Input:
|
||||
// See InlineVisitor
|
||||
|
||||
// STATE
|
||||
RenamedInterfacesSet m_renamedInterfaces; // Name of renamed interface variables
|
||||
StringSet m_renamedInterfaces; // Name of renamed interface variables
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCell* m_cellp; // Cell being cloned
|
||||
|
||||
@@ -410,9 +411,8 @@ private:
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) {
|
||||
// Track what scope it was originally under so V3LinkDot can resolve it
|
||||
string newname = m_cellp->name();
|
||||
if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
|
||||
nodep->inlinedDots(newname);
|
||||
string newdots = VString::dot(m_cellp->name(), ".", nodep->inlinedDots());
|
||||
nodep->inlinedDots(newdots);
|
||||
for (string tryname = nodep->dotted(); 1;) {
|
||||
if (m_renamedInterfaces.count(tryname)) {
|
||||
nodep->dotted(m_cellp->name() + "__DOT__" + nodep->dotted());
|
||||
@@ -430,9 +430,8 @@ private:
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) {
|
||||
// Track what scope it was originally under so V3LinkDot can resolve it
|
||||
string newname = m_cellp->name();
|
||||
if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
|
||||
nodep->inlinedDots(newname);
|
||||
string newdots = VString::dot(m_cellp->name(), ".", nodep->inlinedDots());
|
||||
nodep->inlinedDots(newdots);
|
||||
if (m_renamedInterfaces.count(nodep->dotted())) {
|
||||
nodep->dotted(m_cellp->name() + "__DOT__" + nodep->dotted());
|
||||
}
|
||||
@@ -459,9 +458,7 @@ private:
|
||||
}
|
||||
virtual void visit(AstCoverDecl* nodep) {
|
||||
// Fix path in coverage statements
|
||||
nodep->hier(m_cellp->prettyName()
|
||||
+ (nodep->hier()!="" ? ".":"")
|
||||
+ nodep->hier());
|
||||
nodep->hier(VString::dot(m_cellp->prettyName(), ".", nodep->hier()));
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
@@ -537,7 +534,7 @@ private:
|
||||
// this loop as it clone()s itself.
|
||||
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
|
||||
if (!pinp->exprp()) continue;
|
||||
V3Inst::pinReconnectSimple(pinp, nodep, m_modp, false);
|
||||
V3Inst::pinReconnectSimple(pinp, nodep, false);
|
||||
}
|
||||
|
||||
// Clone original module
|
||||
|
||||
+19
-22
@@ -49,8 +49,7 @@ private:
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCell* m_cellp; // Current cell
|
||||
AstCell* m_cellp; // Current cell
|
||||
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
@@ -60,13 +59,6 @@ private:
|
||||
//int m_debug; int debug() { return m_debug; }
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
//if (nodep->name() == "t_chg") m_debug = 9; else m_debug=0;
|
||||
m_modp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstCell* nodep) {
|
||||
UINFO(4," CELL "<<nodep<<endl);
|
||||
m_cellp = nodep;
|
||||
@@ -86,9 +78,9 @@ private:
|
||||
// Use user1p on the PIN to indicate we created an assign for this pin
|
||||
if (!nodep->user1SetOnce()) {
|
||||
// Simplify it
|
||||
V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, false);
|
||||
// Make a ASSIGNW (expr, pin)
|
||||
AstNode* exprp = nodep->exprp()->cloneTree(false);
|
||||
V3Inst::pinReconnectSimple(nodep, m_cellp, false);
|
||||
// Make an ASSIGNW (expr, pin)
|
||||
AstNode* exprp = nodep->exprp()->cloneTree(false);
|
||||
if (exprp->width() != nodep->modVarp()->width())
|
||||
nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple");
|
||||
if (nodep->modVarp()->isInout()) {
|
||||
@@ -96,7 +88,7 @@ private:
|
||||
} else if (nodep->modVarp()->isOutput()) {
|
||||
AstNode* rhsp = new AstVarXRef (exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
|
||||
AstAssignW* assp = new AstAssignW (exprp->fileline(), exprp, rhsp);
|
||||
m_modp->addStmtp(assp);
|
||||
m_cellp->addNextHere(assp);
|
||||
} else if (nodep->modVarp()->isInput()) {
|
||||
// Don't bother moving constants now,
|
||||
// we'll be pushing the const down to the cell soon enough.
|
||||
@@ -104,7 +96,7 @@ private:
|
||||
(exprp->fileline(),
|
||||
new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), true),
|
||||
exprp);
|
||||
m_modp->addStmtp(assp);
|
||||
m_cellp->addNextHere(assp);
|
||||
if (debug()>=9) assp->dumpTree(cout," _new: ");
|
||||
} else if (nodep->modVarp()->isIfaceRef()
|
||||
|| (nodep->modVarp()->subDTypep()->castUnpackArrayDType()
|
||||
@@ -115,7 +107,7 @@ private:
|
||||
AstVarXRef* xrefp = exprp->castVarXRef();
|
||||
if (!refp && !xrefp) exprp->v3fatalSrc("Interfaces: Pin is not connected to a VarRef or VarXRef");
|
||||
AstAssignVarScope* assp = new AstAssignVarScope(exprp->fileline(), lhsp, exprp);
|
||||
m_modp->addStmtp(assp);
|
||||
m_cellp->addNextHere(assp);
|
||||
} else {
|
||||
nodep->v3error("Assigned pin is neither input nor output");
|
||||
}
|
||||
@@ -133,6 +125,7 @@ private:
|
||||
}
|
||||
|
||||
// Save some time
|
||||
virtual void visit(AstNodeMath*) {}
|
||||
virtual void visit(AstNodeAssign*) {}
|
||||
virtual void visit(AstAlways*) {}
|
||||
|
||||
@@ -144,7 +137,6 @@ private:
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
explicit InstVisitor(AstNetlist* nodep) {
|
||||
m_modp=NULL;
|
||||
m_cellp=NULL;
|
||||
//
|
||||
nodep->accept(*this);
|
||||
@@ -496,7 +488,7 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModule*,
|
||||
static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp,
|
||||
bool forTristate, bool alwaysCvt) {
|
||||
// If a pin connection is "simple" leave it as-is
|
||||
// Else create a intermediate wire to perform the interconnect
|
||||
@@ -545,7 +537,8 @@ public:
|
||||
// Important to add statement next to cell, in case there is a generate with same named cell
|
||||
cellp->addNextHere(newvarp);
|
||||
if (pinVarp->isInout()) {
|
||||
pinVarp->v3fatalSrc("Unsupported: Inout connections to pins must be direct one-to-one connection (without any expression)");
|
||||
pinVarp->v3fatalSrc("Unsupported: Inout connections to pins must be"
|
||||
" direct one-to-one connection (without any expression)");
|
||||
} else if (pinVarp->isOutput()) {
|
||||
// See also V3Inst
|
||||
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
|
||||
@@ -572,9 +565,9 @@ public:
|
||||
//######################################################################
|
||||
// Inst class functions
|
||||
|
||||
AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModule* modp,
|
||||
AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp,
|
||||
bool forTristate, bool alwaysCvt) {
|
||||
return InstStatic::pinReconnectSimple(pinp, cellp, modp, forTristate, alwaysCvt);
|
||||
return InstStatic::pinReconnectSimple(pinp, cellp, forTristate, alwaysCvt);
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
@@ -582,12 +575,16 @@ AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModu
|
||||
|
||||
void V3Inst::instAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
InstVisitor visitor (nodep);
|
||||
{
|
||||
InstVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("inst", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Inst::dearrayAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
InstDeVisitor visitor (nodep);
|
||||
{
|
||||
InstDeVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("dearray", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ class V3Inst {
|
||||
public:
|
||||
static void instAll(AstNetlist* nodep);
|
||||
static void dearrayAll(AstNetlist* nodep);
|
||||
static AstAssignW* pinReconnectSimple(AstPin* nodep, AstCell* cellp, AstNodeModule* modp,
|
||||
static AstAssignW* pinReconnectSimple(AstPin* nodep, AstCell* cellp,
|
||||
bool forTristate, bool alwaysCvt=false);
|
||||
};
|
||||
|
||||
|
||||
+6
-3
@@ -42,6 +42,7 @@ public:
|
||||
L1800_2005,
|
||||
L1800_2009,
|
||||
L1800_2012,
|
||||
L1800_2017,
|
||||
// ***Add new elements below also***
|
||||
_ENUM_END
|
||||
};
|
||||
@@ -54,12 +55,14 @@ public:
|
||||
"1364-2005",
|
||||
"1800-2005",
|
||||
"1800-2009",
|
||||
"1800-2012"
|
||||
"1800-2012",
|
||||
"1800-2017"
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
static V3LangCode mostRecent() { return V3LangCode(L1800_2012); }
|
||||
bool systemVerilog() const { return m_e == L1800_2005 || m_e == L1800_2009 || m_e == L1800_2012; }
|
||||
static V3LangCode mostRecent() { return V3LangCode(L1800_2017); }
|
||||
bool systemVerilog() const { return m_e == L1800_2005 || m_e == L1800_2009
|
||||
|| m_e == L1800_2012 || m_e == L1800_2017; }
|
||||
bool legal() const { return m_e != L_ERROR; }
|
||||
//
|
||||
enum en m_e;
|
||||
|
||||
+4
-2
@@ -518,7 +518,9 @@ public:
|
||||
|
||||
void V3Life::lifeAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
LifeState state;
|
||||
LifeTopVisitor visitor (nodep, &state);
|
||||
{
|
||||
LifeState state;
|
||||
LifeTopVisitor visitor (nodep, &state);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("life", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+4
-2
@@ -110,7 +110,7 @@ class LifePostDlyVisitor : public LifePostBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Cleared on entire tree
|
||||
// AstVarScope::user() -> Sequence # of first virtex setting this var.
|
||||
// AstVarScope::user() -> Sequence # of first vertex setting this var.
|
||||
// AstVarScope::user2() -> Sequence # of last consumption of this var
|
||||
// AstVarScope::user4() -> AstVarScope*: Passed to LifePostElim to substitute this var
|
||||
AstUser1InUse m_inuser1;
|
||||
@@ -213,6 +213,8 @@ public:
|
||||
void V3LifePost::lifepostAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
// Mark redundant AssignPost
|
||||
LifePostDlyVisitor visitor (nodep);
|
||||
{
|
||||
LifePostDlyVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("life_post", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+3
-1
@@ -413,7 +413,9 @@ private:
|
||||
idtypep->cellp(nodep); // Only set when real parent cell known.
|
||||
AstVar* varp;
|
||||
if (nodep->rangep()) {
|
||||
AstNodeArrayDType* arrp = new AstUnpackArrayDType(nodep->fileline(),VFlagChildDType(), idtypep, nodep->rangep()->cloneTree(true));
|
||||
AstNodeArrayDType* arrp
|
||||
= new AstUnpackArrayDType(nodep->fileline(), VFlagChildDType(),
|
||||
idtypep, nodep->rangep()->cloneTree(true));
|
||||
varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName,
|
||||
VFlagChildDType(), arrp);
|
||||
} else {
|
||||
|
||||
+32
-23
@@ -78,6 +78,7 @@
|
||||
#include "V3Graph.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3ParseImp.h"
|
||||
#include "V3String.h"
|
||||
|
||||
//######################################################################
|
||||
// LinkDot state, as a visitor of each AstNode
|
||||
@@ -262,7 +263,8 @@ public:
|
||||
AstCell* nodep, const string& scopename) {
|
||||
if (!abovep) nodep->v3fatalSrc("Null symbol table inserting node");
|
||||
VSymEnt* symp = new VSymEnt(&m_syms, nodep);
|
||||
UINFO(9," INSERTcel se"<<(void*)symp<<" "<<scopename<<" above=se"<<(void*)abovep<<" mods=se"<<(void*)modSymp<<" node="<<nodep<<endl);
|
||||
UINFO(9," INSERTcel se"<<(void*)symp<<" "<<scopename<<" above=se"<<(void*)abovep
|
||||
<<" mods=se"<<(void*)modSymp<<" node="<<nodep<<endl);
|
||||
symp->parentp(abovep);
|
||||
symp->fallbackp(dunitEntp()); // Needed so can find $unit stuff
|
||||
nodep->user1p(symp);
|
||||
@@ -283,7 +285,8 @@ public:
|
||||
// This refrences to another Sym, and eventually resolves to a module with a prefix
|
||||
if (!abovep) nodep->v3fatalSrc("Null symbol table inserting node");
|
||||
VSymEnt* symp = new VSymEnt(&m_syms, nodep);
|
||||
UINFO(9," INSERTinl se"<<(void*)symp<<" "<<basename<<" above=se"<<(void*)abovep<<" mods=se"<<(void*)modSymp<<" node="<<nodep<<endl);
|
||||
UINFO(9," INSERTinl se"<<(void*)symp<<" "<<basename<<" above=se"<<(void*)abovep
|
||||
<<" mods=se"<<(void*)modSymp<<" node="<<nodep<<endl);
|
||||
symp->parentp(abovep);
|
||||
symp->fallbackp(modSymp);
|
||||
symp->symPrefix(nodep->name()+"__DOT__");
|
||||
@@ -604,7 +607,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
// METHODS
|
||||
int debug() { return LinkDotState::debug(); }
|
||||
|
||||
virtual AstConst* parseParamLiteral(FileLine* fl, string literal) {
|
||||
virtual AstConst* parseParamLiteral(FileLine* fl, const string& literal) {
|
||||
bool success = false;
|
||||
if (literal[0] == '"') {
|
||||
// This is a string
|
||||
@@ -1551,7 +1554,8 @@ private:
|
||||
inline void checkNoDot(AstNode* nodep) {
|
||||
if (VL_UNLIKELY(m_ds.m_dotPos != DP_NONE)) {
|
||||
//UINFO(9,"ds="<<m_ds.ascii()<<endl);
|
||||
nodep->v3error("Syntax Error: Not expecting "<<nodep->type()<<" under a "<<nodep->backp()->type()<<" in dotted expression");
|
||||
nodep->v3error("Syntax Error: Not expecting "<<nodep->type()<<" under a "
|
||||
<<nodep->backp()->type()<<" in dotted expression");
|
||||
m_ds.m_dotErr = true;
|
||||
}
|
||||
}
|
||||
@@ -1804,8 +1808,7 @@ private:
|
||||
|| foundp->nodep()->castModule()) { // if top
|
||||
if (allowScope) {
|
||||
ok = true;
|
||||
if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
|
||||
m_ds.m_dotText += nodep->name();
|
||||
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
|
||||
m_ds.m_dotSymp = foundp;
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
// Upper AstDot visitor will handle it from here
|
||||
@@ -1815,7 +1818,8 @@ private:
|
||||
AstCell* cellp = foundp->nodep()->castCell();
|
||||
if (cellp->modp()->castIface()) {
|
||||
// Interfaces can be referenced like a variable for interconnect
|
||||
VSymEnt* cellEntp = m_statep->getNodeSym(cellp); if (!cellEntp) nodep->v3fatalSrc("No interface sym entry");
|
||||
VSymEnt* cellEntp = m_statep->getNodeSym(cellp);
|
||||
if (!cellEntp) nodep->v3fatalSrc("No interface sym entry");
|
||||
VSymEnt* parentEntp = cellEntp->parentp(); // Container of the var; probably a module or generate begin
|
||||
string findName = nodep->name()+"__Viftop";
|
||||
VSymEnt* ifaceSymp = parentEntp->findIdFallback(findName);
|
||||
@@ -1823,8 +1827,7 @@ private:
|
||||
if (!ifaceRefVarp) nodep->v3fatalSrc("Can't find interface var ref: "<<findName);
|
||||
//
|
||||
ok = true;
|
||||
if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
|
||||
m_ds.m_dotText += nodep->name();
|
||||
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
|
||||
m_ds.m_dotSymp = foundp;
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
UINFO(9," cell -> iface varref "<<foundp->nodep()<<endl);
|
||||
@@ -1841,8 +1844,7 @@ private:
|
||||
if (!ifacerefp->ifaceViaCellp()) ifacerefp->v3fatalSrc("Unlinked interface");
|
||||
// Really this is a scope reference into an interface
|
||||
UINFO(9,"varref-ifaceref "<<m_ds.m_dotText<<" "<<nodep<<endl);
|
||||
if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
|
||||
m_ds.m_dotText += nodep->name();
|
||||
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
|
||||
m_ds.m_dotSymp = m_statep->getNodeSym(ifacerefp->ifaceViaCellp());
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
ok = true;
|
||||
@@ -1893,8 +1895,7 @@ private:
|
||||
if (!cellp) nodep->v3fatalSrc("Modport not referenced from a cell");
|
||||
AstIface* ifacep = cellp->modp()->castIface();
|
||||
//string cellName = m_ds.m_dotText; // Use cellp->name
|
||||
if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
|
||||
m_ds.m_dotText += nodep->name();
|
||||
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
|
||||
m_ds.m_dotSymp = m_statep->getNodeSym(modportp);
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
ok = true;
|
||||
@@ -2011,7 +2012,8 @@ private:
|
||||
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
|
||||
AstVarScope* vscp = foundp ? foundp->nodep()->castVarScope() : NULL;
|
||||
if (!vscp) {
|
||||
nodep->v3error("Can't find varpin scope of '"<<baddot<<"' in dotted signal: "<<nodep->dotted()+"."+nodep->prettyName());
|
||||
nodep->v3error("Can't find varpin scope of '"<<baddot
|
||||
<<"' in dotted signal: "<<nodep->dotted()+"."+nodep->prettyName());
|
||||
okSymp->cellErrorScopes(nodep);
|
||||
} else {
|
||||
while (vscp->user2p()) { // If V3Inline aliased it, pick up the new signal
|
||||
@@ -2110,10 +2112,8 @@ private:
|
||||
}
|
||||
dotSymp = m_statep->findDotted(dotSymp, nodep->dotted(), baddot, okSymp); // Maybe NULL
|
||||
}
|
||||
VSymEnt* foundp = NULL;
|
||||
AstNodeFTask* taskp = NULL;
|
||||
foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
|
||||
taskp = foundp ? foundp->nodep()->castNodeFTask() : NULL; // Maybe NULL
|
||||
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
|
||||
AstNodeFTask* taskp = foundp ? foundp->nodep()->castNodeFTask() : NULL; // Maybe NULL
|
||||
if (taskp) {
|
||||
nodep->taskp(taskp);
|
||||
nodep->packagep(foundp->packagep());
|
||||
@@ -2128,7 +2128,8 @@ private:
|
||||
} else if (nodep->dotted() == "") {
|
||||
nodep->v3error("Can't find definition of task/function: "<<nodep->prettyName());
|
||||
} else {
|
||||
nodep->v3error("Can't find definition of '"<<baddot<<"' in dotted task/function: "<<nodep->dotted()+"."+nodep->prettyName());
|
||||
nodep->v3error("Can't find definition of '"<<baddot
|
||||
<<"' in dotted task/function: "<<nodep->dotted()+"."+nodep->prettyName());
|
||||
okSymp->cellErrorScopes(nodep);
|
||||
}
|
||||
}
|
||||
@@ -2316,21 +2317,29 @@ public:
|
||||
int V3LinkDot::debug() { return LinkDotState::debug(); }
|
||||
|
||||
void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) {
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot.tree"));
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) {
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot.tree"));
|
||||
}
|
||||
LinkDotState state (rootp, step);
|
||||
LinkDotFindVisitor visitor(rootp,&state);
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-find.tree"));
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) {
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-find.tree"));
|
||||
}
|
||||
if (step == LDS_PRIMARY || step == LDS_PARAMED) {
|
||||
// Initial link stage, resolve parameters
|
||||
LinkDotParamVisitor visitors(rootp,&state);
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param.tree"));
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) {
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param.tree"));
|
||||
}
|
||||
}
|
||||
else if (step == LDS_ARRAYED) {}
|
||||
else if (step == LDS_SCOPED) {
|
||||
// Well after the initial link when we're ready to operate on the flat design,
|
||||
// process AstScope's. This needs to be separate pass after whole hierarchy graph created.
|
||||
LinkDotScopeVisitor visitors(rootp,&state);
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree"));
|
||||
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) {
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree"));
|
||||
}
|
||||
}
|
||||
else v3fatalSrc("Bad case");
|
||||
state.dump();
|
||||
|
||||
+8
-4
@@ -35,19 +35,23 @@ private:
|
||||
static void linkDotGuts(AstNetlist* nodep, VLinkDotStep step);
|
||||
public:
|
||||
static void linkDotPrimary(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl); linkDotGuts(nodep,LDS_PRIMARY);
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
linkDotGuts(nodep,LDS_PRIMARY);
|
||||
V3Global::dumpCheckGlobalTree("linkdot", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
static void linkDotParamed(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl); linkDotGuts(nodep,LDS_PARAMED);
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
linkDotGuts(nodep,LDS_PARAMED);
|
||||
V3Global::dumpCheckGlobalTree("paramlink", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
static void linkDotArrayed(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl); linkDotGuts(nodep,LDS_ARRAYED);
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
linkDotGuts(nodep,LDS_ARRAYED);
|
||||
V3Global::dumpCheckGlobalTree("linkdot", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
static void linkDotScope(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl); linkDotGuts(nodep,LDS_SCOPED);
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
linkDotGuts(nodep,LDS_SCOPED);
|
||||
V3Global::dumpCheckGlobalTree("linkdot", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
};
|
||||
|
||||
+3
-1
@@ -262,6 +262,8 @@ public:
|
||||
|
||||
void V3LinkJump::linkJump(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
LinkJumpVisitor bvisitor (nodep);
|
||||
{
|
||||
LinkJumpVisitor bvisitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("link", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
@@ -278,7 +278,9 @@ public:
|
||||
|
||||
void V3LinkLValue::linkLValue(AstNetlist* rootp) {
|
||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
||||
LinkLValueVisitor visitor(rootp, false);
|
||||
{
|
||||
LinkLValueVisitor visitor(rootp, false);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("linklvalue", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
void V3LinkLValue::linkLValueSet(AstNode* nodep) {
|
||||
|
||||
+24
-14
@@ -340,6 +340,7 @@ private:
|
||||
FileLine* fl = varsp->fileline();
|
||||
AstNode* varp = new AstVar(fl, AstVarType::BLOCKTEMP,
|
||||
varsp->name(), nodep->findSigned32DType());
|
||||
// These will be the left and right dimensions of the array:
|
||||
AstNode* leftp = new AstAttrOf(fl, AstAttrType::DIM_LEFT,
|
||||
new AstVarRef(fl, arrayp->name(), false),
|
||||
new AstConst(fl, dimension));
|
||||
@@ -347,19 +348,26 @@ private:
|
||||
new AstVarRef(fl, arrayp->name(), false),
|
||||
new AstConst(fl, dimension));
|
||||
AstNode* stmtsp = varp;
|
||||
stmtsp->addNext(new AstAssign(fl, new AstVarRef(fl, varp->name(), true), leftp));
|
||||
AstNode* comparep =
|
||||
new AstCond(fl, new AstLte(fl, leftp->cloneTree(true), rightp->cloneTree(true)),
|
||||
// left increments up to right
|
||||
new AstLte(fl, new AstVarRef(fl, varp->name(), false), rightp->cloneTree(true)),
|
||||
// left decrements down to right
|
||||
new AstGte(fl, new AstVarRef(fl, varp->name(), false), rightp));
|
||||
AstNode* incp =
|
||||
new AstAssign(fl, new AstVarRef(fl, varp->name(), true),
|
||||
new AstAdd(fl, new AstVarRef(fl, varp->name(), false),
|
||||
new AstNegate(fl, new AstAttrOf(fl, AstAttrType::DIM_INCREMENT,
|
||||
new AstVarRef(fl, arrayp->name(), false),
|
||||
new AstConst(fl, dimension)))));
|
||||
// Assign left-dimension into the loop var:
|
||||
stmtsp->addNext(new AstAssign
|
||||
(fl, new AstVarRef(fl, varp->name(), true), leftp));
|
||||
// This will turn into a bool constant, indicating whether
|
||||
// we count the loop variable up or down:
|
||||
AstNode* countupp = new AstLte(fl, leftp->cloneTree(true),
|
||||
rightp->cloneTree(true));
|
||||
AstNode* comparep = new AstCond(
|
||||
fl, countupp->cloneTree(true),
|
||||
// Left increments up to right
|
||||
new AstLte(fl, new AstVarRef(fl, varp->name(), false),
|
||||
rightp->cloneTree(true)),
|
||||
// Left decrements down to right
|
||||
new AstGte(fl, new AstVarRef(fl, varp->name(), false), rightp));
|
||||
AstNode* incp = new AstAssign(
|
||||
fl, new AstVarRef(fl, varp->name(), true),
|
||||
new AstAdd(fl, new AstVarRef(fl, varp->name(), false),
|
||||
new AstCond(fl, countupp,
|
||||
new AstConst(fl, 1),
|
||||
new AstConst(fl, -1))));
|
||||
stmtsp->addNext(new AstWhile(fl, comparep, newp, incp));
|
||||
newp = new AstBegin(nodep->fileline(),"",stmtsp);
|
||||
dimension--;
|
||||
@@ -430,6 +438,8 @@ public:
|
||||
|
||||
void V3LinkParse::linkParse(AstNetlist* rootp) {
|
||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
||||
LinkParseVisitor visitor(rootp);
|
||||
{
|
||||
LinkParseVisitor visitor(rootp);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("linkparse", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
||||
@@ -514,7 +514,9 @@ public:
|
||||
|
||||
void V3LinkResolve::linkResolve(AstNetlist* rootp) {
|
||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
||||
LinkResolveVisitor visitor(rootp);
|
||||
LinkBotupVisitor visitorb(rootp);
|
||||
{
|
||||
LinkResolveVisitor visitor(rootp);
|
||||
LinkBotupVisitor visitorb(rootp);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("linkresolve", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
||||
+6
-3
@@ -66,6 +66,7 @@ protected:
|
||||
int m_stdFuncAsn:1; // Found simple assignment
|
||||
int m_done:1; // Removed
|
||||
};
|
||||
// cppcheck-suppress unusedStructMember
|
||||
uint32_t m_flags;
|
||||
VarFlags(AstNode* nodep) { m_flags = nodep->user2(); }
|
||||
void setNodeFlags(AstNode* nodep) { nodep->user2(m_flags); }
|
||||
@@ -247,8 +248,10 @@ public:
|
||||
|
||||
void V3Localize::localizeAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
LocalizeVisitor visitor (nodep);
|
||||
// Fix up hiernames
|
||||
LocalizeDehierVisitor dvisitor (nodep);
|
||||
{
|
||||
LocalizeVisitor visitor (nodep);
|
||||
// Fix up hiernames
|
||||
LocalizeDehierVisitor dvisitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("localize", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
||||
+3
-1
@@ -148,6 +148,8 @@ public:
|
||||
|
||||
void V3Name::nameAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
NameVisitor visitor (nodep);
|
||||
{
|
||||
NameVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("name", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
||||
+1
-1
@@ -142,7 +142,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
|
||||
if (!m_sized) {
|
||||
static int warned = false;
|
||||
if (!warned++) {
|
||||
m_fileline->v3error("As that number was unsized ('d...) it is limited to 32 bits (IEEE 2012 5.7.1)");
|
||||
m_fileline->v3error("As that number was unsized ('d...) it is limited to 32 bits (IEEE 2017 5.7.1)");
|
||||
}
|
||||
}
|
||||
while (*(cp+1)) cp++; // Skip ahead so don't get multiple warnings
|
||||
|
||||
+11
-7
@@ -155,11 +155,11 @@ void V3Options::addParameter(const string& paramline, bool allowPlus) {
|
||||
}
|
||||
}
|
||||
|
||||
bool V3Options::hasParameter(string name) {
|
||||
bool V3Options::hasParameter(const string& name) {
|
||||
return m_parameters.find(name) != m_parameters.end();
|
||||
}
|
||||
|
||||
string V3Options::parameter(string name) {
|
||||
string V3Options::parameter(const string& name) {
|
||||
string value = m_parameters.find(name)->second;
|
||||
m_parameters.erase(m_parameters.find(name));
|
||||
return value;
|
||||
@@ -604,7 +604,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
else if ( !strncmp (sw, "+incdir+", 8)) {
|
||||
addIncDirUser (parseFileArg(optdir, string (sw+strlen("+incdir+"))));
|
||||
}
|
||||
else if (parseLangExt(sw, "+systemverilogext+", V3LangCode::L1800_2012)
|
||||
else if (parseLangExt(sw, "+systemverilogext+", V3LangCode::L1800_2017)
|
||||
|| parseLangExt(sw, "+verilog1995ext+", V3LangCode::L1364_1995)
|
||||
|| parseLangExt(sw, "+verilog2001ext+", V3LangCode::L1364_2001)
|
||||
|| parseLangExt(sw, "+1364-1995ext+", V3LangCode::L1364_1995)
|
||||
@@ -612,7 +612,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
|| parseLangExt(sw, "+1364-2005ext+", V3LangCode::L1364_2005)
|
||||
|| parseLangExt(sw, "+1800-2005ext+", V3LangCode::L1800_2005)
|
||||
|| parseLangExt(sw, "+1800-2009ext+", V3LangCode::L1800_2009)
|
||||
|| parseLangExt(sw, "+1800-2012ext+", V3LangCode::L1800_2012)) {
|
||||
|| parseLangExt(sw, "+1800-2012ext+", V3LangCode::L1800_2012)
|
||||
|| parseLangExt(sw, "+1800-2017ext+", V3LangCode::L1800_2017)) {
|
||||
// Nothing to do here - all done in the test
|
||||
|
||||
}
|
||||
@@ -659,6 +660,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
else if ( onoff (sw, "-covsp", flag/*ref*/) ) { } // TBD
|
||||
else if ( !strcmp (sw, "-debug-abort") ) { abort(); } // Undocumented, see also --debug-sigsegv
|
||||
else if ( onoff (sw, "-debug-check", flag/*ref*/) ){ m_debugCheck = flag; }
|
||||
else if ( onoff (sw, "-debug-leak", flag/*ref*/) ){ m_debugLeak = flag; }
|
||||
else if ( !strcmp (sw, "-debug-sigsegv") ) { throwSigsegv(); } // Undocumented, see also --debug-abort
|
||||
else if ( !strcmp (sw, "-debug-fatalsrc") ) { v3fatalSrc("--debug-fatal-src"); } // Undocumented, see also --debug-abort
|
||||
else if ( onoff (sw, "-decoration", flag/*ref*/) ) { m_decoration = flag; }
|
||||
@@ -674,7 +676,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
else if ( onoff (sw, "-pins-sc-biguint", flag/*ref*/) ){ m_pinsScBigUint = flag; m_pinsBv = 513; }
|
||||
else if ( onoff (sw, "-pins-uint8", flag/*ref*/) ){ m_pinsUint8 = flag; }
|
||||
else if ( !strcmp (sw, "-private") ) { m_public = false; }
|
||||
else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/) ) { m_profileCFuncs = flag; }
|
||||
else if ( onoff (sw, "-prof-cfuncs", flag/*ref*/) ) { m_profCFuncs = flag; }
|
||||
else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/) ) { m_profCFuncs = flag; } // Undocumented, for backward compat
|
||||
else if ( onoff (sw, "-public", flag/*ref*/) ) { m_public = flag; }
|
||||
else if ( !strncmp(sw, "-pvalue+", strlen("-pvalue+"))) { addParameter(string(sw+strlen("-pvalue+")), false); }
|
||||
else if ( onoff (sw, "-relative-cfuncs", flag/*ref*/) ) { m_relativeCFuncs = flag; }
|
||||
@@ -1218,6 +1221,7 @@ V3Options::V3Options() {
|
||||
m_coverageUnderscore = false;
|
||||
m_coverageUser = false;
|
||||
m_debugCheck = false;
|
||||
m_debugLeak = true;
|
||||
m_decoration = true;
|
||||
m_exe = false;
|
||||
m_ignc = false;
|
||||
@@ -1231,7 +1235,7 @@ V3Options::V3Options() {
|
||||
m_pinsScUint = false;
|
||||
m_pinsScBigUint = false;
|
||||
m_pinsUint8 = false;
|
||||
m_profileCFuncs = false;
|
||||
m_profCFuncs = false;
|
||||
m_preprocOnly = false;
|
||||
m_preprocNoLine = false;
|
||||
m_public = false;
|
||||
@@ -1284,7 +1288,7 @@ V3Options::V3Options() {
|
||||
|
||||
VName::maxLength(128); // Linux filename limits 256; leave half for prefix
|
||||
|
||||
optimize(true);
|
||||
optimize(1);
|
||||
// Default +libext+
|
||||
addLibExtV(""); // So include "filename.v" will find the same file
|
||||
addLibExtV(".v");
|
||||
|
||||
+8
-5
@@ -75,6 +75,7 @@ class V3Options {
|
||||
bool m_coverageUnderscore;// main switch: --coverage-underscore
|
||||
bool m_coverageUser; // main switch: --coverage-func
|
||||
bool m_debugCheck; // main switch: --debug-check
|
||||
bool m_debugLeak; // main switch: --debug-leak
|
||||
bool m_decoration; // main switch: --decoration
|
||||
bool m_exe; // main switch: --exe
|
||||
bool m_ignc; // main switch: --ignc
|
||||
@@ -85,7 +86,7 @@ class V3Options {
|
||||
bool m_pinsScUint; // main switch: --pins-sc-uint
|
||||
bool m_pinsScBigUint;// main switch: --pins-sc-biguint
|
||||
bool m_pinsUint8; // main switch: --pins-uint8
|
||||
bool m_profileCFuncs;// main switch: --profile-cfuncs
|
||||
bool m_profCFuncs; // main switch: --prof-cfuncs
|
||||
bool m_public; // main switch: --public
|
||||
bool m_relativeCFuncs; // main switch: --relative-cfuncs
|
||||
bool m_relativeIncludes; // main switch: --relative-includes
|
||||
@@ -229,6 +230,7 @@ class V3Options {
|
||||
bool coverageUnderscore() const { return m_coverageUnderscore; }
|
||||
bool coverageUser() const { return m_coverageUser; }
|
||||
bool debugCheck() const { return m_debugCheck; }
|
||||
bool debugLeak() const { return m_debugLeak; }
|
||||
bool decoration() const { return m_decoration; }
|
||||
bool exe() const { return m_exe; }
|
||||
bool trace() const { return m_trace; }
|
||||
@@ -242,7 +244,7 @@ class V3Options {
|
||||
bool pinsScUint() const { return m_pinsScUint; }
|
||||
bool pinsScBigUint() const { return m_pinsScBigUint; }
|
||||
bool pinsUint8() const { return m_pinsUint8; }
|
||||
bool profileCFuncs() const { return m_profileCFuncs; }
|
||||
bool profCFuncs() const { return m_profCFuncs; }
|
||||
bool allPublic() const { return m_public; }
|
||||
bool lintOnly() const { return m_lintOnly; }
|
||||
bool ignc() const { return m_ignc; }
|
||||
@@ -263,7 +265,8 @@ class V3Options {
|
||||
int outputSplitCFuncs() const { return m_outputSplitCFuncs; }
|
||||
int outputSplitCTrace() const { return m_outputSplitCTrace; }
|
||||
int pinsBv() const { return m_pinsBv; }
|
||||
int threads() const { return m_threads; }
|
||||
int threads() const { return m_threads; }
|
||||
bool mtasks() const { return (m_threads > 1); }
|
||||
int traceDepth() const { return m_traceDepth; }
|
||||
int traceMaxArray() const { return m_traceMaxArray; }
|
||||
int traceMaxWidth() const { return m_traceMaxWidth; }
|
||||
@@ -293,8 +296,8 @@ class V3Options {
|
||||
const V3StringList& forceIncs() const { return m_forceIncs; }
|
||||
const V3LangCode& defaultLanguage() const { return m_defaultLanguage; }
|
||||
|
||||
bool hasParameter(string name);
|
||||
string parameter(string name);
|
||||
bool hasParameter(const string& name);
|
||||
string parameter(const string& name);
|
||||
void checkParameters();
|
||||
|
||||
bool isFuture(const string& flag) const;
|
||||
|
||||
+11
-7
@@ -548,7 +548,7 @@ private:
|
||||
: (domainp->hasSettle() ? "_settle"
|
||||
: (domainp->isMulti() ? "_multiclk" : "_sequent"))));
|
||||
name = name+"__"+scopep->nameDotless()+"__"+cvtToStr(funcnum);
|
||||
if (v3Global.opt.profileCFuncs()) {
|
||||
if (v3Global.opt.profCFuncs()) {
|
||||
name += "__PROF__"+forWhatp->fileline()->profileFuncname();
|
||||
}
|
||||
return name;
|
||||
@@ -1525,7 +1525,7 @@ void OrderVisitor::processMoveOne(OrderMoveVertex* vertexp, OrderMoveDomScope* d
|
||||
}
|
||||
else { // Normal logic
|
||||
// Make or borrow a CFunc to contain the new statements
|
||||
if (v3Global.opt.profileCFuncs()
|
||||
if (v3Global.opt.profCFuncs()
|
||||
|| (v3Global.opt.outputSplitCFuncs()
|
||||
&& v3Global.opt.outputSplitCFuncs() < m_pomNewStmts)) {
|
||||
// Put every statement into a unique function to ease profiling or reduce function size
|
||||
@@ -1566,14 +1566,16 @@ void OrderVisitor::processMoveOne(OrderMoveVertex* vertexp, OrderMoveDomScope* d
|
||||
processMoveDoneOne (vertexp);
|
||||
}
|
||||
|
||||
inline void OrderMoveDomScope::ready(OrderVisitor* ovp) { // Check the domScope is on ready list, add if not
|
||||
// Check the domScope is on ready list, add if not
|
||||
inline void OrderMoveDomScope::ready(OrderVisitor* ovp) {
|
||||
if (!m_onReadyList) {
|
||||
m_onReadyList = true;
|
||||
m_readyDomScopeE.pushBack(ovp->m_pomReadyDomScope, this);
|
||||
}
|
||||
}
|
||||
|
||||
inline void OrderMoveDomScope::movedVertex(OrderVisitor* ovp, OrderMoveVertex* vertexp) { // Mark one vertex as finished, remove from ready list if done
|
||||
// Mark one vertex as finished, remove from ready list if done
|
||||
inline void OrderMoveDomScope::movedVertex(OrderVisitor* ovp, OrderMoveVertex* vertexp) {
|
||||
UASSERT(m_onReadyList, "Moving vertex from ready when nothing was on que as ready.");
|
||||
if (m_readyVertices.empty()) { // Else more work to get to later
|
||||
m_onReadyList = false;
|
||||
@@ -1645,8 +1647,10 @@ void OrderVisitor::process() {
|
||||
|
||||
void V3Order::orderAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
OrderClkMarkVisitor markVisitor(nodep);
|
||||
OrderVisitor visitor;
|
||||
visitor.main(nodep);
|
||||
{
|
||||
OrderClkMarkVisitor markVisitor(nodep);
|
||||
OrderVisitor visitor;
|
||||
visitor.main(nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("order", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-1
@@ -38,7 +38,8 @@ public:
|
||||
static string filenameFromDirBase (const string& dir, const string& basename);
|
||||
static string filenameNonDir (const string& filename); ///< Return non-directory part of filename
|
||||
static string filenameNonExt (const string& filename); ///< Return non-extensioned (no .) part of filename
|
||||
static string filenameNonDirExt (const string& filename) { return filenameNonExt(filenameNonDir(filename)); } ///< Return basename of filename
|
||||
static string filenameNonDirExt (const string& filename) { ///< Return basename of filename
|
||||
return filenameNonExt(filenameNonDir(filename)); }
|
||||
static string filenameDir (const string& filename); ///< Return directory part of filename
|
||||
static string filenameSubstitute (const string& filename); ///< Return filename with env vars removed
|
||||
static string filenameRealPath(const string& fn); ///< Return realpath of filename
|
||||
|
||||
+11
-1
@@ -652,6 +652,14 @@ void ParamVisitor::visitCell(AstCell* nodep) {
|
||||
longname += "_" + paramSmallName(srcModp, pinp->modVarp()) + paramValueNumber(pinIrefp);
|
||||
any_overrides = true;
|
||||
ifaceRefRefs.push_back(make_pair(portIrefp,pinIrefp));
|
||||
if (portIrefp->ifacep() != pinIrefp->ifacep()
|
||||
// Might be different only due to param cloning, so check names too
|
||||
&& portIrefp->ifaceName() != pinIrefp->ifaceName()) {
|
||||
pinp->v3error("Port '"<<pinp->prettyName()<<"' expects '"
|
||||
<<AstNode::prettyName(portIrefp->ifaceName())
|
||||
<<"' interface but pin connects '"
|
||||
<<AstNode::prettyName(pinIrefp->ifaceName())<<"' interface");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -782,6 +790,8 @@ void ParamVisitor::visitCell(AstCell* nodep) {
|
||||
|
||||
void V3Param::param(AstNetlist* rootp) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ParamVisitor visitor (rootp);
|
||||
{
|
||||
ParamVisitor visitor (rootp);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("param", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
||||
+3
-1
@@ -427,6 +427,8 @@ public:
|
||||
|
||||
void V3Premit::premitAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
PremitVisitor visitor (nodep);
|
||||
{
|
||||
PremitVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("premit", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+10
-5
@@ -33,6 +33,8 @@
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
#include VL_INCLUDE_UNORDERED_MAP
|
||||
#include VL_INCLUDE_UNORDERED_SET
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Scope.h"
|
||||
@@ -50,9 +52,10 @@ private:
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// TYPES
|
||||
typedef map<AstPackage*, AstScope*> PackageScopeMap;
|
||||
typedef map<pair<AstVar*, AstScope*>, AstVarScope*> VarScopeMap;
|
||||
typedef set<pair<AstVarRef*, AstScope*> > VarRefScopeSet;
|
||||
typedef vl_unordered_map<AstPackage*, AstScope*> PackageScopeMap;
|
||||
// These cannot be unordered unless make a specialized hashing pair (gcc-8)
|
||||
typedef std::map<std::pair<AstVar*, AstScope*>, AstVarScope*> VarScopeMap;
|
||||
typedef std::set<std::pair<AstVarRef*, AstScope*> > VarRefScopeSet;
|
||||
|
||||
// STATE, inside processing a single module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
@@ -416,7 +419,9 @@ public:
|
||||
|
||||
void V3Scope::scopeAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ScopeVisitor visitor (nodep);
|
||||
ScopeCleanupVisitor cleanVisitor (nodep);
|
||||
{
|
||||
ScopeVisitor visitor (nodep);
|
||||
ScopeCleanupVisitor cleanVisitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("scope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+5
-2
@@ -718,7 +718,9 @@ private:
|
||||
nodep->bodysp()->iterateAndNext(*this);
|
||||
nodep->incsp()->iterateAndNext(*this);
|
||||
if (loops++ > unrollCount()*16) {
|
||||
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "+cvtToStr(unrollCount()));
|
||||
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an"
|
||||
"infinite loop, or set --unroll-count above "
|
||||
+ cvtToStr(unrollCount()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -752,7 +754,8 @@ private:
|
||||
|
||||
// Prep for next loop
|
||||
if (loops++ > unrollCount()*16) {
|
||||
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "+cvtToStr(unrollCount()));
|
||||
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite"
|
||||
" loop, or set --unroll-count above "+cvtToStr(unrollCount()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -74,7 +74,10 @@ class SliceVisitor : public AstNVisitor {
|
||||
// Insert an ArraySel, except for a few special cases
|
||||
AstUnpackArrayDType* arrayp = nodep->dtypep()->skipRefp()->castUnpackArrayDType();
|
||||
if (!arrayp) { // V3Width should have complained, but...
|
||||
if (!m_assignError) nodep->v3error(nodep->prettyTypeName()<<" is not an unpacked array, but is in an unpacked array context");
|
||||
if (!m_assignError) {
|
||||
nodep->v3error(nodep->prettyTypeName()
|
||||
<<" is not an unpacked array, but is in an unpacked array context");
|
||||
}
|
||||
m_assignError = true;
|
||||
return nodep->cloneTree(false); // Likely will cause downstream errors
|
||||
}
|
||||
@@ -239,6 +242,8 @@ public:
|
||||
|
||||
void V3Slice::sliceAll(AstNetlist* rootp) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
SliceVisitor visitor(rootp);
|
||||
{
|
||||
SliceVisitor visitor(rootp);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("slice", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+6
-2
@@ -578,11 +578,15 @@ public:
|
||||
|
||||
void V3Split::splitReorderAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
SplitVisitor visitor (nodep, true);
|
||||
{
|
||||
SplitVisitor visitor (nodep, true);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("reorder", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
void V3Split::splitAlwaysAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
SplitVisitor visitor (nodep, false);
|
||||
{
|
||||
SplitVisitor visitor (nodep, false);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("split", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
||||
+3
-1
@@ -215,6 +215,8 @@ public:
|
||||
|
||||
void V3SplitAs::splitAsAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
SplitAsVisitor visitor (nodep);
|
||||
{
|
||||
SplitAsVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("splitas", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+9
-2
@@ -69,6 +69,12 @@ bool VString::wildmatch(const char* s, const char* p) {
|
||||
return (*s == '\0');
|
||||
}
|
||||
|
||||
string VString::dot(const string& a, const string& dot, const string& b) {
|
||||
if (b=="") return a;
|
||||
if (a=="") return b;
|
||||
return a+dot+b;
|
||||
}
|
||||
|
||||
string VString::downcase(const string& str) {
|
||||
string out = str;
|
||||
for (string::iterator pos = out.begin(); pos != out.end(); ++pos) {
|
||||
@@ -205,7 +211,7 @@ string VHashSha1::digestBinary() {
|
||||
finalize();
|
||||
string out; out.reserve(20);
|
||||
for (size_t i=0; i<20; ++i) {
|
||||
out[i] = (m_inthash[i >> 2] >> (((3 - i) & 0x3) << 3)) & 0xff;
|
||||
out += (m_inthash[i >> 2] >> (((3 - i) & 0x3) << 3)) & 0xff;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -214,7 +220,8 @@ uint64_t VHashSha1::digestUInt64() {
|
||||
const string& binhash = digestBinary();
|
||||
uint64_t out = 0;
|
||||
for (size_t byte=0; byte<sizeof(uint64_t); ++byte) {
|
||||
out = (out<<8) | binhash[byte];
|
||||
unsigned char c = binhash[byte];
|
||||
out = (out<<8) | c;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -33,8 +33,13 @@ class VString {
|
||||
static bool wildmatchi(const char* s, const char* p);
|
||||
public:
|
||||
// METHODS (generic string utilities)
|
||||
// Return true if p with ? or *'s matches s
|
||||
static bool wildmatch(const char* s, const char* p);
|
||||
// Return {a}{dot}{b}, omitting dot if a or b are empty
|
||||
static string dot(const string& a, const string& dot, const string& b);
|
||||
// Convert string to lowercase
|
||||
static string downcase(const string& str);
|
||||
// Replace any %'s with %%
|
||||
static string quotePercent(const string& str);
|
||||
};
|
||||
|
||||
|
||||
+3
-1
@@ -400,6 +400,8 @@ public:
|
||||
|
||||
void V3Subst::substituteAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
SubstVisitor visitor (nodep);
|
||||
{
|
||||
SubstVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("subst", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+3
-1
@@ -66,10 +66,12 @@ private:
|
||||
static inline int debug() { return 0; } // NOT runtime, too hot of a function
|
||||
#endif
|
||||
public:
|
||||
void dumpIterate(ostream& os, VSymConstMap& doneSymsr, const string& indent, int numLevels, const string& searchName) const {
|
||||
void dumpIterate(ostream& os, VSymConstMap& doneSymsr, const string& indent,
|
||||
int numLevels, const string& searchName) const {
|
||||
os<<indent<<"+ "<<left<<setw(30)<<(searchName==""?"\"\"":searchName)<<setw(0)<<right;
|
||||
os<<" se"<<(void*)(this)<<setw(0);
|
||||
os<<" fallb=se"<<(void*)(m_fallbackp);
|
||||
if (m_symPrefix!="") os<<" symPrefix="<<m_symPrefix;
|
||||
os<<" n="<<nodep();
|
||||
os<<endl;
|
||||
if (doneSymsr.find(this) != doneSymsr.end()) {
|
||||
|
||||
+7
-2
@@ -305,7 +305,10 @@ private:
|
||||
|
||||
// Simulate
|
||||
simvis.mainTableEmulate(nodep);
|
||||
if (!simvis.optimizable()) simvis.whyNotNodep()->v3fatalSrc("Optimizable cleared, even though earlier test run said not: "<<simvis.whyNotMessage());
|
||||
if (!simvis.optimizable()) {
|
||||
simvis.whyNotNodep()->v3fatalSrc("Optimizable cleared, even though earlier test run said not: "
|
||||
<<simvis.whyNotMessage());
|
||||
}
|
||||
|
||||
// If a output changed, add it to table
|
||||
int outnum = 0;
|
||||
@@ -465,6 +468,8 @@ void TableSimulateVisitor::varRefCb(AstVarRef* nodep) {
|
||||
|
||||
void V3Table::tableAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
TableVisitor visitor (nodep);
|
||||
{
|
||||
TableVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("table", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+8
-5
@@ -600,7 +600,8 @@ private:
|
||||
bool bitvec = (portp->basicp()->keyword().isDpiBitVal() && portp->width() > 32);
|
||||
bool logicvec = (portp->basicp()->keyword().isDpiLogicVal() && portp->width() > 1);
|
||||
if (isRtn && (bitvec || logicvec)) {
|
||||
portp->v3error("DPI functions cannot return > 32 bits or four-state; use a two-state type or task instead: "<<portp->prettyName());
|
||||
portp->v3error("DPI functions cannot return > 32 bits or four-state;"
|
||||
" use a two-state type or task instead: "<<portp->prettyName());
|
||||
// Code below works, but won't compile right, and IEEE illegal
|
||||
}
|
||||
string stmt;
|
||||
@@ -795,7 +796,7 @@ private:
|
||||
makePortList(nodep, rtnvarp, dpip);
|
||||
}
|
||||
|
||||
bool duplicatedDpiProto(AstNodeFTask* nodep, string dpiproto) {
|
||||
bool duplicatedDpiProto(AstNodeFTask* nodep, const string& dpiproto) {
|
||||
// Only create one DPI extern prototype for each specified cname
|
||||
// as it's legal for the user to attach multiple tasks to one dpi cname
|
||||
DpiNames::iterator iter = m_dpiNames.find(nodep->cname());
|
||||
@@ -927,7 +928,7 @@ private:
|
||||
&& portp->dtypep()->basicp()
|
||||
&& portp->dtypep()->basicp()->keyword().isDpiUnreturnable()) {
|
||||
portp->v3error("DPI function may not return type "<<portp->basicp()->prettyTypeName()
|
||||
<<" (IEEE 2012 35.5.5)");
|
||||
<<" (IEEE 2017 35.5.5)");
|
||||
}
|
||||
portp->unlinkFrBack();
|
||||
rtnvarp = portp;
|
||||
@@ -1395,7 +1396,9 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
|
||||
|
||||
void V3Task::taskAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
TaskStateVisitor visitors (nodep);
|
||||
TaskVisitor visitor (nodep, &visitors);
|
||||
{
|
||||
TaskStateVisitor visitors (nodep);
|
||||
TaskVisitor visitor (nodep, &visitors);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("task", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-1
@@ -36,7 +36,8 @@ typedef vector<V3TaskConnect> V3TaskConnects; // [ [port, pin-connects-to] ... ]
|
||||
class V3Task {
|
||||
public:
|
||||
static void taskAll(AstNetlist* nodep);
|
||||
static V3TaskConnects taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp); // Return vector of [port, pin-connects-to] (SLOW)
|
||||
/// Return vector of [port, pin-connects-to] (SLOW)
|
||||
static V3TaskConnects taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+7
-2
@@ -205,7 +205,10 @@ private:
|
||||
if (TraceTraceVertex* vvertexp = dynamic_cast<TraceTraceVertex*>(itp)) {
|
||||
AstTraceInc* nodep = vvertexp->nodep();
|
||||
if (nodep->valuep()) {
|
||||
if (nodep->valuep()->backp() != nodep) nodep->v3fatalSrc("Trace duplicate back needs consistency, so we can map duplicates back to TRACEINCs");
|
||||
if (nodep->valuep()->backp() != nodep) {
|
||||
nodep->v3fatalSrc("Trace duplicate back needs consistency,"
|
||||
" so we can map duplicates back to TRACEINCs");
|
||||
}
|
||||
hashed.hash(nodep->valuep());
|
||||
UINFO(8, " Hashed "<<hex<<hashed.nodeHash(nodep->valuep())<<" "<<nodep<<endl);
|
||||
|
||||
@@ -712,6 +715,8 @@ public:
|
||||
|
||||
void V3Trace::traceAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
TraceVisitor visitor (nodep);
|
||||
{
|
||||
TraceVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("trace", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+3
-1
@@ -325,6 +325,8 @@ public:
|
||||
|
||||
void V3TraceDecl::traceDeclAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
TraceDeclVisitor visitor (nodep);
|
||||
{
|
||||
TraceDeclVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("tracedecl", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+40
-32
@@ -221,7 +221,8 @@ public:
|
||||
TristateVertex* vvertexp = static_cast<TristateVertex*>(itp);
|
||||
if (vvertexp->isTristate() && !vvertexp->processed()) {
|
||||
// Not v3errorSrc as no reason to stop the world
|
||||
vvertexp->nodep()->v3error("Unsupported tristate construct (in graph; not converted): "<<vvertexp->nodep()->prettyTypeName());
|
||||
vvertexp->nodep()->v3error("Unsupported tristate construct"
|
||||
" (in graph; not converted): "<<vvertexp->nodep()->prettyTypeName());
|
||||
}
|
||||
}
|
||||
m_graph.clear();
|
||||
@@ -984,32 +985,37 @@ class TristateVisitor : public TristateBaseVisitor {
|
||||
|
||||
virtual void visit(AstPull* nodep) {
|
||||
UINFO(9,dbgState()<<nodep<<endl);
|
||||
if (m_graphing) {
|
||||
if (AstVarRef* lhsp = nodep->lhsp()->castVarRef()) {
|
||||
lhsp->lvalue(true);
|
||||
m_logicp = nodep;
|
||||
m_tgraph.setTristate(nodep);
|
||||
associateLogic(nodep, lhsp->varp());
|
||||
m_logicp = NULL;
|
||||
} else {
|
||||
nodep->v3error("Unsupported pullup/down (weak driver) construct.");
|
||||
}
|
||||
} else {
|
||||
// Replace any pullup/pulldowns with assignw logic and set the
|
||||
// direction of the pull in the user3() data on the var. Given
|
||||
// the complexity of merging tristate drivers at any level, the
|
||||
// current limitation of this implementation is that a pullup/down
|
||||
// gets applied to all bits of a bus and a bus cannot have drivers
|
||||
// in opposite directions on indvidual pins.
|
||||
if (AstVarRef* lhsp = nodep->lhsp()->castVarRef()) {
|
||||
lhsp->lvalue(true);
|
||||
m_tgraph.didProcess(nodep);
|
||||
m_tgraph.didProcess(lhsp->varp());
|
||||
AstVar* varp = lhsp->varp();
|
||||
setPullDirection(varp, nodep);
|
||||
} else {
|
||||
nodep->v3error("Unsupported pullup/down (weak driver) construct.");
|
||||
}
|
||||
AstVarRef* varrefp = NULL;
|
||||
if (nodep->lhsp()->castVarRef()) {
|
||||
varrefp = nodep->lhsp()->castVarRef();
|
||||
} else if (nodep->lhsp()->castSel()
|
||||
&& nodep->lhsp()->castSel()->fromp()->castVarRef()) {
|
||||
varrefp = nodep->lhsp()->castSel()->fromp()->castVarRef();
|
||||
}
|
||||
if (!varrefp) {
|
||||
if (debug()>=4) nodep->dumpTree(cout, "- ");
|
||||
nodep->v3error("Unsupported pullup/down (weak driver) construct.");
|
||||
} else {
|
||||
if (m_graphing) {
|
||||
varrefp->lvalue(true);
|
||||
m_logicp = nodep;
|
||||
m_tgraph.setTristate(nodep);
|
||||
associateLogic(nodep, varrefp->varp());
|
||||
m_logicp = NULL;
|
||||
} else {
|
||||
// Replace any pullup/pulldowns with assignw logic and set the
|
||||
// direction of the pull in the user3() data on the var. Given
|
||||
// the complexity of merging tristate drivers at any level, the
|
||||
// current limitation of this implementation is that a pullup/down
|
||||
// gets applied to all bits of a bus and a bus cannot have drivers
|
||||
// in opposite directions on indvidual pins.
|
||||
varrefp->lvalue(true);
|
||||
m_tgraph.didProcess(nodep);
|
||||
m_tgraph.didProcess(varrefp->varp());
|
||||
setPullDirection(varrefp->varp(), nodep);
|
||||
}
|
||||
}
|
||||
if (!m_graphing) {
|
||||
nodep->unlinkFrBack();
|
||||
pushDeletep(nodep); VL_DANGLING(nodep); // Node must persist as user3p points to it
|
||||
}
|
||||
@@ -1060,7 +1066,7 @@ class TristateVisitor : public TristateBaseVisitor {
|
||||
if (!enModVarp) {
|
||||
if (nodep->exprp()) {
|
||||
// May have an output only that later connects to a tristate, so simplify now.
|
||||
V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, false);
|
||||
V3Inst::pinReconnectSimple(nodep, m_cellp, false);
|
||||
}
|
||||
iteratePinGuts(nodep);
|
||||
return; // No __en signals on this pin
|
||||
@@ -1086,7 +1092,7 @@ class TristateVisitor : public TristateBaseVisitor {
|
||||
} else if (inDeclProcessing) { // Not an input that was a converted tristate
|
||||
// Input only may have driver in underneath module which would stomp
|
||||
// the input value. So make a temporary connection.
|
||||
AstAssignW* reAssignp = V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, true, true);
|
||||
AstAssignW* reAssignp = V3Inst::pinReconnectSimple(nodep, m_cellp, true, true);
|
||||
UINFO(5,"Input pin buffering: "<<reAssignp<<endl);
|
||||
m_tgraph.setTristate(reAssignp->lhsp());
|
||||
}
|
||||
@@ -1140,7 +1146,7 @@ class TristateVisitor : public TristateBaseVisitor {
|
||||
TristatePinVisitor visitor (outexprp, m_tgraph, true);
|
||||
}
|
||||
if (debug()>=9) outpinp->dumpTree(cout,"-pin-opr: ");
|
||||
outAssignp = V3Inst::pinReconnectSimple(outpinp, m_cellp, m_modp, true); // Note may change outpinp->exprp()
|
||||
outAssignp = V3Inst::pinReconnectSimple(outpinp, m_cellp, true); // Note may change outpinp->exprp()
|
||||
if (debug()>=9) outpinp->dumpTree(cout,"-pin-out: ");
|
||||
if (debug()>=9 && outAssignp) outAssignp->dumpTree(cout,"-pin-out: ");
|
||||
// Must still iterate the outAssignp, as need to build output equation
|
||||
@@ -1148,7 +1154,7 @@ class TristateVisitor : public TristateBaseVisitor {
|
||||
|
||||
// Existing pin becomes an input, and we mark each resulting signal as tristate
|
||||
TristatePinVisitor visitor (nodep->exprp(), m_tgraph, false);
|
||||
AstNode* inAssignp = V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, true); // Note may change nodep->exprp()
|
||||
AstNode* inAssignp = V3Inst::pinReconnectSimple(nodep, m_cellp, true); // Note may change nodep->exprp()
|
||||
if (debug()>=9) nodep->dumpTree(cout,"-pin-in: ");
|
||||
if (debug()>=9 && inAssignp) inAssignp->dumpTree(cout,"-pin-as: ");
|
||||
|
||||
@@ -1336,6 +1342,8 @@ public:
|
||||
|
||||
void V3Tristate::tristateAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
TristateVisitor visitor (nodep);
|
||||
{
|
||||
TristateVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("tristate", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+3
-1
@@ -479,6 +479,8 @@ public:
|
||||
|
||||
void V3Unknown::unknownAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UnknownVisitor visitor (nodep);
|
||||
{
|
||||
UnknownVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("unknown", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+14
-9
@@ -185,10 +185,11 @@ private:
|
||||
}
|
||||
|
||||
bool canSimulate(AstNode *nodep) {
|
||||
SimulateVisitor simvis;
|
||||
AstNode* clone = nodep->cloneTree(true);
|
||||
simvis.mainCheckTree(clone);
|
||||
return simvis.optimizable();
|
||||
SimulateVisitor simvis;
|
||||
AstNode* clonep = nodep->cloneTree(true);
|
||||
simvis.mainCheckTree(clonep);
|
||||
pushDeletep(clonep); clonep = NULL;
|
||||
return simvis.optimizable();
|
||||
}
|
||||
|
||||
bool simulateTree(AstNode *nodep, const V3Number *loopValue, AstNode *dtypep, V3Number &outNum) {
|
||||
@@ -333,7 +334,9 @@ private:
|
||||
|
||||
++m_statIters;
|
||||
if (++times > unrollCount()*3) {
|
||||
nodep->v3error("Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "<<unrollCount());
|
||||
nodep->v3error("Loop unrolling took too long;"
|
||||
" probably this is an infinite loop, or set --unroll-count above "
|
||||
<<unrollCount());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -455,7 +458,7 @@ private:
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
UnrollVisitor(AstNode* nodep, bool generate, string beginName) {
|
||||
UnrollVisitor(AstNode* nodep, bool generate, const string& beginName) {
|
||||
m_forVarp = NULL;
|
||||
m_forVscp = NULL;
|
||||
m_ignoreIncp = NULL;
|
||||
@@ -477,11 +480,13 @@ public:
|
||||
|
||||
void V3Unroll::unrollAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UnrollVisitor visitor (nodep, false, "");
|
||||
{
|
||||
UnrollVisitor visitor (nodep, false, "");
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("unroll", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Unroll::unrollGen(AstNodeFor* nodep, string beginName) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
void V3Unroll::unrollGen(AstNodeFor* nodep, const string& beginName) {
|
||||
UINFO(5,__FUNCTION__<<": "<<endl);
|
||||
UnrollVisitor visitor (nodep, true, beginName);
|
||||
}
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@
|
||||
class V3Unroll {
|
||||
public:
|
||||
static void unrollAll(AstNetlist* nodep);
|
||||
static void unrollGen(AstNodeFor* nodep, string beginName);
|
||||
static void unrollGen(AstNodeFor* nodep, const string& beginName);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+51
-31
@@ -299,14 +299,10 @@ private:
|
||||
virtual void visit(AstDivD* nodep) { visit_real_add_sub(nodep); }
|
||||
virtual void visit(AstMulD* nodep) { visit_real_add_sub(nodep); }
|
||||
virtual void visit(AstPowD* nodep) { visit_real_add_sub(nodep); }
|
||||
virtual void visit(AstNodeSystemBiop* nodep) { visit_real_add_sub(nodep); }
|
||||
// Real: Output real
|
||||
virtual void visit(AstNegateD* nodep) { visit_real_neg_ceil(nodep); }
|
||||
virtual void visit(AstCeilD* nodep) { visit_real_neg_ceil(nodep); }
|
||||
virtual void visit(AstExpD* nodep) { visit_real_neg_ceil(nodep); }
|
||||
virtual void visit(AstFloorD* nodep) { visit_real_neg_ceil(nodep); }
|
||||
virtual void visit(AstLogD* nodep) { visit_real_neg_ceil(nodep); }
|
||||
virtual void visit(AstLog10D* nodep) { visit_real_neg_ceil(nodep); }
|
||||
virtual void visit(AstSqrtD* nodep) { visit_real_neg_ceil(nodep); }
|
||||
virtual void visit(AstNodeSystemUniop* nodep) { visit_real_neg_ceil(nodep); }
|
||||
|
||||
// Widths: out signed/unsigned width = lhs width, input un|signed
|
||||
virtual void visit(AstSigned* nodep) { visit_signed_unsigned(nodep, AstNumeric::SIGNED); }
|
||||
@@ -450,7 +446,7 @@ private:
|
||||
if (!constp) { nodep->v3error("Replication value isn't a constant."); return; }
|
||||
uint32_t times = constp->toUInt();
|
||||
if (times==0 && !nodep->backp()->castConcat()) { // Concat Visitor will clean it up.
|
||||
nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE 2012 11.4.12.1)"); times=1;
|
||||
nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE 2017 11.4.12.1)"); times=1;
|
||||
}
|
||||
if (nodep->lhsp()->isString()) {
|
||||
AstNode* newp = new AstReplicateN(nodep->fileline(),nodep->lhsp()->unlinkFrBack(),
|
||||
@@ -481,7 +477,7 @@ private:
|
||||
if (!constp) { nodep->v3error("Replication value isn't a constant."); return; }
|
||||
uint32_t times = constp->toUInt();
|
||||
if (times==0 && !nodep->backp()->castConcat()) { // Concat Visitor will clean it up.
|
||||
nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE 2012 11.4.12.1)");
|
||||
nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE 2017 11.4.12.1)");
|
||||
}
|
||||
nodep->dtypeSetString();
|
||||
}
|
||||
@@ -556,6 +552,7 @@ private:
|
||||
// LSB is self-determined (IEEE 2012 11.5.1)
|
||||
// We also use SELs to shorten a signed constant etc, in this case they are signed.
|
||||
if (nodep->didWidth()) return;
|
||||
if (!m_vup) nodep->v3fatalSrc("Select under an unexpected context");
|
||||
if (m_vup->prelim()) {
|
||||
if (debug()>=9) nodep->dumpTree(cout,"-selWidth: ");
|
||||
userIterateAndNext(nodep->fromp(), WidthVP(CONTEXT,PRELIM).p());
|
||||
@@ -949,6 +946,10 @@ private:
|
||||
}
|
||||
m_attrp = oldAttr;
|
||||
}
|
||||
virtual void visit(AstPull* nodep) {
|
||||
// May have select underneath, let seek natural size
|
||||
userIterateChildren(nodep, WidthVP(SELF,BOTH).p());
|
||||
}
|
||||
virtual void visit(AstText* nodep) {
|
||||
// Only used in CStmts which don't care....
|
||||
}
|
||||
@@ -1197,7 +1198,9 @@ private:
|
||||
if (nodep->valuep()->dtypep()->widthSized()) {
|
||||
width = nodep->valuep()->width();
|
||||
} else {
|
||||
if (nodep->valuep()->width()>32) nodep->valuep()->v3warn(WIDTH,"Assigning >32 bit to unranged parameter (defaults to 32 bits)");
|
||||
if (nodep->valuep()->width()>32) {
|
||||
nodep->valuep()->v3warn(WIDTH,"Assigning >32 bit to unranged parameter (defaults to 32 bits)");
|
||||
}
|
||||
width = 32;
|
||||
}
|
||||
// Can't just inherit valuep()->dtypep() as mwidth might not equal width
|
||||
@@ -1242,7 +1245,8 @@ private:
|
||||
if (nodep->didWidth()) return;
|
||||
if (!nodep->varp()) {
|
||||
if (m_paramsOnly && nodep->castVarXRef()) {
|
||||
checkConstantOrReplace(nodep, "Parameter-resolved constants must not use dotted references: "+nodep->prettyName()); VL_DANGLING(nodep);
|
||||
checkConstantOrReplace(nodep, "Parameter-resolved constants must not use dotted references: "
|
||||
+nodep->prettyName()); VL_DANGLING(nodep);
|
||||
return;
|
||||
} else {
|
||||
nodep->v3fatalSrc("Unlinked varref");
|
||||
@@ -1294,7 +1298,7 @@ private:
|
||||
}
|
||||
if (!itemp->valuep()) {
|
||||
if (num.isEqZero() && itemp != nodep->itemsp())
|
||||
itemp->v3error("Enum value illegally wrapped around (IEEE 2012 6.19)");
|
||||
itemp->v3error("Enum value illegally wrapped around (IEEE 2017 6.19)");
|
||||
if (!nodep->dtypep()->basicp()
|
||||
&& !nodep->dtypep()->basicp()->keyword().isIntNumeric()) {
|
||||
itemp->v3error("Enum names without values only allowed on numeric types");
|
||||
@@ -1491,13 +1495,15 @@ private:
|
||||
} else {
|
||||
AstSel* newp = new AstSel(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
memberp->lsb(), memberp->width());
|
||||
newp->dtypep(memberp->subDTypep()->skipRefToEnump()); // Must skip over the member to find the union; as the member may disappear later
|
||||
// Must skip over the member to find the union; as the member may disappear later
|
||||
newp->dtypep(memberp->subDTypep()->skipRefToEnump());
|
||||
newp->didWidth(true); // Don't replace dtype with basic type
|
||||
UINFO(9," MEMBERSEL -> "<<newp<<endl);
|
||||
UINFO(9," dt-> "<<newp->dtypep()<<endl);
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
// Should be able to treat it as a normal-ish nodesel - maybe. The lhsp() will be strange until this stage; create the number here?
|
||||
// Should be able to treat it as a normal-ish nodesel - maybe.
|
||||
// The lhsp() will be strange until this stage; create the number here?
|
||||
}
|
||||
}
|
||||
if (!memberp) { // Very bogus, but avoids core dump
|
||||
@@ -1659,7 +1665,9 @@ private:
|
||||
nodep->dtypep(m_vup->dtypep());
|
||||
}
|
||||
AstNodeDType* vdtypep = nodep->dtypep();
|
||||
if (!vdtypep) nodep->v3error("Unsupported/Illegal: Assignment pattern member not underneath a supported construct: "<<nodep->backp()->prettyTypeName());
|
||||
if (!vdtypep) nodep->v3error("Unsupported/Illegal: Assignment pattern"
|
||||
" member not underneath a supported construct: "
|
||||
<<nodep->backp()->prettyTypeName());
|
||||
{
|
||||
vdtypep = vdtypep->skipRefp();
|
||||
nodep->dtypep(vdtypep);
|
||||
@@ -1719,7 +1727,8 @@ private:
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
patp->keyp()->v3error("Assignment pattern key not supported/understood: "<<patp->keyp()->prettyTypeName());
|
||||
patp->keyp()->v3error("Assignment pattern key not"
|
||||
" supported/understood: "<<patp->keyp()->prettyTypeName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2187,16 +2196,21 @@ private:
|
||||
nodep->dtypeSetSigned32(); // Spec says integer return
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSysFuncAsTask* nodep) {
|
||||
assertAtStatement(nodep);
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP(SELF,BOTH).p());
|
||||
}
|
||||
virtual void visit(AstSystemT* nodep) {
|
||||
assertAtStatement(nodep);
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP(SELF,BOTH).p());
|
||||
}
|
||||
virtual void visit(AstReadMem* nodep) {
|
||||
virtual void visit(AstNodeReadWriteMem* nodep) {
|
||||
assertAtStatement(nodep);
|
||||
userIterateAndNext(nodep->filenamep(), WidthVP(SELF,BOTH).p());
|
||||
userIterateAndNext(nodep->memp(), WidthVP(SELF,BOTH).p());
|
||||
if (!nodep->memp()->dtypep()->skipRefp()->castUnpackArrayDType()) {
|
||||
nodep->memp()->v3error("Unsupported: $readmem into other than unpacked array");
|
||||
nodep->memp()->v3error("Unsupported: " << nodep->verilogKwd()
|
||||
<< " into other than unpacked array");
|
||||
}
|
||||
userIterateAndNext(nodep->lsbp(), WidthVP(SELF,BOTH).p());
|
||||
userIterateAndNext(nodep->msbp(), WidthVP(SELF,BOTH).p());
|
||||
@@ -2213,7 +2227,7 @@ private:
|
||||
assertAtStatement(nodep);
|
||||
userIterateChildren(nodep, WidthVP(SELF,BOTH).p());
|
||||
}
|
||||
virtual void visit(AstPslCover* nodep) {
|
||||
virtual void visit(AstNodePslCoverOrAssert* nodep) {
|
||||
assertAtStatement(nodep);
|
||||
iterateCheckBool(nodep,"Property",nodep->propp(),BOTH); // it's like an if() condition.
|
||||
userIterateAndNext(nodep->stmtsp(), NULL);
|
||||
@@ -2949,9 +2963,12 @@ private:
|
||||
bool widthBad (AstNode* nodep, AstNodeDType* expDTypep) {
|
||||
int expWidth = expDTypep->width();
|
||||
int expWidthMin = expDTypep->widthMin();
|
||||
if (!nodep->dtypep()) nodep->v3fatalSrc("Under node "<<nodep->prettyTypeName()<<" has no dtype?? Missing Visitor func?");
|
||||
if (nodep->width()==0) nodep->v3fatalSrc("Under node "<<nodep->prettyTypeName()<<" has no expected width?? Missing Visitor func?");
|
||||
if (expWidth==0) nodep->v3fatalSrc("Node "<<nodep->prettyTypeName()<<" has no expected width?? Missing Visitor func?");
|
||||
if (!nodep->dtypep()) nodep->v3fatalSrc("Under node "<<nodep->prettyTypeName()
|
||||
<<" has no dtype?? Missing Visitor func?");
|
||||
if (nodep->width()==0) nodep->v3fatalSrc("Under node "<<nodep->prettyTypeName()
|
||||
<<" has no expected width?? Missing Visitor func?");
|
||||
if (expWidth==0) nodep->v3fatalSrc("Node "<<nodep->prettyTypeName()
|
||||
<<" has no expected width?? Missing Visitor func?");
|
||||
if (expWidthMin==0) expWidthMin = expWidth;
|
||||
if (nodep->dtypep()->width() == expWidth) return false;
|
||||
if (nodep->dtypep()->widthSized() && nodep->width() != expWidthMin) return true;
|
||||
@@ -3155,8 +3172,7 @@ private:
|
||||
} else {
|
||||
bool bad = widthBad(underp,nodep->findLogicBoolDType());
|
||||
if (bad) {
|
||||
bool warnOn = true; // Not used
|
||||
if (warnOn) {
|
||||
{ // if (warnOn), but not needed here
|
||||
if (debug()>4) nodep->backp()->dumpTree(cout," back: ");
|
||||
nodep->v3warn(WIDTH,"Logical Operator "<<nodep->prettyTypeName()
|
||||
<<" expects 1 bit on the "<<side<<", but "<<side<<"'s "
|
||||
@@ -3653,7 +3669,7 @@ private:
|
||||
// Find valid values and populate
|
||||
if (!nodep->itemsp()) nodep->v3fatalSrc("enum without items");
|
||||
vector<AstNode*> values;
|
||||
values.reserve(msbdim+1);
|
||||
values.resize(msbdim+1);
|
||||
for (unsigned i=0; i<(msbdim+1); ++i) {
|
||||
values[i] = NULL;
|
||||
}
|
||||
@@ -3858,12 +3874,14 @@ int V3Width::debug() {
|
||||
|
||||
void V3Width::width(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
// We should do it in bottom-up module order, but it works in any order.
|
||||
WidthClearVisitor cvisitor (nodep);
|
||||
WidthVisitor visitor (false, false);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
WidthRemoveVisitor rvisitor;
|
||||
(void)rvisitor.mainAcceptEdit(nodep);
|
||||
{
|
||||
// We should do it in bottom-up module order, but it works in any order.
|
||||
WidthClearVisitor cvisitor (nodep);
|
||||
WidthVisitor visitor (false, false);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
WidthRemoveVisitor rvisitor;
|
||||
(void)rvisitor.mainAcceptEdit(nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("width", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
@@ -3899,6 +3917,8 @@ AstNode* V3Width::widthGenerateParamsEdit(
|
||||
|
||||
void V3Width::widthCommit(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
WidthCommitVisitor visitor (nodep);
|
||||
{
|
||||
WidthCommitVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("widthcommit", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user